HUGE REFACTOR for memory mod: unified to `MemorySet`!

toolchain_update
WangRunji 7 years ago
parent b715cecf8d
commit 2e9ffb84fa

@ -8,15 +8,14 @@ pub mod keyboard;
pub mod pit; pub mod pit;
pub mod ide; pub mod ide;
pub fn init(mut page_map: impl FnMut(usize)) -> acpi::AcpiResult { pub fn init(mut page_map: impl FnMut(usize, usize)) -> acpi::AcpiResult {
assert_has_not_been_called!(); assert_has_not_been_called!();
// TODO Handle this temp page map. page_map(0, 1); // EBDA
page_map(0); // EBDA page_map(0xe0_000, 0x100 - 0xe0);
for addr in (0xE0000 .. 0x100000).step_by(0x1000) { page_map(0x07fe1000, 1); // RSDT
page_map(addr); page_map(0xfee00000, 1); // LAPIC
} page_map(0xfec00000, 1); // IOAPIC
page_map(0x7fe1000); // RSDT
let acpi = acpi::init().expect("Failed to init ACPI"); let acpi = acpi::init().expect("Failed to init ACPI");
assert_eq!(acpi.lapic_addr as usize, 0xfee00000); assert_eq!(acpi.lapic_addr as usize, 0xfee00000);
@ -24,10 +23,6 @@ pub fn init(mut page_map: impl FnMut(usize)) -> acpi::AcpiResult {
if cfg!(feature = "use_apic") { if cfg!(feature = "use_apic") {
pic::disable(); pic::disable();
page_map(0xfee00000); // LAPIC
page_map(0xFEC00000); // IOAPIC
apic::init(acpi.lapic_addr, acpi.ioapic_id); apic::init(acpi.lapic_addr, acpi.ioapic_id);
} else { } else {
pic::init(); pic::init();

@ -144,7 +144,10 @@ impl ActivePageTable {
pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable { pub fn switch(&mut self, new_table: InactivePageTable) -> InactivePageTable {
use x86_64::PhysicalAddress; use x86_64::PhysicalAddress;
use x86_64::registers::control_regs; use x86_64::registers::control_regs;
debug!("switch table to {:?}", new_table.p4_frame); debug!("switch table {:?} -> {:?}", Frame::of_addr(control_regs::cr3().0 as usize), new_table.p4_frame);
if new_table.p4_frame.start_address() == control_regs::cr3() {
return new_table;
}
let old_table = InactivePageTable { let old_table = InactivePageTable {
p4_frame: Frame::of_addr(control_regs::cr3().0 as usize), p4_frame: Frame::of_addr(control_regs::cr3().0 as usize),

@ -1,6 +1,7 @@
use arch::driver::{acpi::AcpiResult, apic::start_ap}; use arch::driver::{acpi::AcpiResult, apic::start_ap};
use memory::{MemoryController, PhysAddr}; use memory::*;
use core::ptr::{read_volatile, write_volatile}; use core::ptr::{read_volatile, write_volatile};
use x86_64::registers::control_regs::cr3;
extern { extern {
fn entryother_start(); // physical addr of entryother fn entryother_start(); // physical addr of entryother
@ -9,26 +10,23 @@ extern {
const ENTRYOTHER_ADDR: u32 = 0x7000; const ENTRYOTHER_ADDR: u32 = 0x7000;
pub fn start_other_cores(acpi: &AcpiResult, mc: &mut MemoryController) { pub fn start_other_cores(acpi: &AcpiResult, ms: &mut MemorySet) {
mc.map_page_identity(ENTRYOTHER_ADDR as usize - 1); use consts::KERNEL_OFFSET;
mc.map_page_identity(ENTRYOTHER_ADDR as usize); ms.push(MemoryArea::new_identity(ENTRYOTHER_ADDR as usize - 1, ENTRYOTHER_ADDR as usize + 1, MemoryAttr::default(), "entry_other"));
mc.map_page_identity(entryother_start as usize); ms.push(MemoryArea::new_identity(entryother_start as usize, entryother_start as usize + 1, MemoryAttr::default(), "entry_other"));
mc.map_page_p2v(PhysAddr(0)); ms.push(MemoryArea::new_kernel(KERNEL_OFFSET, KERNEL_OFFSET + 1, MemoryAttr::default(), "entry_other3"));
copy_entryother(); copy_entryother();
let args = unsafe{ &mut *(ENTRYOTHER_ADDR as *mut EntryArgs).offset(-1) }; let args = unsafe{ &mut *(ENTRYOTHER_ADDR as *mut EntryArgs).offset(-1) };
let page_table = unsafe{ *(0xFFFF_FFFF_FFFF_FFF8 as *const u32) } & 0xFFFF_F000;
for i in 1 .. acpi.cpu_num { for i in 1 .. acpi.cpu_num {
let apic_id = acpi.cpu_acpi_ids[i as usize]; let apic_id = acpi.cpu_acpi_ids[i as usize];
let kstack = mc.alloc_stack(7).unwrap(); let ms = MemorySet::new(7);
let kstack_top = kstack.top() as u64;
use core::mem::forget;
forget(kstack); // TODO pass this kstack to new AP
*args = EntryArgs { *args = EntryArgs {
kstack: kstack_top, kstack: ms.kstack_top() as u64,
page_table: page_table, page_table: ms._page_table_addr().0 as u32,
stack: 0x8000, // just enough stack to get us to entry64mp stack: 0x8000, // just enough stack to get us to entry64mp
}; };
unsafe { MS = Some(ms); }
start_ap(apic_id, ENTRYOTHER_ADDR); start_ap(apic_id, ENTRYOTHER_ADDR);
while unsafe { !read_volatile(&STARTED[i as usize]) } {} while unsafe { !read_volatile(&STARTED[i as usize]) } {}
} }
@ -45,6 +43,7 @@ fn copy_entryother() {
} }
#[repr(C)] #[repr(C)]
#[derive(Debug)]
struct EntryArgs { struct EntryArgs {
kstack: u64, kstack: u64,
page_table: u32, page_table: u32,
@ -53,7 +52,9 @@ struct EntryArgs {
use consts::MAX_CPU_NUM; use consts::MAX_CPU_NUM;
static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM]; static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM];
static mut MS: Option<MemorySet> = None;
pub unsafe fn notify_started(cpu_id: u8) { pub unsafe fn notify_started(cpu_id: u8) -> MemorySet {
write_volatile(&mut STARTED[cpu_id as usize], true); write_volatile(&mut STARTED[cpu_id as usize], true);
MS.take().unwrap()
} }

@ -70,7 +70,7 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
let boot_info = unsafe { multiboot2::load(multiboot_information_address) }; let boot_info = unsafe { multiboot2::load(multiboot_information_address) };
// set up guard page and map the heap pages // set up guard page and map the heap pages
let mut memory_controller = memory::init(boot_info); let mut kernel_memory = memory::init(boot_info);
arch::gdt::init(); arch::gdt::init();
@ -79,12 +79,14 @@ pub extern "C" fn rust_main(multiboot_information_address: usize) -> ! {
test!(guard_page); test!(guard_page);
test!(find_mp); test!(find_mp);
let acpi = arch::driver::init( use memory::*;
|addr: usize| memory_controller.map_page_identity(addr)); let acpi = arch::driver::init(|addr: usize, count: usize| {
// memory_controller.print_page_table(); kernel_memory.push(MemoryArea::new_identity(addr, addr + count * 0x1000, MemoryAttr::default(), "acpi"))
});
arch::smp::start_other_cores(&acpi, &mut memory_controller); // FIXME: PageFault when SMP
process::init(memory_controller); // arch::smp::start_other_cores(&acpi, &mut kernel_memory);
process::init(kernel_memory);
fs::load_sfs(); fs::load_sfs();
@ -127,7 +129,7 @@ pub extern "C" fn other_main() -> ! {
arch::driver::apic::other_init(); arch::driver::apic::other_init();
let cpu_id = arch::driver::apic::lapic_id(); let cpu_id = arch::driver::apic::lapic_id();
println!("Hello world! from CPU {}!", arch::driver::apic::lapic_id()); println!("Hello world! from CPU {}!", arch::driver::apic::lapic_id());
unsafe{ arch::smp::notify_started(cpu_id); } let ms = unsafe { arch::smp::notify_started(cpu_id) };
// unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault // unsafe{ let a = *(0xdeadbeaf as *const u8); } // Page fault
loop {} loop {}
} }

@ -9,38 +9,38 @@ pub struct MemoryArea {
start_addr: VirtAddr, start_addr: VirtAddr,
end_addr: VirtAddr, end_addr: VirtAddr,
phys_start_addr: Option<PhysAddr>, phys_start_addr: Option<PhysAddr>,
flags: u64, flags: MemoryAttr,
name: &'static str, name: &'static str,
} }
impl MemoryArea { impl MemoryArea {
pub fn new(start_addr: VirtAddr, end_addr: VirtAddr, flags: EntryFlags, name: &'static str) -> Self { pub fn new(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self {
assert!(start_addr <= end_addr, "invalid memory area"); assert!(start_addr <= end_addr, "invalid memory area");
MemoryArea { MemoryArea {
start_addr, start_addr,
end_addr, end_addr,
phys_start_addr: None, phys_start_addr: None,
flags: flags.bits(), flags,
name, name,
} }
} }
pub fn new_identity(start_addr: VirtAddr, end_addr: VirtAddr, flags: EntryFlags, name: &'static str) -> Self { pub fn new_identity(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self {
assert!(start_addr <= end_addr, "invalid memory area"); assert!(start_addr <= end_addr, "invalid memory area");
MemoryArea { MemoryArea {
start_addr, start_addr,
end_addr, end_addr,
phys_start_addr: Some(PhysAddr(start_addr as u64)), phys_start_addr: Some(PhysAddr(start_addr as u64)),
flags: flags.bits(), flags,
name, name,
} }
} }
pub fn new_kernel(start_addr: VirtAddr, end_addr: VirtAddr, flags: EntryFlags, name: &'static str) -> Self { pub fn new_kernel(start_addr: VirtAddr, end_addr: VirtAddr, flags: MemoryAttr, name: &'static str) -> Self {
assert!(start_addr <= end_addr, "invalid memory area"); assert!(start_addr <= end_addr, "invalid memory area");
MemoryArea { MemoryArea {
start_addr, start_addr,
end_addr, end_addr,
phys_start_addr: Some(PhysAddr::from_kernel_virtual(start_addr)), phys_start_addr: Some(PhysAddr::from_kernel_virtual(start_addr)),
flags: flags.bits(), flags,
name, name,
} }
} }
@ -62,21 +62,70 @@ impl MemoryArea {
let p3 = Page::of_addr(other.end_addr - 1) + 1; let p3 = Page::of_addr(other.end_addr - 1) + 1;
!(p1 <= p2 || p0 >= p3) !(p1 <= p2 || p0 >= p3)
} }
fn map(&self, pt: &mut Mapper) {
match self.phys_start_addr {
Some(phys_start) => {
for page in Page::range_of(self.start_addr, self.end_addr) {
let frame = Frame::of_addr(phys_start.get() + page.start_address() - self.start_addr);
pt.map_to(page, frame.clone(), self.flags.0);
}
}
None => {
for page in Page::range_of(self.start_addr, self.end_addr) {
pt.map(page, self.flags.0);
}
}
}
}
fn unmap(&self, pt: &mut Mapper) {
for page in Page::range_of(self.start_addr, self.end_addr) {
pt.unmap(page);
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub struct MemoryAttr(EntryFlags);
impl Default for MemoryAttr {
fn default() -> Self {
MemoryAttr(EntryFlags::PRESENT | EntryFlags::NO_EXECUTE | EntryFlags::WRITABLE)
}
}
impl MemoryAttr {
pub fn user(mut self) -> Self {
self.0 |= EntryFlags::USER_ACCESSIBLE;
self
}
pub fn readonly(mut self) -> Self {
self.0.remove(EntryFlags::WRITABLE);
self
}
pub fn execute(mut self) -> Self {
self.0.remove(EntryFlags::NO_EXECUTE);
self
}
pub fn hide(mut self) -> Self {
self.0.remove(EntryFlags::PRESENT);
self
}
} }
/// 内存空间集合,包含若干段连续空间 /// 内存空间集合,包含若干段连续空间
/// 对应ucore中 `mm_struct` /// 对应ucore中 `mm_struct`
#[derive(Clone)]
pub struct MemorySet { pub struct MemorySet {
areas: Vec<MemoryArea>, areas: Vec<MemoryArea>,
// page_table: Option<InactivePageTable>, page_table: InactivePageTable,
kstack: Option<Stack>,
} }
impl MemorySet { impl MemorySet {
pub fn new() -> Self { pub fn new(stack_size_in_pages: usize) -> Self {
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::new(), areas: Vec::<MemoryArea>::new(),
// page_table: None, page_table: new_page_table_with_kernel(),
kstack: Some(alloc_stack(stack_size_in_pages)),
} }
} }
/// Used for remap_kernel() where heap alloc is unavailable /// Used for remap_kernel() where heap alloc is unavailable
@ -85,7 +134,8 @@ impl MemorySet {
let cap = slice.len() / size_of::<MemoryArea>(); let cap = slice.len() / size_of::<MemoryArea>();
MemorySet { MemorySet {
areas: Vec::<MemoryArea>::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap), areas: Vec::<MemoryArea>::from_raw_parts(slice.as_ptr() as *mut MemoryArea, 0, cap),
// page_table: None, page_table: new_page_table(),
kstack: None,
} }
} }
pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> { pub fn find_area(&self, addr: VirtAddr) -> Option<&MemoryArea> {
@ -95,34 +145,63 @@ impl MemorySet {
assert!(self.areas.iter() assert!(self.areas.iter()
.find(|other| area.is_overlap_with(other)) .find(|other| area.is_overlap_with(other))
.is_none(), "memory area overlap"); .is_none(), "memory area overlap");
active_table().with(&mut self.page_table, |mapper| area.map(mapper));
self.areas.push(area); self.areas.push(area);
} }
pub fn map(&self, pt: &mut Mapper) { pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
for area in self.areas.iter() { self.areas.iter()
match area.phys_start_addr {
Some(phys_start) => {
for page in Page::range_of(area.start_addr, area.end_addr) {
let frame = Frame::of_addr(phys_start.get() + page.start_address() - area.start_addr);
pt.map_to(page, frame.clone(), EntryFlags::from_bits(area.flags.into()).unwrap());
}
},
None => {
for page in Page::range_of(area.start_addr, area.end_addr) {
pt.map(page, EntryFlags::from_bits(area.flags.into()).unwrap());
} }
}, pub fn with(&self, mut f: impl FnMut()) {
use core::{ptr, mem};
let page_table = unsafe { ptr::read(&self.page_table as *const InactivePageTable) };
let mut active_table = active_table();
let backup = active_table.switch(page_table);
f();
mem::forget(active_table.switch(backup));
}
pub fn switch(&self) {
use core::{ptr, mem};
let page_table = unsafe { ptr::read(&self.page_table as *const InactivePageTable) };
mem::forget(active_table().switch(page_table));
}
pub fn set_kstack(&mut self, stack: Stack) {
assert!(self.kstack.is_none());
self.kstack = Some(stack);
}
pub fn kstack_top(&self) -> usize {
self.kstack.as_ref().unwrap().top()
}
pub fn clone(&self, stack_size_in_pages: usize) -> Self {
let mut page_table = new_page_table_with_kernel();
active_table().with(&mut page_table, |mapper| {
for area in self.areas.iter() {
area.map(mapper);
} }
});
MemorySet {
areas: self.areas.clone(),
page_table,
kstack: Some(alloc_stack(stack_size_in_pages)),
} }
} }
pub fn unmap(&self, pt: &mut Mapper) { /// Only for SMP
for area in self.areas.iter() { pub fn _page_table_addr(&self) -> PhysAddr {
for page in Page::range_of(area.start_addr, area.end_addr) { use core::mem;
pt.unmap(page); unsafe { mem::transmute_copy::<_, Frame>(&self.page_table) }.start_address()
} }
} }
impl Drop for MemorySet {
fn drop(&mut self) {
debug!("MemorySet dropping");
let Self { ref mut page_table, ref areas, .. } = self;
active_table().with(page_table, |mapper| {
for area in areas.iter() {
area.unmap(mapper);
} }
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> { })
self.areas.iter()
} }
} }
@ -134,44 +213,25 @@ impl Debug for MemorySet {
} }
} }
#[cfg(test)] fn new_page_table() -> InactivePageTable {
mod test { let frame = alloc_frame();
use super::*; let mut active_table = active_table();
InactivePageTable::new(frame, &mut active_table)
#[test]
fn push_and_find() {
let mut ms = MemorySet::new();
ms.push(MemoryArea {
start_addr: 0x0,
end_addr: 0x8,
flags: 0x0,
name: "code",
});
ms.push(MemoryArea {
start_addr: 0x8,
end_addr: 0x10,
flags: 0x1,
name: "data",
});
assert_eq!(ms.find_area(0x6).unwrap().name, "code");
assert_eq!(ms.find_area(0x11), None);
} }
#[test] fn new_page_table_with_kernel() -> InactivePageTable {
#[should_panic] let frame = alloc_frame();
fn push_overlap() { let mut active_table = active_table();
let mut ms = MemorySet::new(); let mut page_table = InactivePageTable::new(frame, &mut active_table);
ms.push(MemoryArea {
start_addr: 0x0, use consts::{KERNEL_HEAP_PML4, KERNEL_PML4};
end_addr: 0x8, let e510 = active_table.p4()[KERNEL_PML4].clone();
flags: 0x0, let e509 = active_table.p4()[KERNEL_HEAP_PML4].clone();
name: "code",
}); active_table.with(&mut page_table, |pt: &mut Mapper| {
ms.push(MemoryArea { pt.p4_mut()[KERNEL_PML4] = e510;
start_addr: 0x4, pt.p4_mut()[KERNEL_HEAP_PML4] = e509;
end_addr: 0x10, pt.identity_map(Frame::of_addr(0xfee00000), EntryFlags::WRITABLE); // LAPIC
flags: 0x1,
name: "data",
}); });
} page_table
} }

@ -1,6 +1,6 @@
pub use self::area_frame_allocator::AreaFrameAllocator; pub use self::area_frame_allocator::AreaFrameAllocator;
pub use arch::paging::*; pub use arch::paging::*;
pub use self::stack_allocator::Stack; pub use self::stack_allocator::*;
pub use self::address::*; pub use self::address::*;
pub use self::frame::*; pub use self::frame::*;
pub use self::memory_set::*; pub use self::memory_set::*;
@ -8,7 +8,7 @@ pub use self::memory_set::*;
use multiboot2::BootInformation; use multiboot2::BootInformation;
use consts::KERNEL_OFFSET; use consts::KERNEL_OFFSET;
use arch::paging; use arch::paging;
use spin::Mutex; use spin::{Mutex, MutexGuard};
use super::HEAP_ALLOCATOR; use super::HEAP_ALLOCATOR;
mod memory_set; mod memory_set;
@ -19,6 +19,7 @@ mod address;
mod frame; mod frame;
pub static FRAME_ALLOCATOR: Mutex<Option<AreaFrameAllocator>> = Mutex::new(None); pub static FRAME_ALLOCATOR: Mutex<Option<AreaFrameAllocator>> = Mutex::new(None);
pub static STACK_ALLOCATOR: Mutex<Option<StackAllocator>> = Mutex::new(None);
pub fn alloc_frame() -> Frame { pub fn alloc_frame() -> Frame {
FRAME_ALLOCATOR.lock() FRAME_ALLOCATOR.lock()
@ -26,18 +27,49 @@ pub fn alloc_frame() -> Frame {
.allocate_frame().expect("no more frame") .allocate_frame().expect("no more frame")
} }
fn alloc_stack(size_in_pages: usize) -> Stack {
let mut active_table = active_table();
STACK_ALLOCATOR.lock()
.as_mut().expect("stack allocator is not initialized")
.alloc_stack(&mut active_table, size_in_pages).expect("no more stack")
}
/// The only way to get active page table
fn active_table() -> MutexGuard<'static, ActivePageTable> {
static ACTIVE_TABLE: Mutex<ActivePageTable> = Mutex::new(unsafe { ActivePageTable::new() });
ACTIVE_TABLE.lock()
}
// Return true to continue, false to halt // Return true to continue, false to halt
pub fn page_fault_handler(addr: VirtAddr) -> bool { pub fn page_fault_handler(addr: VirtAddr) -> bool {
// Handle copy on write // Handle copy on write
let mut page_table = unsafe { ActivePageTable::new() }; active_table().try_copy_on_write(addr)
page_table.try_copy_on_write(addr)
} }
pub fn init(boot_info: BootInformation) -> MemoryController { pub fn init(boot_info: BootInformation) -> MemorySet {
assert_has_not_been_called!("memory::init must be called only once"); assert_has_not_been_called!("memory::init must be called only once");
info!("{:?}", boot_info); info!("{:?}", boot_info);
init_frame_allocator(&boot_info);
let kernel_memory = remap_the_kernel(boot_info);
use self::paging::Page;
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
unsafe { HEAP_ALLOCATOR.lock().init(KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE); }
*STACK_ALLOCATOR.lock() = Some({
let stack_alloc_range = Page::range_of(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE,
KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE + 0x1000000);
stack_allocator::StackAllocator::new(stack_alloc_range)
});
kernel_memory
}
fn init_frame_allocator(boot_info: &BootInformation) {
let memory_map_tag = boot_info.memory_map_tag().expect( let memory_map_tag = boot_info.memory_map_tag().expect(
"Memory map tag required"); "Memory map tag required");
let elf_sections_tag = boot_info.elf_sections_tag().expect( let elf_sections_tag = boot_info.elf_sections_tag().expect(
@ -54,53 +86,40 @@ pub fn init(boot_info: BootInformation) -> MemoryController {
*FRAME_ALLOCATOR.lock() = Some(AreaFrameAllocator::new( *FRAME_ALLOCATOR.lock() = Some(AreaFrameAllocator::new(
kernel_start, kernel_end, kernel_start, kernel_end,
boot_info_start, boot_info_end, boot_info_start, boot_info_end,
memory_map_tag.memory_areas() memory_map_tag.memory_areas(),
)); ));
let kernel_stack = remap_the_kernel(boot_info);
use self::paging::Page;
use consts::{KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
unsafe { HEAP_ALLOCATOR.lock().init(KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE); }
let stack_allocator = {
let stack_alloc_range = Page::range_of(KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE,
KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE + 0x1000000);
stack_allocator::StackAllocator::new(stack_alloc_range)
};
MemoryController {
kernel_stack: Some(kernel_stack),
active_table: unsafe { ActivePageTable::new() },
stack_allocator,
}
} }
pub fn remap_the_kernel(boot_info: BootInformation) -> Stack { fn remap_the_kernel(boot_info: BootInformation) -> MemorySet {
let mut active_table = unsafe { ActivePageTable::new() };
let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap()); let mut memory_set = MemorySet::from(boot_info.elf_sections_tag().unwrap());
use consts::{KERNEL_OFFSET, KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE}; use consts::{KERNEL_OFFSET, KERNEL_HEAP_OFFSET, KERNEL_HEAP_SIZE};
memory_set.push(MemoryArea::new_kernel(KERNEL_OFFSET + 0xb8000, KERNEL_OFFSET + 0xb9000, EntryFlags::WRITABLE, "VGA")); memory_set.push(MemoryArea::new_kernel(KERNEL_OFFSET + 0xb8000, KERNEL_OFFSET + 0xb9000, MemoryAttr::default(), "VGA"));
memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, EntryFlags::WRITABLE, "kernel_heap")); memory_set.push(MemoryArea::new(KERNEL_HEAP_OFFSET, KERNEL_HEAP_OFFSET + KERNEL_HEAP_SIZE, MemoryAttr::default(), "kernel_heap"));
let mut page_table = InactivePageTable::new(alloc_frame(), &mut active_table);
active_table.with(&mut page_table, |pt| memory_set.map(pt));
debug!("{:#x?}", memory_set); debug!("{:#x?}", memory_set);
let old_table = active_table.switch(page_table); memory_set.switch();
info!("NEW TABLE!!!"); info!("NEW TABLE!!!");
// turn the stack bottom into a guard page let kstack = get_init_kstack_and_set_guard_page();
memory_set.set_kstack(kstack);
memory_set
}
fn get_init_kstack_and_set_guard_page() -> Stack {
assert_has_not_been_called!();
extern { fn stack_bottom(); } extern { fn stack_bottom(); }
let stack_bottom = PhysAddr(stack_bottom as u64).to_kernel_virtual(); let stack_bottom = PhysAddr(stack_bottom as u64).to_kernel_virtual();
let stack_bottom_page = Page::of_addr(stack_bottom); let stack_bottom_page = Page::of_addr(stack_bottom);
active_table.unmap(stack_bottom_page);
let kernel_stack = Stack::new(stack_bottom + 8 * PAGE_SIZE, stack_bottom + 1 * PAGE_SIZE); // turn the stack bottom into a guard page
active_table().unmap(stack_bottom_page);
debug!("guard page at {:#x}", stack_bottom_page.start_address()); debug!("guard page at {:#x}", stack_bottom_page.start_address());
kernel_stack Stack::new(stack_bottom + 8 * PAGE_SIZE, stack_bottom + 1 * PAGE_SIZE)
} }
use multiboot2::{ElfSectionsTag, ElfSection, ElfSectionFlags}; use multiboot2::{ElfSectionsTag, ElfSection, ElfSectionFlags};
@ -111,11 +130,7 @@ impl From<ElfSectionsTag> for MemorySet {
// WARNING: must ensure it's large enough // WARNING: must ensure it's large enough
static mut SPACE: [u8; 0x1000] = [0; 0x1000]; static mut SPACE: [u8; 0x1000] = [0; 0x1000];
let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE) }; let mut set = unsafe { MemorySet::new_from_raw_space(&mut SPACE) };
for section in sections.sections() { for section in sections.sections().filter(|s| s.is_allocated()) {
if !section.is_allocated() {
// section is not loaded to memory
continue;
}
set.push(MemoryArea::from(section)); set.push(MemoryArea::from(section));
} }
set set
@ -133,76 +148,17 @@ impl From<ElfSection> for MemoryArea {
start_addr += KERNEL_OFFSET; start_addr += KERNEL_OFFSET;
end_addr += KERNEL_OFFSET; end_addr += KERNEL_OFFSET;
} }
MemoryArea::new_kernel(start_addr, end_addr, EntryFlags::from(section.flags()), name) MemoryArea::new_kernel(start_addr, end_addr, MemoryAttr::from(section.flags()), name)
} }
} }
impl From<ElfSectionFlags> for EntryFlags { impl From<ElfSectionFlags> for MemoryAttr {
fn from(elf_flags: ElfSectionFlags) -> Self { fn from(elf_flags: ElfSectionFlags) -> Self {
let mut flags = EntryFlags::empty(); let mut flags = MemoryAttr::default();
if elf_flags.contains(ElfSectionFlags::ALLOCATED) { if !elf_flags.contains(ElfSectionFlags::ALLOCATED) { flags = flags.hide(); }
// section is loaded to memory if !elf_flags.contains(ElfSectionFlags::WRITABLE) { flags = flags.readonly(); }
flags = flags | EntryFlags::PRESENT; if elf_flags.contains(ElfSectionFlags::EXECUTABLE) { flags = flags.execute(); }
}
if elf_flags.contains(ElfSectionFlags::WRITABLE) {
flags = flags | EntryFlags::WRITABLE;
}
if !elf_flags.contains(ElfSectionFlags::EXECUTABLE) {
flags = flags | EntryFlags::NO_EXECUTE;
}
flags flags
} }
} }
pub struct MemoryController {
pub kernel_stack: Option<Stack>,
active_table: paging::ActivePageTable,
stack_allocator: stack_allocator::StackAllocator,
}
impl MemoryController {
pub fn alloc_stack(&mut self, size_in_pages: usize) -> Option<Stack> {
let &mut MemoryController { ref mut kernel_stack,
ref mut active_table,
ref mut stack_allocator } = self;
stack_allocator.alloc_stack(active_table, size_in_pages)
}
pub fn new_page_table(&mut self) -> InactivePageTable {
let frame = alloc_frame();
let page_table = InactivePageTable::new(frame, &mut self.active_table);
page_table
}
pub fn map_page_identity(&mut self, addr: usize) {
let frame = Frame::of_addr(addr);
let flags = EntryFlags::WRITABLE;
self.active_table.identity_map(frame, flags);
}
pub fn map_page_p2v(&mut self, addr: PhysAddr) {
let page = Page::of_addr(addr.to_kernel_virtual());
let frame = Frame::of_addr(addr.get());
let flags = EntryFlags::WRITABLE;
self.active_table.map_to(page, frame, flags);
}
pub fn make_page_table(&mut self, set: &MemorySet) -> InactivePageTable {
let mut page_table = InactivePageTable::new(alloc_frame(), &mut self.active_table);
use consts::{KERNEL_HEAP_PML4, KERNEL_PML4};
let e510 = self.active_table.p4()[KERNEL_PML4].clone();
let e509 = self.active_table.p4()[KERNEL_HEAP_PML4].clone();
self.active_table.with(&mut page_table, |pt: &mut Mapper| {
set.map(pt);
pt.p4_mut()[KERNEL_PML4] = e510;
pt.p4_mut()[KERNEL_HEAP_PML4] = e509;
pt.identity_map(Frame::of_addr(0xfee00000), EntryFlags::WRITABLE); // LAPIC
});
page_table
}
pub fn with(&mut self, page_table: InactivePageTable, mut f: impl FnMut()) -> InactivePageTable {
let backup = self.active_table.switch(page_table);
f();
self.active_table.switch(backup)
}
}

