diff --git a/kernel/link.ld b/kernel/link.ld index 81c1ad2..32a0f28 100644 --- a/kernel/link.ld +++ b/kernel/link.ld @@ -1,16 +1,24 @@ SECTIONS { . = 0xffffffff80000000; .text ALIGN(0x1000) : { + _text_start = .; *(.text*) + _text_end = .; } .rodata ALIGN(0x1000) : { + _rodata_start = .; *(.rodata*) + _rodata_end = .; } .data ALIGN(0x1000) : { + _data_start = .; *(.data*) *(.got) + _data_end = .; } .bss ALIGN(0x1000) : { + _bss_start = .; *(.bss*) + _bss_end = .; } } diff --git a/kernel/src/cpu/paging.rs b/kernel/src/cpu/paging.rs index fdb0f3c..e99b487 100644 --- a/kernel/src/cpu/paging.rs +++ b/kernel/src/cpu/paging.rs @@ -1,9 +1,88 @@ +use core::arch::asm; + +use alloc::boxed::Box; +use bitfield::bitfield; use bitvec::{bitvec, order::Lsb0}; use log::info; use crate::misc::loader_struct::LoaderStruct; -pub fn setup_paging(loader_struct: &LoaderStruct) { +bitfield! { + #[derive(Clone, Copy)] + struct PageEntry(u64); + present, set_present: 0, 0; + write, set_write: 1, 1; + user, set_user: 2, 2; + write_through, set_write_through: 3, 3; + cache_disable, set_cache_disable: 4, 4; + accessed, set_accessed: 5, 5; + dirty, set_dirty: 6, 6; + page_size, set_page_size: 7, 7; + global, set_global: 8, 8; + available, set_available: 11, 9; + address, set_address: 62, 12; + execute_disable, set_execute_disable: 63, 63; +} +#[repr(C, align(0x1000))] +pub struct PageTable { + entries_phys: [PageEntry; 512], + entries_virt: [Option>; 512], +} + +extern "C" { + static _text_start: u8; + static _text_end: u8; + static _rodata_start: u8; + static _rodata_end: u8; + static _data_start: u8; + static _data_end: u8; + static _bss_start: u8; + static _bss_end: u8; +} + +const KERNEL_VIRT_START: u64 = 0xffffffff80000000; +static mut KERNEL_PHYS_START: u64 = 0; + +fn virt_to_phys(virt: u64) -> u64 { + unsafe { + return virt - KERNEL_VIRT_START + KERNEL_PHYS_START; + } +} +fn get_table_entry(table: &mut PageTable, i: usize) -> &mut PageTable { + if table.entries_virt[i].is_none() { + const NONE: Option> = None; + let new_table = Box::new(PageTable { + entries_phys: [PageEntry(0); 512], + entries_virt: [NONE; 512], + }); + table.entries_phys[i].set_address(virt_to_phys(new_table.as_ref() as *const PageTable as u64) / 0x1000); + table.entries_virt[i] = Some(new_table); + table.entries_phys[i].set_write(1); + table.entries_phys[i].set_present(1); + } + return table.entries_virt[i].as_mut().unwrap(); +} +pub fn map(pml4: &mut PageTable, virt: u64, phys: u64, write: bool, exec: bool) { + if virt < 0x1000 { + panic!("First page shouldn't be mapped"); + } + let virt_page = virt as usize / 0x1000; + let table_i = virt_page % 512; + let directory_i = virt_page / 512 % 512; + let pdpt_i = virt_page / 512 / 512 % 512; + let pml4_i = virt_page / 512 / 512 / 512 % 512; + let pdpt = get_table_entry(pml4, pml4_i); + let directory = get_table_entry(pdpt, pdpt_i); + let table = get_table_entry(directory, directory_i); + table.entries_phys[table_i].set_address(phys / 0x1000); + table.entries_phys[table_i].set_write(write as u64); + table.entries_phys[table_i].set_execute_disable(!exec as u64); + table.entries_phys[table_i].set_present(1); +} +pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64) { + unsafe { + KERNEL_PHYS_START = phys_start; + } let mut memory_size = 0; for i in loader_struct.available_memory { if i.initial_page + i.page_count > memory_size { @@ -18,4 +97,50 @@ pub fn setup_paging(loader_struct: &LoaderStruct) { frames_vec.set(page as usize, false); } } + let text_start; + let text_end; + let rodata_start; + let rodata_end; + let data_start; + let data_end; + let bss_start; + let bss_end; + unsafe { + text_start = &_text_start as *const u8 as u64 / 0x1000; + text_end = (&_text_end as *const u8 as u64 + 0xfff) / 0x1000; + rodata_start = &_rodata_start as *const u8 as u64 / 0x1000; + rodata_end = (&_rodata_end as *const u8 as u64 + 0xfff) / 0x1000; + data_start = &_data_start as *const u8 as u64 / 0x1000; + data_end = (&_data_end as *const u8 as u64 + 0xfff) / 0x1000; + bss_start = &_bss_start as *const u8 as u64 / 0x1000; + bss_end = (&_bss_end as *const u8 as u64 + 0xfff) / 0x1000; + } + const NONE: Option> = None; + let pml4 = Box::leak(Box::new(PageTable { + entries_phys: [PageEntry(0); 512], + entries_virt: [NONE; 512], + })); + for i in text_start..text_end { + let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; + frames_vec.set(phys as usize / 0x1000, true); + map(pml4, i * 0x1000, phys, false, true); + } + for i in rodata_start..rodata_end { + let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; + frames_vec.set(phys as usize / 0x1000, true); + map(pml4, i * 0x1000, phys, false, false); + } + for i in data_start..data_end { + let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; + frames_vec.set(phys as usize / 0x1000, true); + map(pml4, i * 0x1000, phys, true, false); + } + for i in bss_start..bss_end { + let phys = i * 0x1000 - KERNEL_VIRT_START + phys_start; + frames_vec.set(phys as usize / 0x1000, true); + map(pml4, i * 0x1000, phys, true, false); + } + unsafe { + asm!("mov cr3, {}", in(reg) virt_to_phys(pml4 as *const PageTable as u64)); + } } diff --git a/kernel/src/main.rs b/kernel/src/main.rs index 3e3f56e..663d3b1 100644 --- a/kernel/src/main.rs +++ b/kernel/src/main.rs @@ -44,7 +44,7 @@ extern "C" fn main(temp_loader_struct: &LoaderStruct) -> ! { } setup_gdt(); setup_idt(); - setup_paging(&loader_struct); + setup_paging(&loader_struct, loader_struct.phys_kernel_start); loop { unsafe { asm!("hlt"); diff --git a/kernel/src/misc/loader_struct.rs b/kernel/src/misc/loader_struct.rs index a76984f..43ea14a 100644 --- a/kernel/src/misc/loader_struct.rs +++ b/kernel/src/misc/loader_struct.rs @@ -8,5 +8,6 @@ pub struct LoaderStructMemoryRegion { #[derive(Clone, Copy)] pub struct LoaderStruct { pub magic: u64, + pub phys_kernel_start: u64, pub available_memory: [LoaderStructMemoryRegion; 1024], } diff --git a/loader/src/elf.rs b/loader/src/elf.rs index 0ea7cd7..3c4bf46 100644 --- a/loader/src/elf.rs +++ b/loader/src/elf.rs @@ -8,7 +8,7 @@ use uefi::table::{ use crate::paging::{map, PageTable}; -pub const KERNEL_VIRT_START: u64 = 0xffffffff80000000; +const KERNEL_VIRT_START: u64 = 0xffffffff80000000; pub fn load_kernel(kernel: &[u8], system_table: &SystemTable) -> (u64, u64) { let file: ElfBytes = ElfBytes::minimal_parse(kernel).unwrap(); diff --git a/loader/src/loader_struct.rs b/loader/src/loader_struct.rs index 488b71e..15f78f6 100644 --- a/loader/src/loader_struct.rs +++ b/loader/src/loader_struct.rs @@ -9,12 +9,14 @@ pub struct LoaderStructMemoryRegion { #[repr(C)] pub struct LoaderStruct { magic: u64, + phys_kernel_start: u64, available_memory: [LoaderStructMemoryRegion; 1024], } -pub fn generate_loader_struct(memory_map: &MemoryMap) -> LoaderStruct { +pub fn generate_loader_struct(memory_map: &MemoryMap, phys_start: u64) -> LoaderStruct { let mut loader_struct = LoaderStruct { magic: 0x123456789abcdef0, + phys_kernel_start: phys_start, available_memory: [LoaderStructMemoryRegion { initial_page: 0, page_count: 0 }; 1024], }; let mut next_entry = 0; diff --git a/loader/src/main.rs b/loader/src/main.rs index 312d8dd..8741f86 100644 --- a/loader/src/main.rs +++ b/loader/src/main.rs @@ -37,7 +37,7 @@ fn main(image_handle: Handle, mut system_table: SystemTable) -> Status { } let pml4 = setup_paging(&memory_map); map_kernel(KERNEL, pml4, kernel_start); - let loader_struct = generate_loader_struct(&memory_map); + let loader_struct = generate_loader_struct(&memory_map, kernel_start); info!("Jumping to kernel..."); unsafe { (mem::transmute::<_, extern "C" fn(&LoaderStruct) -> !>(kernel_entry))(&loader_struct);