Red Bear OS kernel baseline
From release 0.1.0 pre-patched archive. This includes all Red Bear modifications previously maintained as patches in local/patches/kernel/.
This commit is contained in:
@@ -0,0 +1,91 @@
|
||||
use core::sync::{
|
||||
atomic,
|
||||
atomic::{AtomicU32, AtomicUsize, Ordering},
|
||||
};
|
||||
use rmm::{PageMapper, TableKind};
|
||||
|
||||
const NO_PROCESSOR: u32 = !0;
|
||||
static LOCK_OWNER: AtomicU32 = AtomicU32::new(NO_PROCESSOR);
|
||||
static LOCK_COUNT: AtomicUsize = AtomicUsize::new(0);
|
||||
|
||||
// TODO: Support, perhaps via const generics, embedding address checking in PageMapper, thereby
|
||||
// statically enforcing that the kernel mapper can only map things in the kernel half, and vice
|
||||
// versa.
|
||||
/// A guard to the global lock protecting the upper 128 TiB of kernel address space.
|
||||
///
|
||||
/// NOTE: Use this with great care! Since heap allocations may also require this lock when the heap
|
||||
/// needs to be expended, it must not be held while memory allocations are done!
|
||||
// TODO: Make the lock finer-grained so that e.g. the heap part can be independent from e.g.
|
||||
// PHYS_PML4?
|
||||
pub struct KernelMapper<const RW: bool> {
|
||||
mapper: crate::memory::PageMapper,
|
||||
}
|
||||
|
||||
impl KernelMapper<false> {
|
||||
pub fn lock_ro() -> Self {
|
||||
KernelMapper::lock()
|
||||
}
|
||||
}
|
||||
|
||||
impl KernelMapper<true> {
|
||||
pub fn lock_rw() -> Self {
|
||||
KernelMapper::lock()
|
||||
}
|
||||
}
|
||||
|
||||
impl<const RW: bool> KernelMapper<RW> {
|
||||
fn lock() -> Self {
|
||||
let mapper =
|
||||
unsafe { PageMapper::current(TableKind::Kernel, crate::memory::TheFrameAllocator) };
|
||||
|
||||
let current_processor = crate::cpu_id();
|
||||
loop {
|
||||
match LOCK_OWNER.compare_exchange_weak(
|
||||
NO_PROCESSOR,
|
||||
current_processor.get(),
|
||||
Ordering::Acquire,
|
||||
Ordering::Relaxed,
|
||||
) {
|
||||
Ok(_) => break,
|
||||
// already owned by this hardware thread
|
||||
Err(id) if id == current_processor.get() => break,
|
||||
// either CAS failed, or some other hardware thread holds the lock
|
||||
Err(_) => core::hint::spin_loop(),
|
||||
}
|
||||
}
|
||||
|
||||
let prev_count = LOCK_COUNT.fetch_add(1, Ordering::Relaxed);
|
||||
atomic::compiler_fence(Ordering::Acquire);
|
||||
|
||||
let ro = prev_count > 0;
|
||||
|
||||
if RW && ro {
|
||||
panic!("KernelMapper locked re-entrant when write access is requested");
|
||||
}
|
||||
|
||||
Self { mapper }
|
||||
}
|
||||
}
|
||||
|
||||
impl<const RW: bool> core::ops::Deref for KernelMapper<RW> {
|
||||
type Target = crate::memory::PageMapper;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.mapper
|
||||
}
|
||||
}
|
||||
|
||||
impl core::ops::DerefMut for KernelMapper<true> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.mapper
|
||||
}
|
||||
}
|
||||
|
||||
impl<const RW: bool> Drop for KernelMapper<RW> {
|
||||
fn drop(&mut self) {
|
||||
if LOCK_COUNT.fetch_sub(1, Ordering::Relaxed) == 1 {
|
||||
LOCK_OWNER.store(NO_PROCESSOR, Ordering::Release);
|
||||
}
|
||||
atomic::compiler_fence(Ordering::Release);
|
||||
}
|
||||
}
|
||||
+1090
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,85 @@
|
||||
// Some code was borrowed from [Phil Opp's Blog](http://os.phil-opp.com/modifying-page-tables.html)
|
||||
|
||||
use core::fmt::Debug;
|
||||
use rmm::{Arch, VirtualAddress};
|
||||
|
||||
use crate::memory::RmmA;
|
||||
|
||||
/// Size of pages
|
||||
pub const PAGE_SIZE: usize = RmmA::PAGE_SIZE;
|
||||
pub const PAGE_MASK: usize = RmmA::PAGE_OFFSET_MASK;
|
||||
|
||||
/// Page
|
||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
|
||||
pub struct Page {
|
||||
number: usize,
|
||||
}
|
||||
|
||||
impl Page {
|
||||
pub fn start_address(self) -> VirtualAddress {
|
||||
VirtualAddress::new(self.number * PAGE_SIZE)
|
||||
}
|
||||
|
||||
pub fn containing_address(address: VirtualAddress) -> Page {
|
||||
//TODO assert!(address.data() < 0x0000_8000_0000_0000 || address.data() >= 0xffff_8000_0000_0000,
|
||||
// "invalid address: 0x{:x}", address.data());
|
||||
Page {
|
||||
number: address.data() / PAGE_SIZE,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn range_inclusive(start: Page, r#final: Page) -> PageIter {
|
||||
PageIter {
|
||||
start,
|
||||
end: r#final.next(),
|
||||
}
|
||||
}
|
||||
pub fn next(self) -> Page {
|
||||
self.next_by(1)
|
||||
}
|
||||
pub fn next_by(self, n: usize) -> Page {
|
||||
Self {
|
||||
number: self.number + n,
|
||||
}
|
||||
}
|
||||
pub fn offset_from(self, other: Self) -> usize {
|
||||
self.number - other.number
|
||||
}
|
||||
}
|
||||
impl Debug for Page {
|
||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"[page at {:p}]",
|
||||
self.start_address().data() as *const u8
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct PageIter {
|
||||
start: Page,
|
||||
end: Page,
|
||||
}
|
||||
|
||||
impl Iterator for PageIter {
|
||||
type Item = Page;
|
||||
|
||||
fn next(&mut self) -> Option<Page> {
|
||||
if self.start < self.end {
|
||||
let page = self.start;
|
||||
self.start = self.start.next();
|
||||
Some(page)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Round down to the nearest multiple of page size
|
||||
pub fn round_down_pages(number: usize) -> usize {
|
||||
number.div_floor(PAGE_SIZE) * PAGE_SIZE
|
||||
}
|
||||
/// Round up to the nearest multiple of page size
|
||||
pub fn round_up_pages(number: usize) -> usize {
|
||||
number.next_multiple_of(PAGE_SIZE)
|
||||
}
|
||||
Reference in New Issue
Block a user