@ -73,13 +73,6 @@ impl Stack {
pub fn bottom(&self) -> usize { pub fn bottom(&self) -> usize {
self.bottom self.bottom
} }
/// Push a value of type `T` at the top of the stack, return the rsp after.
pub fn push_at_top<T>(&self, value: T) -> usize {
let ptr = unsafe { (self.top as *mut T).offset(-1) };
unsafe { *ptr = value; }
ptr as usize
}
} }
impl Drop for Stack { impl Drop for Stack {

@ -1,4 +1,4 @@
use memory::MemoryController; use memory::MemorySet;
use spin::Once; use spin::Once;
use sync::SpinNoIrqLock; use sync::SpinNoIrqLock;
use core::slice; use core::slice;
@ -12,21 +12,19 @@ mod processor;
mod scheduler; mod scheduler;
pub fn init(mut mc: MemoryController) { pub fn init(mut ms: MemorySet) {
PROCESSOR.call_once(|| { PROCESSOR.call_once(|| {
SpinNoIrqLock::new({ SpinNoIrqLock::new({
let initproc = Process::new_init(&mut mc); let initproc = Process::new_init(ms);
let idleproc = Process::new("idle", idle_thread, 0, &mut mc); let idleproc = Process::new("idle", idle_thread, 0);
let mut processor = Processor::new(); let mut processor = Processor::new();
processor.add(initproc); processor.add(initproc);
processor.add(idleproc); processor.add(idleproc);
processor processor
})}); })});
MC.call_once(|| SpinNoIrqLock::new(mc));
} }
pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new(); pub static PROCESSOR: Once<SpinNoIrqLock<Processor>> = Once::new();
pub static MC: Once<SpinNoIrqLock<MemoryController>> = Once::new();
extern fn idle_thread(arg: usize) -> ! { extern fn idle_thread(arg: usize) -> ! {
loop { loop {
@ -40,16 +38,14 @@ extern fn idle_thread(arg: usize) -> ! {
pub fn add_user_process(name: impl AsRef<str>, data: &[u8]) { pub fn add_user_process(name: impl AsRef<str>, data: &[u8]) {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = PROCESSOR.try().unwrap().lock();
let mut mc = MC.try().unwrap().lock(); let mut new = Process::new_user(data);
let mut new = Process::new_user(data, &mut mc);
new.name = String::from(name.as_ref()); new.name = String::from(name.as_ref());
processor.add(new); processor.add(new);
} }
pub fn add_kernel_process(entry: extern fn(usize) -> !, arg: usize) -> Pid { pub fn add_kernel_process(entry: extern fn(usize) -> !, arg: usize) -> Pid {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = PROCESSOR.try().unwrap().lock();
let mut mc = MC.try().unwrap().lock(); let mut new = Process::new("", entry, arg);
let mut new = Process::new("", entry, arg, &mut mc);
processor.add(new) processor.add(new)
} }

@ -1,5 +1,5 @@
use super::*; use super::*;
use memory::{self, Stack, InactivePageTable}; use memory::{self, Stack, InactivePageTable, MemoryAttr};
use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2}; use xmas_elf::{ElfFile, program::{Flags, ProgramHeader}, header::HeaderPt2};
use core::slice; use core::slice;
use alloc::{rc::Rc, String}; use alloc::{rc::Rc, String};
@ -10,9 +10,7 @@ pub struct Process {
pub(in process) pid: Pid, pub(in process) pid: Pid,
pub(in process) parent: Pid, pub(in process) parent: Pid,
pub(in process) name: String, pub(in process) name: String,
kstack: Stack, pub(in process) memory_set: MemorySet,
pub(in process) memory_set: Option<MemorySet>,
pub(in process) page_table: Option<InactivePageTable>,
pub(in process) status: Status, pub(in process) status: Status,
pub(in process) context: Context, pub(in process) context: Context,
pub(in process) is_user: bool, pub(in process) is_user: bool,
@ -32,18 +30,16 @@ pub enum Status {
impl Process { impl Process {
/// Make a new kernel thread /// Make a new kernel thread
pub fn new(name: &str, entry: extern fn(usize) -> !, arg: usize, mc: &mut MemoryController) -> Self { pub fn new(name: &str, entry: extern fn(usize) -> !, arg: usize) -> Self {
let kstack = mc.alloc_stack(7).unwrap(); let ms = MemorySet::new(7);
let data = InitStack::new_kernel_thread(entry, arg, kstack.top()); let data = InitStack::new_kernel_thread(entry, arg, ms.kstack_top());
let context = unsafe { data.push_at(kstack.top()) }; let context = unsafe { data.push_at(ms.kstack_top()) };
Process { Process {
pid: 0, pid: 0,
parent: 0, parent: 0,
name: String::from(name), name: String::from(name),
kstack, memory_set: ms,
memory_set: None,
page_table: None,
status: Status::Ready, status: Status::Ready,
context, context,
is_user: false, is_user: false,
@ -52,15 +48,13 @@ impl Process {
/// Make the first kernel thread `initproc` /// Make the first kernel thread `initproc`
/// Should be called only once /// Should be called only once
pub fn new_init(mc: &mut MemoryController) -> Self { pub fn new_init(ms: MemorySet) -> Self {
assert_has_not_been_called!(); assert_has_not_been_called!();
Process { Process {
pid: 0, pid: 0,
parent: 0, parent: 0,
name: String::from("init"), name: String::from("init"),
kstack: mc.kernel_stack.take().unwrap(), memory_set: ms,
memory_set: None,
page_table: None,
status: Status::Running, status: Status::Running,
context: unsafe { Context::null() }, // will be set at first schedule context: unsafe { Context::null() }, // will be set at first schedule
is_user: false, is_user: false,
@ -70,7 +64,7 @@ impl Process {
/// Make a new user thread /// Make a new user thread
/// The program elf data is placed at [begin, end) /// The program elf data is placed at [begin, end)
/// uCore x86 32bit program is planned to be supported. /// uCore x86 32bit program is planned to be supported.
pub fn new_user(data: &[u8], mc: &mut MemoryController) -> Self { pub fn new_user(data: &[u8]) -> Self {
// Parse elf // Parse elf
let begin = data.as_ptr() as usize; let begin = data.as_ptr() as usize;
let elf = ElfFile::new(data).expect("failed to read elf"); let elf = ElfFile::new(data).expect("failed to read elf");
@ -88,9 +82,7 @@ impl Process {
// Make page table // Make page table
let mut memory_set = MemorySet::from(&elf); let mut memory_set = MemorySet::from(&elf);
memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top, memory_set.push(MemoryArea::new(user_stack_buttom, user_stack_top, MemoryAttr::default().user(), "user_stack"));
EntryFlags::WRITABLE | EntryFlags::NO_EXECUTE | EntryFlags::USER_ACCESSIBLE, "user_stack"));
let page_table = mc.make_page_table(&memory_set);
trace!("{:#x?}", memory_set); trace!("{:#x?}", memory_set);
let entry_addr = match elf.header.pt2 { let entry_addr = match elf.header.pt2 {
@ -99,7 +91,7 @@ impl Process {
}; };
// Temporary switch to it, in order to copy data // Temporary switch to it, in order to copy data
let page_table = mc.with(page_table, || { memory_set.with(|| {
for ph in elf.program_iter() { for ph in elf.program_iter() {
let (virt_addr, offset, file_size) = match ph { let (virt_addr, offset, file_size) = match ph {
ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize), ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.offset as usize, ph.file_size as usize),
@ -119,17 +111,14 @@ impl Process {
// Allocate kernel stack and push trap frame // Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap();
let data = InitStack::new_user_thread(entry_addr, user_stack_top - 8, is32); let data = InitStack::new_user_thread(entry_addr, user_stack_top - 8, is32);
let context = unsafe { data.push_at(kstack.top()) }; let context = unsafe { data.push_at(memory_set.kstack_top()) };
Process { Process {
pid: 0, pid: 0,
parent: 0, parent: 0,
name: String::new(), name: String::new(),
kstack, memory_set,
memory_set: Some(memory_set),
page_table: Some(page_table),
status: Status::Ready, status: Status::Ready,
context, context,
is_user: true, is_user: true,
@ -137,12 +126,11 @@ impl Process {
} }
/// Fork /// Fork
pub fn fork(&self, tf: &TrapFrame, mc: &mut MemoryController) -> Self { pub fn fork(&self, tf: &TrapFrame) -> Self {
assert!(self.is_user); assert!(self.is_user);
// Clone memory set, make a new page table // Clone memory set, make a new page table
let memory_set = self.memory_set.as_ref().unwrap().clone(); let memory_set = self.memory_set.clone(7);
let page_table = mc.make_page_table(&memory_set);
// Copy data to temp space // Copy data to temp space
use alloc::Vec; use alloc::Vec;
@ -151,24 +139,21 @@ impl Process {
}).collect(); }).collect();
// Temporary switch to it, in order to copy data // Temporary switch to it, in order to copy data
let page_table = mc.with(page_table, || { memory_set.with(|| {
for (area, data) in memory_set.iter().zip(datas.iter()) { for (area, data) in memory_set.iter().zip(datas.iter()) {
unsafe { area.as_slice_mut() }.copy_from_slice(data.as_slice()) unsafe { area.as_slice_mut() }.copy_from_slice(data.as_slice())
} }
}); });
// Allocate kernel stack and push trap frame // Allocate kernel stack and push trap frame
let kstack = mc.alloc_stack(7).unwrap();
let data = InitStack::new_fork(tf); let data = InitStack::new_fork(tf);
let context = unsafe { data.push_at(kstack.top()) }; let context = unsafe { data.push_at(memory_set.kstack_top()) };
Process { Process {
pid: 0, pid: 0,
parent: self.pid, parent: self.pid,
name: self.name.clone() + "_fork", name: self.name.clone() + "_fork",
kstack, memory_set,
memory_set: Some(memory_set),
page_table: Some(page_table),
status: Status::Ready, status: Status::Ready,
context, context,
is_user: true, is_user: true,
@ -187,29 +172,23 @@ use memory::{MemorySet, MemoryArea, PhysAddr, FromToVirtualAddress, EntryFlags};
impl<'a> From<&'a ElfFile<'a>> for MemorySet { impl<'a> From<&'a ElfFile<'a>> for MemorySet {
fn from(elf: &'a ElfFile<'a>) -> Self { fn from(elf: &'a ElfFile<'a>) -> Self {
let mut set = MemorySet::new(); let mut set = MemorySet::new(7);
for ph in elf.program_iter() { for ph in elf.program_iter() {
let (virt_addr, mem_size, flags) = match ph { let (virt_addr, mem_size, flags) = match ph {
ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags), ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags), ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
}; };
set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, EntryFlags::from(flags), "")); set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, MemoryAttr::from(flags), ""));
} }
set set
} }
} }
impl From<Flags> for EntryFlags { impl From<Flags> for MemoryAttr {
fn from(elf_flags: Flags) -> Self { fn from(elf_flags: Flags) -> Self {
let mut flags = EntryFlags::PRESENT | EntryFlags::USER_ACCESSIBLE; let mut flags = MemoryAttr::default().user();
// if elf_flags.is_write() {
// TODO: handle readonly // TODO: handle readonly
if true { if elf_flags.is_execute() { flags = flags.execute(); }
flags = flags | EntryFlags::WRITABLE;
}
if !elf_flags.is_execute() {
flags = flags | EntryFlags::NO_EXECUTE;
}
flags flags
} }
} }

@ -11,9 +11,6 @@ pub struct Processor {
procs: BTreeMap<Pid, Process>, procs: BTreeMap<Pid, Process>,
current_pid: Pid, current_pid: Pid,
event_hub: EventHub<Event>, event_hub: EventHub<Event>,
/// All kernel threads share one page table.
/// When running user process, it will be stored here.
kernel_page_table: Option<InactivePageTable>,
/// Choose what on next schedule ? /// Choose what on next schedule ?
next: Option<Pid>, next: Option<Pid>,
// WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow // WARNING: if MAX_PROCESS_NUM is too large, will cause stack overflow
@ -27,7 +24,6 @@ impl Processor {
procs: BTreeMap::<Pid, Process>::new(), procs: BTreeMap::<Pid, Process>::new(),
current_pid: 0, current_pid: 0,
event_hub: EventHub::new(), event_hub: EventHub::new(),
kernel_page_table: None,
next: None, next: None,
// NOTE: max_time_slice <= 5 to ensure 'priority' test pass // NOTE: max_time_slice <= 5 to ensure 'priority' test pass
scheduler: RRScheduler::new(5), scheduler: RRScheduler::new(5),
@ -139,19 +135,7 @@ impl Processor {
self.scheduler.remove(pid); self.scheduler.remove(pid);
// switch page table // switch page table
if from.is_user || to.is_user { to.memory_set.switch();
let (from_pt, to_pt) = match (from.is_user, to.is_user) {
(true, true) => (&mut from.page_table, &mut to.page_table),
(true, false) => (&mut from.page_table, &mut self.kernel_page_table),
(false, true) => (&mut self.kernel_page_table, &mut to.page_table),
_ => panic!(),
};
assert!(from_pt.is_none());
assert!(to_pt.is_some());
let mut active_table = unsafe { ActivePageTable::new() };
let old_table = active_table.switch(to_pt.take().unwrap());
*from_pt = Some(old_table);
}
info!("switch from {} to {}\n rsp: ??? -> {:?}", pid0, pid, to.context); info!("switch from {} to {}\n rsp: ??? -> {:?}", pid0, pid, to.context);
unsafe { unsafe {

@ -86,8 +86,7 @@ fn sys_close(fd: usize) -> i32 {
/// Fork the current process. Return the child's PID. /// Fork the current process. Return the child's PID.
fn sys_fork(tf: &TrapFrame) -> i32 { fn sys_fork(tf: &TrapFrame) -> i32 {
let mut processor = PROCESSOR.try().unwrap().lock(); let mut processor = PROCESSOR.try().unwrap().lock();
let mut mc = MC.try().unwrap().lock(); let new = processor.current().fork(tf);
let new = processor.current().fork(tf, &mut mc);
let pid = processor.add(new); let pid = processor.add(new);
info!("fork: {} -> {}", processor.current_pid(), pid); info!("fork: {} -> {}", processor.current_pid(), pid);
pid as i32 pid as i32

Loading…
Cancel
Save