Improve kernel paging code

This commit is contained in:
Mathieu Strypsteen 2024-07-06 20:23:38 +02:00
parent 5509ec251a
commit 8eba784e7c
4 changed files with 116 additions and 49 deletions

32
kernel/Cargo.lock generated
View file

@ -8,6 +8,12 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6b2d54853319fd101b8dd81de382bcbf3e03410a64d8928bbee85a3e7dcde483"
[[package]]
name = "autocfg"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c4b4d0bd25bd0b74681c0ad21497610ce1b7c91b1022cd21c80c6fbdd9476b0"
[[package]]
name = "bitfield"
version = "0.15.0"
@ -48,9 +54,20 @@ dependencies = [
"bitvec",
"com_logger",
"log",
"spin",
"static-alloc",
]
[[package]]
name = "lock_api"
version = "0.4.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07af8b9cdd281b7915f413fa73f29ebd5d55d0d3f0155584dade1ff18cea1b17"
dependencies = [
"autocfg",
"scopeguard",
]
[[package]]
name = "log"
version = "0.4.22"
@ -63,6 +80,21 @@ version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc33ff2d4973d518d823d61aa239014831e521c75da58e3df4840d3f47749d09"
[[package]]
name = "scopeguard"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49"
[[package]]
name = "spin"
version = "0.9.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6980e8d7511241f8acf4aebddbb1ff938df5eebe98691418c4468d0b72a96a67"
dependencies = [
"lock_api",
]
[[package]]
name = "static-alloc"
version = "0.2.5"

View file

@ -8,4 +8,5 @@ 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"
spin = "0.9.8"
static-alloc = "0.2.5"

View file

@ -15,50 +15,44 @@ struct GDTEntry {
struct GDT {
entries: [GDTEntry; 3],
}
#[repr(C, packed)]
struct GDTDescriptor {
limit: u16,
base: u64,
}
static mut GDT: GDT = GDT {
entries: [
GDTEntry {
limit_low: 0,
base_low: 0,
base_middle: 0,
access: 0,
flags: 0,
base_high: 0,
},
GDTEntry {
limit_low: 0,
base_low: 0,
base_middle: 0,
access: 0x9a,
flags: 0x20,
base_high: 0,
},
GDTEntry {
limit_low: 0,
base_low: 0,
base_middle: 0,
access: 0x92,
flags: 0,
base_high: 0,
},
],
};
pub fn setup_gdt() {
let ptr;
unsafe {
ptr = GDT.entries.as_ptr() as u64;
}
let gdt = Box::leak(Box::new(GDT {
entries: [
GDTEntry {
limit_low: 0,
base_low: 0,
base_middle: 0,
access: 0,
flags: 0,
base_high: 0,
},
GDTEntry {
limit_low: 0,
base_low: 0,
base_middle: 0,
access: 0x9a,
flags: 0x20,
base_high: 0,
},
GDTEntry {
limit_low: 0,
base_low: 0,
base_middle: 0,
access: 0x92,
flags: 0,
base_high: 0,
},
],
}));
let gdt_descriptor = Box::leak(Box::new(GDTDescriptor {
limit: (size_of::<GDT>() - 1) as u16,
base: ptr,
base: gdt.entries.as_ptr() as u64,
}));
unsafe {
asm!("

View file

@ -4,6 +4,7 @@ use alloc::boxed::Box;
use bitfield::bitfield;
use bitvec::{bitvec, order::Lsb0};
use log::info;
use spin::{Mutex, Once};
use crate::misc::loader_struct::LoaderStruct;
@ -41,13 +42,9 @@ extern "C" {
}
const KERNEL_VIRT_START: u64 = 0xffffffff80000000;
static mut KERNEL_PHYS_START: u64 = 0;
static KERNEL_PHYS_START: Once<u64> = Once::new();
static CURRENT_PML4: Mutex<Option<&mut PageTable>> = Mutex::new(None);
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<Box<PageTable>> = None;
@ -58,11 +55,46 @@ fn get_table_entry(table: &mut PageTable, i: usize) -> &mut PageTable {
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_user(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) {
fn get_page(pml4: &mut PageTable, virt: u64) -> Option<&mut PageEntry> {
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 = &mut pml4.entries_virt[pml4_i];
if pdpt.is_some() {
let pdpt = pdpt.as_mut().unwrap();
let directory = &mut pdpt.entries_virt[pdpt_i];
if directory.is_some() {
let directory = directory.as_mut().unwrap();
let table = &mut directory.entries_virt[directory_i];
if table.is_some() {
let table = table.as_mut().unwrap();
return Some(&mut table.entries_phys[table_i]);
}
}
}
None
}
fn virt_to_phys(virt: u64) -> u64 {
let mut current_pml4 = CURRENT_PML4.lock();
match current_pml4.as_mut() {
None => virt - KERNEL_VIRT_START + KERNEL_PHYS_START.get().unwrap(),
Some(pml4) => {
let page = get_page(pml4, virt);
match page {
None => 0,
Some(page) => page.address() * 0x1000 + virt % 0x1000,
}
}
}
}
pub fn map(pml4: &mut PageTable, virt: u64, phys: u64, user: bool, write: bool, exec: bool) {
if virt < 0x1000 {
panic!("First page shouldn't be mapped");
}
@ -75,14 +107,13 @@ pub fn map(pml4: &mut PageTable, virt: u64, phys: u64, write: bool, exec: bool)
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_user(user as u64);
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;
}
KERNEL_PHYS_START.call_once(|| phys_start);
let mut memory_size = 0;
for i in loader_struct.available_memory {
if i.initial_page + i.page_count > memory_size {
@ -120,27 +151,36 @@ pub fn setup_paging(loader_struct: &LoaderStruct, phys_start: u64) {
entries_phys: [PageEntry(0); 512],
entries_virt: [NONE; 512],
}));
for i in 256..512 {
get_table_entry(pml4, i);
pml4.entries_phys[i].set_user(0);
if i != 511 {
pml4.entries_phys[i].set_execute_disable(1);
}
}
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);
map(pml4, i * 0x1000, phys, false, 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);
map(pml4, i * 0x1000, phys, false, 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);
map(pml4, i * 0x1000, phys, false, 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);
map(pml4, i * 0x1000, phys, false, true, false);
}
unsafe {
asm!("mov cr3, {}", in(reg) virt_to_phys(pml4 as *const PageTable as u64));
}
let mut current_pml4 = CURRENT_PML4.lock();
*current_pml4 = Some(pml4);
}