diff --git a/.gitmodules b/.gitmodules index 78bc9604..c28c829b 100644 --- a/.gitmodules +++ b/.gitmodules @@ -3,4 +3,4 @@ url = https://github.com/rcore-os/rcore-user.git [submodule "rboot"] path = rboot - url = https://github.com/rcore-os/rboot.git + url = https://github.com/rcore-os/rboot.git \ No newline at end of file diff --git a/crate/memory/src/memory_set/handler/delay.rs b/crate/memory/src/memory_set/handler/delay.rs index 2eb8b341..fa66043a 100644 --- a/crate/memory/src/memory_set/handler/delay.rs +++ b/crate/memory/src/memory_set/handler/delay.rs @@ -49,10 +49,20 @@ impl MemoryHandler for Delay { } } - fn handle_page_fault(&self, pt: &mut dyn PageTable, addr: VirtAddr) -> bool { + fn handle_page_fault_ext( + &self, + pt: &mut dyn PageTable, + addr: VirtAddr, + access: super::AccessType, + ) -> bool { let entry = pt.get_entry(addr).expect("failed to get entry"); if entry.present() { - // not a delay case + // permission check. + if access.check_access(entry) { + return true; + } + // permisison check failed. + error!("Permission check failed at 0x{:x}.", addr); return false; } let frame = self.allocator.alloc().expect("failed to alloc frame"); diff --git a/crate/memory/src/memory_set/handler/file.rs b/crate/memory/src/memory_set/handler/file.rs index c3d1acd4..55871896 100644 --- a/crate/memory/src/memory_set/handler/file.rs +++ b/crate/memory/src/memory_set/handler/file.rs @@ -58,10 +58,24 @@ impl MemoryHandler for File { } } - fn handle_page_fault(&self, pt: &mut dyn PageTable, addr: usize) -> bool { + fn handle_page_fault_ext( + &self, + pt: &mut dyn PageTable, + addr: usize, + access: super::AccessType, + ) -> bool { let addr = addr & !(PAGE_SIZE - 1); let entry = pt.get_entry(addr).expect("failed to get entry"); if entry.present() { + // permission check. + if access.check_access(entry) { + return true; + } + // permisison check failed. + error!( + "Permission check failed at 0x{:x}, access = {:?}.", + addr, access + ); return false; } let execute = entry.execute(); diff --git a/crate/memory/src/memory_set/handler/mod.rs b/crate/memory/src/memory_set/handler/mod.rs index 79ee6460..a7b5d9fc 100644 --- a/crate/memory/src/memory_set/handler/mod.rs +++ b/crate/memory/src/memory_set/handler/mod.rs @@ -1,5 +1,45 @@ use super::*; - +#[derive(Copy, Clone, Debug)] +pub struct AccessType { + pub write: bool, + pub execute: bool, + pub user: bool, +} +impl AccessType { + pub fn unknown() -> Self { + AccessType { + write: true, + execute: true, + user: true, + } + } + pub fn read(user: bool) -> Self { + AccessType { + write: false, + execute: false, + user, + } + } + pub fn write(user: bool) -> Self { + AccessType { + write: true, + execute: false, + user, + } + } + pub fn execute(user: bool) -> Self { + AccessType { + write: false, + execute: true, + user, + } + } + pub fn check_access(self, entry: &dyn paging::Entry) -> bool { + ((!self.write) || entry.writable()) + && ((!self.execute) || entry.execute()) + && ((!self.user) || entry.user()) + } +} // here may be a interesting part for lab pub trait MemoryHandler: Debug + Send + Sync + 'static { fn box_clone(&self) -> Box; @@ -22,7 +62,20 @@ pub trait MemoryHandler: Debug + Send + Sync + 'static { /// Handle page fault on `addr` /// Return true if success, false if error - fn handle_page_fault(&self, pt: &mut dyn PageTable, addr: VirtAddr) -> bool; + fn handle_page_fault(&self, pt: &mut dyn PageTable, addr: VirtAddr) -> bool { + self.handle_page_fault_ext(pt, addr, AccessType::unknown()) + } + + /// Handle page fault on `addr` and access type `access` + /// Return true if success (or should-retry), false if error + fn handle_page_fault_ext( + &self, + pt: &mut dyn PageTable, + addr: VirtAddr, + _access: AccessType, + ) -> bool { + self.handle_page_fault(pt, addr) + } } impl Clone for Box { diff --git a/crate/memory/src/memory_set/handler/shared.rs b/crate/memory/src/memory_set/handler/shared.rs index f3deae13..e9ee61db 100644 --- a/crate/memory/src/memory_set/handler/shared.rs +++ b/crate/memory/src/memory_set/handler/shared.rs @@ -35,7 +35,7 @@ impl SharedGuard { self.target.insert(virt_addr, phys_addr); Some(phys_addr) } - + pub fn dealloc(&mut self, virt_addr: usize) { let phys_addr = self.target.get(&virt_addr).unwrap().clone(); self.allocator.dealloc(phys_addr); diff --git a/crate/memory/src/memory_set/mod.rs b/crate/memory/src/memory_set/mod.rs index f6324bb4..a4083317 100644 --- a/crate/memory/src/memory_set/mod.rs +++ b/crate/memory/src/memory_set/mod.rs @@ -376,6 +376,15 @@ impl MemorySet { &mut self.page_table } + pub fn handle_page_fault_ext(&mut self, addr: VirtAddr, access: handler::AccessType) -> bool { + let area = self.areas.iter().find(|area| area.contains(addr)); + match area { + Some(area) => area + .handler + .handle_page_fault_ext(&mut self.page_table, addr, access), + None => false, + } + } pub fn handle_page_fault(&mut self, addr: VirtAddr) -> bool { let area = self.areas.iter().find(|area| area.contains(addr)); match area { diff --git a/kernel/Cargo.lock b/kernel/Cargo.lock index eb3f3631..f63e1dd0 100644 --- a/kernel/Cargo.lock +++ b/kernel/Cargo.lock @@ -50,7 +50,7 @@ source = "git+https://github.com/rcore-os/apic-rs?rev=fb86bd7#fb86bd7c798608a18c dependencies = [ "bit_field 0.10.1", "bitflags", - "x86", + "x86 0.33.0", ] [[package]] @@ -89,9 +89,9 @@ dependencies = [ [[package]] name = "bit-vec" -version = "0.6.2" +version = "0.6.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5f0dc55f2d8a1a85650ac47858bb001b4c0dd73d79e3c455a842925e68d29cd3" +checksum = "349f9b6a179ed607305526ca489b34ad0a41aed5f7980fa90eb03160b69598fb" [[package]] name = "bit_field" @@ -114,7 +114,7 @@ checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" [[package]] name = "bitmap-allocator" version = "0.1.0" -source = "git+https://github.com/rcore-os/bitmap-allocator#03bd9909d0dc85e99f5559b97a163ab81073df83" +source = "git+https://github.com/rcore-os/bitmap-allocator?rev=03bd990#03bd9909d0dc85e99f5559b97a163ab81073df83" dependencies = [ "bit_field 0.9.0", ] @@ -164,9 +164,9 @@ dependencies = [ [[package]] name = "cc" -version = "1.0.60" +version = "1.0.67" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" +checksum = "e3c69b077ad434294d3ce9f1f6143a2a4b89a8a2d54ef813d85003a4fd1137fd" [[package]] name = "cfg-if" @@ -456,6 +456,15 @@ dependencies = [ "rustc_version", ] +[[package]] +name = "raw-cpuid" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c27cb5785b85bd05d4eb171556c9a1a514552e26123aeae6bb7d811353148026" +dependencies = [ + "bitflags", +] + [[package]] name = "rboot" version = "0.1.3" @@ -495,7 +504,7 @@ dependencies = [ "paste", "pc-keyboard", "pci", - "raw-cpuid", + "raw-cpuid 8.0.0", "rboot", "rcore-console", "rcore-fs", @@ -623,8 +632,8 @@ dependencies = [ [[package]] name = "riscv" -version = "0.5.6" -source = "git+https://github.com/rcore-os/riscv?rev=38f3786#38f3786966ba15cc76977375162e3f3622a30f4b" +version = "0.6.0" +source = "git+https://github.com/rcore-riscv-hypervisor-dev/riscv.git?rev=3f5efb1#3f5efb1b8d4ceb12e291ef3d7b27120ea038eb83" dependencies = [ "bare-metal", "bit_field 0.10.1", @@ -671,27 +680,28 @@ dependencies = [ [[package]] name = "rvm" -version = "1.0.1" -source = "git+https://github.com/rcore-os/RVM?rev=939eb0a#939eb0aafd100e9944e4f2fe90eebfa8149d2b85" +version = "1.2.0" +source = "git+https://github.com/rcore-riscv-hypervisor-dev/RVM?rev=2867e78#2867e782463fe81e572d7c3cd68abaf79252f50c" dependencies = [ "bit-set", "bit_field 0.10.1", "bitflags", - "bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator)", + "bitmap-allocator 0.1.0 (git+https://github.com/rcore-os/bitmap-allocator?rev=03bd990)", "lazy_static", "log", "numeric-enum-macro", - "raw-cpuid", + "raw-cpuid 9.0.0", + "riscv", "rvm_macros", "spin", - "x86", + "x86 0.36.0", "x86_64", ] [[package]] name = "rvm_macros" version = "0.1.0" -source = "git+https://github.com/rcore-os/RVM?rev=939eb0a#939eb0aafd100e9944e4f2fe90eebfa8149d2b85" +source = "git+https://github.com/rcore-riscv-hypervisor-dev/RVM?rev=2867e78#2867e782463fe81e572d7c3cd68abaf79252f50c" dependencies = [ "quote", "syn", @@ -766,7 +776,7 @@ name = "trapframe" version = "0.4.3" source = "git+https://github.com/rcore-os/trapframe-rs?rev=bdfe5aa#bdfe5aaebcdd64636c8831c2b8c17e4fede40c0b" dependencies = [ - "raw-cpuid", + "raw-cpuid 8.0.0", "x86_64", ] @@ -845,7 +855,7 @@ checksum = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" [[package]] name = "virtio-drivers" version = "0.1.0" -source = "git+https://github.com/rcore-os/virtio-drivers?rev=dfa70e14#dfa70e1425c9eac1b30e671be61b557a3ce56e7e" +source = "git+https://github.com/rcore-riscv-hypervisor-dev/virtio-drivers?rev=1201a0b#1201a0b40c016301c8135e564439e40a769facc8" dependencies = [ "bitflags", "log", @@ -903,7 +913,18 @@ checksum = "2786ac694ed572ab5d2bbcd9e188805dba26b3501973dd69718914fb3d4a5a69" dependencies = [ "bit_field 0.10.1", "bitflags", - "raw-cpuid", + "raw-cpuid 8.0.0", +] + +[[package]] +name = "x86" +version = "0.36.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "268696f47813d5744c80c868e014485e27b30d40eaeeff2f7685b10b70215e5c" +dependencies = [ + "bit_field 0.10.1", + "bitflags", + "raw-cpuid 9.0.0", ] [[package]] diff --git a/kernel/Cargo.toml b/kernel/Cargo.toml index c97cf643..2cc0e74c 100644 --- a/kernel/Cargo.toml +++ b/kernel/Cargo.toml @@ -22,6 +22,7 @@ authors = [ default = [] board_qemu = [] board_u540 = ["link_user"] +board_rcore_vmm_guest = ["link_user"] # (for aarch64 RaspberryPi3) nographic = [] consolegraphic = [] @@ -72,11 +73,11 @@ rlibc = "1.0" smoltcp = { git = "https://github.com/rcore-os/smoltcp", rev = "5bd87c7c", default-features = false, features = ["alloc", "log", "ethernet", "proto-ipv4", "proto-igmp", "socket-icmp", "socket-udp", "socket-tcp", "socket-raw"] } spin = "0.5" trapframe = { git = "https://github.com/rcore-os/trapframe-rs", rev = "bdfe5aa" } -virtio-drivers = { git = "https://github.com/rcore-os/virtio-drivers", rev = "dfa70e14" } +virtio-drivers = { git = "https://github.com/rcore-riscv-hypervisor-dev/virtio-drivers", rev = "1201a0b" } volatile = "0.2" woke = "0.0.2" xmas-elf = "0.7" -rvm = { git = "https://github.com/rcore-os/RVM", rev = "939eb0a", optional = true } +rvm = { git = "https://github.com/rcore-riscv-hypervisor-dev/RVM", rev = "2867e78", optional = true } [target.'cfg(target_arch = "x86_64")'.dependencies] apic = { git = "https://github.com/rcore-os/apic-rs", rev = "fb86bd7" } @@ -88,7 +89,7 @@ uart_16550 = "0.2.7" x86_64 = "0.11" [target.'cfg(any(target_arch = "riscv32", target_arch = "riscv64"))'.dependencies] -riscv = { git = "https://github.com/rcore-os/riscv", rev = "38f3786", features = ["inline-asm"] } +riscv = { git = "https://github.com/rcore-riscv-hypervisor-dev/riscv" , rev = "3f5efb1", features = ["inline-asm", "hypervisor"] } [target.'cfg(target_arch = "aarch64")'.dependencies] aarch64 = { git = "https://github.com/rcore-os/aarch64", version = "3.0.1" } diff --git a/kernel/Makefile b/kernel/Makefile index 5f1cebd4..d3c18a67 100644 --- a/kernel/Makefile +++ b/kernel/Makefile @@ -22,12 +22,15 @@ # | pc [ x86_64 only] Run on real pc # | u540 [riscv64 only] Run on HiFive U540, use Sv39 # | raspi3 [aarch64 only] Run on Raspberry Pi 3 Model B/B+ +# | rcore_vmm_guest [riscv64 only] Run on rust-rvm-vmm/RVM. Requires variable GUEST_USER_IMG to be specified. # NET = on | off [ x86_64 only] Enable NIC # PCI_PASSTHRU = 0000:00:00.1 [ x86_64 only] Passthrough the specified PCI device # INIT = /bin/ls [riscv64 only] Run specified program instead of user shell # EXTRA_NIC = on | off [ x86_64 only] Add an additional e1000 nic # ACCEL = on | off [ x86_64 only] Enable/disable kvm/hvf acceleration -# HYPERVISOR = on | off [ x86_64 only] Enable/disable the RVM hypervisor, and set ACCEL to on +# HYPERVISOR = on | off [ x86_64 and riscv64 only] Enable/disable the RVM hypervisor, and set ACCEL to on under x86_64 +# UART2 = on | off [riscv64 only] Add an extra virtio-driven UART port on unix domain socket /tmp/rcore_uart2 +# GUEST_USER_IMG = Image path of user programs. Specially taken out to allow out-of-tree user image. # FEATURES = profile | ... Add additional features ARCH ?= riscv64 @@ -40,6 +43,7 @@ INIT ?= EXTRA_NIC ?= off ACCEL ?= off HYPERVISOR ?= off +UART2 ?= off qemu := qemu-system-$(ARCH) target := $(ARCH) @@ -53,7 +57,14 @@ user_dir := ../user ### export environments ### +ifeq ($(BOARD), rcore_vmm_guest) +ifeq ($(GUEST_USER_IMG), ) +$(error For building guest rCore image you have to specify the variable GUEST_USER_IMG .) +endif +export USER_IMG = $(GUEST_USER_IMG) +else export USER_IMG = $(user_dir)/build/$(ARCH).img +endif export USER_QCOW2 = $(user_dir)/build/$(ARCH).qcow2 ifeq ($(ARCH), aarch64) @@ -124,10 +135,27 @@ qemu_opts += \ -serial mon:stdio \ -bios ../tools/opensbi/fu540.elf \ -device loader,addr=0x80200000,file=$(kernel_img) +else ifeq ($(BOARD), rcore_vmm_guest) +qemu_opts += \ + -machine virt \ + -cpu rv64,x-h=true \ + -serial mon:stdio \ + -bios ../tools/opensbi/fw_jump.elf \ + -m 1G\ + -kernel $(kernel_img) else qemu_opts += \ -machine virt \ - -serial mon:stdio \ + -cpu rv64,x-h=true \ + -m 2G \ + -serial mon:stdio +ifeq ($(UART2), on) +qemu_opts += \ +-chardev socket,path=/tmp/rcore_uart2,server=on,wait=off,id=uart2 \ +-device virtio-serial-device,id=uart2-bus \ +-device virtconsole,chardev=uart2 +endif +qemu_opts += \ -bios ../tools/opensbi/fw_jump.elf \ -device loader,addr=0x80200000,file=$(kernel_img) \ -drive file=$(USER_QCOW2),format=qcow2,id=sfs \ @@ -173,8 +201,10 @@ endif ifeq ($(HYPERVISOR), on) FEATURES += hypervisor +ifeq ($(ARCH), x86_64) ACCEL = on endif +endif ifeq ($(ACCEL), on) ifeq ($(shell uname), Darwin) @@ -257,6 +287,8 @@ debug: $(kernel) $(kernel_img) @sleep 1 @$(gdb) $(kernel) -x ../tools/gdbinit +justdebug: + @$(qemu) $(qemu_opts) -s -S build: $(kernel_img) asm: @@ -347,4 +379,4 @@ endif .PHONY: addr2line: - @python3.7 ../tools/addr2line.py $(prefix)addr2line $(ARCH) $(MODE) + @python3 ../tools/addr2line.py $(prefix)addr2line $(ARCH) $(MODE) diff --git a/kernel/src/arch/riscv/board/rcore_vmm_guest/mod.rs b/kernel/src/arch/riscv/board/rcore_vmm_guest/mod.rs new file mode 100644 index 00000000..4486638a --- /dev/null +++ b/kernel/src/arch/riscv/board/rcore_vmm_guest/mod.rs @@ -0,0 +1,14 @@ +use crate::drivers::*; +use crate::memory::phys_to_virt; +use riscv::register::sie; + +/// Enable external interrupt +pub unsafe fn init_external_interrupt() { + sie::set_sext(); +} + +pub fn init(dtb: usize) { + serial::uart16550::driver_init(); + irq::plic::driver_init(); + device_tree::init(dtb); +} diff --git a/kernel/src/arch/riscv/interrupt/consts.rs b/kernel/src/arch/riscv/interrupt/consts.rs index 01e20bc9..bcfc197e 100644 --- a/kernel/src/arch/riscv/interrupt/consts.rs +++ b/kernel/src/arch/riscv/interrupt/consts.rs @@ -14,6 +14,15 @@ pub fn is_page_fault(trap: usize) -> bool { trap == InstructionPageFault || trap == LoadPageFault || trap == StorePageFault } +pub fn is_execute_page_fault(trap: usize) -> bool { + trap == InstructionPageFault +} +pub fn is_read_page_fault(trap: usize) -> bool { + trap == LoadPageFault +} +pub fn is_write_page_fault(trap: usize) -> bool { + trap == StorePageFault +} pub fn is_syscall(trap: usize) -> bool { trap == Syscall } diff --git a/kernel/src/arch/riscv/interrupt/mod.rs b/kernel/src/arch/riscv/interrupt/mod.rs index ea4f1d44..cb320a6a 100644 --- a/kernel/src/arch/riscv/interrupt/mod.rs +++ b/kernel/src/arch/riscv/interrupt/mod.rs @@ -36,18 +36,30 @@ pub unsafe fn restore(flags: usize) { /// This function is called from `trap.asm`. #[no_mangle] pub extern "C" fn trap_handler(tf: &mut TrapFrame) { + trap_handler_no_frame(&mut tf.sepc); +} + +use crate::memory::AccessType; +#[inline] +pub fn trap_handler_no_frame(sepc: &mut usize) { use self::scause::{Exception as E, Interrupt as I, Trap}; let scause = scause::read(); let stval = stval::read(); + let is_user = false; trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), scause.cause()); match scause.cause() { Trap::Interrupt(I::SupervisorExternal) => external(), Trap::Interrupt(I::SupervisorSoft) => ipi(), Trap::Interrupt(I::SupervisorTimer) => timer(), - Trap::Exception(E::LoadPageFault) => page_fault(stval, tf), - Trap::Exception(E::StorePageFault) => page_fault(stval, tf), - Trap::Exception(E::InstructionPageFault) => page_fault(stval, tf), - _ => panic!("unhandled trap {:?}", scause.cause()), + Trap::Exception(E::LoadPageFault) => page_fault(stval, sepc, AccessType::read(is_user)), + Trap::Exception(E::StorePageFault) => page_fault(stval, sepc, AccessType::write(is_user)), + Trap::Exception(E::InstructionPageFault) => { + page_fault(stval, sepc, AccessType::execute(is_user)) + } + _ => { + let bits = scause.bits(); + panic!("unhandled trap {:?} ({})", scause.cause(), bits); + } } trace!("Interrupt end"); } @@ -57,7 +69,6 @@ fn external() { unsafe { super::board::handle_external_interrupt(); } - IRQ_MANAGER .read() .try_handle_interrupt(Some(SupervisorExternal)); @@ -73,22 +84,23 @@ pub fn timer() { crate::trap::timer(); } -fn page_fault(stval: usize, tf: &mut TrapFrame) { +fn page_fault(stval: usize, sepc: &mut usize, access: AccessType) { let addr = stval; - trace!("\nEXCEPTION: Page Fault @ {:#x}", addr); + info!("\nEXCEPTION: Page Fault @ {:#x}", addr); - if crate::memory::handle_page_fault(addr) { + if crate::memory::handle_page_fault_ext(addr, access) { return; } extern "C" { fn _copy_user_start(); fn _copy_user_end(); } - if tf.sepc >= _copy_user_start as usize && tf.sepc < _copy_user_end as usize { - debug!("fixup for addr {:x?}", addr); - tf.sepc = crate::memory::read_user_fixup as usize; + if *sepc >= _copy_user_start as usize && *sepc < _copy_user_end as usize { + info!("fixup for addr {:x?}", addr); + *sepc = crate::memory::read_user_fixup as usize; return; } + error!("unhandled page fault {:#x} from {:#x}", addr, sepc); panic!("unhandled page fault"); } @@ -116,8 +128,8 @@ pub fn wait_for_interrupt() { } } -pub fn handle_user_page_fault(thread: &Arc, addr: usize) -> bool { - thread.vm.lock().handle_page_fault(addr) +pub fn handle_user_page_fault_ext(thread: &Arc, addr: usize, access: AccessType) -> bool { + thread.vm.lock().handle_page_fault_ext(addr, access) } pub fn handle_reserved_inst(tf: &mut UserContext) -> bool { diff --git a/kernel/src/arch/riscv/io.rs b/kernel/src/arch/riscv/io.rs index e4b706d0..0b2cc9b7 100644 --- a/kernel/src/arch/riscv/io.rs +++ b/kernel/src/arch/riscv/io.rs @@ -1,11 +1,33 @@ +use crate::drivers::SerialDriver; use crate::drivers::SERIAL_DRIVERS; +use alloc::sync::Arc; use core::fmt::{Arguments, Write}; +pub struct HeaplessWrite>(T); +impl> core::fmt::Write for HeaplessWrite { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + self.0.as_ref().write(s.as_bytes()); + Ok(()) + } +} +pub struct HeaplessSBIWrite; +impl core::fmt::Write for HeaplessSBIWrite { + fn write_str(&mut self, s: &str) -> core::fmt::Result { + for ch in s.as_bytes() { + super::sbi::console_putchar(*ch as usize); + } + Ok(()) + } +} pub fn putfmt(fmt: Arguments) { // output to serial let mut drivers = SERIAL_DRIVERS.write(); if let Some(serial) = drivers.first_mut() { - serial.write(format!("{}", fmt).as_bytes()); + HeaplessWrite(&serial).write_fmt(fmt).unwrap(); + } else { + // might miss some early messages. + // no no no i don't accept it. + // note that we can't use heap here. + HeaplessSBIWrite.write_fmt(fmt).unwrap(); } - // might miss some early messages, but it's okay } diff --git a/kernel/src/arch/riscv/mod.rs b/kernel/src/arch/riscv/mod.rs index 81caa258..f7156928 100644 --- a/kernel/src/arch/riscv/mod.rs +++ b/kernel/src/arch/riscv/mod.rs @@ -3,7 +3,10 @@ use trapframe; #[cfg(feature = "board_u540")] #[path = "board/u540/mod.rs"] pub mod board; -#[cfg(not(feature = "board_u540"))] +#[cfg(feature = "board_rcore_vmm_guest")] +#[path = "board/rcore_vmm_guest/mod.rs"] +pub mod board; +#[cfg(not(any(feature = "board_u540", feature = "board_rcore_vmm_guest")))] #[path = "board/virt/mod.rs"] pub mod board; @@ -16,7 +19,7 @@ pub mod io; pub mod memory; pub mod paging; pub mod rand; -mod sbi; +pub mod sbi; pub mod signal; pub mod syscall; pub mod timer; @@ -36,8 +39,6 @@ fn start_all_harts() { #[no_mangle] pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { - let device_tree_vaddr = phys_to_virt(device_tree_paddr); - unsafe { cpu::set_cpu_id(hartid); } @@ -46,15 +47,15 @@ pub extern "C" fn rust_main(hartid: usize, device_tree_paddr: usize) -> ! { .compare_exchange(false, true, Ordering::SeqCst, Ordering::SeqCst) .is_ok() { - LOTTERY_HART_ID.store(hartid, Ordering::SeqCst); + DEVICE_TREE_PADDR.store(device_tree_paddr, Ordering::SeqCst); start_all_harts(); } - let main_hart = LOTTERY_HART_ID.load(Ordering::SeqCst); - if hartid != main_hart { + + if hartid != BOOT_HART_ID { while !AP_CAN_INIT.load(Ordering::Relaxed) {} others_main(hartid); } - + let device_tree_vaddr = phys_to_virt(DEVICE_TREE_PADDR.load(Ordering::SeqCst)); unsafe { memory::clear_bss(); } @@ -93,7 +94,7 @@ fn others_main(hartid: usize) -> ! { static AP_CAN_INIT: AtomicBool = AtomicBool::new(false); static FIRST_HART: AtomicBool = AtomicBool::new(false); -static LOTTERY_HART_ID: AtomicUsize = AtomicUsize::new(0); +static DEVICE_TREE_PADDR: AtomicUsize = AtomicUsize::new(0); #[cfg(not(feature = "board_u540"))] const BOOT_HART_ID: usize = 0; diff --git a/kernel/src/arch/riscv/paging.rs b/kernel/src/arch/riscv/paging.rs index 0a32de1d..fda48a1c 100644 --- a/kernel/src/arch/riscv/paging.rs +++ b/kernel/src/arch/riscv/paging.rs @@ -5,7 +5,9 @@ use log::*; use rcore_memory::paging::*; use riscv::addr::*; use riscv::asm::{sfence_vma, sfence_vma_all}; -use riscv::paging::{FrameAllocator, FrameDeallocator}; +use riscv::paging::MapperFlushable; +use riscv::paging::PTE; +use riscv::paging::{FrameAllocatorFor, FrameDeallocatorFor}; use riscv::paging::{Mapper, PageTable as RvPageTable, PageTableEntry, PageTableFlags as EF}; use riscv::register::satp; @@ -14,6 +16,13 @@ type TopLevelPageTable<'a> = riscv::paging::Rv32PageTable<'a>; #[cfg(target_arch = "riscv64")] type TopLevelPageTable<'a> = riscv::paging::Rv39PageTable<'a>; +use riscv::use_sv32; +use riscv::use_sv39; +#[cfg(target_arch = "riscv32")] +use_sv32!(); +#[cfg(target_arch = "riscv64")] +use_sv39!(); + pub struct PageTableImpl { page_table: TopLevelPageTable<'static>, root_frame: Frame, @@ -29,7 +38,7 @@ impl PageTable for PageTableImpl { // map the 4K `page` to the 4K `frame` with `flags` let flags = EF::VALID | EF::READABLE | EF::WRITABLE; let page = Page::of_addr(VirtAddr::new(addr)); - let frame = Frame::of_addr(PhysAddr::new(target)); + let frame = Frame::of_addr(PhysAddr::new_u64(target as u64)); // we may need frame allocator to alloc frame for new page table(first/second) self.page_table .map_to(page, frame, flags, &mut FrameAllocatorForRiscv) @@ -99,11 +108,11 @@ impl Entry for PageEntry { self.0.flags_mut().set(EF::VALID | EF::READABLE, value); } fn target(&self) -> usize { - self.0.addr().as_usize() + self.0.addr::().as_usize() } fn set_target(&mut self, target: usize) { let flags = self.0.flags(); - let frame = Frame::of_addr(PhysAddr::new(target)); + let frame = Frame::of_addr(PhysAddr::new_u64(target as u64)); self.0.set(frame, flags); } fn writable_shared(&self) -> bool { @@ -153,7 +162,7 @@ impl PageTableImpl { #[cfg(target_arch = "riscv64")] let mask = 0x0fffffff_ffffffff; let frame = Frame::of_ppn(PageTableImpl::active_token() & mask); - let table = frame.as_kernel_mut(PHYSICAL_MEMORY_OFFSET); + let table = frame.as_kernel_mut(PHYSICAL_MEMORY_OFFSET as u64); ManuallyDrop::new(PageTableImpl { page_table: TopLevelPageTable::new(table, PHYSICAL_MEMORY_OFFSET), root_frame: frame, @@ -170,7 +179,7 @@ impl PageTableImpl { impl PageTableExt for PageTableImpl { fn new_bare() -> Self { let target = alloc_frame().expect("failed to allocate frame"); - let frame = Frame::of_addr(PhysAddr::new(target)); + let frame = Frame::of_addr(PhysAddr::new_u64(target as u64)); let table = unsafe { &mut *(phys_to_virt(target) as *mut RvPageTable) }; table.zero(); @@ -202,8 +211,8 @@ impl PageTableExt for PageTableImpl { } let flags = EF::VALID | EF::READABLE | EF::WRITABLE | EF::EXECUTABLE | EF::ACCESSED | EF::DIRTY; - let frame = Frame::of_addr(PhysAddr::new( - (0xFFFFFF80_00000000 + (i << 30)) - PHYSICAL_MEMORY_OFFSET, + let frame = Frame::of_addr(PhysAddr::new_u64( + ((0xFFFFFF80_00000000 + (i << 30)) - PHYSICAL_MEMORY_OFFSET) as u64, )); table[i].set(frame, flags); } @@ -239,13 +248,13 @@ impl Drop for PageTableImpl { struct FrameAllocatorForRiscv; -impl FrameAllocator for FrameAllocatorForRiscv { +impl FrameAllocatorFor for FrameAllocatorForRiscv { fn alloc(&mut self) -> Option { - alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new(addr))) + alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new_u64(addr as u64))) } } -impl FrameDeallocator for FrameAllocatorForRiscv { +impl FrameDeallocatorFor for FrameAllocatorForRiscv { fn dealloc(&mut self, frame: Frame) { dealloc_frame(frame.start_address().as_usize()); } diff --git a/kernel/src/arch/riscv/sbi.rs b/kernel/src/arch/riscv/sbi.rs index 31d37df2..29169c9e 100644 --- a/kernel/src/arch/riscv/sbi.rs +++ b/kernel/src/arch/riscv/sbi.rs @@ -63,6 +63,30 @@ pub fn sbi_hart_get_status(hartid: usize) -> SBIRet { ) } +pub fn sbi_set_timer(stime_value: u64) -> SBIRet { + #[cfg(target_pointer_width = "32")] + let ret = sbi_call( + SBICall { + eid: SBI_EID_TIME, + fid: SBI_FID_TIME_SET, + }, + stime_value as usize, + (stime_value >> 32) as usize, + 0, + ); + #[cfg(target_pointer_width = "64")] + let ret = sbi_call( + SBICall { + eid: SBI_EID_TIME, + fid: SBI_FID_TIME_SET, + }, + stime_value as usize, + 0, + 0, + ); + ret +} + const SBI_SUCCESS: isize = 0; const SBI_ERR_FAILED: isize = -1; const SBI_ERR_NOT_SUPPORTED: isize = -2; @@ -75,6 +99,8 @@ const SBI_EID_HSM: usize = 0x48534D; const SBI_FID_HSM_START: usize = 0; const SBI_FID_HSM_STOP: usize = 1; const SBI_FID_HSM_STATUS: usize = 2; +const SBI_EID_TIME: usize = 0x54494D45; +const SBI_FID_TIME_SET: usize = 0; /// Legacy calls. diff --git a/kernel/src/arch/riscv/timer.rs b/kernel/src/arch/riscv/timer.rs index 648e53c4..0ba6bb43 100644 --- a/kernel/src/arch/riscv/timer.rs +++ b/kernel/src/arch/riscv/timer.rs @@ -33,13 +33,11 @@ pub fn init() { /// Set the next timer interrupt pub fn set_next() { // 100Hz @ QEMU - let timebase = 250000; - sbi::set_timer(get_cycle() + timebase); + let timebase = 100000; + sbi::sbi_set_timer(get_cycle() + timebase); } pub fn timer_now() -> Duration { - // TODO: get actual freq - const FREQUENCY: u16 = 2600; let time = get_cycle(); - Duration::from_nanos(time * 1000 / FREQUENCY as u64) + Duration::from_nanos(time * 100) } diff --git a/kernel/src/drivers/bus/virtio_mmio.rs b/kernel/src/drivers/bus/virtio_mmio.rs index 80bf4b77..5305894c 100644 --- a/kernel/src/drivers/bus/virtio_mmio.rs +++ b/kernel/src/drivers/bus/virtio_mmio.rs @@ -2,6 +2,7 @@ use super::super::block::virtio_blk; use super::super::gpu::virtio_gpu; use super::super::input::virtio_input; use super::super::net::virtio_net; +use super::super::serial::virtio_console; use crate::drivers::device_tree::DEVICE_TREE_REGISTRY; use crate::memory::phys_to_virt; use device_tree::util::SliceRead; @@ -35,6 +36,7 @@ pub fn virtio_probe(node: &Node) { DeviceType::Block => virtio_blk::init(header), DeviceType::GPU => virtio_gpu::init(header), DeviceType::Input => virtio_input::init(header), + DeviceType::Console => virtio_console::init(node, header), t => warn!("Unrecognized virtio device: {:?}", t), } } diff --git a/kernel/src/drivers/irq/plic.rs b/kernel/src/drivers/irq/plic.rs index 59c4e728..f8374523 100644 --- a/kernel/src/drivers/irq/plic.rs +++ b/kernel/src/drivers/irq/plic.rs @@ -45,7 +45,10 @@ impl IntcDriver for Plic { /// Register interrupt controller local irq fn register_local_irq(&self, irq: usize, driver: Arc) { // enable irq for context 1 - write(self.base + 0x2080, 1 << irq); + write( + self.base + 0x2080, + read::(self.base + 0x2080) | (1 << irq), + ); // set priority to 7 write(self.base + irq * 4, 7); let mut manager = self.manager.lock(); @@ -58,7 +61,7 @@ pub const SupervisorExternal: usize = usize::MAX / 2 + 1 + 8; fn init_dt(dt: &Node) { let addr = dt.prop_u64("reg").unwrap() as usize; let phandle = dt.prop_u32("phandle").unwrap(); - info!("Found riscv plic at {:#x}", addr); + info!("Found riscv plic at {:#x}, {:?}", addr, dt); let base = phys_to_virt(addr); let plic = Arc::new(Plic { base, diff --git a/kernel/src/drivers/rtc/rtc_goldfish.rs b/kernel/src/drivers/rtc/rtc_goldfish.rs index 7657f7f8..7f4287a8 100644 --- a/kernel/src/drivers/rtc/rtc_goldfish.rs +++ b/kernel/src/drivers/rtc/rtc_goldfish.rs @@ -43,10 +43,11 @@ impl RtcDriver for RtcGoldfish { } fn init_dt(dt: &Node) { + use crate::memory::phys_to_virt; let addr = dt.prop_u64("reg").unwrap() as usize; - RTC_DRIVERS - .write() - .push(Arc::new(RtcGoldfish { base: addr })); + RTC_DRIVERS.write().push(Arc::new(RtcGoldfish { + base: phys_to_virt(addr), + })); } pub fn driver_init() { diff --git a/kernel/src/drivers/serial/mod.rs b/kernel/src/drivers/serial/mod.rs index bcefa307..f4ca2a34 100644 --- a/kernel/src/drivers/serial/mod.rs +++ b/kernel/src/drivers/serial/mod.rs @@ -11,10 +11,21 @@ pub mod com; pub mod keyboard; pub mod uart16550; +pub mod virtio_console; + pub trait SerialDriver: Driver { // read one byte from tty fn read(&self) -> u8; // write bytes to tty fn write(&self, data: &[u8]); + + // get if it is ready. as a hint. + fn try_read(&self) -> Option { + Some(self.read()) + } +} +use crate::sync::Condvar; +lazy_static! { + pub static ref SERIAL_ACTIVITY: Condvar = Condvar::new(); } diff --git a/kernel/src/drivers/serial/uart16550.rs b/kernel/src/drivers/serial/uart16550.rs index fb66fb76..58f9c992 100644 --- a/kernel/src/drivers/serial/uart16550.rs +++ b/kernel/src/drivers/serial/uart16550.rs @@ -23,6 +23,7 @@ impl Driver for SerialPort { fn try_handle_interrupt(&self, irq: Option) -> bool { if let Some(c) = self.getchar_option() { crate::trap::serial(c); + super::SERIAL_ACTIVITY.notify_all(); true } else { false @@ -72,7 +73,8 @@ impl SerialPort { /// non-blocking version of putchar() pub fn putchar(&self, c: u8) { for _ in 0..100 { - if (read::(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == 0 { + if (read::(self.base + COM_LSR * self.multiplier) & COM_LSR_TXRDY) == COM_LSR_TXRDY + { break; } } @@ -112,6 +114,9 @@ impl SerialDriver for SerialPort { self.putchar(*byte); } } + fn try_read(&self) -> Option { + self.getchar_option() + } } const COM_RX: usize = 0; // In: Receive buffer (DLAB=0) @@ -149,6 +154,7 @@ pub fn init_dt(dt: &Node) { if let Some(manager) = DEVICE_TREE_INTC.write().get_mut(&intc) { manager.register_local_irq(irq, com.clone()); info!("registered uart16550 to intc"); + info!("Init uart16550 at {:#x}, {:?}", base, dt); found = true; } } diff --git a/kernel/src/drivers/serial/virtio_console.rs b/kernel/src/drivers/serial/virtio_console.rs new file mode 100644 index 00000000..22284950 --- /dev/null +++ b/kernel/src/drivers/serial/virtio_console.rs @@ -0,0 +1,80 @@ +use alloc::boxed::Box; +use alloc::string::String; +use alloc::sync::Arc; + +use super::super::{DeviceType, Driver, DRIVERS, IRQ_MANAGER, SERIAL_DRIVERS}; +use crate::drivers::device_tree::{DEVICE_TREE_INTC, DEVICE_TREE_REGISTRY}; +use crate::{ + drivers::{BlockDriver, NetDriver}, + sync::SpinNoIrqLock as Mutex, +}; +use device_tree::Node; +use log::*; +use virtio_drivers::VirtIOConsole; +use virtio_drivers::{VirtIOHeader, VirtIOInput}; + +struct VirtIOConsoleDriver(Mutex>); +pub fn init(dt: &Node, header: &'static mut VirtIOHeader) { + let mut console = VirtIOConsole::new(header).expect("failed to create virtio console"); + let driver = Arc::new(VirtIOConsoleDriver(Mutex::new(console))); + let irq_opt = dt.prop_u32("interrupts").ok().map(|irq| irq as usize); + let mut found = false; + if let Ok(intc) = dt.prop_u32("interrupt-parent") { + if let Some(irq) = irq_opt { + if let Some(manager) = DEVICE_TREE_INTC.write().get_mut(&intc) { + manager.register_local_irq(irq, driver.clone()); + info!("registered virtio_console to intc"); + found = true; + } + } + } + if !found { + info!("registered virtio_console to root"); + IRQ_MANAGER.write().register_opt(irq_opt, driver.clone()); + } + SERIAL_DRIVERS.write().push(driver); +} +impl Driver for VirtIOConsoleDriver { + fn try_handle_interrupt(&self, _irq: Option) -> bool { + let mut console = self.0.lock(); + let ack = console.ack_interrupt().expect("failed to ack interrupt"); + if ack { + super::SERIAL_ACTIVITY.notify_all(); + } + ack + } + + fn device_type(&self) -> DeviceType { + DeviceType::Serial + } + + fn get_id(&self) -> String { + String::from("virtio_console") + } + + fn as_net(&self) -> Option<&dyn NetDriver> { + None + } + + fn as_block(&self) -> Option<&dyn BlockDriver> { + None + } +} + +impl crate::drivers::serial::SerialDriver for VirtIOConsoleDriver { + fn read(&self) -> u8 { + let mut console = self.0.lock(); + console.recv(true).unwrap().unwrap_or(0) + } + + fn write(&self, data: &[u8]) { + let mut console = self.0.lock(); + for byte in data { + console.send(*byte).unwrap(); + } + } + fn try_read(&self) -> Option { + let mut console = self.0.lock(); + console.recv(true).unwrap() + } +} diff --git a/kernel/src/fs/devfs/mod.rs b/kernel/src/fs/devfs/mod.rs index 0e590734..4d7dfdcc 100644 --- a/kernel/src/fs/devfs/mod.rs +++ b/kernel/src/fs/devfs/mod.rs @@ -2,10 +2,12 @@ mod fbdev; mod random; +mod serial; mod shm; mod tty; pub use fbdev::*; pub use random::*; +pub use serial::*; pub use shm::*; pub use tty::*; diff --git a/kernel/src/fs/devfs/serial.rs b/kernel/src/fs/devfs/serial.rs new file mode 100644 index 00000000..39b9e8e9 --- /dev/null +++ b/kernel/src/fs/devfs/serial.rs @@ -0,0 +1,78 @@ +use crate::drivers::serial::SERIAL_ACTIVITY; +use crate::drivers::SerialDriver; +use crate::drivers::SERIAL_DRIVERS; +use crate::syscall::spin_and_wait; +use alloc::sync::Arc; +use alloc::vec::Vec; +use core::any::Any; +use rcore_fs::vfs::*; +pub struct Serial { + id: usize, + driver: Arc, +} + +impl Serial { + pub fn new(id: usize, driver: Arc) -> Self { + Serial { id, driver } + } + pub fn wrap_all_serial_devices() -> Vec { + let drivers = SERIAL_DRIVERS.read(); + drivers + .iter() + .cloned() + .enumerate() + .map(|(i, x)| Serial::new(i, x)) + .collect() + } +} + +impl INode for Serial { + fn read_at(&self, _offset: usize, buf: &mut [u8]) -> Result { + let mut n = 0; + for r in buf.iter_mut() { + if let Some(x) = self.driver.try_read() { + *r = x; + n += 1; + } else { + break; + } + } + Ok(n) + } + + fn write_at(&self, _offset: usize, buf: &[u8]) -> Result { + self.driver.write(buf); + Ok(buf.len()) + } + + fn poll(&self) -> Result { + Ok(PollStatus { + read: true, + write: true, + error: false, + }) + } + + fn metadata(&self) -> Result { + Ok(Metadata { + dev: 1, + inode: 1, + size: 0, + blk_size: 0, + blocks: 0, + atime: Timespec { sec: 0, nsec: 0 }, + mtime: Timespec { sec: 0, nsec: 0 }, + ctime: Timespec { sec: 0, nsec: 0 }, + type_: FileType::CharDevice, + mode: 0o666, + nlinks: 1, + uid: 0, + gid: 0, + rdev: make_rdev(4, self.id), + }) + } + + fn as_any_ref(&self) -> &dyn Any { + self + } +} diff --git a/kernel/src/fs/mod.rs b/kernel/src/fs/mod.rs index ef9af81f..eddebd61 100644 --- a/kernel/src/fs/mod.rs +++ b/kernel/src/fs/mod.rs @@ -11,7 +11,7 @@ use rcore_fs_sfs::{INodeImpl, SimpleFileSystem}; use self::devfs::{Fbdev, RandomINode}; -pub use self::devfs::{ShmINode, TTY}; +pub use self::devfs::{Serial, ShmINode, TTY}; pub use self::file::*; pub use self::file_like::*; pub use self::pipe::Pipe; @@ -82,6 +82,10 @@ lazy_static! { devfs.add("tty", TTY.clone()).expect("failed to mknod /dev/tty"); devfs.add("fb0", Arc::new(Fbdev::default())).expect("failed to mknod /dev/fb0"); devfs.add("shm", Arc::new(ShmINode::default())).expect("failed to mkdir shm"); + for (i, serial) in Serial::wrap_all_serial_devices().into_iter().enumerate(){ + devfs.add(&format!("ttyS{}", i), Arc::new(serial)).expect("failed to add a serial"); + } + #[cfg(feature = "hypervisor")] devfs.add("rvm", Arc::new(crate::rvm::RvmINode::new())).expect("failed to mknod /dev/rvm"); diff --git a/kernel/src/memory.rs b/kernel/src/memory.rs index e551d410..551439ee 100644 --- a/kernel/src/memory.rs +++ b/kernel/src/memory.rs @@ -139,6 +139,19 @@ pub fn handle_page_fault(addr: usize) -> bool { lock.handle_page_fault(addr) } +/// Handle page fault at `addr` with access type `access`. +/// Return true to continue, false to halt. +pub fn handle_page_fault_ext(addr: usize, access: crate::memory::AccessType) -> bool { + debug!( + "page fault from kernel @ {:#x} with access type {:?}", + addr, access + ); + + let thread = current_thread().unwrap(); + let mut lock = thread.vm.lock(); + lock.handle_page_fault_ext(addr, access) +} + pub fn init_heap() { use crate::consts::KERNEL_HEAP_SIZE; const MACHINE_ALIGN: usize = mem::size_of::(); @@ -190,7 +203,6 @@ pub unsafe extern "C" fn read_user_fixup() -> usize { } pub fn copy_from_user(addr: *const T) -> Option { - #[naked] #[inline(never)] #[link_section = ".text.copy_user"] unsafe extern "C" fn read_user(dst: *mut T, src: *const T) -> usize { @@ -208,7 +220,6 @@ pub fn copy_from_user(addr: *const T) -> Option { } pub fn copy_to_user(addr: *mut T, src: *const T) -> bool { - #[naked] #[inline(never)] #[link_section = ".text.copy_user"] unsafe extern "C" fn write_user(dst: *mut T, src: *const T) -> usize { diff --git a/kernel/src/process/thread.rs b/kernel/src/process/thread.rs index 3891aae2..adb598ee 100644 --- a/kernel/src/process/thread.rs +++ b/kernel/src/process/thread.rs @@ -5,7 +5,7 @@ use super::{ use crate::arch::interrupt::consts::{ is_intr, is_page_fault, is_reserved_inst, is_syscall, is_timer_intr, }; -use crate::arch::interrupt::{get_trap_num, handle_reserved_inst, handle_user_page_fault}; +use crate::arch::interrupt::{get_trap_num, handle_reserved_inst}; use crate::arch::{ cpu, fp::FpState, @@ -505,10 +505,8 @@ pub fn spawn(thread: Arc) { thread_context.fp.restore(); cx.run(); thread_context.fp.save(); - let trap_num = get_trap_num(&cx); trace!("back from user: {:#x?} trap_num {:#x}", cx, trap_num); - let mut exit = false; let mut do_yield = false; match trap_num { @@ -517,10 +515,36 @@ pub fn spawn(thread: Arc) { // page fault let addr = get_page_fault_addr(); info!("page fault from user @ {:#x}", addr); - - if !handle_user_page_fault(&thread, addr) { - // TODO: SIGSEGV - panic!("page fault handle failed"); + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + use crate::arch::interrupt::consts::{ + is_execute_page_fault, is_read_page_fault, is_write_page_fault, + }; + use crate::arch::interrupt::handle_user_page_fault_ext; + let access_type = match trap_num { + _ if is_execute_page_fault(trap_num) => { + crate::memory::AccessType::execute(true) + } + _ if is_read_page_fault(trap_num) => { + crate::memory::AccessType::read(true) + } + _ if is_write_page_fault(trap_num) => { + crate::memory::AccessType::write(true) + } + _ => unreachable!(), + }; + if !handle_user_page_fault_ext(&thread, addr, access_type) { + // TODO: SIGSEGV + panic!("page fault handle failed"); + } + } + #[cfg(not(any(target_arch = "riscv32", target_arch = "riscv64")))] + { + use crate::arch::interrupt::handle_user_page_fault; + if !handle_user_page_fault(&thread, addr) { + // TODO: SIGSEGV + panic!("page fault handle failed"); + } } } _ if is_syscall(trap_num) => exit = handle_syscall(&thread, cx).await, diff --git a/kernel/src/rvm/inode.rs b/kernel/src/rvm/inode.rs index b5955965..2d274e5a 100644 --- a/kernel/src/rvm/inode.rs +++ b/kernel/src/rvm/inode.rs @@ -26,6 +26,16 @@ const RVM_VCPU_READ_STATE: u32 = RVM_IO + 0x13; const RVM_VCPU_WRITE_STATE: u32 = RVM_IO + 0x14; const RVM_VCPU_INTERRUPT: u32 = RVM_IO + 0x15; +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] +mod riscv_intr_constants { + pub const RVM_RISCV_SET_SSIP: u32 = 0; + pub const RVM_RISCV_CLEAR_SSIP: u32 = 1; + pub const RVM_RISCV_SET_SEIP: u32 = 2; + pub const RVM_RISCV_CLEAR_SEIP: u32 = 3; +} +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] +use riscv_intr_constants::*; + pub struct RvmINode { guests: RwLock>, vcpus: RwLock>, @@ -44,6 +54,7 @@ struct RvmGuestAddMemoryRegionArgs { vmid: u16, guest_start_paddr: u64, memory_size: u64, + userspace_addr: u64, } #[repr(C)] @@ -118,16 +129,19 @@ impl INode for RvmINode { self.guest_create().map_err(into_fs_error) } RVM_GUEST_ADD_MEMORY_REGION => { - let args = UserInPtr::::from(data) - .read() - .or(Err(FsError::InvalidParam))?; + let mut ptr = UserInOutPtr::::from(data); + let mut args = ptr.read().or(Err(FsError::InvalidParam))?; info!("[RVM] ioctl RVM_GUEST_ADD_MEMORY_REGION {:x?}", args); - self.guest_add_memory_region( - args.vmid as usize, - args.guest_start_paddr as usize, - args.memory_size as usize, - ) - .map_err(into_fs_error) + let userspace_addr = self + .guest_add_memory_region( + args.vmid as usize, + args.guest_start_paddr as usize, + args.memory_size as usize, + ) + .map_err(into_fs_error)?; + args.userspace_addr = userspace_addr as u64; + ptr.write(args).or(Err(FsError::DeviceError))?; + Ok(0) } RVM_GUEST_SET_TRAP => { let args = UserInPtr::::from(data) @@ -354,7 +368,7 @@ impl RvmINode { Err(RvmError::InvalidParam) } } - + #[cfg(any(target_arch = "x86_64"))] fn vcpu_interrupt(&self, vcpu_id: usize, vector: u32) -> RvmResult<()> { if let Some(vcpu) = self.vcpus.write().get_mut(&vcpu_id) { vcpu.inner.lock().virtual_interrupt(vector) @@ -362,6 +376,25 @@ impl RvmINode { Err(RvmError::InvalidParam) } } + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + fn vcpu_interrupt(&self, vcpu_id: usize, arg: u32) -> RvmResult<()> { + if let Some(vcpu) = self.vcpus.write().get_mut(&vcpu_id) { + //vcpu.inner.lock().virtual_interrupt(vector) + let irq = &vcpu.irq; + match arg { + self::RVM_RISCV_SET_SSIP => irq.set_software_interrupt(true), + self::RVM_RISCV_CLEAR_SSIP => irq.set_software_interrupt(false), + self::RVM_RISCV_SET_SEIP => irq.set_external_interrupt(true), + self::RVM_RISCV_CLEAR_SEIP => irq.set_external_interrupt(false), + _ => { + return Err(RvmError::InvalidParam); + } + } + Ok(()) + } else { + Err(RvmError::InvalidParam) + } + } // TODO: remove guest & vcpu } diff --git a/kernel/src/rvm/memory.rs b/kernel/src/rvm/memory.rs index 2e80cb7e..834ddeee 100644 --- a/kernel/src/rvm/memory.rs +++ b/kernel/src/rvm/memory.rs @@ -85,6 +85,7 @@ impl MemoryHandler for RvmPageTableHandlerDelay { if target == 0 { target = self.allocator.alloc().expect("failed to alloc frame"); } + info!("guest_paddr={}, target={}", guest_paddr, target); rvm_pt .map(guest_paddr, target, GuestMemoryAttr::default()) .expect("failed to create GPA -> HPA mapping"); diff --git a/kernel/src/rvm/mod.rs b/kernel/src/rvm/mod.rs index 8bb03eb9..666fd6c7 100644 --- a/kernel/src/rvm/mod.rs +++ b/kernel/src/rvm/mod.rs @@ -28,15 +28,20 @@ fn into_fs_error(e: RvmError) -> FsError { } mod rvm_extern_fn { - use crate::memory::{alloc_frame, dealloc_frame, phys_to_virt}; - #[rvm::extern_fn(alloc_frame)] - fn rvm_alloc_frame() -> Option { - alloc_frame() + use crate::memory::{alloc_frame_contiguous, dealloc_frame, phys_to_virt}; + use rvm::PAGE_SIZE; + #[rvm::extern_fn(alloc_frames)] + fn rvm_alloc_frames(n: usize, align_log2: usize) -> Option { + alloc_frame_contiguous(n, align_log2) } - #[rvm::extern_fn(dealloc_frame)] - fn rvm_dealloc_frame(paddr: usize) { - dealloc_frame(paddr) + #[rvm::extern_fn(dealloc_frames)] + fn rvm_dealloc_frames(paddr: usize, n: usize, _align_log2: usize) { + for i in 0..n { + dealloc_frame(paddr + i * PAGE_SIZE) + } + //use crate::memory::dealloc_frame_contiguous; + //dealloc_frame_contiguous(paddr, n, align_log2) } #[rvm::extern_fn(phys_to_virt)] @@ -45,11 +50,31 @@ mod rvm_extern_fn { } #[cfg(target_arch = "x86_64")] - #[rvm::extern_fn(x86_all_traps_handler_addr)] - unsafe fn rvm_x86_all_traps_handler_addr() -> usize { - extern "C" { - fn __alltraps(); + #[rvm::extern_fn(is_host_timer_interrupt)] + fn rvm_x86_is_host_timer_interrupt(_vec: u8) -> bool { + // TODO: fill in the blanks. + false + } + #[cfg(target_arch = "x86_64")] + #[rvm::extern_fn(is_host_serial_interrupt)] + fn rvm_x86_is_host_serial_interrupt(_vec: u8) -> bool { + // TODO: fill in the blanks. + false + } + + #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] + #[rvm::extern_fn(riscv_trap_handler_no_frame)] + fn rvm_riscv_trap_handler_no_frame(sepc: &mut usize) { + crate::arch::interrupt::trap_handler_no_frame(sepc); + } + + #[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] + #[rvm::extern_fn(riscv_check_hypervisor_extension)] + fn rvm_riscv_check_hypervisor_extension() -> bool { + if cfg!(feature = "hypervisor") { + true + } else { + false } - __alltraps as usize } } diff --git a/kernel/src/rvm/structs.rs b/kernel/src/rvm/structs.rs index 7934b8ba..8bb7f3ba 100644 --- a/kernel/src/rvm/structs.rs +++ b/kernel/src/rvm/structs.rs @@ -17,6 +17,10 @@ pub(super) struct Guest { pub(super) struct Vcpu { pub(super) inner: Mutex, + //#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + //inner_id: usize, + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + pub(super) irq: Arc, } impl Guest { @@ -47,8 +51,22 @@ impl Guest { impl Vcpu { pub fn new(entry: u64, guest: Arc) -> RvmResult { - Ok(Self { - inner: Mutex::new(VcpuInner::new(entry, guest)?), - }) + #[cfg(any(target_arch = "x86_64"))] + { + Ok(Self { + inner: Mutex::new(VcpuInner::new(entry, guest)?), + }) + } + #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] + { + let inner = VcpuInner::new(entry, Arc::clone(&guest))?; + let inner_id = inner.get_id(); + let irq = guest.get_irq_by_id(inner_id); + return Ok(Self { + inner: Mutex::new(inner), + //inner_id, + irq, + }); + } } } diff --git a/kernel/src/syscall/misc.rs b/kernel/src/syscall/misc.rs index a5ed8019..a0052b19 100644 --- a/kernel/src/syscall/misc.rs +++ b/kernel/src/syscall/misc.rs @@ -190,7 +190,7 @@ impl Syscall<'_> { for elm in slice { unsafe { // to prevent overflow - *elm = (i + crate::trap::TICK as u8 as u16) as u8; + *elm = (i + crate::trap::wall_tick() as u8 as u16) as u8; } i += 1; } diff --git a/kernel/src/syscall/time.rs b/kernel/src/syscall/time.rs index e5367fc0..b31923a4 100644 --- a/kernel/src/syscall/time.rs +++ b/kernel/src/syscall/time.rs @@ -46,7 +46,7 @@ impl Syscall<'_> { let rusage = unsafe { self.vm().check_write_ptr(rusage)? }; let tick_base = *TICK_BASE; - let tick = unsafe { crate::trap::TICK as u64 }; + let tick = unsafe { crate::trap::wall_tick() as u64 }; let usec = (tick - tick_base) * USEC_PER_TICK as u64; let new_rusage = RUsage { @@ -68,7 +68,7 @@ impl Syscall<'_> { let buf = unsafe { self.vm().check_write_ptr(buf)? }; let _tick_base = *TICK_BASE; - let tick = unsafe { crate::trap::TICK as u64 }; + let tick = unsafe { crate::trap::wall_tick() as u64 }; let new_buf = Tms { tms_utime: 0, @@ -85,7 +85,7 @@ impl Syscall<'_> { // should be initialized together lazy_static! { pub static ref EPOCH_BASE: u64 = crate::drivers::rtc::read_epoch(); - pub static ref TICK_BASE: u64 = unsafe { crate::trap::TICK as u64 }; + pub static ref TICK_BASE: u64 = unsafe { crate::trap::wall_tick() as u64 }; } // 1ms msec @@ -102,7 +102,7 @@ const NSEC_PER_MSEC: u64 = 1_000_000; fn get_epoch_usec() -> u64 { let tick_base = *TICK_BASE; let epoch_base = *EPOCH_BASE; - let tick = unsafe { crate::trap::TICK as u64 }; + let tick = unsafe { crate::trap::wall_tick() as u64 }; (tick - tick_base) * USEC_PER_TICK as u64 + epoch_base * USEC_PER_SEC } diff --git a/kernel/src/trap.rs b/kernel/src/trap.rs index 13430cb8..67d8b08d 100644 --- a/kernel/src/trap.rs +++ b/kernel/src/trap.rs @@ -3,19 +3,32 @@ use crate::consts::INFORM_PER_MSEC; use crate::process::*; use crate::sync::SpinNoIrqLock as Mutex; use crate::{signal::SignalUserContext, sync::Condvar}; +use core::sync::atomic::{AtomicUsize, Ordering}; use core::time::Duration; use naive_timer::Timer; use trapframe::TrapFrame; use trapframe::UserContext; +pub static TICK: AtomicUsize = AtomicUsize::new(0); +pub static TICK_ALL_PROCESSORS: AtomicUsize = AtomicUsize::new(0); -pub static mut TICK: usize = 0; - +pub unsafe fn wall_tick() -> usize { + return TICK.load(Ordering::Relaxed); +} +pub fn cpu_tick() -> usize { + return TICK_ALL_PROCESSORS.load(Ordering::Relaxed); +} +pub fn do_tick() { + if crate::arch::cpu::id() == 0 { + let ret = TICK.fetch_add(1, Ordering::Relaxed); + } + TICK_ALL_PROCESSORS.fetch_add(1, Ordering::Relaxed); +} lazy_static! { pub static ref TICK_ACTIVITY: Condvar = Condvar::new(); } pub fn uptime_msec() -> usize { - unsafe { crate::trap::TICK * crate::consts::USEC_PER_TICK / 1000 } + unsafe { crate::trap::wall_tick() * crate::consts::USEC_PER_TICK / 1000 } } lazy_static! { @@ -23,6 +36,9 @@ lazy_static! { } pub fn timer() { + do_tick(); + //let ret=unsafe{wall_tick()}; + let now = crate::arch::timer::timer_now(); NAIVE_TIMER.lock().expire(now); } diff --git a/tools/gdbinit-sbi b/tools/gdbinit-sbi new file mode 100644 index 00000000..ebc6f552 --- /dev/null +++ b/tools/gdbinit-sbi @@ -0,0 +1,2 @@ +file ../tools/sbi/fw_jump.elf +target remote 127.0.0.1:1234 diff --git a/user b/user index 94620bd6..1c5e883f 160000 --- a/user +++ b/user @@ -1 +1 @@ -Subproject commit 94620bd696ac61b40129d845671cde83001fdf61 +Subproject commit 1c5e883fcfb0dc18895dce7b1931d7cf3a4261b1