mirror of https://github.com/vinc/moros.git
Add process page table (#454)
* Refactor kernel page table * Add mapper and frame_allocator * Set physical memory offset in bootloader crate * Load process page table * Set stack and boot-info addresses * Fix alloc error * Remove unused code * Add comment
This commit is contained in:
parent
e43d2e3c71
commit
bcdfd713ae
|
@ -42,5 +42,10 @@ uart_16550 = "0.2.19"
|
|||
vte = "0.13.0"
|
||||
x86_64 = "0.14.11"
|
||||
|
||||
[package.metadata.bootloader]
|
||||
physical-memory-offset = "0xFFFF800000000000"
|
||||
kernel-stack-address = "0xFFFFFF8000000000"
|
||||
boot-info-address = "0xFFFFFFFF80000000"
|
||||
|
||||
[package.metadata.bootimage]
|
||||
test-success-exit-code = 33 # (0x10 << 1) | 1
|
||||
|
|
|
@ -8,6 +8,7 @@ use core::cmp;
|
|||
use core::ops::{Index, IndexMut};
|
||||
use linked_list_allocator::LockedHeap;
|
||||
use spin::Mutex;
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use x86_64::structures::paging::mapper::MapToError;
|
||||
use x86_64::structures::paging::{FrameAllocator, Mapper, Page, PageTableFlags, Size4KiB};
|
||||
use x86_64::VirtAddr;
|
||||
|
@ -21,7 +22,10 @@ fn max_memory() -> u64 {
|
|||
option_env!("MOROS_MEMORY").unwrap_or("32").parse::<u64>().unwrap() << 20 // MB
|
||||
}
|
||||
|
||||
pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl FrameAllocator<Size4KiB>) -> Result<(), MapToError<Size4KiB>> {
|
||||
pub fn init_heap() -> Result<(), MapToError<Size4KiB>> {
|
||||
let mapper = sys::mem::mapper();
|
||||
let mut frame_allocator = sys::mem::frame_allocator();
|
||||
|
||||
// Use half of the memory for the heap caped to 16MB by default because the
|
||||
// allocator is slow.
|
||||
let heap_size = cmp::min(sys::mem::memory_size(), max_memory()) / 2;
|
||||
|
@ -39,7 +43,7 @@ pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl
|
|||
for page in pages {
|
||||
let frame = frame_allocator.allocate_frame().ok_or(MapToError::FrameAllocationFailed)?;
|
||||
unsafe {
|
||||
mapper.map_to(page, frame, flags, frame_allocator)?.flush();
|
||||
mapper.map_to(page, frame, flags, &mut frame_allocator)?.flush();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -50,10 +54,9 @@ pub fn init_heap(mapper: &mut impl Mapper<Size4KiB>, frame_allocator: &mut impl
|
|||
Ok(())
|
||||
}
|
||||
|
||||
pub fn alloc_pages(addr: u64, size: usize) -> Result<(), ()> {
|
||||
pub fn alloc_pages(mapper: &mut OffsetPageTable, addr: u64, size: usize) -> Result<(), ()> {
|
||||
//debug!("Alloc pages (addr={:#x}, size={})", addr, size);
|
||||
let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) };
|
||||
let mut frame_allocator = unsafe { sys::mem::BootInfoFrameAllocator::init(sys::mem::MEMORY_MAP.unwrap()) };
|
||||
let mut frame_allocator = sys::mem::frame_allocator();
|
||||
let flags = PageTableFlags::PRESENT | PageTableFlags::WRITABLE | PageTableFlags::USER_ACCESSIBLE;
|
||||
let pages = {
|
||||
let start_page = Page::containing_address(VirtAddr::new(addr));
|
||||
|
@ -84,8 +87,7 @@ pub fn alloc_pages(addr: u64, size: usize) -> Result<(), ()> {
|
|||
use x86_64::structures::paging::page::PageRangeInclusive;
|
||||
|
||||
// TODO: Replace `free` by `dealloc`
|
||||
pub fn free_pages(addr: u64, size: usize) {
|
||||
let mut mapper = unsafe { sys::mem::mapper(VirtAddr::new(sys::mem::PHYS_MEM_OFFSET)) };
|
||||
pub fn free_pages(mapper: &mut OffsetPageTable, addr: u64, size: usize) {
|
||||
let pages: PageRangeInclusive<Size4KiB> = {
|
||||
let start_page = Page::containing_address(VirtAddr::new(addr));
|
||||
let end_page = Page::containing_address(VirtAddr::new(addr + (size as u64) - 1));
|
||||
|
|
|
@ -9,6 +9,8 @@ use x86_64::instructions::interrupts;
|
|||
use x86_64::instructions::port::Port;
|
||||
use x86_64::registers::control::Cr2;
|
||||
use x86_64::structures::idt::{InterruptDescriptorTable, InterruptStackFrame, InterruptStackFrameValue, PageFaultErrorCode};
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use x86_64::VirtAddr;
|
||||
|
||||
const PIC1: u16 = 0x21;
|
||||
const PIC2: u16 = 0xA1;
|
||||
|
@ -110,7 +112,12 @@ extern "x86-interrupt" fn double_fault_handler(stack_frame: InterruptStackFrame,
|
|||
extern "x86-interrupt" fn page_fault_handler(_stack_frame: InterruptStackFrame, error_code: PageFaultErrorCode) {
|
||||
//debug!("EXCEPTION: PAGE FAULT ({:?})", error_code);
|
||||
let addr = Cr2::read().as_u64();
|
||||
if sys::allocator::alloc_pages(addr, 1).is_err() {
|
||||
|
||||
let page_table = unsafe { sys::process::page_table() };
|
||||
let phys_mem_offset = unsafe { sys::mem::PHYS_MEM_OFFSET.unwrap() };
|
||||
let mut mapper = unsafe { OffsetPageTable::new(page_table, VirtAddr::new(phys_mem_offset)) };
|
||||
|
||||
if sys::allocator::alloc_pages(&mut mapper, addr, 1).is_err() {
|
||||
let csi_color = api::console::Style::color("LightRed");
|
||||
let csi_reset = api::console::Style::reset();
|
||||
printk!("{}Error:{} Could not allocate address {:#x}\n", csi_color, csi_reset, addr);
|
||||
|
@ -161,7 +168,7 @@ macro_rules! wrap {
|
|||
"push r11",
|
||||
"mov rsi, rsp", // Arg #2: register list
|
||||
"mov rdi, rsp", // Arg #1: interupt frame
|
||||
"add rdi, 9 * 8",
|
||||
"add rdi, 9 * 8", // 9 registers * 8 bytes
|
||||
"call {}",
|
||||
"pop r11",
|
||||
"pop r10",
|
||||
|
|
|
@ -6,9 +6,10 @@ use x86_64::registers::control::Cr3;
|
|||
use x86_64::structures::paging::{FrameAllocator, OffsetPageTable, PageTable, PhysFrame, Size4KiB, Translate};
|
||||
use x86_64::{PhysAddr, VirtAddr};
|
||||
|
||||
// NOTE: mutable but changed only once during initialization
|
||||
pub static mut PHYS_MEM_OFFSET: u64 = 0;
|
||||
pub static mut PHYS_MEM_OFFSET: Option<u64> = None;
|
||||
pub static mut MEMORY_MAP: Option<&MemoryMap> = None;
|
||||
pub static mut MAPPER: Option<OffsetPageTable<'static>> = None;
|
||||
|
||||
pub static MEMORY_SIZE: AtomicU64 = AtomicU64::new(0);
|
||||
|
||||
static ALLOCATED_FRAMES: AtomicUsize = AtomicUsize::new(0);
|
||||
|
@ -25,41 +26,45 @@ pub fn init(boot_info: &'static BootInfo) {
|
|||
log!("MEM {} KB\n", memory_size >> 10);
|
||||
MEMORY_SIZE.store(memory_size, Ordering::Relaxed);
|
||||
|
||||
unsafe { PHYS_MEM_OFFSET = boot_info.physical_memory_offset };
|
||||
let phys_mem_offset = boot_info.physical_memory_offset;
|
||||
|
||||
unsafe { PHYS_MEM_OFFSET.replace(phys_mem_offset) };
|
||||
unsafe { MEMORY_MAP.replace(&boot_info.memory_map) };
|
||||
unsafe { MAPPER.replace(OffsetPageTable::new(active_page_table(), VirtAddr::new(phys_mem_offset))) };
|
||||
|
||||
let mut mapper = unsafe { mapper(VirtAddr::new(PHYS_MEM_OFFSET)) };
|
||||
let mut frame_allocator = unsafe { BootInfoFrameAllocator::init(&boot_info.memory_map) };
|
||||
|
||||
sys::allocator::init_heap(&mut mapper, &mut frame_allocator).expect("heap initialization failed");
|
||||
sys::allocator::init_heap().expect("heap initialization failed");
|
||||
});
|
||||
}
|
||||
|
||||
pub fn mapper() -> &'static mut OffsetPageTable<'static> {
|
||||
unsafe { sys::mem::MAPPER.as_mut().unwrap() }
|
||||
}
|
||||
|
||||
pub fn memory_size() -> u64 {
|
||||
MEMORY_SIZE.load(Ordering::Relaxed)
|
||||
}
|
||||
|
||||
pub fn phys_to_virt(addr: PhysAddr) -> VirtAddr {
|
||||
VirtAddr::new(addr.as_u64() + unsafe { PHYS_MEM_OFFSET })
|
||||
let phys_mem_offset = unsafe { PHYS_MEM_OFFSET.unwrap() };
|
||||
VirtAddr::new(addr.as_u64() + phys_mem_offset)
|
||||
}
|
||||
|
||||
pub fn virt_to_phys(addr: VirtAddr) -> Option<PhysAddr> {
|
||||
let mapper = unsafe { mapper(VirtAddr::new(PHYS_MEM_OFFSET)) };
|
||||
mapper.translate_addr(addr)
|
||||
mapper().translate_addr(addr)
|
||||
}
|
||||
|
||||
pub unsafe fn mapper(physical_memory_offset: VirtAddr) -> OffsetPageTable<'static> {
|
||||
let level_4_table = active_level_4_table(physical_memory_offset);
|
||||
OffsetPageTable::new(level_4_table, physical_memory_offset)
|
||||
pub unsafe fn active_page_table() -> &'static mut PageTable {
|
||||
let (frame, _) = Cr3::read();
|
||||
let phys_addr = frame.start_address();
|
||||
let virt_addr = phys_to_virt(phys_addr);
|
||||
let page_table_ptr: *mut PageTable = virt_addr.as_mut_ptr();
|
||||
&mut *page_table_ptr // unsafe
|
||||
}
|
||||
|
||||
unsafe fn active_level_4_table(physical_memory_offset: VirtAddr) -> &'static mut PageTable {
|
||||
let (level_4_table_frame, _) = Cr3::read();
|
||||
|
||||
let phys = level_4_table_frame.start_address();
|
||||
let virt = physical_memory_offset + phys.as_u64();
|
||||
let page_table_ptr: *mut PageTable = virt.as_mut_ptr();
|
||||
|
||||
pub unsafe fn create_page_table(frame: PhysFrame) -> &'static mut PageTable {
|
||||
let phys_addr = frame.start_address();
|
||||
let virt_addr = phys_to_virt(phys_addr);
|
||||
let page_table_ptr: *mut PageTable = virt_addr.as_mut_ptr();
|
||||
&mut *page_table_ptr // unsafe
|
||||
}
|
||||
|
||||
|
@ -91,3 +96,7 @@ unsafe impl FrameAllocator<Size4KiB> for BootInfoFrameAllocator {
|
|||
self.usable_frames().nth(next)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn frame_allocator() -> BootInfoFrameAllocator {
|
||||
unsafe { BootInfoFrameAllocator::init(MEMORY_MAP.unwrap()) }
|
||||
}
|
||||
|
|
|
@ -12,6 +12,11 @@ use lazy_static::lazy_static;
|
|||
use object::{Object, ObjectSegment};
|
||||
use spin::RwLock;
|
||||
use x86_64::structures::idt::InterruptStackFrameValue;
|
||||
use x86_64::registers::control::Cr3;
|
||||
use x86_64::structures::paging::FrameAllocator;
|
||||
use x86_64::structures::paging::OffsetPageTable;
|
||||
use x86_64::structures::paging::PhysFrame;
|
||||
use x86_64::structures::paging::PageTable;
|
||||
|
||||
const MAX_HANDLES: usize = 64;
|
||||
const MAX_PROCS: usize = 2; // TODO: Update this when more than one process can run at once
|
||||
|
@ -183,9 +188,29 @@ pub fn set_stack_frame(stack_frame: InterruptStackFrameValue) {
|
|||
pub fn exit() {
|
||||
let table = PROCESS_TABLE.read();
|
||||
let proc = &table[id()];
|
||||
sys::allocator::free_pages(proc.code_addr, MAX_PROC_SIZE);
|
||||
|
||||
let page_table = unsafe { sys::mem::create_page_table(proc.page_table_frame) };
|
||||
let phys_mem_offset = unsafe { sys::mem::PHYS_MEM_OFFSET.unwrap() };
|
||||
let mut mapper = unsafe { OffsetPageTable::new(page_table, VirtAddr::new(phys_mem_offset)) };
|
||||
|
||||
sys::allocator::free_pages(&mut mapper, proc.code_addr, MAX_PROC_SIZE);
|
||||
MAX_PID.fetch_sub(1, Ordering::SeqCst);
|
||||
set_id(0); // FIXME: No process manager so we switch back to process 0
|
||||
|
||||
unsafe {
|
||||
let (_, flags) = Cr3::read();
|
||||
Cr3::write(page_table_frame(), flags);
|
||||
}
|
||||
}
|
||||
|
||||
unsafe fn page_table_frame() -> PhysFrame {
|
||||
let table = PROCESS_TABLE.read();
|
||||
let proc = &table[id()];
|
||||
proc.page_table_frame
|
||||
}
|
||||
|
||||
pub unsafe fn page_table() -> &'static mut PageTable {
|
||||
sys::mem::create_page_table(page_table_frame())
|
||||
}
|
||||
|
||||
/************************
|
||||
|
@ -209,7 +234,7 @@ pub fn init_process_addr(addr: u64) {
|
|||
|
||||
#[repr(align(8), C)]
|
||||
#[derive(Debug, Clone, Copy, Default)]
|
||||
pub struct Registers {
|
||||
pub struct Registers { // Saved scratch registers
|
||||
pub r11: usize,
|
||||
pub r10: usize,
|
||||
pub r9: usize,
|
||||
|
@ -229,7 +254,8 @@ pub struct Process {
|
|||
id: usize,
|
||||
code_addr: u64,
|
||||
stack_addr: u64,
|
||||
entry_point: u64,
|
||||
entry_point_addr: u64,
|
||||
page_table_frame: PhysFrame,
|
||||
stack_frame: InterruptStackFrameValue,
|
||||
registers: Registers,
|
||||
data: ProcessData,
|
||||
|
@ -248,8 +274,9 @@ impl Process {
|
|||
id,
|
||||
code_addr: 0,
|
||||
stack_addr: 0,
|
||||
entry_point: 0,
|
||||
entry_point_addr: 0,
|
||||
stack_frame: isf,
|
||||
page_table_frame: Cr3::read().0,
|
||||
registers: Registers::default(),
|
||||
data: ProcessData::new("/", None),
|
||||
}
|
||||
|
@ -269,18 +296,32 @@ impl Process {
|
|||
}
|
||||
|
||||
fn create(bin: &[u8]) -> Result<usize, ()> {
|
||||
let page_table_frame = sys::mem::frame_allocator().allocate_frame().expect("frame allocation failed");
|
||||
let page_table = unsafe { sys::mem::create_page_table(page_table_frame) };
|
||||
let kernel_page_table = unsafe { sys::mem::active_page_table() };
|
||||
|
||||
// FIXME: for now we just copy everything
|
||||
for (user_page, kernel_page) in page_table.iter_mut().zip(kernel_page_table.iter()) {
|
||||
*user_page = kernel_page.clone();
|
||||
}
|
||||
|
||||
let phys_mem_offset = unsafe { sys::mem::PHYS_MEM_OFFSET.unwrap() };
|
||||
let mut mapper = unsafe { OffsetPageTable::new(page_table, VirtAddr::new(phys_mem_offset)) };
|
||||
|
||||
let proc_size = MAX_PROC_SIZE as u64;
|
||||
let code_addr = CODE_ADDR.fetch_add(proc_size, Ordering::SeqCst);
|
||||
let stack_addr = code_addr + proc_size;
|
||||
//debug!("code_addr: {:#x}", code_addr);
|
||||
//debug!("stack_addr: {:#x}", stack_addr);
|
||||
|
||||
let mut entry_point = 0;
|
||||
let mut entry_point_addr = 0;
|
||||
let code_ptr = code_addr as *mut u8;
|
||||
let code_size = bin.len();
|
||||
sys::allocator::alloc_pages(&mut mapper, code_addr, code_size).expect("proc mem alloc");
|
||||
if bin[0..4] == ELF_MAGIC { // ELF binary
|
||||
if let Ok(obj) = object::File::parse(bin) {
|
||||
//sys::allocator::alloc_pages(code_addr, proc_size as usize).expect("proc mem alloc");
|
||||
entry_point = obj.entry();
|
||||
entry_point_addr = obj.entry();
|
||||
sys::allocator::alloc_pages(&mut mapper, code_addr + entry_point_addr, code_size).expect("proc mem alloc");
|
||||
for segment in obj.segments() {
|
||||
let addr = segment.address() as usize;
|
||||
if let Ok(data) = segment.data() {
|
||||
|
@ -292,7 +333,7 @@ impl Process {
|
|||
}
|
||||
}
|
||||
} else if bin[0..4] == BIN_MAGIC { // Flat binary
|
||||
//sys::allocator::alloc_pages(code_addr, proc_size as usize).expect("proc mem alloc");
|
||||
//sys::allocator::alloc_pages(&mut mapper, code_addr, code_size).expect("proc mem alloc");
|
||||
for (i, b) in bin.iter().skip(4).enumerate() {
|
||||
unsafe { core::ptr::write(code_ptr.add(i), *b) };
|
||||
}
|
||||
|
@ -301,8 +342,8 @@ impl Process {
|
|||
}
|
||||
|
||||
let parent = {
|
||||
let table = PROCESS_TABLE.read();
|
||||
table[id()].clone()
|
||||
let process_table = PROCESS_TABLE.read();
|
||||
process_table[id()].clone()
|
||||
};
|
||||
|
||||
let data = parent.data.clone();
|
||||
|
@ -310,19 +351,24 @@ impl Process {
|
|||
let stack_frame = parent.stack_frame;
|
||||
|
||||
let id = MAX_PID.fetch_add(1, Ordering::SeqCst);
|
||||
let proc = Process { id, code_addr, stack_addr, entry_point, data, stack_frame, registers };
|
||||
let proc = Process {
|
||||
id, code_addr, stack_addr, entry_point_addr, page_table_frame, data, stack_frame, registers
|
||||
};
|
||||
|
||||
let mut table = PROCESS_TABLE.write();
|
||||
table[id] = Box::new(proc);
|
||||
let mut process_table = PROCESS_TABLE.write();
|
||||
process_table[id] = Box::new(proc);
|
||||
|
||||
Ok(id)
|
||||
}
|
||||
|
||||
// Switch to user mode and execute the program
|
||||
fn exec(&self, args_ptr: usize, args_len: usize) {
|
||||
let page_table = unsafe { sys::process::page_table() };
|
||||
let phys_mem_offset = unsafe { sys::mem::PHYS_MEM_OFFSET.unwrap() };
|
||||
let mut mapper = unsafe { OffsetPageTable::new(page_table, VirtAddr::new(phys_mem_offset)) };
|
||||
|
||||
let heap_addr = self.code_addr + (self.stack_addr - self.code_addr) / 2;
|
||||
//debug!("heap_addr: {:#x}", heap_addr);
|
||||
sys::allocator::alloc_pages(heap_addr, 1).expect("proc heap alloc");
|
||||
sys::allocator::alloc_pages(&mut mapper, heap_addr, 1).expect("proc heap alloc");
|
||||
|
||||
let args_ptr = ptr_from_addr(args_ptr as u64) as usize;
|
||||
let args: &[&str] = unsafe { core::slice::from_raw_parts(args_ptr as *const &str, args_len) };
|
||||
|
@ -348,7 +394,11 @@ impl Process {
|
|||
let args_ptr = args.as_ptr() as u64;
|
||||
|
||||
set_id(self.id); // Change PID
|
||||
|
||||
unsafe {
|
||||
let (_, flags) = Cr3::read();
|
||||
Cr3::write(self.page_table_frame, flags);
|
||||
|
||||
asm!(
|
||||
"cli", // Disable interrupts
|
||||
"push {:r}", // Stack segment (SS)
|
||||
|
@ -360,7 +410,7 @@ impl Process {
|
|||
in(reg) GDT.1.user_data.0,
|
||||
in(reg) self.stack_addr,
|
||||
in(reg) GDT.1.user_code.0,
|
||||
in(reg) self.code_addr + self.entry_point,
|
||||
in(reg) self.code_addr + self.entry_point_addr,
|
||||
in("rdi") args_ptr,
|
||||
in("rsi") args_len,
|
||||
);
|
||||
|
|
Loading…
Reference in New Issue