Improve paging
This commit is contained in:
parent
1c25f3a388
commit
82ebfc839a
8 changed files with 96 additions and 51 deletions
7
kernel/Cargo.lock
generated
7
kernel/Cargo.lock
generated
|
@ -8,6 +8,12 @@ version = "0.1.1"
|
|||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483"
|
||||
|
||||
[[package]]
|
||||
name = "bitfield"
|
||||
version = "0.15.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "c821a6e124197eb56d907ccc2188eab1038fb919c914f47976e64dd8dbc855d1"
|
||||
|
||||
[[package]]
|
||||
name = "bitvec"
|
||||
version = "1.0.1"
|
||||
|
@ -38,6 +44,7 @@ checksum = "e6d5a32815ae3f33302d95fdcb2ce17862f8c65363dcfd29360480ba1001fc9c"
|
|||
name = "kernel"
|
||||
version = "0.0.1"
|
||||
dependencies = [
|
||||
"bitfield",
|
||||
"bitvec",
|
||||
"com_logger",
|
||||
"log",
|
||||
|
|
|
@ -4,6 +4,7 @@ version = "0.0.1"
|
|||
edition = "2021"
|
||||
|
||||
[dependencies]
|
||||
bitfield = "0.15.0"
|
||||
bitvec = {version = "1.0.1", default-features = false, features = ["alloc", "atomic"]}
|
||||
com_logger = { git = "https://git.strypsteen.com/mathieu/com_logger", version = "0.1.1" }
|
||||
log = "0.4.22"
|
||||
|
|
|
@ -8,6 +8,7 @@ SECTIONS {
|
|||
}
|
||||
.data ALIGN(0x1000) : {
|
||||
*(.data*)
|
||||
*(.got)
|
||||
}
|
||||
.bss ALIGN(0x1000) : {
|
||||
*(.bss*)
|
||||
|
|
|
@ -22,7 +22,7 @@ struct GDTDescriptor {
|
|||
base: u64,
|
||||
}
|
||||
|
||||
const GDT: GDT = GDT {
|
||||
static mut GDT: GDT = GDT {
|
||||
entries: [
|
||||
GDTEntry {
|
||||
limit_low: 0,
|
||||
|
@ -52,9 +52,13 @@ const GDT: GDT = GDT {
|
|||
};
|
||||
|
||||
pub fn setup_gdt() {
|
||||
let ptr;
|
||||
unsafe {
|
||||
ptr = GDT.entries.as_ptr() as u64;
|
||||
}
|
||||
let gdt_descriptor = Box::leak(Box::new(GDTDescriptor {
|
||||
limit: (size_of::<GDT>() - 1) as u16,
|
||||
base: GDT.entries.as_ptr() as u64,
|
||||
base: ptr,
|
||||
}));
|
||||
unsafe {
|
||||
asm!("
|
||||
|
|
|
@ -17,7 +17,7 @@ mod cpu;
|
|||
mod misc;
|
||||
|
||||
#[global_allocator]
|
||||
static A: Bump<[u8; 8 * 1024 * 1024]> = Bump::uninit();
|
||||
static ALLOC: Bump<[u8; 8 * 1024 * 1024]> = Bump::uninit();
|
||||
|
||||
global_asm!(
|
||||
"
|
||||
|
|
|
@ -6,9 +6,11 @@ use uefi::table::{
|
|||
Boot, SystemTable,
|
||||
};
|
||||
|
||||
use crate::paging::{map, PageTable};
|
||||
|
||||
pub const KERNEL_VIRT_START: u64 = 0xffffffff80000000;
|
||||
|
||||
pub fn load_kernel(kernel: &[u8], system_table: &SystemTable<Boot>) -> (u64, usize, u64) {
|
||||
pub fn load_kernel(kernel: &[u8], system_table: &SystemTable<Boot>) -> (u64, u64) {
|
||||
let file: ElfBytes<LittleEndian> = ElfBytes::minimal_parse(kernel).unwrap();
|
||||
let mut kernel_size = 0;
|
||||
for i in file.segments().unwrap() {
|
||||
|
@ -18,6 +20,9 @@ pub fn load_kernel(kernel: &[u8], system_table: &SystemTable<Boot>) -> (u64, usi
|
|||
if i.p_vaddr < KERNEL_VIRT_START {
|
||||
panic!("Invalid kernel segments")
|
||||
}
|
||||
if i.p_vaddr % 0x1000 != 0 {
|
||||
panic!("Invalid alignment");
|
||||
}
|
||||
let end_addr = i.p_vaddr - KERNEL_VIRT_START + i.p_memsz;
|
||||
if end_addr > kernel_size {
|
||||
kernel_size = end_addr;
|
||||
|
@ -37,5 +42,18 @@ pub fn load_kernel(kernel: &[u8], system_table: &SystemTable<Boot>) -> (u64, usi
|
|||
ptr::copy(kernel[i.p_offset.try_into().unwrap()..].as_ptr(), start_addr as *mut u8, i.p_filesz.try_into().unwrap());
|
||||
}
|
||||
}
|
||||
(phys_start, kernel_size as usize, file.ehdr.e_entry)
|
||||
(phys_start, file.ehdr.e_entry)
|
||||
}
|
||||
pub fn map_kernel(kernel: &[u8], pml4: &mut PageTable, kernel_start: u64) {
|
||||
let file: ElfBytes<LittleEndian> = ElfBytes::minimal_parse(kernel).unwrap();
|
||||
for i in file.segments().unwrap() {
|
||||
if i.p_type != PT_LOAD {
|
||||
continue;
|
||||
}
|
||||
for j in 0..(i.p_memsz + 0xfff) / 0x1000 {
|
||||
let virt = i.p_vaddr + j * 0x1000;
|
||||
let phys = virt - KERNEL_VIRT_START + kernel_start;
|
||||
map(pml4, virt, phys, i.p_flags & 2 != 0, i.p_flags & 1 != 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,7 @@ extern crate alloc;
|
|||
|
||||
use core::{arch::asm, mem, panic::PanicInfo};
|
||||
|
||||
use elf::load_kernel;
|
||||
use elf::{load_kernel, map_kernel};
|
||||
use loader_struct::{generate_loader_struct, LoaderStruct};
|
||||
use log::{error, info};
|
||||
use paging::setup_paging;
|
||||
|
@ -21,7 +21,7 @@ mod loader_struct;
|
|||
mod paging;
|
||||
|
||||
#[global_allocator]
|
||||
static A: Bump<[u8; 8 * 1024 * 1024]> = Bump::uninit();
|
||||
static ALLOC: Bump<[u8; 8 * 1024 * 1024]> = Bump::uninit();
|
||||
|
||||
const KERNEL: &[u8] = include_bytes!("../../kernel/target/x86_64-unknown-none/release/kernel");
|
||||
|
||||
|
@ -30,12 +30,13 @@ fn main(image_handle: Handle, mut system_table: SystemTable<Boot>) -> Status {
|
|||
com_logger::init();
|
||||
info!("Starting bootloader...");
|
||||
uefi::helpers::init(&mut system_table).unwrap();
|
||||
let (kernel_start, kernel_size, kernel_entry) = load_kernel(KERNEL, &system_table);
|
||||
let (kernel_start, kernel_entry) = load_kernel(KERNEL, &system_table);
|
||||
let memory_map;
|
||||
unsafe {
|
||||
memory_map = system_table.exit_boot_services(MemoryType::LOADER_DATA).1;
|
||||
}
|
||||
setup_paging(&memory_map, kernel_start, kernel_size);
|
||||
let pml4 = setup_paging(&memory_map);
|
||||
map_kernel(KERNEL, pml4, kernel_start);
|
||||
let loader_struct = generate_loader_struct(&memory_map);
|
||||
info!("Jumping to kernel...");
|
||||
unsafe {
|
||||
|
|
|
@ -4,76 +4,89 @@ use alloc::boxed::Box;
|
|||
use bitfield::bitfield;
|
||||
use uefi::table::boot::{MemoryMap, MemoryType};
|
||||
|
||||
use crate::elf;
|
||||
|
||||
bitfield! {
|
||||
#[derive(Clone, Copy)]
|
||||
struct PageEntry(u64);
|
||||
present, set_present: 1, 0;
|
||||
write, set_write: 2, 1;
|
||||
user, set_user: 3, 2;
|
||||
write_through, set_write_through: 4, 3;
|
||||
cache_disable, set_cache_disable: 5, 4;
|
||||
accessed, set_accessed: 6, 5;
|
||||
dirty, set_dirty: 7, 6;
|
||||
page_size, set_page_size: 8, 7;
|
||||
global, set_global: 9, 8;
|
||||
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: 63, 12;
|
||||
address, set_address: 62, 12;
|
||||
execute_disable, set_execute_disable: 63, 63;
|
||||
}
|
||||
|
||||
#[repr(C, align(0x1000))]
|
||||
struct PageTable {
|
||||
entries: [PageEntry; 512],
|
||||
pub struct PageTable {
|
||||
entries_phys: [PageEntry; 512],
|
||||
entries_virt: [Option<Box<PageTable>>; 512],
|
||||
}
|
||||
|
||||
fn get_table_entry(table: &mut PageTable, i: usize) -> &mut PageTable {
|
||||
if table.entries[i].present() == 0 {
|
||||
let new_table = Box::leak(Box::new(PageTable { entries: [PageEntry(0); 512] }));
|
||||
table.entries[i].set_address(new_table as *const PageTable as u64 / 0x1000);
|
||||
table.entries[i].set_present(1);
|
||||
table.entries[i].set_write(1);
|
||||
}
|
||||
let ptr = (table.entries[i].address() * 0x1000) as *mut PageTable;
|
||||
unsafe {
|
||||
return ptr.as_mut().unwrap();
|
||||
if table.entries_virt[i].is_none() {
|
||||
const NONE: Option<Box<PageTable>> = None;
|
||||
let new_table = Box::new(PageTable {
|
||||
entries_phys: [PageEntry(0); 512],
|
||||
entries_virt: [NONE; 512],
|
||||
});
|
||||
table.entries_phys[i].set_address(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();
|
||||
}
|
||||
fn map(pml4: &mut PageTable, mut virt: usize, phys: usize) {
|
||||
virt /= 0x1000;
|
||||
let table_i = virt % 512;
|
||||
let directory_i = virt / 512 % 512;
|
||||
let pdpt_i = virt / 512 / 512 % 512;
|
||||
let pml4_i = virt / 512 / 512 / 512 % 512;
|
||||
pub fn map(pml4: &mut PageTable, virt: u64, phys: u64, write: bool, exec: bool) {
|
||||
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[table_i].set_address(phys as u64 / 0x1000);
|
||||
table.entries[table_i].set_present(1);
|
||||
table.entries[table_i].set_write(1);
|
||||
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(memory_map: &MemoryMap, kernel_start: u64, kernel_size: usize) {
|
||||
let pml4 = Box::leak(Box::new(PageTable { entries: [PageEntry(0); 512] }));
|
||||
pub fn setup_paging(memory_map: &MemoryMap) -> &mut PageTable {
|
||||
const NONE: Option<Box<PageTable>> = None;
|
||||
let pml4 = Box::leak(Box::new(PageTable {
|
||||
entries_phys: [PageEntry(0); 512],
|
||||
entries_virt: [NONE; 512],
|
||||
}));
|
||||
for i in memory_map.entries() {
|
||||
if i.ty == MemoryType::LOADER_CODE
|
||||
|| i.ty == MemoryType::LOADER_DATA
|
||||
|| i.ty == MemoryType::RUNTIME_SERVICES_CODE
|
||||
|| i.ty == MemoryType::RUNTIME_SERVICES_DATA
|
||||
|| i.ty == MemoryType::BOOT_SERVICES_CODE
|
||||
|| i.ty == MemoryType::BOOT_SERVICES_DATA
|
||||
{
|
||||
for j in 0..i.page_count {
|
||||
let addr = i.phys_start + j * 0x1000;
|
||||
map(pml4, addr as usize, addr as usize);
|
||||
let mut write = true;
|
||||
let mut exec = false;
|
||||
if i.ty == MemoryType::LOADER_CODE || i.ty == MemoryType::RUNTIME_SERVICES_CODE {
|
||||
exec = true;
|
||||
}
|
||||
if i.ty == MemoryType::RUNTIME_SERVICES_CODE {
|
||||
write = false;
|
||||
}
|
||||
map(pml4, addr, addr, write, exec);
|
||||
}
|
||||
}
|
||||
}
|
||||
for i in 0..((kernel_size + 0xfff) / 0x1000) {
|
||||
let virt = elf::KERNEL_VIRT_START as usize + i * 0x1000;
|
||||
let phys = kernel_start as usize + i * 0x1000;
|
||||
map(pml4, virt, phys);
|
||||
}
|
||||
unsafe {
|
||||
asm!("mov cr3, {}", in(reg) pml4 as *const PageTable as u64);
|
||||
// Write Protect
|
||||
asm!("mov rax, cr0; bts rax, 16; mov cr0, rax", out("rax") _);
|
||||
// No-Execute Enable
|
||||
asm!("rdmsr; bts rax, 11; wrmsr", in("rcx") 0xc0000080 as u64, out("rax") _, out("rdx") _);
|
||||
}
|
||||
pml4
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue