mirror of
https://github.com/ZeroOSProject/ZeroOS.git
synced 2026-09-13 02:24:42 +08:00
vi and busybox
This commit is contained in:
+258
@@ -0,0 +1,258 @@
|
||||
use core::arch::asm;
|
||||
|
||||
use crate::memory::{PAGE_SIZE, PhysicalMemoryManager};
|
||||
|
||||
const PRESENT: u64 = 1 << 0;
|
||||
const WRITABLE: u64 = 1 << 1;
|
||||
const HUGE_PAGE: u64 = 1 << 7;
|
||||
const CR4_PSE: u64 = 1 << 4;
|
||||
|
||||
const ENTRY_COUNT: usize = 512;
|
||||
const IDENTITY_MAP_GIB: usize = 512;
|
||||
const PDPTE_COUNT: usize = IDENTITY_MAP_GIB / 2;
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct PageFlags(u64);
|
||||
|
||||
impl PageFlags {
|
||||
#[allow(dead_code)]
|
||||
pub const PRESENT: Self = Self(PRESENT);
|
||||
pub const WRITABLE: Self = Self(WRITABLE);
|
||||
#[allow(dead_code)]
|
||||
pub const USER: Self = Self(1 << 2);
|
||||
#[allow(dead_code)]
|
||||
pub const NO_EXECUTE: Self = Self(1 << 63);
|
||||
|
||||
pub const fn bits(self) -> u64 {
|
||||
self.0
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
pub const fn union(self, other: Self) -> Self {
|
||||
Self(self.0 | other.0)
|
||||
}
|
||||
}
|
||||
|
||||
#[repr(C, align(4096))]
|
||||
pub struct PageTable {
|
||||
entries: [u64; ENTRY_COUNT],
|
||||
}
|
||||
|
||||
impl PageTable {
|
||||
fn zero(&mut self) {
|
||||
self.entries.fill(0);
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AddressSpace {
|
||||
pml4: *mut PageTable,
|
||||
identity_pdpt: *mut PageTable,
|
||||
identity_pds: [*mut PageTable; PDPTE_COUNT],
|
||||
}
|
||||
|
||||
impl AddressSpace {
|
||||
pub unsafe fn new_kernel(memory: &mut PhysicalMemoryManager) -> Option<Self> {
|
||||
let pml4 = memory.alloc_page()? as *mut PageTable;
|
||||
let identity_pdpt = memory.alloc_page()? as *mut PageTable;
|
||||
let mut identity_pds = [core::ptr::null_mut(); PDPTE_COUNT];
|
||||
|
||||
let identity_flags = PRESENT | WRITABLE | PageFlags::USER.bits();
|
||||
|
||||
unsafe {
|
||||
(*pml4).zero();
|
||||
(*identity_pdpt).zero();
|
||||
(*pml4).entries[0] = identity_pdpt as u64 | identity_flags;
|
||||
}
|
||||
|
||||
for (pdpt_index, pd) in identity_pds.iter_mut().enumerate() {
|
||||
*pd = memory.alloc_page()? as *mut PageTable;
|
||||
|
||||
unsafe {
|
||||
(**pd).zero();
|
||||
(*identity_pdpt).entries[pdpt_index] = *pd as u64 | identity_flags;
|
||||
|
||||
for pd_index in 0..ENTRY_COUNT {
|
||||
let physical = ((pdpt_index * ENTRY_COUNT + pd_index) as u64) * 2 * 1024 * 1024;
|
||||
(**pd).entries[pd_index] = physical | identity_flags | HUGE_PAGE;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Some(Self {
|
||||
pml4,
|
||||
identity_pdpt,
|
||||
identity_pds,
|
||||
})
|
||||
}
|
||||
|
||||
pub unsafe fn map_page(
|
||||
&mut self,
|
||||
memory: &mut PhysicalMemoryManager,
|
||||
virtual_address: u64,
|
||||
physical_address: u64,
|
||||
flags: PageFlags,
|
||||
) -> Option<()> {
|
||||
if !is_aligned(virtual_address) || !is_aligned(physical_address) {
|
||||
return None;
|
||||
}
|
||||
|
||||
let table = unsafe { self.walk_create(memory, virtual_address)? };
|
||||
let index = pt_index(virtual_address);
|
||||
|
||||
unsafe {
|
||||
if (*table).entries[index] & PRESENT != 0 {
|
||||
return None;
|
||||
}
|
||||
(*table).entries[index] = physical_address | flags.bits() | PRESENT;
|
||||
flush_tlb_one(virtual_address);
|
||||
}
|
||||
|
||||
Some(())
|
||||
}
|
||||
|
||||
pub unsafe fn unmap_page(&mut self, virtual_address: u64) -> Option<u64> {
|
||||
let table = unsafe { self.walk(virtual_address)? };
|
||||
let index = pt_index(virtual_address);
|
||||
|
||||
unsafe {
|
||||
let entry = (*table).entries[index];
|
||||
if entry & PRESENT == 0 {
|
||||
return None;
|
||||
}
|
||||
(*table).entries[index] = 0;
|
||||
flush_tlb_one(virtual_address);
|
||||
Some(entry & 0x000f_ffff_ffff_f000)
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn translate(&self, virtual_address: u64) -> Option<u64> {
|
||||
let pml4 = unsafe { &*self.pml4 };
|
||||
let pml4e = pml4.entries[pml4_index(virtual_address)];
|
||||
let pdpt = next_table(pml4e)?;
|
||||
|
||||
let pdpte = unsafe { (*pdpt).entries[pdpt_index(virtual_address)] };
|
||||
if pdpte & HUGE_PAGE != 0 {
|
||||
return Some((pdpte & 0x000f_ffff_c000_0000) | (virtual_address & 0x3fff_ffff));
|
||||
}
|
||||
let pd = next_table(pdpte)?;
|
||||
|
||||
let pde = unsafe { (*pd).entries[pd_index(virtual_address)] };
|
||||
if pde & HUGE_PAGE != 0 {
|
||||
return Some((pde & 0x000f_ffff_ffe0_0000) | (virtual_address & 0x1f_ffff));
|
||||
}
|
||||
let pt = next_table(pde)?;
|
||||
|
||||
let pte = unsafe { (*pt).entries[pt_index(virtual_address)] };
|
||||
if pte & PRESENT == 0 {
|
||||
None
|
||||
} else {
|
||||
Some((pte & 0x000f_ffff_ffff_f000) | (virtual_address & 0xfff))
|
||||
}
|
||||
}
|
||||
|
||||
pub unsafe fn activate(&self) {
|
||||
unsafe {
|
||||
let cr4: u64;
|
||||
asm!("mov {}, cr4", out(reg) cr4, options(nostack, preserves_flags));
|
||||
asm!(
|
||||
"mov cr4, {}",
|
||||
in(reg) cr4 | CR4_PSE,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
asm!(
|
||||
"mov cr3, {}",
|
||||
in(reg) self.pml4 as u64,
|
||||
options(nostack, preserves_flags)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn root_table(&self) -> u64 {
|
||||
self.pml4 as u64
|
||||
}
|
||||
|
||||
pub fn identity_tables(&self) -> (*mut PageTable, [*mut PageTable; PDPTE_COUNT]) {
|
||||
(self.identity_pdpt, self.identity_pds)
|
||||
}
|
||||
|
||||
unsafe fn walk_create(
|
||||
&mut self,
|
||||
memory: &mut PhysicalMemoryManager,
|
||||
virtual_address: u64,
|
||||
) -> Option<*mut PageTable> {
|
||||
let mut table = self.pml4;
|
||||
for index in [
|
||||
pml4_index(virtual_address),
|
||||
pdpt_index(virtual_address),
|
||||
pd_index(virtual_address),
|
||||
] {
|
||||
unsafe {
|
||||
let entry = &mut (*table).entries[index];
|
||||
if *entry & HUGE_PAGE != 0 {
|
||||
return None;
|
||||
}
|
||||
if *entry & PRESENT == 0 {
|
||||
let new_table = memory.alloc_page()? as *mut PageTable;
|
||||
(*new_table).zero();
|
||||
*entry = new_table as u64 | PRESENT | WRITABLE | PageFlags::USER.bits();
|
||||
}
|
||||
table = (*entry & 0x000f_ffff_ffff_f000) as *mut PageTable;
|
||||
}
|
||||
}
|
||||
|
||||
Some(table)
|
||||
}
|
||||
|
||||
unsafe fn walk(&self, virtual_address: u64) -> Option<*mut PageTable> {
|
||||
let mut table = self.pml4;
|
||||
for index in [
|
||||
pml4_index(virtual_address),
|
||||
pdpt_index(virtual_address),
|
||||
pd_index(virtual_address),
|
||||
] {
|
||||
unsafe {
|
||||
let entry = (*table).entries[index];
|
||||
if entry & PRESENT == 0 || entry & HUGE_PAGE != 0 {
|
||||
return None;
|
||||
}
|
||||
table = (entry & 0x000f_ffff_ffff_f000) as *mut PageTable;
|
||||
}
|
||||
}
|
||||
|
||||
Some(table)
|
||||
}
|
||||
}
|
||||
|
||||
fn next_table(entry: u64) -> Option<*mut PageTable> {
|
||||
if entry & PRESENT == 0 {
|
||||
None
|
||||
} else {
|
||||
Some((entry & 0x000f_ffff_ffff_f000) as *mut PageTable)
|
||||
}
|
||||
}
|
||||
|
||||
fn pml4_index(address: u64) -> usize {
|
||||
((address >> 39) & 0x1ff) as usize
|
||||
}
|
||||
|
||||
fn pdpt_index(address: u64) -> usize {
|
||||
((address >> 30) & 0x1ff) as usize
|
||||
}
|
||||
|
||||
fn pd_index(address: u64) -> usize {
|
||||
((address >> 21) & 0x1ff) as usize
|
||||
}
|
||||
|
||||
fn pt_index(address: u64) -> usize {
|
||||
((address >> 12) & 0x1ff) as usize
|
||||
}
|
||||
|
||||
fn is_aligned(address: u64) -> bool {
|
||||
address as usize & (PAGE_SIZE - 1) == 0
|
||||
}
|
||||
|
||||
unsafe fn flush_tlb_one(virtual_address: u64) {
|
||||
unsafe {
|
||||
asm!("invlpg [{}]", in(reg) virtual_address, options(nostack, preserves_flags));
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user