Compare commits
No commits in common. "238e822751558e1a8eca5d380ee88f326b2c3729" and "8f441135e073d3f86cbd247155f6c0e1a27321a1" have entirely different histories.
238e822751
...
8f441135e0
|
|
@ -1,4 +1,3 @@
|
||||||
use core::fmt::Debug;
|
|
||||||
use core::marker::PhantomData;
|
use core::marker::PhantomData;
|
||||||
use core::mem;
|
use core::mem;
|
||||||
use core::ops::Not;
|
use core::ops::Not;
|
||||||
|
|
@ -658,15 +657,6 @@ pub struct RBTree<N: UnsafeNode> {
|
||||||
root: Option<NonNull<N>>,
|
root: Option<NonNull<N>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<N: UnsafeNode> Debug for RBTree<N>
|
|
||||||
where
|
|
||||||
N::Key: Debug,
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.debug_set().entries(self.iter()).finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<N: UnsafeNode> RBTree<N> {
|
impl<N: UnsafeNode> RBTree<N> {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { root: None }
|
Self { root: None }
|
||||||
|
|
@ -1163,9 +1153,7 @@ impl<'a, N: UnsafeNode + 'a> Iterator for TreeIter<'a, N> {
|
||||||
fn next(&mut self) -> Option<Self::Item> {
|
fn next(&mut self) -> Option<Self::Item> {
|
||||||
self.range
|
self.range
|
||||||
.next()
|
.next()
|
||||||
.as_ref()
|
.map(|n| unsafe { n.node().unwrap().as_ref().key() })
|
||||||
.and_then(Handle::node)
|
|
||||||
.map(|n| unsafe { n.as_ref().key() })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1173,9 +1161,7 @@ impl<'a, N: UnsafeNode + 'a> DoubleEndedIterator for TreeIter<'a, N> {
|
||||||
fn next_back(&mut self) -> Option<Self::Item> {
|
fn next_back(&mut self) -> Option<Self::Item> {
|
||||||
self.range
|
self.range
|
||||||
.next_back()
|
.next_back()
|
||||||
.as_ref()
|
.map(|n| unsafe { n.node().unwrap().as_ref().key() })
|
||||||
.and_then(Handle::node)
|
|
||||||
.map(|n| unsafe { n.as_ref().key() })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,7 +20,6 @@ harness = false
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "stack_overflow"
|
name = "stack_overflow"
|
||||||
harness = false
|
harness = false
|
||||||
test = false # currently doesn't work reliably because the stack corrupts something
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
bit_field = "0.10.3"
|
bit_field = "0.10.3"
|
||||||
|
|
|
||||||
|
|
@ -100,19 +100,12 @@ const impl Default for MemoryRegion {
|
||||||
pub struct BootInfo {
|
pub struct BootInfo {
|
||||||
pub hhdm_base: u64,
|
pub hhdm_base: u64,
|
||||||
pub memory_map: &'static [MemoryRegion],
|
pub memory_map: &'static [MemoryRegion],
|
||||||
pub executable_file: Option<&'static [u8]>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub static BOOT_INFO: OnceLock<BootInfo> = OnceLock::new();
|
pub static BOOT_INFO: OnceLock<BootInfo> = OnceLock::new();
|
||||||
static mut MEMORY_MAP: [MemoryRegion; 128] = [MemoryRegion::default(); 128];
|
static mut MEMORY_MAP: [MemoryRegion; 128] = [MemoryRegion::default(); 128];
|
||||||
|
|
||||||
pub fn init_boot_info<I: Iterator<Item = MemoryRegion>>(
|
pub fn init_boot_info<I: Iterator<Item = MemoryRegion>>(hhdm_base: u64, memory_map: I) {
|
||||||
hhdm_base: u64,
|
|
||||||
memory_map: I,
|
|
||||||
executable_file: Option<&'static [u8]>,
|
|
||||||
) {
|
|
||||||
_ = crate::memory::HHDM_BASE.try_insert(hhdm_base);
|
|
||||||
|
|
||||||
BOOT_INFO.initialize(|| {
|
BOOT_INFO.initialize(|| {
|
||||||
for (i, region) in memory_map.enumerate() {
|
for (i, region) in memory_map.enumerate() {
|
||||||
assert!(i < 128, "Memory map has more than 128 entries");
|
assert!(i < 128, "Memory map has more than 128 entries");
|
||||||
|
|
@ -124,7 +117,6 @@ pub fn init_boot_info<I: Iterator<Item = MemoryRegion>>(
|
||||||
Ok::<_, !>(BootInfo {
|
Ok::<_, !>(BootInfo {
|
||||||
hhdm_base,
|
hhdm_base,
|
||||||
memory_map: unsafe { (&raw const MEMORY_MAP).as_ref_unchecked() },
|
memory_map: unsafe { (&raw const MEMORY_MAP).as_ref_unchecked() },
|
||||||
executable_file,
|
|
||||||
})
|
})
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,4 @@
|
||||||
use core::{cell::UnsafeCell, fmt::Debug, ptr::NonNull};
|
use core::{cell::UnsafeCell, ffi::CStr, fmt::Debug, ptr::NonNull};
|
||||||
|
|
||||||
use crate::serial_println;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub struct BaseRevision(UnsafeCell<[u64; 3]>);
|
pub struct BaseRevision(UnsafeCell<[u64; 3]>);
|
||||||
|
|
@ -328,46 +326,6 @@ impl LimineFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[used]
|
|
||||||
#[unsafe(link_section = ".limine_requests_start")]
|
|
||||||
static LIMINE_REQUESTS_START: RequestsStartMarker = REQUESTS_START_MARKER;
|
|
||||||
|
|
||||||
#[used]
|
#[used]
|
||||||
#[unsafe(link_section = ".limine_requests")]
|
#[unsafe(link_section = ".limine_requests")]
|
||||||
pub static EXECUTABLE_FILE_REQUEST: ExecutableFileRequest = ExecutableFileRequest::new();
|
pub static EXECUTABLE_FILE_REQUEST: ExecutableFileRequest = ExecutableFileRequest::new();
|
||||||
|
|
||||||
#[used]
|
|
||||||
#[unsafe(link_section = ".limine_requests")]
|
|
||||||
pub static LIMINE_BASE_REVISION: BaseRevision = BaseRevision::from_revision(6);
|
|
||||||
|
|
||||||
#[used]
|
|
||||||
#[unsafe(link_section = ".limine_requests")]
|
|
||||||
pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
|
||||||
|
|
||||||
#[used]
|
|
||||||
#[unsafe(link_section = ".limine_requests")]
|
|
||||||
pub static HHDM_REQUEST: HhdmRequest = HhdmRequest::new();
|
|
||||||
|
|
||||||
#[used]
|
|
||||||
#[unsafe(link_section = ".limine_requests")]
|
|
||||||
pub static MEMMAP_REQUEST: MemMapRequest = MemMapRequest::new();
|
|
||||||
|
|
||||||
#[used]
|
|
||||||
#[unsafe(link_section = ".limine_requests_end")]
|
|
||||||
static LIMINE_REQUESTS_END: RequestsEndMarker = REQUESTS_END_MARKER;
|
|
||||||
|
|
||||||
pub fn init_limine_boot_info() {
|
|
||||||
crate::boot::init_boot_info(
|
|
||||||
HHDM_REQUEST
|
|
||||||
.offset()
|
|
||||||
.expect("HHDM offset not provided by bootloader"),
|
|
||||||
MEMMAP_REQUEST
|
|
||||||
.entries()
|
|
||||||
.iter()
|
|
||||||
.inspect(|e| {
|
|
||||||
serial_println!("{e:?}");
|
|
||||||
})
|
|
||||||
.map(|&&e| e.into()),
|
|
||||||
EXECUTABLE_FILE_REQUEST.file().map(|f| f.bytes()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -23,9 +23,25 @@ static GDT: LazyLock<GlobalDescriptorTable> = LazyLock::new(GlobalDescriptorTabl
|
||||||
#[unsafe(no_mangle)]
|
#[unsafe(no_mangle)]
|
||||||
extern "C" fn _start() -> ! {
|
extern "C" fn _start() -> ! {
|
||||||
kernel::logger::init(log::LevelFilter::Trace);
|
kernel::logger::init(log::LevelFilter::Trace);
|
||||||
assert!(kernel::limine::LIMINE_BASE_REVISION.is_supported());
|
assert!(limine_requests::LIMINE_BASE_REVISION.is_supported());
|
||||||
|
|
||||||
kernel::limine::init_limine_boot_info();
|
_ = kernel::memory::HHDM_BASE
|
||||||
|
.try_insert(
|
||||||
|
limine_requests::HHDM_REQUEST
|
||||||
|
.offset()
|
||||||
|
.expect("HHDM offset not provided by bootloader"),
|
||||||
|
)
|
||||||
|
.expect("HHDM offset already set");
|
||||||
|
|
||||||
|
kernel::boot::init_boot_info(
|
||||||
|
limine_requests::HHDM_REQUEST
|
||||||
|
.offset()
|
||||||
|
.expect("HHDM offset not provided by bootloader"),
|
||||||
|
limine_requests::MEMMAP_REQUEST
|
||||||
|
.entries()
|
||||||
|
.iter()
|
||||||
|
.map(|&&e| e.into()),
|
||||||
|
);
|
||||||
|
|
||||||
kernel::serial_println!(
|
kernel::serial_println!(
|
||||||
"HHDM offset: 0x{:#x}",
|
"HHDM offset: 0x{:#x}",
|
||||||
|
|
@ -34,19 +50,20 @@ extern "C" fn _start() -> ! {
|
||||||
|
|
||||||
kernel::serial_println!(
|
kernel::serial_println!(
|
||||||
"Memory map: {:#?}",
|
"Memory map: {:#?}",
|
||||||
kernel::limine::MEMMAP_REQUEST.entries()
|
limine_requests::MEMMAP_REQUEST.entries()
|
||||||
);
|
);
|
||||||
|
|
||||||
GDT.load();
|
GDT.load();
|
||||||
IDT.load();
|
IDT.load();
|
||||||
|
|
||||||
|
|
||||||
kernel::serial_println!("entry point: 0x{:x}", _start as *const () as usize);
|
kernel::serial_println!("entry point: 0x{:x}", _start as *const () as usize);
|
||||||
kernel::serial_println!(
|
kernel::serial_println!(
|
||||||
"entry point phy: {:?}",
|
"entry point phy: {:?}",
|
||||||
kernel::x86_64::paging::get_physical_addr(VirtAddr(_start as *const () as u64))
|
kernel::x86_64::paging::get_physical_addr(VirtAddr(_start as *const () as u64))
|
||||||
);
|
);
|
||||||
|
|
||||||
let pmm = kernel::memory::PhysicalMemoryManager::from_memory_map(
|
let pmm = kernel::memory::PhysicalMemoryAllocator::from_memory_map(
|
||||||
kernel::boot::BOOT_INFO
|
kernel::boot::BOOT_INFO
|
||||||
.get()
|
.get()
|
||||||
.expect("Boot info not initialized")
|
.expect("Boot info not initialized")
|
||||||
|
|
@ -58,7 +75,7 @@ extern "C" fn _start() -> ! {
|
||||||
|
|
||||||
kernel::serial_println!("PMM: {pmm:#?}");
|
kernel::serial_println!("PMM: {pmm:#?}");
|
||||||
|
|
||||||
let fb = kernel::limine::FRAMEBUFFER_REQUEST
|
let fb = limine_requests::FRAMEBUFFER_REQUEST
|
||||||
.framebuffers()
|
.framebuffers()
|
||||||
.first()
|
.first()
|
||||||
.expect("No framebuffer found");
|
.expect("No framebuffer found");
|
||||||
|
|
@ -78,3 +95,34 @@ extern "C" fn _start() -> ! {
|
||||||
|
|
||||||
kernel::x86_64::halt_loop()
|
kernel::x86_64::halt_loop()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mod limine_requests {
|
||||||
|
use kernel::limine::{
|
||||||
|
BaseRevision, FramebufferRequest, REQUESTS_END_MARKER, REQUESTS_START_MARKER,
|
||||||
|
RequestsEndMarker, RequestsStartMarker,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".limine_requests_start")]
|
||||||
|
static LIMINE_REQUESTS_START: RequestsStartMarker = REQUESTS_START_MARKER;
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".limine_requests")]
|
||||||
|
pub static LIMINE_BASE_REVISION: BaseRevision = BaseRevision::from_revision(6);
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".limine_requests")]
|
||||||
|
pub static FRAMEBUFFER_REQUEST: FramebufferRequest = FramebufferRequest::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".limine_requests")]
|
||||||
|
pub static HHDM_REQUEST: kernel::limine::HhdmRequest = kernel::limine::HhdmRequest::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".limine_requests")]
|
||||||
|
pub static MEMMAP_REQUEST: kernel::limine::MemMapRequest = kernel::limine::MemMapRequest::new();
|
||||||
|
|
||||||
|
#[used]
|
||||||
|
#[unsafe(link_section = ".limine_requests_end")]
|
||||||
|
static LIMINE_REQUESTS_END: RequestsEndMarker = REQUESTS_END_MARKER;
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,4 @@
|
||||||
use core::{
|
use core::{alloc::Allocator, cell::Cell, fmt::Debug, num::NonZeroUsize, ptr::NonNull};
|
||||||
alloc::Allocator,
|
|
||||||
cell::Cell,
|
|
||||||
fmt::Debug,
|
|
||||||
num::{NonZero, NonZeroUsize},
|
|
||||||
ptr::NonNull,
|
|
||||||
};
|
|
||||||
|
|
||||||
use bit_field::BitField;
|
use bit_field::BitField;
|
||||||
use rbtree::RBTree;
|
use rbtree::RBTree;
|
||||||
|
|
@ -15,8 +9,6 @@ pub static HHDM_BASE: OnceLock<u64> = OnceLock::new();
|
||||||
|
|
||||||
pub trait VirtAddrTranslationExt: Sized {
|
pub trait VirtAddrTranslationExt: Sized {
|
||||||
fn into_phy_addr(self) -> Option<PhyAddr>;
|
fn into_phy_addr(self) -> Option<PhyAddr>;
|
||||||
|
|
||||||
#[expect(clippy::wrong_self_convention)]
|
|
||||||
fn is_mapped(self) -> bool {
|
fn is_mapped(self) -> bool {
|
||||||
self.into_phy_addr().is_some()
|
self.into_phy_addr().is_some()
|
||||||
}
|
}
|
||||||
|
|
@ -137,118 +129,7 @@ pub struct PhysicalMemoryManager {
|
||||||
///
|
///
|
||||||
/// When a range of pages is freed, we try to locate its buddy and merge
|
/// When a range of pages is freed, we try to locate its buddy and merge
|
||||||
/// them into a larger chunk recursively.
|
/// them into a larger chunk recursively.
|
||||||
buddies: [RBTree<PhysicalPageNode>; 40],
|
buddies: [u64; 40],
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for PhysicalMemoryManager {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
f.debug_struct("PhysicalMemoryManager")
|
|
||||||
.field_with("buddies", |f| {
|
|
||||||
f.debug_list()
|
|
||||||
.entries(self.buddies.iter().enumerate().map(|(i, tree)| {
|
|
||||||
struct BuddyDbg<'a> {
|
|
||||||
index: usize,
|
|
||||||
tree: &'a RBTree<PhysicalPageNode>,
|
|
||||||
}
|
|
||||||
impl Debug for BuddyDbg<'_> {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
write!(f, "{:#x}: {:?}", 1u64 << self.index, self.tree)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
BuddyDbg { index: i, tree }
|
|
||||||
}))
|
|
||||||
.finish()
|
|
||||||
})
|
|
||||||
.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PhysicalMemoryManager {
|
|
||||||
pub fn from_memory_map(memory_map: &[crate::boot::MemoryRegion]) -> Self {
|
|
||||||
let usable_regions = memory_map
|
|
||||||
.iter()
|
|
||||||
.filter(|region| region.region_type.is_usable());
|
|
||||||
|
|
||||||
let buddies = [(); 40].map(|_| RBTree::default());
|
|
||||||
|
|
||||||
let mut pmm = PhysicalMemoryManager { buddies };
|
|
||||||
|
|
||||||
usable_regions.for_each(|region| {
|
|
||||||
let idx = region.start / crate::x86_64::PAGE_SIZE as u64;
|
|
||||||
let count = region.length / crate::x86_64::PAGE_SIZE as u64;
|
|
||||||
|
|
||||||
pmm.free_region(idx as usize, count as usize);
|
|
||||||
});
|
|
||||||
|
|
||||||
pmm
|
|
||||||
}
|
|
||||||
|
|
||||||
fn free_region(&mut self, page_index: usize, mut count: usize) {
|
|
||||||
serial_println!(
|
|
||||||
"Freeing region: page_index = {:#x}, count = {:#x}",
|
|
||||||
page_index,
|
|
||||||
count
|
|
||||||
);
|
|
||||||
while let Some(bit) = NonZero::new(count.isolate_lowest_one()).map(NonZero::get) {
|
|
||||||
count -= bit;
|
|
||||||
|
|
||||||
let mut bin = bit.trailing_zeros() as usize;
|
|
||||||
|
|
||||||
let mut index = page_index + count;
|
|
||||||
let mut buddy: NonNull<PhysicalPageNode>;
|
|
||||||
loop {
|
|
||||||
// each bin corresponds to a power-of-two number of pages.
|
|
||||||
// each chunk of pages has a buddy that is the same size (in the same bin)
|
|
||||||
|
|
||||||
// for example, the chunk [0, 4) has a buddy [4, 8).
|
|
||||||
let buddy_index = if index & bit == 0 {
|
|
||||||
// if the chunk is aligned to the size of the chunk, its buddy
|
|
||||||
// is located at page_index + bit.
|
|
||||||
index + bit
|
|
||||||
} else {
|
|
||||||
// if the chunk is not aligned to the size of the chunk, its
|
|
||||||
// buddy is located at page_index - bit.
|
|
||||||
index - bit
|
|
||||||
};
|
|
||||||
|
|
||||||
serial_println!(
|
|
||||||
"looking for buddy: page_index = {:#x}, buddy_index = {:#x}, bin = {}",
|
|
||||||
index,
|
|
||||||
buddy_index,
|
|
||||||
bin
|
|
||||||
);
|
|
||||||
|
|
||||||
match self.buddies[bin].remove(PhysicalPageNodeKey::from_page_index(buddy_index)) {
|
|
||||||
Some(chunk) => {
|
|
||||||
serial_println!(
|
|
||||||
"found buddy: page_index = {:#x}, buddy_index = {:#x}, bin = {}",
|
|
||||||
index,
|
|
||||||
buddy_index,
|
|
||||||
bin
|
|
||||||
);
|
|
||||||
buddy = chunk;
|
|
||||||
index = PhysicalPageNode::page_index(buddy).min(index);
|
|
||||||
bin += 1;
|
|
||||||
}
|
|
||||||
None => break,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let node_ptr = PhysicalPageNode::new_from_page_index(index);
|
|
||||||
serial_println!(
|
|
||||||
"inserting node: page_index = {:#x}, size = {:#x}, bin = {}",
|
|
||||||
index,
|
|
||||||
bit,
|
|
||||||
bin
|
|
||||||
);
|
|
||||||
let None = self.buddies[bin].insert_node(node_ptr) else {
|
|
||||||
panic!(
|
|
||||||
"Attempted to free a region that is already free: page_index = {}, count = {}",
|
|
||||||
page_index, bit
|
|
||||||
)
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct PhysicalMemoryAllocator {
|
pub struct PhysicalMemoryAllocator {
|
||||||
|
|
@ -818,27 +699,6 @@ impl Debug for PhysicalPageNode {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PhysicalPageNode {
|
impl PhysicalPageNode {
|
||||||
fn phy(&self) -> Option<PhyAddr> {
|
|
||||||
PhyAddr::from_hhdm_virt(self)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn page_index(this: NonNull<Self>) -> usize {
|
|
||||||
let phy = PhyAddr::from_hhdm_virt(VirtAddr::from(this));
|
|
||||||
phy.expect("PhysicalPageNode is not in HHDM").page_index() as usize
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_from_page_index(page_index: usize) -> NonNull<Self> {
|
|
||||||
let phy = PhyAddr::from_page_index(page_index);
|
|
||||||
let virt = phy.as_hhdm_virt();
|
|
||||||
let ptr = virt.as_mut::<Self>();
|
|
||||||
|
|
||||||
unsafe {
|
|
||||||
ptr.write(Self::new_red());
|
|
||||||
}
|
|
||||||
|
|
||||||
NonNull::new(ptr).unwrap()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn new_red() -> Self {
|
fn new_red() -> Self {
|
||||||
PhysicalPageNode(Cell::new(1 << 120))
|
PhysicalPageNode(Cell::new(1 << 120))
|
||||||
}
|
}
|
||||||
|
|
@ -897,26 +757,6 @@ impl PhysicalPageNode {
|
||||||
/// the key does not require any additional bits.
|
/// the key does not require any additional bits.
|
||||||
struct PhysicalPageNodeKey;
|
struct PhysicalPageNodeKey;
|
||||||
|
|
||||||
impl Debug for PhysicalPageNodeKey {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
write!(f, "{:?}", self.phy())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl PhysicalPageNodeKey {
|
|
||||||
fn from_page_index(page_index: usize) -> &'static Self {
|
|
||||||
let phy = PhyAddr::from_page_index(page_index);
|
|
||||||
let virt = phy.as_hhdm_virt();
|
|
||||||
let ptr = virt.as_ptr::<Self>();
|
|
||||||
|
|
||||||
unsafe { &*ptr }
|
|
||||||
}
|
|
||||||
|
|
||||||
fn phy(&self) -> Option<PhyAddr> {
|
|
||||||
PhyAddr::from_hhdm_virt(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Eq for PhysicalPageNodeKey {}
|
impl Eq for PhysicalPageNodeKey {}
|
||||||
|
|
||||||
impl PartialEq for PhysicalPageNodeKey {
|
impl PartialEq for PhysicalPageNodeKey {
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,4 @@
|
||||||
#![allow(dead_code)]
|
use core::ffi::{CStr, c_void};
|
||||||
use core::ffi::c_void;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
limine::LimineFile,
|
limine::LimineFile,
|
||||||
|
|
@ -337,11 +336,13 @@ impl Elf64Sym {
|
||||||
if let Some(bytes) = crate::limine::EXECUTABLE_FILE_REQUEST
|
if let Some(bytes) = crate::limine::EXECUTABLE_FILE_REQUEST
|
||||||
.file()
|
.file()
|
||||||
.map(LimineFile::bytes)
|
.map(LimineFile::bytes)
|
||||||
&& let Ok(ehdr) = plain::from_bytes::<Elf64Ehdr>(bytes)
|
|
||||||
&& let Some(symtab) = ehdr.symtab(bytes)
|
|
||||||
{
|
{
|
||||||
|
if let Ok(ehdr) = plain::from_bytes::<Elf64Ehdr>(bytes) {
|
||||||
|
if let Some(symtab) = ehdr.symtab(bytes) {
|
||||||
return symtab;
|
return symtab;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
&[]
|
&[]
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
@ -374,7 +375,6 @@ impl Elf64Sym {
|
||||||
_ => panic!("Invalid bind value"),
|
_ => panic!("Invalid bind value"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn kind(&self) -> Elf64SymType {
|
fn kind(&self) -> Elf64SymType {
|
||||||
match self.info & 0xf {
|
match self.info & 0xf {
|
||||||
0 => Elf64SymType::Notype,
|
0 => Elf64SymType::Notype,
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
use core::{
|
use core::{
|
||||||
arch::asm,
|
arch::asm,
|
||||||
fmt::Debug,
|
fmt::Debug,
|
||||||
mem::{MaybeUninit, offset_of},
|
mem::offset_of,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -468,44 +468,16 @@ impl DerefMut for TssEntry {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const PRIVILEGE_STACK_TABLE_SIZE: usize = 3;
|
|
||||||
const INTERRUPT_STACK_TABLE_SIZE: usize = 7;
|
|
||||||
|
|
||||||
#[repr(C, packed(4))]
|
#[repr(C, packed(4))]
|
||||||
pub struct TaskStateSegment {
|
pub struct TaskStateSegment {
|
||||||
_reserved1: [u8; 4],
|
_reserved1: [u8; 4],
|
||||||
pub privilege_stack_table: [u64; PRIVILEGE_STACK_TABLE_SIZE],
|
pub privilege_stack_table: [u64; 3],
|
||||||
_reserved2: [u8; 8],
|
_reserved2: [u8; 8],
|
||||||
pub interrupt_stack_table: [u64; INTERRUPT_STACK_TABLE_SIZE],
|
pub interrupt_stack_table: [u64; 7],
|
||||||
_reserved3: [u8; 10],
|
_reserved3: [u8; 10],
|
||||||
pub iomap_base: u16,
|
pub iomap_base: u16,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for TaskStateSegment {
|
|
||||||
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
|
|
||||||
let mut dbg = f.debug_struct("TaskStateSegment");
|
|
||||||
|
|
||||||
let rsps = self.privilege_stack_table;
|
|
||||||
let ists = self.interrupt_stack_table;
|
|
||||||
|
|
||||||
dbg.field("RSP0", &format_args!("{:#x}", rsps[0]))
|
|
||||||
.field("RSP1", &format_args!("{:#x}", rsps[1]))
|
|
||||||
.field("RSP2", &format_args!("{:#x}", rsps[2]));
|
|
||||||
|
|
||||||
dbg.field("IST1", &format_args!("{:#x}", ists[0]))
|
|
||||||
.field("IST2", &format_args!("{:#x}", ists[1]))
|
|
||||||
.field("IST3", &format_args!("{:#x}", ists[2]))
|
|
||||||
.field("IST4", &format_args!("{:#x}", ists[3]))
|
|
||||||
.field("IST5", &format_args!("{:#x}", ists[4]))
|
|
||||||
.field("IST6", &format_args!("{:#x}", ists[5]))
|
|
||||||
.field("IST7", &format_args!("{:#x}", ists[6]));
|
|
||||||
|
|
||||||
dbg.field("iomap_base", &format_args!("{:#x}", self.iomap_base));
|
|
||||||
|
|
||||||
dbg.finish()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl TaskStateSegment {
|
impl TaskStateSegment {
|
||||||
pub const fn new() -> Self {
|
pub const fn new() -> Self {
|
||||||
Self {
|
Self {
|
||||||
|
|
@ -517,13 +489,6 @@ impl TaskStateSegment {
|
||||||
_reserved3: [0; 10],
|
_reserved3: [0; 10],
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn set_stack(&mut self, index: u8, stack: &'static Stack) {
|
|
||||||
assert!(
|
|
||||||
(index as usize) < INTERRUPT_STACK_TABLE_SIZE,
|
|
||||||
"Interrupt stack table index out of bounds"
|
|
||||||
);
|
|
||||||
self.interrupt_stack_table[index as usize] = stack.top().to_address();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
const impl Default for TaskStateSegment {
|
const impl Default for TaskStateSegment {
|
||||||
|
|
@ -535,39 +500,17 @@ const impl Default for TaskStateSegment {
|
||||||
pub const DF_STACK: u8 = 0;
|
pub const DF_STACK: u8 = 0;
|
||||||
pub const NMI_STACK: u8 = 1;
|
pub const NMI_STACK: u8 = 1;
|
||||||
pub const MC_STACK: u8 = 2;
|
pub const MC_STACK: u8 = 2;
|
||||||
pub const PF_STACK: u8 = 3;
|
|
||||||
|
|
||||||
const STACK_SIZE: usize = super::PAGE_SIZE * 5;
|
|
||||||
#[repr(align(4096))]
|
|
||||||
pub struct Stack {
|
|
||||||
_bytes: MaybeUninit<[u8; STACK_SIZE]>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Stack {
|
|
||||||
const fn new() -> Self {
|
|
||||||
Stack {
|
|
||||||
_bytes: MaybeUninit::uninit(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
fn top(&self) -> *const u8 {
|
|
||||||
unsafe {
|
|
||||||
(&raw const *self)
|
|
||||||
.cast::<u8>()
|
|
||||||
.byte_add(super::PAGE_SIZE * 5)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub static TSS: LazyLock<TaskStateSegment> = LazyLock::new(|| {
|
pub static TSS: LazyLock<TaskStateSegment> = LazyLock::new(|| {
|
||||||
let mut tss = TaskStateSegment::new();
|
let mut tss = TaskStateSegment::new();
|
||||||
static mut STACKS: [Stack; 4] = [const { Stack::new() }; 4];
|
const STACK_SIZE: usize = super::PAGE_SIZE * 5;
|
||||||
|
static mut STACKS: [[u8; STACK_SIZE]; 3] = [[0; STACK_SIZE]; 3];
|
||||||
|
|
||||||
tss.set_stack(DF_STACK, unsafe { &STACKS[DF_STACK as usize] });
|
let stack_top = |n: usize| unsafe { STACKS[n].as_ptr().add(STACK_SIZE).to_address() };
|
||||||
tss.set_stack(NMI_STACK, unsafe { &STACKS[NMI_STACK as usize] });
|
|
||||||
tss.set_stack(MC_STACK, unsafe { &STACKS[MC_STACK as usize] });
|
|
||||||
tss.set_stack(PF_STACK, unsafe { &STACKS[PF_STACK as usize] });
|
|
||||||
|
|
||||||
serial_println!("Initialized TSS {:#?}", tss);
|
tss.interrupt_stack_table[DF_STACK as usize] = stack_top(DF_STACK as usize);
|
||||||
|
tss.interrupt_stack_table[NMI_STACK as usize] = stack_top(NMI_STACK as usize);
|
||||||
|
tss.interrupt_stack_table[MC_STACK as usize] = stack_top(MC_STACK as usize);
|
||||||
|
|
||||||
tss
|
tss
|
||||||
});
|
});
|
||||||
|
|
|
||||||
|
|
@ -89,9 +89,6 @@ impl Entry {
|
||||||
ExceptionVector::NON_MASKABLE_INTERRUPT => {
|
ExceptionVector::NON_MASKABLE_INTERRUPT => {
|
||||||
options.set_interrupt_stack_table_index(super::gdt::NMI_STACK);
|
options.set_interrupt_stack_table_index(super::gdt::NMI_STACK);
|
||||||
}
|
}
|
||||||
ExceptionVector::PAGE_FAULT => {
|
|
||||||
options.set_interrupt_stack_table_index(super::gdt::PF_STACK);
|
|
||||||
}
|
|
||||||
ExceptionVector::MACHINE_CHECK => {
|
ExceptionVector::MACHINE_CHECK => {
|
||||||
options.set_interrupt_stack_table_index(super::gdt::MC_STACK);
|
options.set_interrupt_stack_table_index(super::gdt::MC_STACK);
|
||||||
}
|
}
|
||||||
|
|
@ -523,12 +520,7 @@ extern "C" fn global_interrupt_handler(
|
||||||
serial_println!("Breakpoint interrupt handled successfully.");
|
serial_println!("Breakpoint interrupt handled successfully.");
|
||||||
}
|
}
|
||||||
ExceptionVector::PAGE_FAULT => {
|
ExceptionVector::PAGE_FAULT => {
|
||||||
let cr2 = super::registers::Cr2::read();
|
serial_println!("Page fault occurred! Error code: {:#x}", error_code);
|
||||||
serial_println!(
|
|
||||||
"Page fault occurred! Error code: {:#x} CR2: {:#x}",
|
|
||||||
error_code,
|
|
||||||
cr2.0
|
|
||||||
);
|
|
||||||
debug_backtrace(&Context {
|
debug_backtrace(&Context {
|
||||||
rip: frame.instruction_pointer,
|
rip: frame.instruction_pointer,
|
||||||
registers: *registers,
|
registers: *registers,
|
||||||
|
|
|
||||||
|
|
@ -64,17 +64,6 @@ bitflags::bitflags! {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Cr2(pub u64);
|
|
||||||
impl Cr2 {
|
|
||||||
pub fn read() -> Self {
|
|
||||||
let value: u64;
|
|
||||||
unsafe {
|
|
||||||
asm!("mov {}, cr2", out(reg) value, options(nomem, nostack, preserves_flags));
|
|
||||||
}
|
|
||||||
Self(value)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Cr4 {
|
impl Cr4 {
|
||||||
pub fn read() -> Self {
|
pub fn read() -> Self {
|
||||||
let value: u64;
|
let value: u64;
|
||||||
|
|
|
||||||
|
|
@ -5,7 +5,6 @@
|
||||||
use core::{cell::UnsafeCell, mem::offset_of};
|
use core::{cell::UnsafeCell, mem::offset_of};
|
||||||
|
|
||||||
use kernel::{
|
use kernel::{
|
||||||
serial_println,
|
|
||||||
sync::LazyLock,
|
sync::LazyLock,
|
||||||
x86_64::{
|
x86_64::{
|
||||||
gdt::{DF_STACK, GlobalDescriptorTable, RING0},
|
gdt::{DF_STACK, GlobalDescriptorTable, RING0},
|
||||||
|
|
@ -18,7 +17,6 @@ pub static GDT: LazyLock<GlobalDescriptorTable> = LazyLock::new(GlobalDescriptor
|
||||||
#[unsafe(export_name = "_start")]
|
#[unsafe(export_name = "_start")]
|
||||||
pub extern "C" fn main() -> ! {
|
pub extern "C" fn main() -> ! {
|
||||||
kernel::serial_println!("Hello, world!");
|
kernel::serial_println!("Hello, world!");
|
||||||
kernel::limine::init_limine_boot_info();
|
|
||||||
|
|
||||||
GDT.load();
|
GDT.load();
|
||||||
kernel::serial_println!("[ok] GDT loaded");
|
kernel::serial_println!("[ok] GDT loaded");
|
||||||
|
|
@ -27,13 +25,12 @@ pub extern "C" fn main() -> ! {
|
||||||
_stack_frame: &mut idt::InterruptStackFrame,
|
_stack_frame: &mut idt::InterruptStackFrame,
|
||||||
_error_code: u64,
|
_error_code: u64,
|
||||||
) -> ! {
|
) -> ! {
|
||||||
kernel::serial_println!("[ok] Fault handler called");
|
kernel::serial_println!("[ok] Double fault handler called");
|
||||||
kernel::testing::exit_qemu(kernel::testing::QemuExitCode::Success)
|
kernel::testing::exit_qemu(kernel::testing::QemuExitCode::Success)
|
||||||
}
|
}
|
||||||
|
|
||||||
static IDT: LazyLock<InterruptDescriptorTable> = LazyLock::new(|| {
|
static IDT: LazyLock<InterruptDescriptorTable> = LazyLock::new(|| {
|
||||||
let mut idt = InterruptDescriptorTable::new_default();
|
let mut idt = InterruptDescriptorTable::new_default();
|
||||||
|
|
||||||
idt.double_fault = unsafe {
|
idt.double_fault = unsafe {
|
||||||
Entry::new(
|
Entry::new(
|
||||||
double_fault_handler as *const (),
|
double_fault_handler as *const (),
|
||||||
|
|
@ -41,19 +38,7 @@ pub extern "C" fn main() -> ! {
|
||||||
idt::EntryOptions::empty_interrupt_gate()
|
idt::EntryOptions::empty_interrupt_gate()
|
||||||
.with_present(true)
|
.with_present(true)
|
||||||
.with_privilege_level(RING0)
|
.with_privilege_level(RING0)
|
||||||
.with_interrupt_stack_table_index(kernel::x86_64::gdt::DF_STACK),
|
.with_interrupt_stack_table_index(DF_STACK),
|
||||||
)
|
|
||||||
};
|
|
||||||
|
|
||||||
// this should fire #PF since we have it installed anways in the default idt
|
|
||||||
idt.page_fault = unsafe {
|
|
||||||
Entry::new(
|
|
||||||
double_fault_handler as *const (),
|
|
||||||
offset_of!(GlobalDescriptorTable, kernel_code) as u16,
|
|
||||||
idt::EntryOptions::empty_interrupt_gate()
|
|
||||||
.with_present(true)
|
|
||||||
.with_privilege_level(RING0)
|
|
||||||
.with_interrupt_stack_table_index(kernel::x86_64::gdt::PF_STACK),
|
|
||||||
)
|
)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue