diff --git a/crate/memory/src/lib.rs b/crate/memory/src/lib.rs index 649d29d..ac956fa 100644 --- a/crate/memory/src/lib.rs +++ b/crate/memory/src/lib.rs @@ -12,5 +12,6 @@ pub mod cow; pub mod swap; pub mod memory_set; mod addr; +pub mod no_mmu; pub use crate::addr::*; \ No newline at end of file diff --git a/crate/memory/src/no_mmu.rs b/crate/memory/src/no_mmu.rs new file mode 100644 index 0000000..1fe2123 --- /dev/null +++ b/crate/memory/src/no_mmu.rs @@ -0,0 +1,66 @@ +use alloc::vec::Vec; +use alloc::alloc::{Layout, GlobalAlloc}; +use core::marker::PhantomData; + +pub trait NoMMUSupport { + type Alloc: GlobalAlloc; + fn allocator() -> &'static Self::Alloc; +} + +#[derive(Clone, Debug)] +pub struct MemorySet { + areas: Vec>, + support: PhantomData, +} + +impl MemorySet { + pub fn new() -> Self { + Self { + areas: Vec::new(), + support: PhantomData, + } + } + /// Allocate `size` bytes space. Return the slice. + pub fn push(&mut self, size: usize) -> &'static mut [u8] { + let area = MemoryArea::new(size); + let slice = unsafe { area.as_buf() }; + self.areas.push(area); + slice + } + // empty impls + pub fn with(&self, f: impl FnOnce() -> T) -> T { f() } + pub fn token(&self) -> usize { 0 } + pub unsafe fn activate(&self) {} +} + +#[derive(Debug)] +struct MemoryArea { + ptr: usize, + layout: Layout, + support: PhantomData, +} + +impl MemoryArea { + fn new(size: usize) -> Self { + let layout = Layout::from_size_align(size, 1).unwrap(); + let ptr = unsafe { S::allocator().alloc(layout) } as usize; + MemoryArea { ptr, layout, support: PhantomData } + } + unsafe fn as_buf(&self) -> &'static mut [u8] { + core::slice::from_raw_parts_mut(self.ptr as *mut u8, self.layout.size()) + } +} + +impl Clone for MemoryArea { + fn clone(&self) -> Self { + let new_area = MemoryArea::new(self.layout.size()); + unsafe { new_area.as_buf().copy_from_slice(self.as_buf()) } + new_area + } +} + +impl Drop for MemoryArea { + fn drop(&mut self) { + unsafe { S::allocator().dealloc(self.ptr as *mut u8, self.layout) } + } +} \ No newline at end of file diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index 4a525d8..5a0a2b9 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -37,7 +37,7 @@ name = "bcm2837" version = "0.1.0" dependencies = [ "cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)", - "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -65,7 +65,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "bootloader" version = "0.3.4" -source = "git+https://github.com/wangrunji0408/bootloader#dd5723c3d7d50856073a5003e0a355ea0fc3d46c" +source = "git+https://github.com/wangrunji0408/bootloader#24bdcafc302e7d2659ac126049a45571462907d9" dependencies = [ "apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)", "fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -132,7 +132,7 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.43" +version = "0.2.44" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -185,7 +185,7 @@ version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -324,7 +324,7 @@ dependencies = [ "uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "ucore-memory 0.1.0", "ucore-process 0.1.0", - "volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", + "volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)", "x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)", "xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -361,7 +361,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "volatile" -version = "0.2.4" +version = "0.2.5" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -446,7 +446,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7" "checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797" "checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1" -"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d" +"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311" "checksum linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655d57c71827fe0891ce72231b6aa5e14033dae3f604609e6a6f807267c1678d" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" @@ -472,7 +472,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41" -"checksum volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "54d4343a2df2d65144a874f95950754ee7b7e8594f6027aae8c7d0f4858a3fe8" +"checksum volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ca391c55768e479d5c2f8beb40c136df09257292a809ea514e82cfdfc15d00" "checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index 4df6d88..8f3f947 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -5,8 +5,8 @@ authors = ["Runji Wang "] edition = "2018" [features] -link_user_program = [] no_bbl = [] +no_mmu = [] board_raspi3 = [] [profile.dev] diff --git a/kernel/Makefile b/kernel/Makefile index 2329032..e973700 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -52,7 +52,8 @@ qemu_opts := \ -machine $(board) \ -serial null -serial mon:stdio \ -nographic \ - -kernel $(bin) + -kernel $(bin) \ + -smp cores=$(smp) endif ifdef d @@ -66,10 +67,8 @@ features := $(features) no_bbl endif endif -# Link user binaries at ../user -ifdef link_user -features := $(features) link_user_program -assembly_object_files := $(assembly_object_files) $(user_obj) +ifdef nommu +features := $(features) no_mmu endif features := $(features) board_$(board) diff --git a/kernel/src/arch/riscv32/memory.rs b/kernel/src/arch/riscv32/memory.rs index 7251227..7ba0b9f 100644 --- a/kernel/src/arch/riscv32/memory.rs +++ b/kernel/src/arch/riscv32/memory.rs @@ -2,12 +2,24 @@ use core::{slice, mem}; use riscv::{addr::*, register::sstatus}; use ucore_memory::PAGE_SIZE; use log::*; -use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet}; +use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, MEMORY_ALLOCATOR}; +use crate::consts::{MEMORY_OFFSET, MEMORY_END}; + +#[cfg(feature = "no_mmu")] +pub fn init() { + init_heap(); + + let heap_bottom = end as usize; + let heap_size = MEMORY_END - heap_bottom; + unsafe { MEMORY_ALLOCATOR.lock().init(heap_bottom, heap_size); } + info!("available memory: [{:#x}, {:#x})", heap_bottom, MEMORY_END); +} /* * @brief: * Init the mermory management module, allow memory access and set up page table and init heap and frame allocator */ +#[cfg(not(feature = "no_mmu"))] pub fn init() { #[repr(align(4096))] // align the PageData struct to 4096 bytes struct PageData([u8; PAGE_SIZE]); @@ -37,7 +49,6 @@ pub fn init_other() { fn init_frame_allocator() { use bit_allocator::BitAlloc; use core::ops::Range; - use crate::consts::{MEMORY_OFFSET, MEMORY_END}; let mut ba = FRAME_ALLOCATOR.lock(); ba.insert(to_range(end as usize + PAGE_SIZE, MEMORY_END)); @@ -63,6 +74,7 @@ fn init_frame_allocator() { * @brief: * remmap the kernel memory address with 4K page recorded in p1 page table */ +#[cfg(not(feature = "no_mmu"))] fn remap_the_kernel() { let mut ms = MemorySet::new_bare(); #[cfg(feature = "no_bbl")] diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index 1b2e069..27b85fe 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -4,16 +4,20 @@ use crate::consts::MEMORY_OFFSET; use super::HEAP_ALLOCATOR; use ucore_memory::{*, paging::PageTable}; use ucore_memory::cow::CowExt; -pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, InactivePageTable}; +pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, InactivePageTable}; use ucore_memory::swap::*; use crate::process::{process}; use crate::sync::{SpinNoIrqLock, SpinNoIrq, MutexGuard}; use alloc::collections::VecDeque; use lazy_static::*; use log::*; +use linked_list_allocator::LockedHeap; +#[cfg(not(feature = "no_mmu"))] +pub type MemorySet = ucore_memory::memory_set::MemorySet; -pub type MemorySet = MemorySet_; +#[cfg(feature = "no_mmu")] +pub type MemorySet = ucore_memory::no_mmu::MemorySet; // x86_64 support up to 256M memory #[cfg(target_arch = "x86_64")] @@ -101,6 +105,7 @@ impl Drop for KernelStack { * @retval: * Return true to continue, false to halt */ +#[cfg(not(feature = "no_mmu"))] pub fn page_fault_handler(addr: usize) -> bool { info!("start handling swap in/out page fault"); //unsafe { ACTIVE_TABLE_SWAP.force_unlock(); } @@ -140,6 +145,25 @@ pub fn init_heap() { info!("heap init end"); } +/// Allocator for the rest memory space on NO-MMU case. +pub static MEMORY_ALLOCATOR: LockedHeap = LockedHeap::empty(); + +#[derive(Debug, Clone, Copy)] +pub struct NoMMUSupportImpl; + +impl ucore_memory::no_mmu::NoMMUSupport for NoMMUSupportImpl { + type Alloc = LockedHeap; + fn allocator() -> &'static Self::Alloc { + &MEMORY_ALLOCATOR + } +} + +#[cfg(feature = "no_mmu")] +pub fn page_fault_handler(_addr: usize) -> bool { + unreachable!() +} + + //pub mod test { // pub fn cow() { // use super::*; diff --git a/kernel/src/process/context.rs b/kernel/src/process/context.rs index 9d6afa5..684541c 100644 --- a/kernel/src/process/context.rs +++ b/kernel/src/process/context.rs @@ -1,6 +1,6 @@ use crate::arch::interrupt::{TrapFrame, Context as ArchContext}; use crate::memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap, alloc_frame, InactivePageTable0}; -use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}}; +use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type, SegmentData}}; use core::fmt::{Debug, Error, Formatter}; use alloc::{boxed::Box, collections::BTreeMap, vec::Vec, sync::Arc, string::String}; use ucore_memory::{Page}; @@ -75,45 +75,44 @@ impl ContextImpl { header::HeaderPt2::Header32(_) => true, header::HeaderPt2::Header64(_) => false, }; - assert_eq!(elf.header.pt2.type_().as_type(), header::Type::Executable, "ELF is not executable"); - // User stack - use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET}; - let (ustack_buttom, mut ustack_top) = match is32 { - true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE), - false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE), - }; + match elf.header.pt2.type_().as_type() { + header::Type::Executable => { +// #[cfg(feature = "no_mmu")] +// panic!("ELF is not shared object"); + }, + header::Type::SharedObject => {}, + _ => panic!("ELF is not executable or shared object"), + } // Make page table let mut memory_set = memory_set_from(&elf); - memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack")); - trace!("{:#x?}", memory_set); - - let entry_addr = elf.header.pt2.entry_point() as usize; + // User stack + use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET}; + #[cfg(not(feature = "no_mmu"))] + let mut ustack_top = { + let (ustack_buttom, ustack_top) = match is32 { + true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE), + false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE), + }; + memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack")); + ustack_top + }; + #[cfg(feature = "no_mmu")] + let mut ustack_top = memory_set.push(USER_STACK_SIZE).as_ptr() as usize + USER_STACK_SIZE; - // Temporary switch to it, in order to copy data unsafe { - memory_set.with(|| { - for ph in elf.program_iter() { - let virt_addr = ph.virtual_addr() as usize; - let offset = ph.offset() as usize; - let file_size = ph.file_size() as usize; - let mem_size = ph.mem_size() as usize; - - let target = unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }; - if file_size != 0 { - target[..file_size].copy_from_slice(&data[offset..offset + file_size]); - } - target[file_size..].iter_mut().for_each(|x| *x = 0); - } - ustack_top = push_args_at_stack(args, ustack_top); - }); + memory_set.with(|| { ustack_top = push_args_at_stack(args, ustack_top) }); } + trace!("{:#x?}", memory_set); + + let entry_addr = elf.header.pt2.entry_point() as usize; let kstack = KernelStack::new(); //set the user Memory pages in the memory set swappable + #[cfg(not(feature = "no_mmu"))] memory_set_map_swappable(&mut memory_set); Box::new(ContextImpl { @@ -135,27 +134,20 @@ impl ContextImpl { let mut memory_set = self.memory_set.clone(); info!("finish mmset clone in fork!"); - info!("before copy data to temp space"); - // Copy data to temp space - use alloc::vec::Vec; - let datas: Vec> = memory_set.iter().map(|area| { - Vec::from(unsafe { area.as_slice() }) - }).collect(); - - info!("Finish copy data to temp space."); - - // Temporarily switch to it, in order to copy data - unsafe { - memory_set.with(|| { - for (area, data) in memory_set.iter().zip(datas.iter()) { - area.as_slice_mut().copy_from_slice(data.as_slice()) - } - }); + // MMU: copy data to the new space + // NoMMU: coping data has been done in `memory_set.clone()` + #[cfg(not(feature = "no_mmu"))] + for area in memory_set.iter() { + let data = Vec::::from(unsafe { area.as_slice() }); + unsafe { memory_set.with(|| { + area.as_slice_mut().copy_from_slice(data.as_slice()) + }) } } info!("temporary copy data!"); let kstack = KernelStack::new(); + #[cfg(not(feature = "no_mmu"))] memory_set_map_swappable(&mut memory_set); info!("FORK() finsihed!"); @@ -169,7 +161,8 @@ impl ContextImpl { } } -impl Drop for ContextImpl{ +#[cfg(not(feature = "no_mmu"))] +impl Drop for ContextImpl { fn drop(&mut self){ info!("come in to drop for ContextImpl"); //set the user Memory pages in the memory set unswappable @@ -232,19 +225,34 @@ unsafe fn push_args_at_stack<'a, Iter>(args: Iter, stack_top: usize) -> usize */ fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> MemorySet { debug!("come in to memory_set_from"); - let mut set = MemorySet::new(); + let mut ms = MemorySet::new(); for ph in elf.program_iter() { if ph.get_type() != Ok(Type::Load) { continue; } - let (virt_addr, mem_size, flags) = match ph { - 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), + let virt_addr = ph.virtual_addr() as usize; + let offset = ph.offset() as usize; + let file_size = ph.file_size() as usize; + let mem_size = ph.mem_size() as usize; + // Get target slice + #[cfg(feature = "no_mmu")] + let target = ms.push(mem_size); + #[cfg(not(feature = "no_mmu"))] + let target = { + ms.push(MemoryArea::new(virt_addr, virt_addr + mem_size, memory_attr_from(ph.flags()), "")); + unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) } }; - set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, memory_attr_from(flags), "")); - + // Copy data + unsafe { + ms.with(|| { + if file_size != 0 { + target[..file_size].copy_from_slice(&elf.input[offset..offset + file_size]); + } + target[file_size..].iter_mut().for_each(|x| *x = 0); + }); + } } - set + ms } fn memory_attr_from(elf_flags: Flags) -> MemoryAttr { @@ -260,6 +268,7 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr { * @brief: * map the memory area in the memory_set swappalbe, specially for the user process */ +#[cfg(not(feature = "no_mmu"))] pub fn memory_set_map_swappable(memory_set: &mut MemorySet){ info!("COME INTO memory set map swappable!"); let pt = unsafe {