From f3c4e7c3180ced01da190c156ff16f6d2d9e8b1d Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 1 Oct 2024 18:12:46 +0900 Subject: [PATCH 01/99] [add] add `henvcfg::set_cde` --- src/h_extension/csrs.rs | 12 ++++++++++++ src/hypervisor_init.rs | 1 + 2 files changed, 13 insertions(+) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index 9a0dcfb..d8b6e40 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -271,6 +271,18 @@ pub mod henvcfg { } } + /// set CDE (60 bit) + pub fn set_cde() { + unsafe { + core::arch::asm!( + " + csrs henvcfg, {bits} + ", + bits = in(reg) 1u64 << 60 + ); + } + } + /// set CBZE (7 bit) pub fn set_cbze() { unsafe { diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index bc6776b..3eb24e0 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -50,6 +50,7 @@ pub extern "C" fn hstart(hart_id: usize, dtb_addr: usize) -> ! { // enable Sstc extention henvcfg::set_stce(); + henvcfg::set_cde(); henvcfg::set_cbze(); henvcfg::set_cbcfe(); From 9ba194f5be8af79d66eada369670f5716794aedf Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 1 Oct 2024 18:16:02 +0900 Subject: [PATCH 02/99] [fix] remove `virtual_instruction_handler` --- src/trap/hypervisor_supervisor/exception.rs | 35 ++------------------- 1 file changed, 3 insertions(+), 32 deletions(-) diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index a38c098..85b38b7 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -13,11 +13,8 @@ use crate::memmap::HostPhysicalAddress; use crate::HYPERVISOR_DATA; use core::arch::asm; -use raki::{Decode, Instruction, Isa::Rv64, OpcodeKind, ZicntrOpcode}; -use riscv::register::{ - scause::{self, Exception}, - stval, -}; +use raki::Instruction; +use riscv::register::scause::{self, Exception}; use sbi_handler::{sbi_base_handler, sbi_rfnc_handler}; /// Delegate exception to supervisor mode from VS-mode. @@ -64,28 +61,6 @@ fn sbi_vs_mode_handler(context: &mut guest::context::Context) { context.set_xreg(11, sbiret.value as u64); } -/// Trap `VirtualInstruction` (cause = 22) -fn virtual_instruction_handler(inst_bytes: u32, context: &mut guest::context::Context) { - let inst = inst_bytes - .decode(Rv64) - .expect("virtual instruction decoding failed"); - - match inst.opc { - OpcodeKind::Zicntr(ZicntrOpcode::RDTIME) => { - let time_val = unsafe { - let time; - asm!("csrr {time_val}, time", time_val = out(reg) time); - time - }; - context.set_xreg( - inst.rd.expect("rd register is not found in rdtime"), - time_val, - ); - } - _ => panic!("unsupported instruction"), - }; -} - /// Trap handler for exception #[allow(clippy::cast_possible_truncation, clippy::module_name_repetitions)] pub unsafe fn trap_exception(exception_cause: Exception) -> ! { @@ -172,11 +147,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { hs_forward_exception(); } - HvException::VirtualInstruction => { - let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; - virtual_instruction_handler(stval::read() as u32, &mut context); - context.set_sepc(context.sepc() + 4); - } + HvException::VirtualInstruction => unreachable!(), }, _ => hs_forward_exception(), } From 3962ccf70b04fe276b44ddf596ff4e872c8482fc Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 1 Oct 2024 18:25:34 +0900 Subject: [PATCH 03/99] [update] ignore rootfs image file --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 4d56d4c..b3b6379 100644 --- a/.gitignore +++ b/.gitignore @@ -21,3 +21,4 @@ Cargo.lock .gdb_history vmlinux vmlinux_debug +rootfs.* From 9a04bd790bd72f30fc38412034cee895504b7a66 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 14:56:19 +0900 Subject: [PATCH 04/99] [update] update crate version of raki --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 23a4326..62887b8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ pedantic = "warn" elf = { version = "0.7.2", default-features = false } fdt = "0.1.5" linked_list_allocator = "0.10.5" -raki = { version = "1.0.0" } +raki = { version = "1.1.0" } riscv = "0.11.1" riscv-rt = "0.11.0" rustsbi = { version = "0.4.0-alpha.1", features = ["machine"] } From 0bddaf209646c77adeacd28c5270f7c26c1535c8 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 16:36:55 +0900 Subject: [PATCH 05/99] [!][fix] set `scounteren` CSR --- src/hypervisor_init.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index 3eb24e0..0b87bb3 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -56,6 +56,10 @@ pub extern "C" fn hstart(hart_id: usize, dtb_addr: usize) -> ! { // enable hypervisor counter hcounteren::set(0xffff_ffff); + // enable supervisor counter + unsafe { + asm!("csrw scounteren, {bits}", bits = in(reg) 0xffff_ffff as u32); + } // specify delegation exception kinds. hedeleg::write( From d3a448e0358fd3e315a8201026f3250394ceab28 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 17:20:20 +0900 Subject: [PATCH 06/99] [wip][add] add handling Zicfiss instruciton --- src/trap/hypervisor_supervisor/exception.rs | 28 +++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 85b38b7..090b503 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -13,8 +13,11 @@ use crate::memmap::HostPhysicalAddress; use crate::HYPERVISOR_DATA; use core::arch::asm; -use raki::Instruction; -use riscv::register::scause::{self, Exception}; +use raki::{Instruction, OpcodeKind, ZicfissOpcode}; +use riscv::register::{ + scause::{self, Exception}, + stval, +}; use sbi_handler::{sbi_base_handler, sbi_rfnc_handler}; /// Delegate exception to supervisor mode from VS-mode. @@ -65,6 +68,27 @@ fn sbi_vs_mode_handler(context: &mut guest::context::Context) { #[allow(clippy::cast_possible_truncation, clippy::module_name_repetitions)] pub unsafe fn trap_exception(exception_cause: Exception) -> ! { match exception_cause { + Exception::IllegalInstruction => { + let fault_inst_value = stval::read(); + let fault_inst = Instruction::try_from(fault_inst_value) + .expect("decoding load fault instruction failed"); + match fault_inst.opc { + OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => (), // no push for now + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => (), // no push for now + OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => (), // no pop/check for now + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => (), // no pop/check for now + _ => unimplemented!(), + } + + let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; + if (fault_inst_value & 0b10) >> 1 == 0 { + // compressed instruction + context.set_sepc(context.sepc() + 2); + } else { + // normal size instruction + context.set_sepc(context.sepc() + 4); + } + } Exception::SupervisorEnvCall => panic!("SupervisorEnvCall should be handled by M-mode"), // Enum not found in `riscv` crate. Exception::Unknown => match HvException::from(scause::read().code()) { From f0e2c84903c6849a8e67cd3f6d2027e430c95254 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 18:04:07 +0900 Subject: [PATCH 07/99] [add] add `emulate_extension` module --- src/emulate_extension.rs | 3 +++ src/emulate_extension/zicfiss.rs | 5 +++++ src/main.rs | 1 + 3 files changed, 9 insertions(+) create mode 100644 src/emulate_extension.rs create mode 100644 src/emulate_extension/zicfiss.rs diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs new file mode 100644 index 0000000..4bac413 --- /dev/null +++ b/src/emulate_extension.rs @@ -0,0 +1,3 @@ +//! Extension emulation + +mod zicfiss; diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs new file mode 100644 index 0000000..3c1f3de --- /dev/null +++ b/src/emulate_extension/zicfiss.rs @@ -0,0 +1,5 @@ +//! Emulation Zicfiss (Shadow Stack) +//! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) + +use raki::ZicfissOpcode; +pub fn instruction(opc: ZicfissOpcode) {} diff --git a/src/main.rs b/src/main.rs index bbec49f..5679bf1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -3,6 +3,7 @@ extern crate alloc; mod device; +mod emulate_extension; mod guest; mod h_extension; mod hypervisor_init; From 201c9a7f658bbd81ccbd0f41e3abadeb4369f99e Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 18:19:14 +0900 Subject: [PATCH 08/99] [wip][update] move an instruction emulation to `emulate_extension` module --- src/emulate_extension.rs | 2 +- src/emulate_extension/zicfiss.rs | 11 ++++++++++- src/trap/hypervisor_supervisor/exception.rs | 8 ++++---- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 4bac413..01c3af6 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -1,3 +1,3 @@ //! Extension emulation -mod zicfiss; +pub mod zicfiss; diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 3c1f3de..f4c168f 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -2,4 +2,13 @@ //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) use raki::ZicfissOpcode; -pub fn instruction(opc: ZicfissOpcode) {} + +/// Emulate Zicfiss instruction. +pub fn instruction(opc: ZicfissOpcode) { + match opc { + ZicfissOpcode::SSPUSH | ZicfissOpcode::C_SSPUSH => todo!(), + ZicfissOpcode::SSPOPCHK | ZicfissOpcode::C_SSPOPCHK => todo!(), + ZicfissOpcode::SSRDP => todo!(), + ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => todo!(), + } +} diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 090b503..f4f95fb 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -4,6 +4,7 @@ mod sbi_handler; use super::hstrap_exit; use crate::device::DeviceEmulateError; +use crate::emulate_extension::zicfiss; use crate::guest; use crate::h_extension::{ csrs::{htinst, htval, vstvec}, @@ -72,11 +73,10 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { let fault_inst_value = stval::read(); let fault_inst = Instruction::try_from(fault_inst_value) .expect("decoding load fault instruction failed"); + + // emulate the instruction match fault_inst.opc { - OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => (), // no push for now - OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => (), // no push for now - OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => (), // no pop/check for now - OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => (), // no pop/check for now + OpcodeKind::Zicfiss(opc) => zicfiss::instruction(opc), _ => unimplemented!(), } From 020d4cfffc9fe0c564bf1e5b320ab9c08b87f972 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 21:16:47 +0900 Subject: [PATCH 09/99] [add] add structs `Zicfiss` and `ShadowStack` --- src/emulate_extension/zicfiss.rs | 49 ++++++++++++++++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index f4c168f..c32d6bd 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -1,8 +1,57 @@ //! Emulation Zicfiss (Shadow Stack) //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) +use crate::memmap::page_table::constants::PAGE_SIZE; +use crate::PageBlock; use raki::ZicfissOpcode; +/// Shadow Stack +struct ShadowStack { + top: *const usize, + bottom: *const usize, + stack_pointer: *mut usize, +} + +impl ShadowStack { + /// Allocate memory region for shadow stack. + pub fn new() -> Self { + let stack_addr = PageBlock::alloc(); + let base_ptr = stack_addr.0 as *const usize; + ShadowStack { + top: unsafe { base_ptr.byte_add(PAGE_SIZE) }, + bottom: base_ptr, + stack_pointer: unsafe { base_ptr.cast_mut().byte_add(PAGE_SIZE) }, + } + } + + /// Push value to shadow stack + pub fn push(&mut self, value: usize) { + unsafe { + self.stack_pointer = self.stack_pointer.byte_sub(core::mem::size_of::()); + if self.stack_pointer.cast_const() < self.bottom { + panic!("stack smashed!"); + } + self.stack_pointer.write_volatile(value); + } + } + + /// Pop value from shadow stack + pub fn pop(&mut self) -> usize { + unsafe { + self.stack_pointer = self.stack_pointer.byte_add(core::mem::size_of::()); + if self.stack_pointer.cast_const() > self.top { + panic!("stack smashed!"); + } + self.stack_pointer.read_volatile() + } + } +} + +/// Singleton for Zicfiss extension +struct Zicfiss { + shadow_stack: ShadowStack, +} + /// Emulate Zicfiss instruction. pub fn instruction(opc: ZicfissOpcode) { match opc { From 6dd59212ab24720929c5921c66c7cbc2ce04616e Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 22:42:19 +0900 Subject: [PATCH 10/99] [wip][add] add global variable `ZICFISS_DATA` --- src/emulate_extension/zicfiss.rs | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index c32d6bd..71044fa 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -2,8 +2,17 @@ //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) use crate::memmap::page_table::constants::PAGE_SIZE; +use crate::memmap::HostPhysicalAddress; use crate::PageBlock; -use raki::ZicfissOpcode; +use crate::HYPERVISOR_DATA; + +use core::cell::OnceCell; +use raki::{Instruction, OpcodeKind, ZicfissOpcode}; +use spin::Mutex; + +/// Singleton for Zicfiss. +/// TODO: change `OnceCell` to `LazyCell`. +static mut ZICFISS_DATA: Mutex> = Mutex::new(OnceCell::new()); /// Shadow Stack struct ShadowStack { From daeb5d0f5554027869dd0d698bcc2f9702c42ba7 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 22:43:11 +0900 Subject: [PATCH 11/99] [add] add `ShadowStack::get_ssp` --- src/emulate_extension/zicfiss.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 71044fa..98db2b8 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -54,6 +54,10 @@ impl ShadowStack { self.stack_pointer.read_volatile() } } + + pub fn get_ssp(&self) -> HostPhysicalAddress { + HostPhysicalAddress(self.stack_pointer as usize) + } } /// Singleton for Zicfiss extension From bf9e59c169973e1f251a5870251f82a722fcefb4 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 22:43:57 +0900 Subject: [PATCH 12/99] [add] implement `Zicfiss::new` --- src/emulate_extension/zicfiss.rs | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 98db2b8..66bee50 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -62,7 +62,22 @@ impl ShadowStack { /// Singleton for Zicfiss extension struct Zicfiss { - shadow_stack: ShadowStack, + /// Shadow stack + pub shadow_stack: ShadowStack, + /// Shadow Stack Enable + /// + /// TODO: handle xenvcfg register. + /// TODO: devide into each priv. + pub sse: bool, +} + +impl Zicfiss { + pub fn new() -> Self { + Zicfiss { + shadow_stack: ShadowStack::new(), + sse: true, + } + } } /// Emulate Zicfiss instruction. From 8ec59138fb8ae62ed357dc47614a0f5686576888 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 22:44:25 +0900 Subject: [PATCH 13/99] [fix] fix `ShadowStack::pop` --- src/emulate_extension/zicfiss.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 66bee50..bc7e5cc 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -47,11 +47,13 @@ impl ShadowStack { /// Pop value from shadow stack pub fn pop(&mut self) -> usize { unsafe { + let pop_value = self.stack_pointer.read_volatile(); self.stack_pointer = self.stack_pointer.byte_add(core::mem::size_of::()); if self.stack_pointer.cast_const() > self.top { panic!("stack smashed!"); } - self.stack_pointer.read_volatile() + + pop_value } } From b1d493f010d5ff4b2a609481f7ee258a888d8481 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 2 Oct 2024 22:45:07 +0900 Subject: [PATCH 14/99] [wip][add] implement instruction emulation --- src/emulate_extension/zicfiss.rs | 53 ++++++++++++++++++--- src/trap/hypervisor_supervisor/exception.rs | 4 +- 2 files changed, 49 insertions(+), 8 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index bc7e5cc..6681601 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -83,11 +83,52 @@ impl Zicfiss { } /// Emulate Zicfiss instruction. -pub fn instruction(opc: ZicfissOpcode) { - match opc { - ZicfissOpcode::SSPUSH | ZicfissOpcode::C_SSPUSH => todo!(), - ZicfissOpcode::SSPOPCHK | ZicfissOpcode::C_SSPOPCHK => todo!(), - ZicfissOpcode::SSRDP => todo!(), - ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D => todo!(), +pub fn instruction(inst: Instruction) { + let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; + unsafe { ZICFISS_DATA.lock().get_or_init(|| Zicfiss::new()) }; + let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; + let zicfiss = zicfiss_data.get_mut().unwrap(); + + match inst.opc { + OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => { + if zicfiss.sse { + let push_value = context.xreg(inst.rs2.unwrap()); + zicfiss.shadow_stack.push(push_value as usize); + } + } + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => { + if zicfiss.sse { + let push_value = context.xreg(inst.rd.unwrap()); + zicfiss.shadow_stack.push(push_value as usize); + } + } + OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => { + if zicfiss.sse { + let pop_value = zicfiss.shadow_stack.pop(); + let expected_value = context.xreg(inst.rs1.unwrap()) as usize; + if pop_value != expected_value { + todo!("shadow stack fault exception: {:#x} != {:#x} (popped value, expected value)", pop_value, expected_value); + } + } + } + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => { + if zicfiss.sse { + let pop_value = zicfiss.shadow_stack.pop(); + let expected_value = context.xreg(inst.rd.unwrap()) as usize; + if pop_value != expected_value { + todo!("shadow stack fault exception: {:#x} != {:#x} (popped value, expected value)", pop_value, expected_value); + } + } + } + OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { + if zicfiss.sse { + let ssp = zicfiss.shadow_stack.get_ssp(); + context.set_xreg(inst.rd.unwrap(), ssp.0 as u64); + } else { + context.set_xreg(inst.rd.unwrap(), 0); + } + } + OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D) => todo!(), + _ => unreachable!(), } } diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index f4f95fb..81dcc5c 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -14,7 +14,7 @@ use crate::memmap::HostPhysicalAddress; use crate::HYPERVISOR_DATA; use core::arch::asm; -use raki::{Instruction, OpcodeKind, ZicfissOpcode}; +use raki::{Instruction, OpcodeKind}; use riscv::register::{ scause::{self, Exception}, stval, @@ -76,7 +76,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { // emulate the instruction match fault_inst.opc { - OpcodeKind::Zicfiss(opc) => zicfiss::instruction(opc), + OpcodeKind::Zicfiss(_) => zicfiss::instruction(fault_inst), _ => unimplemented!(), } From 7a174e6bc0edac9a2d6ffbd83c6f45b8ad259099 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 3 Oct 2024 16:20:01 +0900 Subject: [PATCH 15/99] [add] add `FwftFeature ` --- .../exception/sbi_handler.rs | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index ffdd78c..4aedd3b 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -3,7 +3,7 @@ use sbi_rt::SbiRet; -/// sbi ecall handler for Base Extension (EID: #0x10) +/// SBI ecall handler for Base Extension (EID: #0x10) /// /// All functions in the base extension must be supported by all SBI implementations, /// so there are no error returns defined. (p.13) @@ -33,7 +33,7 @@ pub fn sbi_base_handler(func_id: usize) -> SbiRet { } } -/// sbi ecall handler for RFENCE Extension (EID: #0x52464E43) +/// SBI ecall handler for RFENCE Extension (EID: #0x52464E43) #[allow(clippy::module_name_repetitions, clippy::cast_possible_truncation)] pub fn sbi_rfnc_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { use rustsbi::HartMask; @@ -56,3 +56,30 @@ pub fn sbi_rfnc_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { _ => panic!("unsupported fid: {}", func_id), } } + +/// FWFT Feature +/// Ref: [https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/vv3.0-rc1/riscv-sbi.pdf](https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/vv3.0-rc1/riscv-sbi.pdf) p.78 +#[derive(Debug)] +enum FwftFeature { + MisalignedExcDeleg, + LandingPad, + ShadowStack, + DoubleTrap, + PteAdHwUpdating, + PointerMaskingPmlen, +} + +impl TryFrom for FwftFeature { + type Error = usize; + fn try_from(from: usize) -> Result { + match from { + 0 => Ok(FwftFeature::MisalignedExcDeleg), + 1 => Ok(FwftFeature::LandingPad), + 2 => Ok(FwftFeature::ShadowStack), + 3 => Ok(FwftFeature::DoubleTrap), + 4 => Ok(FwftFeature::PteAdHwUpdating), + 5 => Ok(FwftFeature::PointerMaskingPmlen), + _ => Err(from), + } + } +} From 048c1abf46b518ce02fb2a6e86a1efe3c631cc23 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 3 Oct 2024 16:20:53 +0900 Subject: [PATCH 16/99] [add] implement sbi fwft ecall emulation --- src/emulate_extension/zicfiss.rs | 6 ++-- src/trap/hypervisor_supervisor/exception.rs | 6 ++-- .../exception/sbi_handler.rs | 34 +++++++++++++++++++ 3 files changed, 41 insertions(+), 5 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 6681601..f2a3de8 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -12,7 +12,7 @@ use spin::Mutex; /// Singleton for Zicfiss. /// TODO: change `OnceCell` to `LazyCell`. -static mut ZICFISS_DATA: Mutex> = Mutex::new(OnceCell::new()); +pub static mut ZICFISS_DATA: Mutex> = Mutex::new(OnceCell::new()); /// Shadow Stack struct ShadowStack { @@ -63,7 +63,7 @@ impl ShadowStack { } /// Singleton for Zicfiss extension -struct Zicfiss { +pub struct Zicfiss { /// Shadow stack pub shadow_stack: ShadowStack, /// Shadow Stack Enable @@ -77,7 +77,7 @@ impl Zicfiss { pub fn new() -> Self { Zicfiss { shadow_stack: ShadowStack::new(), - sse: true, + sse: false, } } } diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 81dcc5c..6ed4679 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -19,7 +19,7 @@ use riscv::register::{ scause::{self, Exception}, stval, }; -use sbi_handler::{sbi_base_handler, sbi_rfnc_handler}; +use sbi_handler::{sbi_base_handler, sbi_fwft_handler, sbi_rfnc_handler}; /// Delegate exception to supervisor mode from VS-mode. #[no_mangle] @@ -42,6 +42,7 @@ pub extern "C" fn hs_forward_exception() { /// Handler for Ecall from VS-mode exception #[allow(clippy::cast_possible_truncation)] fn sbi_vs_mode_handler(context: &mut guest::context::Context) { + const EID_FWFT: usize = 0x46574654; let ext_id: usize = context.xreg(17) as usize; let func_id: usize = context.xreg(16) as usize; let arguments: &[u64; 5] = &[ @@ -55,8 +56,9 @@ fn sbi_vs_mode_handler(context: &mut guest::context::Context) { let sbiret = match ext_id { sbi_spec::base::EID_BASE => sbi_base_handler(func_id), sbi_spec::rfnc::EID_RFNC => sbi_rfnc_handler(func_id, arguments), + EID_FWFT => sbi_fwft_handler(func_id, arguments), _ => panic!( - "Unsupported SBI call, eid: {:x}, fid: {:x}", + "Unsupported SBI call, eid: {:#x}, fid: {:#x}", ext_id, func_id ), }; diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 4aedd3b..109e8f2 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -1,6 +1,7 @@ //! Handle VS-mode Ecall exception //! See [https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/v2.0/riscv-sbi.pdf](https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/v2.0/riscv-sbi.pdf) +use crate::emulate_extension::zicfiss::ZICFISS_DATA; use sbi_rt::SbiRet; /// SBI ecall handler for Base Extension (EID: #0x10) @@ -83,3 +84,36 @@ impl TryFrom for FwftFeature { } } } + +/// SBI ecall handler for Firmware Features Extension (EID #0x46574654) +/// +/// FWFT ecall will be emulated because `sbi_rt` is not supported. +pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { + const FWFT_SET: usize = 0; + const FWFT_GET: usize = 1; + + let feature = args[0] as usize; + let value = args[1]; + let _flags = args[2]; + + // TODO remove it. + use crate::emulate_extension::zicfiss::Zicfiss; + unsafe { ZICFISS_DATA.lock().get_or_init(|| Zicfiss::new()) }; + + match func_id { + FWFT_SET => match FwftFeature::try_from(feature).unwrap() { + FwftFeature::ShadowStack => { + unsafe { ZICFISS_DATA.lock() }.get_mut().unwrap().sse = value != 0; + SbiRet::success(0) + } + feat => unimplemented!("unimplemented feature {:?}", feat), + }, + FWFT_GET => match FwftFeature::try_from(feature).unwrap() { + FwftFeature::ShadowStack => { + SbiRet::success(unsafe { ZICFISS_DATA.lock() }.get().unwrap().sse as usize) + } + feat => unimplemented!("unimplemented feature {:?}", feat), + }, + _ => unreachable!(), + } +} From e13e1f55a26e4425c09f96e61f9b7ec9dca578c0 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sat, 5 Oct 2024 18:34:11 +0900 Subject: [PATCH 17/99] [fix] modify `hs_forward_exception` to forward stval value --- src/trap/hypervisor_supervisor/exception.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 6ed4679..8bd7339 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -31,8 +31,10 @@ pub extern "C" fn hs_forward_exception() { asm!( "csrw vsepc, {sepc}", "csrw vscause, {scause}", + "csrw vstval, {stval}", sepc = in(reg) context.sepc(), - scause = in(reg) scause::read().bits() + scause = in(reg) scause::read().bits(), + stval = in(reg) stval::read(), ); context.set_sepc(vstvec::read().bits()); From ad42bc4808fd3d907c97a1a2d8fc06c7a7e4fc9c Mon Sep 17 00:00:00 2001 From: Alingof Date: Sat, 5 Oct 2024 21:30:29 +0900 Subject: [PATCH 18/99] [update] make `hstrap_exit` public --- src/trap/hypervisor_supervisor.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/trap/hypervisor_supervisor.rs b/src/trap/hypervisor_supervisor.rs index 63b87d6..ab8239b 100644 --- a/src/trap/hypervisor_supervisor.rs +++ b/src/trap/hypervisor_supervisor.rs @@ -16,7 +16,7 @@ use riscv::register::scause::{self, Trap}; /// replace stringify macro to const when `asm_const` is stabled. #[inline(always)] #[allow(clippy::inline_always)] -unsafe fn hstrap_exit() -> ! { +pub unsafe fn hstrap_exit() -> ! { // aquire hypervisor data let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; let stack_top = hypervisor_data.get().unwrap().guest().stack_top(); From 2cb2742f61ddb9d9bb0757d62727bede8461778e Mon Sep 17 00:00:00 2001 From: Alingof Date: Sat, 5 Oct 2024 21:31:35 +0900 Subject: [PATCH 19/99] [wip][add] add `pseudo_vs_exception` --- src/emulate_extension.rs | 30 ++++++++++++++++++++++++++++++ src/emulate_extension/zicfiss.rs | 10 ++++++++-- 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 01c3af6..4f7f386 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -1,3 +1,33 @@ //! Extension emulation pub mod zicfiss; + +use crate::h_extension::csrs::vstvec; +use crate::trap::hypervisor_supervisor::hstrap_exit; +use crate::HYPERVISOR_DATA; + +use core::arch::asm; + +/// Throw an VS-level exception. +/// * `exception_num`: Exception number. (store to vscause) +/// * `trap_value`: Trap value. (store to vstval) +pub fn pseudo_vs_exception(exception_num: usize, trap_value: usize) { + unsafe { + let hypervisor_data = HYPERVISOR_DATA.lock(); + let mut context = hypervisor_data.get().unwrap().guest().context; + asm!( + "csrw vsepc, {sepc}", + "csrw vscause, {cause}", + "csrw vstval, {tval}", + sepc = in(reg) context.sepc(), + cause = in(reg) exception_num, + tval = in(reg) trap_value, + ); + + context.set_sepc(vstvec::read().bits()); + + drop(hypervisor_data); + + hstrap_exit(); + } +} diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index f2a3de8..8922489 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -1,6 +1,7 @@ //! Emulation Zicfiss (Shadow Stack) //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) +use super::pseudo_vs_exception; use crate::memmap::page_table::constants::PAGE_SIZE; use crate::memmap::HostPhysicalAddress; use crate::PageBlock; @@ -14,6 +15,11 @@ use spin::Mutex; /// TODO: change `OnceCell` to `LazyCell`. pub static mut ZICFISS_DATA: Mutex> = Mutex::new(OnceCell::new()); +/// Software-check exception. (cause value) +const SOFTWARE_CHECK_EXCEPTION: usize = 18; +/// Shadow stack fault. (tval value) +const SHADOW_STACK_FAULT: usize = 3; + /// Shadow Stack struct ShadowStack { top: *const usize, @@ -107,7 +113,7 @@ pub fn instruction(inst: Instruction) { let pop_value = zicfiss.shadow_stack.pop(); let expected_value = context.xreg(inst.rs1.unwrap()) as usize; if pop_value != expected_value { - todo!("shadow stack fault exception: {:#x} != {:#x} (popped value, expected value)", pop_value, expected_value); + pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) } } } @@ -116,7 +122,7 @@ pub fn instruction(inst: Instruction) { let pop_value = zicfiss.shadow_stack.pop(); let expected_value = context.xreg(inst.rd.unwrap()) as usize; if pop_value != expected_value { - todo!("shadow stack fault exception: {:#x} != {:#x} (popped value, expected value)", pop_value, expected_value); + pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) } } } From a664b4ac87635c79e13f299823d8a8e31a6c7ba2 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 16:15:46 +0900 Subject: [PATCH 20/99] [add] add `Context::sstatus` --- src/guest/context.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/guest/context.rs b/src/guest/context.rs index 32a6f59..2e01ab7 100644 --- a/src/guest/context.rs +++ b/src/guest/context.rs @@ -60,6 +60,11 @@ impl Context { self.get_context().sepc = value; } + /// Return sstatus value. + pub fn sstatus(self) -> usize { + self.get_context().sstatus + } + /// Set sstatus. pub fn set_sstatus(&mut self, value: usize) { self.get_context().sstatus = value; From f1d78e59a71fae788c43a03e60607cd87490bec4 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 16:39:52 +0900 Subject: [PATCH 21/99] [fix] fix updating priv mode in `pseudo_vs_exception` --- src/emulate_extension.rs | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 4f7f386..ac34142 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -7,11 +7,12 @@ use crate::trap::hypervisor_supervisor::hstrap_exit; use crate::HYPERVISOR_DATA; use core::arch::asm; +use riscv::register::sstatus; /// Throw an VS-level exception. /// * `exception_num`: Exception number. (store to vscause) /// * `trap_value`: Trap value. (store to vstval) -pub fn pseudo_vs_exception(exception_num: usize, trap_value: usize) { +pub fn pseudo_vs_exception(exception_num: usize, trap_value: usize) -> ! { unsafe { let hypervisor_data = HYPERVISOR_DATA.lock(); let mut context = hypervisor_data.get().unwrap().guest().context; @@ -24,6 +25,15 @@ pub fn pseudo_vs_exception(exception_num: usize, trap_value: usize) { tval = in(reg) trap_value, ); + let spp = sstatus::read().spp(); + let vsstatus: usize; + asm!("csrr {status}, vsstatus", status = out(reg) vsstatus); + asm!( + "csrw vsstatus, {status}", + status = in(reg) (vsstatus & !(1 << 8)) | (spp as usize) << 8 + ); + context.set_sstatus(context.sstatus() | 1 << 8); + context.set_sepc(vstvec::read().bits()); drop(hypervisor_data); From 48643c8553b406670bbcc3d3e76c63582eaaa157 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 14:48:26 +0900 Subject: [PATCH 22/99] [!][add] add `zicfiss` to `riscv,isa-extensions` in device tree --- guest.dtb | Bin 5092 -> 5108 bytes guest_image/guest.dts | 4 ++-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/guest.dtb b/guest.dtb index 14c012b399538c82dcb7635e8f7fb8e0073ec725..41fe49fcc360a155d8a2bbe5e0249245dca035f2 100644 GIT binary patch delta 61 zcmaE&{zYBj0`I@K3=G0w7#J8V7#IYPOcW4j?AfUCn2GVjWFF=~mbA>`;>nTByBOb1 P7Gd!Rb2rDcwDJQ0j_?$y delta 51 zcmV-30L=gNC*&s(&<+0W000x@0000u000rRkq{RFe6c9w0s-ig3; riscv,cboz-block-size = <0x40>; riscv,cbom-block-size = <0x40>; - riscv,isa-extensions = "i\0m\0a\0f\0d\0c\0h\0zic64b\0zicbom\0zicbop\0zicboz\0ziccamoa\0ziccif\0zicclsm\0ziccrse\0zicntr\0zicsr\0zifencei\0zihintntl\0zihintpause\0zihpm\0zmmul\0za64rs\0zaamo\0zalrsc\0zawrs\0zfa\0zca\0zcd\0zba\0zbb\0zbc\0zbs\0ssccptr\0sscounterenw\0sstc\0sstvala\0sstvecd\0svadu"; + riscv,isa-extensions = "i\0m\0a\0f\0d\0c\0h\0zic64b\0zicbom\0zicbop\0zicboz\0ziccamoa\0ziccif\0zicclsm\0ziccrse\0zicfiss\0zicntr\0zicsr\0zifencei\0zihintntl\0zihintpause\0zihpm\0zmmul\0za64rs\0zaamo\0zalrsc\0zawrs\0zfa\0zca\0zcd\0zba\0zbb\0zbc\0zbs\0ssccptr\0sscounterenw\0sstc\0sstvala\0sstvecd\0svadu"; riscv,isa-base = "rv64i"; - riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zmmul_za64rs_zaamo_zalrsc_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu"; + riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicfiss_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zmmul_za64rs_zaamo_zalrsc_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu"; mmu-type = "riscv,sv57"; interrupt-controller { From 1dd26adab664b0b9eda58eea97511c4b818863dc Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 16:15:18 +0900 Subject: [PATCH 23/99] [fix] fix handling global data in `zicfiss::instruction` --- src/emulate_extension/zicfiss.rs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 8922489..603219f 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -90,7 +90,8 @@ impl Zicfiss { /// Emulate Zicfiss instruction. pub fn instruction(inst: Instruction) { - let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; + let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + let mut context = hypervisor_data.get().unwrap().guest().context; unsafe { ZICFISS_DATA.lock().get_or_init(|| Zicfiss::new()) }; let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; let zicfiss = zicfiss_data.get_mut().unwrap(); @@ -113,6 +114,8 @@ pub fn instruction(inst: Instruction) { let pop_value = zicfiss.shadow_stack.pop(); let expected_value = context.xreg(inst.rs1.unwrap()) as usize; if pop_value != expected_value { + drop(zicfiss_data); + drop(hypervisor_data); pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) } } @@ -122,6 +125,8 @@ pub fn instruction(inst: Instruction) { let pop_value = zicfiss.shadow_stack.pop(); let expected_value = context.xreg(inst.rd.unwrap()) as usize; if pop_value != expected_value { + drop(zicfiss_data); + drop(hypervisor_data); pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) } } From 471610d7677311a739d8a964577b1bcc7011dc35 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 16:29:28 +0900 Subject: [PATCH 24/99] [add] add `CsrData` --- src/emulate_extension.rs | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index ac34142..06254dc 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -9,6 +9,34 @@ use crate::HYPERVISOR_DATA; use core::arch::asm; use riscv::register::sstatus; +/// CSR data for CSRs emulation. +pub struct CsrData(u64); + +impl CsrData { + /// Return raw data. + pub fn bits(&self) -> u64 { + self.0 + } + + /// Write data to CSR. + /// For CSRRW or CSRRWI + pub fn write(&mut self, data: u64) { + self.0 = data; + } + + /// Set bit in CSR. + /// For CSRRS or CSRRSI + pub fn set(&mut self, mask: u64) { + self.0 |= mask; + } + + /// Clear bit in CSR. + /// For CSRRC or CSRRCI + pub fn clear(&mut self, mask: u64) { + self.0 &= !mask; + } +} + /// Throw an VS-level exception. /// * `exception_num`: Exception number. (store to vscause) /// * `trap_value`: Trap value. (store to vstval) From 99f88f355edc6708962403b30d9588ed8366df94 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 16:44:57 +0900 Subject: [PATCH 25/99] [add] add Zicfiss CSRs emulation --- src/emulate_extension/zicfiss.rs | 58 +++++++++++++++++++-- src/trap/hypervisor_supervisor/exception.rs | 15 +++++- 2 files changed, 68 insertions(+), 5 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 603219f..5d2b1de 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -1,14 +1,14 @@ //! Emulation Zicfiss (Shadow Stack) //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) -use super::pseudo_vs_exception; +use super::{pseudo_vs_exception, CsrData}; use crate::memmap::page_table::constants::PAGE_SIZE; use crate::memmap::HostPhysicalAddress; use crate::PageBlock; use crate::HYPERVISOR_DATA; use core::cell::OnceCell; -use raki::{Instruction, OpcodeKind, ZicfissOpcode}; +use raki::{Instruction, OpcodeKind, ZicfissOpcode, ZicsrOpcode}; use spin::Mutex; /// Singleton for Zicfiss. @@ -72,6 +72,10 @@ impl ShadowStack { pub struct Zicfiss { /// Shadow stack pub shadow_stack: ShadowStack, + + /// Shadow stack pointer + pub ssp: CsrData, + /// Shadow Stack Enable /// /// TODO: handle xenvcfg register. @@ -83,11 +87,59 @@ impl Zicfiss { pub fn new() -> Self { Zicfiss { shadow_stack: ShadowStack::new(), + ssp: CsrData(0), sse: false, } } } +/// Emulate Zicfiss CSRs access. +pub fn csrs(inst: Instruction) { + const CSR_SSP: usize = 0x11; + + let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + let mut context = hypervisor_data.get().unwrap().guest().context; + let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; + let zicfiss = zicfiss_data.get_mut().unwrap(); + + let csr_num = inst.rs2.unwrap(); + match csr_num { + CSR_SSP => match inst.opc { + OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.write(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.set(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.clear(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.write(inst.rs1.unwrap() as u64); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.set(inst.rs1.unwrap() as u64); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.clear(inst.rs1.unwrap() as u64); + } + _ => unreachable!(), + }, + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + } + } +} + /// Emulate Zicfiss instruction. pub fn instruction(inst: Instruction) { let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; @@ -140,6 +192,6 @@ pub fn instruction(inst: Instruction) { } } OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D) => todo!(), - _ => unreachable!(), + _ => todo!(), } } diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 8bd7339..a1d1523 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -17,7 +17,7 @@ use core::arch::asm; use raki::{Instruction, OpcodeKind}; use riscv::register::{ scause::{self, Exception}, - stval, + sepc, stval, }; use sbi_handler::{sbi_base_handler, sbi_fwft_handler, sbi_rfnc_handler}; @@ -81,7 +81,18 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { // emulate the instruction match fault_inst.opc { OpcodeKind::Zicfiss(_) => zicfiss::instruction(fault_inst), - _ => unimplemented!(), + OpcodeKind::Zicsr(_) => match fault_inst.rs2.unwrap() { + // ssp + 0x11 => zicfiss::csrs(fault_inst), + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + } + }, + _ => unimplemented!( + "unsupported illegal instruction: {:#?}, at {:#x}", + fault_inst, + sepc::read() + ), } let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; From 7e7111653e05d09494583b44e03d682c0db9474c Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 6 Oct 2024 17:21:33 +0900 Subject: [PATCH 26/99] [!][update] remove `ShadowStack` struct (shadow stack is allocated by guest os) --- src/emulate_extension/zicfiss.rs | 172 +++++++++++++------------------ 1 file changed, 69 insertions(+), 103 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 5d2b1de..fc8a3b5 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -2,9 +2,6 @@ //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) use super::{pseudo_vs_exception, CsrData}; -use crate::memmap::page_table::constants::PAGE_SIZE; -use crate::memmap::HostPhysicalAddress; -use crate::PageBlock; use crate::HYPERVISOR_DATA; use core::cell::OnceCell; @@ -20,59 +17,8 @@ const SOFTWARE_CHECK_EXCEPTION: usize = 18; /// Shadow stack fault. (tval value) const SHADOW_STACK_FAULT: usize = 3; -/// Shadow Stack -struct ShadowStack { - top: *const usize, - bottom: *const usize, - stack_pointer: *mut usize, -} - -impl ShadowStack { - /// Allocate memory region for shadow stack. - pub fn new() -> Self { - let stack_addr = PageBlock::alloc(); - let base_ptr = stack_addr.0 as *const usize; - ShadowStack { - top: unsafe { base_ptr.byte_add(PAGE_SIZE) }, - bottom: base_ptr, - stack_pointer: unsafe { base_ptr.cast_mut().byte_add(PAGE_SIZE) }, - } - } - - /// Push value to shadow stack - pub fn push(&mut self, value: usize) { - unsafe { - self.stack_pointer = self.stack_pointer.byte_sub(core::mem::size_of::()); - if self.stack_pointer.cast_const() < self.bottom { - panic!("stack smashed!"); - } - self.stack_pointer.write_volatile(value); - } - } - - /// Pop value from shadow stack - pub fn pop(&mut self) -> usize { - unsafe { - let pop_value = self.stack_pointer.read_volatile(); - self.stack_pointer = self.stack_pointer.byte_add(core::mem::size_of::()); - if self.stack_pointer.cast_const() > self.top { - panic!("stack smashed!"); - } - - pop_value - } - } - - pub fn get_ssp(&self) -> HostPhysicalAddress { - HostPhysicalAddress(self.stack_pointer as usize) - } -} - /// Singleton for Zicfiss extension pub struct Zicfiss { - /// Shadow stack - pub shadow_stack: ShadowStack, - /// Shadow stack pointer pub ssp: CsrData, @@ -86,56 +32,30 @@ pub struct Zicfiss { impl Zicfiss { pub fn new() -> Self { Zicfiss { - shadow_stack: ShadowStack::new(), ssp: CsrData(0), sse: false, } } -} -/// Emulate Zicfiss CSRs access. -pub fn csrs(inst: Instruction) { - const CSR_SSP: usize = 0x11; + fn ssp_ptr(&self) -> *mut usize { + self.ssp.0 as *mut usize + } - let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; - let mut context = hypervisor_data.get().unwrap().guest().context; - let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; - let zicfiss = zicfiss_data.get_mut().unwrap(); + /// Push value to shadow stack + pub fn ss_push(&mut self, value: usize) { + unsafe { + self.ssp = CsrData(self.ssp_ptr().byte_sub(core::mem::size_of::()) as u64); + self.ssp_ptr().write_volatile(value); + } + } - let csr_num = inst.rs2.unwrap(); - match csr_num { - CSR_SSP => match inst.opc { - OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { - let rs1 = context.xreg(inst.rs1.unwrap()); - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.write(rs1); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { - let rs1 = context.xreg(inst.rs1.unwrap()); - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.set(rs1); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { - let rs1 = context.xreg(inst.rs1.unwrap()); - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.clear(rs1); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.write(inst.rs1.unwrap() as u64); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.set(inst.rs1.unwrap() as u64); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.clear(inst.rs1.unwrap() as u64); - } - _ => unreachable!(), - }, - unsupported_csr_num => { - unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + /// Pop value from shadow stack + pub fn ss_pop(&mut self) -> usize { + unsafe { + let pop_value = self.ssp_ptr().read_volatile(); + self.ssp = CsrData(self.ssp_ptr().byte_add(core::mem::size_of::()) as u64); + + pop_value } } } @@ -152,18 +72,18 @@ pub fn instruction(inst: Instruction) { OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => { if zicfiss.sse { let push_value = context.xreg(inst.rs2.unwrap()); - zicfiss.shadow_stack.push(push_value as usize); + zicfiss.ss_push(push_value as usize); } } OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => { if zicfiss.sse { let push_value = context.xreg(inst.rd.unwrap()); - zicfiss.shadow_stack.push(push_value as usize); + zicfiss.ss_push(push_value as usize); } } OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => { if zicfiss.sse { - let pop_value = zicfiss.shadow_stack.pop(); + let pop_value = zicfiss.ss_pop(); let expected_value = context.xreg(inst.rs1.unwrap()) as usize; if pop_value != expected_value { drop(zicfiss_data); @@ -174,7 +94,7 @@ pub fn instruction(inst: Instruction) { } OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => { if zicfiss.sse { - let pop_value = zicfiss.shadow_stack.pop(); + let pop_value = zicfiss.ss_pop(); let expected_value = context.xreg(inst.rd.unwrap()) as usize; if pop_value != expected_value { drop(zicfiss_data); @@ -185,8 +105,7 @@ pub fn instruction(inst: Instruction) { } OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { if zicfiss.sse { - let ssp = zicfiss.shadow_stack.get_ssp(); - context.set_xreg(inst.rd.unwrap(), ssp.0 as u64); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.0 as u64); } else { context.set_xreg(inst.rd.unwrap(), 0); } @@ -195,3 +114,50 @@ pub fn instruction(inst: Instruction) { _ => todo!(), } } + +/// Emulate Zicfiss CSRs access. +pub fn csrs(inst: Instruction) { + const CSR_SSP: usize = 0x11; + + let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + let mut context = hypervisor_data.get().unwrap().guest().context; + let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; + let zicfiss = zicfiss_data.get_mut().unwrap(); + + let csr_num = inst.rs2.unwrap(); + match csr_num { + CSR_SSP => match inst.opc { + OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.write(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.set(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.clear(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.write(inst.rs1.unwrap() as u64); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.set(inst.rs1.unwrap() as u64); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { + context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); + zicfiss.ssp.clear(inst.rs1.unwrap() as u64); + } + _ => unreachable!(), + }, + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + } + } +} From a1eac019eea08bc8d2ba7695431b5e27721cce57 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 8 Oct 2024 16:57:19 +0900 Subject: [PATCH 27/99] [wip][update] devide `Zicfiss.sse` into each priv level --- src/emulate_extension/zicfiss.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index fc8a3b5..aa6832b 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -21,22 +21,22 @@ const SHADOW_STACK_FAULT: usize = 3; pub struct Zicfiss { /// Shadow stack pointer pub ssp: CsrData, - - /// Shadow Stack Enable - /// - /// TODO: handle xenvcfg register. - /// TODO: devide into each priv. - pub sse: bool, + /// Shadow Stack Enable in henvcfg (for VS-mode) + pub henv_sse: bool, + /// Shadow Stack Enable in senvcfg (for VU-mode) + pub senv_sse: bool, } impl Zicfiss { pub fn new() -> Self { Zicfiss { ssp: CsrData(0), - sse: false, + henv_sse: false, + senv_sse: false, } } + /// Return shadow stack pointer as `*mut usize`. fn ssp_ptr(&self) -> *mut usize { self.ssp.0 as *mut usize } From 9d8e7c70b71cb0f6045b374102c9d629fe621169 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 8 Oct 2024 17:35:50 +0900 Subject: [PATCH 28/99] [fix] fix FWFT SBI call --- src/trap/hypervisor_supervisor/exception/sbi_handler.rs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 109e8f2..25a3d72 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -2,6 +2,8 @@ //! See [https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/v2.0/riscv-sbi.pdf](https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/v2.0/riscv-sbi.pdf) use crate::emulate_extension::zicfiss::ZICFISS_DATA; + +use core::arch::asm; use sbi_rt::SbiRet; /// SBI ecall handler for Base Extension (EID: #0x10) @@ -93,7 +95,7 @@ pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { const FWFT_GET: usize = 1; let feature = args[0] as usize; - let value = args[1]; + let _value = args[1]; let _flags = args[2]; // TODO remove it. @@ -103,14 +105,15 @@ pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { match func_id { FWFT_SET => match FwftFeature::try_from(feature).unwrap() { FwftFeature::ShadowStack => { - unsafe { ZICFISS_DATA.lock() }.get_mut().unwrap().sse = value != 0; + // hypervisor does not use shadow stack. SbiRet::success(0) } feat => unimplemented!("unimplemented feature {:?}", feat), }, FWFT_GET => match FwftFeature::try_from(feature).unwrap() { FwftFeature::ShadowStack => { - SbiRet::success(unsafe { ZICFISS_DATA.lock() }.get().unwrap().sse as usize) + // hypervisor does not use shadow stack. + SbiRet::success(0) } feat => unimplemented!("unimplemented feature {:?}", feat), }, From d5dbf83328a486eaab60ed47afb8bccce1cc131a Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 8 Oct 2024 17:40:31 +0900 Subject: [PATCH 29/99] [add] add `Zicfiss::is_ss_enable` --- src/emulate_extension/zicfiss.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index aa6832b..680cb94 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -58,6 +58,21 @@ impl Zicfiss { pop_value } } + + pub fn is_ss_enable(&self) -> bool { + let context = unsafe { HYPERVISOR_DATA.lock() } + .get() + .unwrap() + .guest() + .context; + + let spp = context.sstatus() >> 8 & 0x1; + if spp == 0 { + self.senv_sse + } else { + self.henv_sse + } + } } /// Emulate Zicfiss instruction. @@ -70,19 +85,19 @@ pub fn instruction(inst: Instruction) { match inst.opc { OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => { - if zicfiss.sse { + if zicfiss.is_ss_enable() { let push_value = context.xreg(inst.rs2.unwrap()); zicfiss.ss_push(push_value as usize); } } OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => { - if zicfiss.sse { + if zicfiss.is_ss_enable() { let push_value = context.xreg(inst.rd.unwrap()); zicfiss.ss_push(push_value as usize); } } OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => { - if zicfiss.sse { + if zicfiss.is_ss_enable() { let pop_value = zicfiss.ss_pop(); let expected_value = context.xreg(inst.rs1.unwrap()) as usize; if pop_value != expected_value { @@ -93,7 +108,7 @@ pub fn instruction(inst: Instruction) { } } OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => { - if zicfiss.sse { + if zicfiss.is_ss_enable() { let pop_value = zicfiss.ss_pop(); let expected_value = context.xreg(inst.rd.unwrap()) as usize; if pop_value != expected_value { @@ -104,7 +119,7 @@ pub fn instruction(inst: Instruction) { } } OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { - if zicfiss.sse { + if zicfiss.is_ss_enable() { context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.0 as u64); } else { context.set_xreg(inst.rd.unwrap(), 0); From f5c9897c916b184c64a5826bdbbf13c544b319ee Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 8 Oct 2024 18:18:07 +0900 Subject: [PATCH 30/99] [fix] fix Zicfiss::is_ss_enable to prevent deadlock --- src/emulate_extension/zicfiss.rs | 21 +++++++------------ .../exception/sbi_handler.rs | 1 - 2 files changed, 8 insertions(+), 14 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 680cb94..06ca5b7 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -59,14 +59,8 @@ impl Zicfiss { } } - pub fn is_ss_enable(&self) -> bool { - let context = unsafe { HYPERVISOR_DATA.lock() } - .get() - .unwrap() - .guest() - .context; - - let spp = context.sstatus() >> 8 & 0x1; + pub fn is_ss_enable(&self, sstatus: usize) -> bool { + let spp = sstatus >> 8 & 0x1; if spp == 0 { self.senv_sse } else { @@ -79,25 +73,26 @@ impl Zicfiss { pub fn instruction(inst: Instruction) { let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; let mut context = hypervisor_data.get().unwrap().guest().context; + let sstatus = context.sstatus(); unsafe { ZICFISS_DATA.lock().get_or_init(|| Zicfiss::new()) }; let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; let zicfiss = zicfiss_data.get_mut().unwrap(); match inst.opc { OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => { - if zicfiss.is_ss_enable() { + if zicfiss.is_ss_enable(sstatus) { let push_value = context.xreg(inst.rs2.unwrap()); zicfiss.ss_push(push_value as usize); } } OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => { - if zicfiss.is_ss_enable() { + if zicfiss.is_ss_enable(sstatus) { let push_value = context.xreg(inst.rd.unwrap()); zicfiss.ss_push(push_value as usize); } } OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => { - if zicfiss.is_ss_enable() { + if zicfiss.is_ss_enable(sstatus) { let pop_value = zicfiss.ss_pop(); let expected_value = context.xreg(inst.rs1.unwrap()) as usize; if pop_value != expected_value { @@ -108,7 +103,7 @@ pub fn instruction(inst: Instruction) { } } OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => { - if zicfiss.is_ss_enable() { + if zicfiss.is_ss_enable(sstatus) { let pop_value = zicfiss.ss_pop(); let expected_value = context.xreg(inst.rd.unwrap()) as usize; if pop_value != expected_value { @@ -119,7 +114,7 @@ pub fn instruction(inst: Instruction) { } } OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { - if zicfiss.is_ss_enable() { + if zicfiss.is_ss_enable(sstatus) { context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.0 as u64); } else { context.set_xreg(inst.rd.unwrap(), 0); diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 25a3d72..ba04aa5 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -3,7 +3,6 @@ use crate::emulate_extension::zicfiss::ZICFISS_DATA; -use core::arch::asm; use sbi_rt::SbiRet; /// SBI ecall handler for Base Extension (EID: #0x10) From 0dd159f9c7f607d6200c43ac635a962715b27eed Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 8 Oct 2024 19:16:46 +0900 Subject: [PATCH 31/99] [add] add `EmulateExtension` trait --- src/emulate_extension.rs | 9 + src/emulate_extension/zicfiss.rs | 175 ++++++++++---------- src/trap/hypervisor_supervisor/exception.rs | 14 +- 3 files changed, 105 insertions(+), 93 deletions(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 06254dc..b222460 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -7,8 +7,17 @@ use crate::trap::hypervisor_supervisor::hstrap_exit; use crate::HYPERVISOR_DATA; use core::arch::asm; +use raki::Instruction; use riscv::register::sstatus; +/// Trait for extention emulation. +pub trait EmulateExtension { + /// Emulate instruction + fn instruction(&mut self, inst: Instruction); + /// Emulate CSR + fn csr(&mut self, inst: Instruction); +} + /// CSR data for CSRs emulation. pub struct CsrData(u64); diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 06ca5b7..b525565 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -1,7 +1,7 @@ //! Emulation Zicfiss (Shadow Stack) //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) -use super::{pseudo_vs_exception, CsrData}; +use super::{pseudo_vs_exception, CsrData, EmulateExtension}; use crate::HYPERVISOR_DATA; use core::cell::OnceCell; @@ -59,7 +59,7 @@ impl Zicfiss { } } - pub fn is_ss_enable(&self, sstatus: usize) -> bool { + fn is_ss_enable(&self, sstatus: usize) -> bool { let spp = sstatus >> 8 & 0x1; if spp == 0 { self.senv_sse @@ -69,105 +69,100 @@ impl Zicfiss { } } -/// Emulate Zicfiss instruction. -pub fn instruction(inst: Instruction) { - let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; - let mut context = hypervisor_data.get().unwrap().guest().context; - let sstatus = context.sstatus(); - unsafe { ZICFISS_DATA.lock().get_or_init(|| Zicfiss::new()) }; - let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; - let zicfiss = zicfiss_data.get_mut().unwrap(); - - match inst.opc { - OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => { - if zicfiss.is_ss_enable(sstatus) { - let push_value = context.xreg(inst.rs2.unwrap()); - zicfiss.ss_push(push_value as usize); +impl EmulateExtension for Zicfiss { + /// Emulate Zicfiss instruction. + fn instruction(&mut self, inst: Instruction) { + let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + let mut context = hypervisor_data.get().unwrap().guest().context; + let sstatus = context.sstatus(); + + match inst.opc { + OpcodeKind::Zicfiss(ZicfissOpcode::SSPUSH) => { + if self.is_ss_enable(sstatus) { + let push_value = context.xreg(inst.rs2.unwrap()); + self.ss_push(push_value as usize); + } } - } - OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => { - if zicfiss.is_ss_enable(sstatus) { - let push_value = context.xreg(inst.rd.unwrap()); - zicfiss.ss_push(push_value as usize); + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPUSH) => { + if self.is_ss_enable(sstatus) { + let push_value = context.xreg(inst.rd.unwrap()); + self.ss_push(push_value as usize); + } } - } - OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => { - if zicfiss.is_ss_enable(sstatus) { - let pop_value = zicfiss.ss_pop(); - let expected_value = context.xreg(inst.rs1.unwrap()) as usize; - if pop_value != expected_value { - drop(zicfiss_data); - drop(hypervisor_data); - pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) + OpcodeKind::Zicfiss(ZicfissOpcode::SSPOPCHK) => { + if self.is_ss_enable(sstatus) { + let pop_value = self.ss_pop(); + let expected_value = context.xreg(inst.rs1.unwrap()) as usize; + if pop_value != expected_value { + drop(hypervisor_data); + pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) + } } } - } - OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => { - if zicfiss.is_ss_enable(sstatus) { - let pop_value = zicfiss.ss_pop(); - let expected_value = context.xreg(inst.rd.unwrap()) as usize; - if pop_value != expected_value { - drop(zicfiss_data); - drop(hypervisor_data); - pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) + OpcodeKind::Zicfiss(ZicfissOpcode::C_SSPOPCHK) => { + if self.is_ss_enable(sstatus) { + let pop_value = self.ss_pop(); + let expected_value = context.xreg(inst.rd.unwrap()) as usize; + if pop_value != expected_value { + drop(hypervisor_data); + pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) + } } } - } - OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { - if zicfiss.is_ss_enable(sstatus) { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.0 as u64); - } else { - context.set_xreg(inst.rd.unwrap(), 0); + OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { + if self.is_ss_enable(sstatus) { + context.set_xreg(inst.rd.unwrap(), self.ssp.0 as u64); + } else { + context.set_xreg(inst.rd.unwrap(), 0); + } } + OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D) => todo!(), + _ => todo!(), } - OpcodeKind::Zicfiss(ZicfissOpcode::SSAMOSWAP_W | ZicfissOpcode::SSAMOSWAP_D) => todo!(), - _ => todo!(), } -} -/// Emulate Zicfiss CSRs access. -pub fn csrs(inst: Instruction) { - const CSR_SSP: usize = 0x11; - - let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; - let mut context = hypervisor_data.get().unwrap().guest().context; - let mut zicfiss_data = unsafe { ZICFISS_DATA.lock() }; - let zicfiss = zicfiss_data.get_mut().unwrap(); - - let csr_num = inst.rs2.unwrap(); - match csr_num { - CSR_SSP => match inst.opc { - OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { - let rs1 = context.xreg(inst.rs1.unwrap()); - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.write(rs1); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { - let rs1 = context.xreg(inst.rs1.unwrap()); - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.set(rs1); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { - let rs1 = context.xreg(inst.rs1.unwrap()); - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.clear(rs1); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.write(inst.rs1.unwrap() as u64); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.set(inst.rs1.unwrap() as u64); - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { - context.set_xreg(inst.rd.unwrap(), zicfiss.ssp.bits()); - zicfiss.ssp.clear(inst.rs1.unwrap() as u64); + /// Emulate Zicfiss CSRs access. + fn csr(&mut self, inst: Instruction) { + const CSR_SSP: usize = 0x11; + + let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + let mut context = hypervisor_data.get().unwrap().guest().context; + + let csr_num = inst.rs2.unwrap(); + match csr_num { + CSR_SSP => match inst.opc { + OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), self.ssp.bits()); + self.ssp.write(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), self.ssp.bits()); + self.ssp.set(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { + let rs1 = context.xreg(inst.rs1.unwrap()); + context.set_xreg(inst.rd.unwrap(), self.ssp.bits()); + self.ssp.clear(rs1); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { + context.set_xreg(inst.rd.unwrap(), self.ssp.bits()); + self.ssp.write(inst.rs1.unwrap() as u64); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { + context.set_xreg(inst.rd.unwrap(), self.ssp.bits()); + self.ssp.set(inst.rs1.unwrap() as u64); + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { + context.set_xreg(inst.rd.unwrap(), self.ssp.bits()); + self.ssp.clear(inst.rs1.unwrap() as u64); + } + _ => unreachable!(), + }, + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") } - _ => unreachable!(), - }, - unsupported_csr_num => { - unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") } } } diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index a1d1523..a5b7b0d 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -4,7 +4,6 @@ mod sbi_handler; use super::hstrap_exit; use crate::device::DeviceEmulateError; -use crate::emulate_extension::zicfiss; use crate::guest; use crate::h_extension::{ csrs::{htinst, htval, vstvec}, @@ -72,6 +71,9 @@ fn sbi_vs_mode_handler(context: &mut guest::context::Context) { /// Trap handler for exception #[allow(clippy::cast_possible_truncation, clippy::module_name_repetitions)] pub unsafe fn trap_exception(exception_cause: Exception) -> ! { + use crate::emulate_extension::zicfiss::ZICFISS_DATA; + use crate::emulate_extension::EmulateExtension; + match exception_cause { Exception::IllegalInstruction => { let fault_inst_value = stval::read(); @@ -80,10 +82,16 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { // emulate the instruction match fault_inst.opc { - OpcodeKind::Zicfiss(_) => zicfiss::instruction(fault_inst), + OpcodeKind::Zicfiss(_) => unsafe { ZICFISS_DATA.lock() } + .get_mut() + .unwrap() + .instruction(fault_inst), OpcodeKind::Zicsr(_) => match fault_inst.rs2.unwrap() { // ssp - 0x11 => zicfiss::csrs(fault_inst), + 0x11 => unsafe { ZICFISS_DATA.lock() } + .get_mut() + .unwrap() + .csr(fault_inst), unsupported_csr_num => { unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") } From 66f353fb8ae13992882f1afdb2434f50fd87380c Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 17:45:23 +0900 Subject: [PATCH 32/99] [add] add `hstateen0` module --- src/h_extension/csrs.rs | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index d8b6e40..552ca6b 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -308,6 +308,30 @@ pub mod henvcfg { } } +pub mod hstateen0 { + //! Hypervisor State Enable 0 Register. + #![allow(dead_code)] + + const HSTATEEN0: usize = 0x60c; + pub struct HstateEn0 { + pub bits: usize, + } + + /// Enable all state except `C` bit + pub fn all_state_set() { + unsafe { + core::arch::asm!("csrs hstateen0, {all_set}", all_set = in(reg) u64::MAX); + } + } + + /// Hypervisor State Enable 0 Register. + pub enum StateEnField { + /// It controls access to the senvcfg CSRs. + EnvCfg = 1 << 62, + } + clear_csr_from_enum!(StateEnField, 0x60c); +} + pub mod htval { //! Hypervisor bad guest physical address. #![allow(dead_code)] From 112f64bd9f2d5aea3b2f9a6bf0c933733008aea2 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 17:46:21 +0900 Subject: [PATCH 33/99] [wip][add] disable `ENVCFG` state via `xstateen0` --- src/hypervisor_init.rs | 11 ++++++++++- src/machine_init.rs | 3 +++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index 0b87bb3..5cdcd33 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -3,7 +3,12 @@ use crate::device::MmioDevice; use crate::guest::Guest; use crate::h_extension::csrs::{ - hcounteren, hedeleg, hedeleg::ExceptionKind, henvcfg, hgatp, hgatp::HgatpMode, hideleg, hie, + hcounteren, hedeleg, + hedeleg::ExceptionKind, + henvcfg, hgatp, + hgatp::HgatpMode, + hideleg, hie, + hstateen0::{self, StateEnField}, hstatus, hvip, vsatp, VsInterruptKind, }; use crate::h_extension::instruction::hfence_gvma_all; @@ -54,6 +59,10 @@ pub extern "C" fn hstart(hart_id: usize, dtb_addr: usize) -> ! { henvcfg::set_cbze(); henvcfg::set_cbcfe(); + // disable `ENVCFG` state + hstateen0::all_state_set(); + hstateen0::clear(StateEnField::EnvCfg); + // enable hypervisor counter hcounteren::set(0xffff_ffff); // enable supervisor counter diff --git a/src/machine_init.rs b/src/machine_init.rs index 6b255a2..1e80295 100644 --- a/src/machine_init.rs +++ b/src/machine_init.rs @@ -83,6 +83,9 @@ pub fn mstart(hart_id: usize, dtb_addr: usize) -> ! { core::ptr::addr_of!(crate::_top_m_stack) as usize + STACK_SIZE_PER_HART * hart_id, ); + // Enable all custom state + asm!("csrs mstateen0, {all_set}", all_set = in(reg) u64::MAX); + // pmp settings pmpcfg0::set_pmp(0, Range::OFF, Permission::NONE, false); pmpaddr0::write(0); From 878a765e78fcddc80642fc722798d841c5b08811 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 17:47:17 +0900 Subject: [PATCH 34/99] [add] add `csr_field` to `EmulateExtension` --- src/emulate_extension.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index b222460..57aa687 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -16,6 +16,8 @@ pub trait EmulateExtension { fn instruction(&mut self, inst: Instruction); /// Emulate CSR fn csr(&mut self, inst: Instruction); + /// Emulate CSR field that already exists. + fn csr_field(&mut self, inst: &Instruction, write_to_csr_value: u64, read_csr_value: &mut u64); } /// CSR data for CSRs emulation. From 80dfafca4cba70c5db2352b434fa4baf8114d2d5 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 20:43:42 +0900 Subject: [PATCH 35/99] [add] implement CSR field emulation (only supported envcfg for now) --- src/emulate_extension/zicfiss.rs | 49 +++++++++++++++++++ src/trap/hypervisor_supervisor/exception.rs | 52 ++++++++++++++++++++- 2 files changed, 100 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index b525565..a0eb912 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -165,4 +165,53 @@ impl EmulateExtension for Zicfiss { } } } + + /// Emulate CSR field that already exists. + fn csr_field(&mut self, inst: &Instruction, write_to_csr_value: u64, read_csr_value: &mut u64) { + const CSR_SENVCFG: usize = 0x10a; + + let csr_num = inst.rs2.unwrap(); + match csr_num { + CSR_SENVCFG => { + // overwritten emulated csr field + *read_csr_value |= (self.senv_sse as u64) << 3; + + // update emulated csr field + match inst.opc { + OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = true; + } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = true; + } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = false; + } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = true; + } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = true; + } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = false; + } + } + _ => unreachable!(), + } + } + _ => (), + } + } } diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index a5b7b0d..c654a03 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -194,7 +194,57 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { hs_forward_exception(); } - HvException::VirtualInstruction => unreachable!(), + HvException::VirtualInstruction => { + let fault_inst_value = stval::read(); + let fault_inst = Instruction::try_from(fault_inst_value) + .expect("decoding load fault instruction failed"); + + // emulate CSR set + match fault_inst.opc { + OpcodeKind::Zicsr(_) => { + match fault_inst.rs2.unwrap() { + // senvcfg + 0x10a => { + let mut read_from_csr_value: u64; + unsafe { + asm!("csrr {0}, senvcfg", out(reg) read_from_csr_value); + } + + let mut context = unsafe { + HYPERVISOR_DATA.lock().get().unwrap().guest().context + }; + let write_to_csr_value = context.xreg(fault_inst.rs1.unwrap()); + + // update emulated CSR field. + unsafe { ZICFISS_DATA.lock() }.get_mut().unwrap().csr_field( + &fault_inst, + write_to_csr_value, + &mut read_from_csr_value, + ); + + // commit result + unsafe { + asm!("csrw senvcfg, {0}", in(reg) write_to_csr_value); + } + context.set_xreg(fault_inst.rd.unwrap(), read_from_csr_value); + } + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + } + } + } + _ => unreachable!(), + } + + let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; + if (fault_inst_value & 0b10) >> 1 == 0 { + // compressed instruction + context.set_sepc(context.sepc() + 2); + } else { + // normal size instruction + context.set_sepc(context.sepc() + 4); + } + } }, _ => hs_forward_exception(), } From 0909e7492c962fde4aed348bda9e26a3b3b3d0a3 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 21:30:43 +0900 Subject: [PATCH 36/99] [fix] update mmu-type to sv39 in dts --- guest.dtb | Bin 5108 -> 5108 bytes guest_image/guest.dts | 2 +- 2 files changed, 1 insertion(+), 1 deletion(-) diff --git a/guest.dtb b/guest.dtb index 41fe49fcc360a155d8a2bbe5e0249245dca035f2..fc2c130a588c0049a319a282bbd374a2467f7104 100644 GIT binary patch delta 15 WcmeyO{zZL*3M-Sb; From 36dcd623a1185e5d6fcafe1d6b3cda83f17cf586 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 21:31:28 +0900 Subject: [PATCH 37/99] [add] add `GuestVirtualAddress` --- src/memmap.rs | 4 ++++ src/memmap/page_table.rs | 20 ++++++++++++++++++-- 2 files changed, 22 insertions(+), 2 deletions(-) diff --git a/src/memmap.rs b/src/memmap.rs index 10d05c4..f777767 100644 --- a/src/memmap.rs +++ b/src/memmap.rs @@ -12,6 +12,10 @@ trait AddressRangeUtil { fn len(&self) -> usize; } +/// Guest Virtual Address +#[derive(Default, Debug, Copy, Clone)] +pub struct GuestVirtualAddress(pub usize); + /// Guest Physical Address #[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Ord, Eq)] pub struct GuestPhysicalAddress(pub usize); diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index f0648e1..c120209 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -2,7 +2,7 @@ pub mod sv39x4; -use crate::memmap::{GuestPhysicalAddress, HostPhysicalAddress}; +use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress, HostPhysicalAddress}; pub mod constants { /// Size of memory areathat a page can point to. @@ -129,6 +129,23 @@ impl PageTableAddress { } } +impl GuestVirtualAddress { + /// Return vpn value with index. + fn vpn(self, index: usize) -> usize { + match index { + 2 => (self.0 >> 30) & 0x1ff, + 1 => (self.0 >> 21) & 0x1ff, + 0 => (self.0 >> 12) & 0x1ff, + _ => unreachable!(), + } + } + + /// Return page offset. + fn page_offset(self) -> usize { + self.0 & 0xfff + } +} + impl GuestPhysicalAddress { /// Return vpn value with index. fn vpn(self, index: usize) -> usize { @@ -141,7 +158,6 @@ impl GuestPhysicalAddress { } /// Return page offset. - #[allow(dead_code)] fn page_offset(self) -> usize { self.0 & 0xfff } From 34e9b6f002722344a83a13b2c9a6cb3b69b141c0 Mon Sep 17 00:00:00 2001 From: Alingof Date: Wed, 9 Oct 2024 21:32:43 +0900 Subject: [PATCH 38/99] [add] add `sv39::trans_addr` --- src/memmap/page_table.rs | 1 + src/memmap/page_table/sv39.rs | 69 +++++++++++++++++++++++++++++++++ src/memmap/page_table/sv39x4.rs | 1 - 3 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 src/memmap/page_table/sv39.rs diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index c120209..ca64e41 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -1,5 +1,6 @@ //! Page table for address translation. +pub mod sv39; pub mod sv39x4; use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress, HostPhysicalAddress}; diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs new file mode 100644 index 0000000..2fc2430 --- /dev/null +++ b/src/memmap/page_table/sv39.rs @@ -0,0 +1,69 @@ +use super::{ + constants::{PAGE_SIZE, PAGE_TABLE_LEN}, + PageTableAddress, PageTableLevel, +}; +use crate::h_extension::csrs::vsatp; +use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress}; + +use core::slice::from_raw_parts_mut; + +/// First page table size +pub const FIRST_LV_PAGE_TABLE_LEN: usize = 512; + +/// Translate gva to gpa in sv39 +#[allow(clippy::cast_possible_truncation)] +pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { + let vsatp = vsatp::read(); + let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); + assert!(matches!(vsatp.mode(), vsatp::Mode::Sv39)); + for level in [ + PageTableLevel::Lv1GB, + PageTableLevel::Lv2MB, + PageTableLevel::Lv4KB, + ] { + let page_table = match level { + PageTableLevel::Lv1GB => unsafe { + from_raw_parts_mut(page_table_addr.to_pte_ptr(), FIRST_LV_PAGE_TABLE_LEN) + }, + PageTableLevel::Lv2MB | PageTableLevel::Lv4KB => unsafe { + from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) + }, + }; + let pte = page_table[gpa.vpn(level as usize)]; + if pte.is_leaf() { + match level { + PageTableLevel::Lv1GB => { + assert!( + pte.ppn(0) == 0, + "Address translation failed: pte.ppn[0] != 0" + ); + assert!( + pte.ppn(1) == 0, + "Address translation failed: pte.ppn[1] != 0" + ); + return GuestPhysicalAddress( + pte.ppn(2) << 30 | gpa.vpn(1) << 21 | gpa.vpn(0) << 12 | gpa.page_offset(), + ); + } + PageTableLevel::Lv2MB => { + assert!( + pte.ppn(0) == 0, + "Address translation failed: pte.ppn[0] != 0" + ); + return GuestPhysicalAddress( + pte.ppn(2) << 30 | pte.ppn(1) << 21 | gpa.vpn(0) << 12 | gpa.page_offset(), + ); + } + PageTableLevel::Lv4KB => { + return GuestPhysicalAddress( + pte.ppn(2) << 30 | pte.ppn(1) << 21 | pte.ppn(0) << 12 | gpa.page_offset(), + ) + } + } + } + + page_table_addr = PageTableAddress(pte.entire_ppn() as usize * PAGE_SIZE); + } + + unreachable!(); +} diff --git a/src/memmap/page_table/sv39x4.rs b/src/memmap/page_table/sv39x4.rs index ee099ef..1520df0 100644 --- a/src/memmap/page_table/sv39x4.rs +++ b/src/memmap/page_table/sv39x4.rs @@ -114,7 +114,6 @@ pub fn generate_page_table(root_table_start_addr: HostPhysicalAddress, memmaps: /// Translate gpa to hpa in sv39x4 #[allow(clippy::cast_possible_truncation)] -#[allow(dead_code)] pub fn trans_addr(gpa: GuestPhysicalAddress) -> HostPhysicalAddress { let hgatp = hgatp::read(); let mut page_table_addr = PageTableAddress(hgatp.ppn() << 12); From 7efb5fa9d52937dcef3e4bac8ede7203c67fb998 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 12:06:32 +0900 Subject: [PATCH 39/99] [add] add `Vsatp` CSR to h_extension module --- src/h_extension/csrs.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index 552ca6b..49ae51b 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -154,6 +154,36 @@ pub mod vsatp { bits: usize, } + impl Vsatp { + /// Current address-translation scheme + #[inline] + pub fn mode(&self) -> Mode { + match self.bits >> 60 { + 0 => Mode::Bare, + 8 => Mode::Sv39, + 9 => Mode::Sv48, + 10 => Mode::Sv57, + 11 => Mode::Sv64, + _ => unreachable!(), + } + } + + /// Physical page number + #[inline] + pub fn ppn(&self) -> usize { + self.bits & 0xFFF_FFFF_FFFF // bits 0-43 + } + } + + /// Translation mode. + pub enum Mode { + Bare = 0, + Sv39 = 8, + Sv48 = 9, + Sv57 = 10, + Sv64 = 11, + } + read_csr_as!(Vsatp, 0x280); write_csr_as!(0x280); } From 37a3a7d7e76088e01f95c29bfadcaf08637a717d Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 13:19:00 +0900 Subject: [PATCH 40/99] [add] add `PteFieldSv39`, `PteFieldSv39x4` trait --- src/memmap/page_table.rs | 17 ----------------- src/memmap/page_table/sv39.rs | 29 ++++++++++++++++++++++++++++- src/memmap/page_table/sv39x4.rs | 27 +++++++++++++++++++++++++++ 3 files changed, 55 insertions(+), 18 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index ca64e41..9cf880f 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -85,23 +85,6 @@ impl PageTableEntry { pte_r == 1 || pte_x == 1 } - /// Return ppn - #[allow(clippy::cast_possible_truncation)] - #[allow(dead_code)] - fn ppn(self, index: usize) -> usize { - match index { - 2 => (self.0 as usize >> 28) & 0x3ff_ffff, // 26 bit - 1 => (self.0 as usize >> 19) & 0x1ff, // 9 bit - 0 => (self.0 as usize >> 10) & 0x1ff, // 9 bit - _ => unreachable!(), - } - } - - /// Return entire ppn - fn entire_ppn(self) -> u64 { - (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit - } - /// Is it has already been created fn already_created(self) -> bool { self.0 & PteFlag::Valid as u64 == 1 diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index 2fc2430..5f7b915 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -1,6 +1,6 @@ use super::{ constants::{PAGE_SIZE, PAGE_TABLE_LEN}, - PageTableAddress, PageTableLevel, + PageTableAddress, PageTableEntry, PageTableLevel, }; use crate::h_extension::csrs::vsatp; use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress}; @@ -10,6 +10,33 @@ use core::slice::from_raw_parts_mut; /// First page table size pub const FIRST_LV_PAGE_TABLE_LEN: usize = 512; +/// Pte field for Sv39x4 +trait PteFieldSv39 { + /// Return ppn + fn entire_ppn(self) -> u64; + /// Return entire ppn field + fn ppn(self, index: usize) -> usize; +} + +impl PteFieldSv39 for PageTableEntry { + /// Return ppn + #[allow(clippy::cast_possible_truncation)] + #[allow(dead_code)] + fn ppn(self, index: usize) -> usize { + match index { + 2 => (self.0 as usize >> 28) & 0x3ff_ffff, // 26 bit + 1 => (self.0 as usize >> 19) & 0x1ff, // 9 bit + 0 => (self.0 as usize >> 10) & 0x1ff, // 9 bit + _ => unreachable!(), + } + } + + /// Return entire ppn field + fn entire_ppn(self) -> u64 { + (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit + } +} + /// Translate gva to gpa in sv39 #[allow(clippy::cast_possible_truncation)] pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { diff --git a/src/memmap/page_table/sv39x4.rs b/src/memmap/page_table/sv39x4.rs index 1520df0..2f86318 100644 --- a/src/memmap/page_table/sv39x4.rs +++ b/src/memmap/page_table/sv39x4.rs @@ -21,6 +21,33 @@ pub const FIRST_LV_PAGE_TABLE_LEN: usize = 2048; pub static ROOT_PAGE_TABLE: [PageTableEntry; FIRST_LV_PAGE_TABLE_LEN] = [PageTableEntry(0u64); FIRST_LV_PAGE_TABLE_LEN]; +/// Pte field for Sv39x4 +trait PteFieldSv39x4 { + /// Return ppn + fn entire_ppn(self) -> u64; + /// Return entire ppn field + fn ppn(self, index: usize) -> usize; +} + +impl PteFieldSv39x4 for PageTableEntry { + /// Return ppn + #[allow(clippy::cast_possible_truncation)] + #[allow(dead_code)] + fn ppn(self, index: usize) -> usize { + match index { + 2 => (self.0 as usize >> 28) & 0x3ff_ffff, // 26 bit + 1 => (self.0 as usize >> 19) & 0x1ff, // 9 bit + 0 => (self.0 as usize >> 10) & 0x1ff, // 9 bit + _ => unreachable!(), + } + } + + /// Return entire ppn field + fn entire_ppn(self) -> u64 { + (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit + } +} + /// Zero filling root page table pub fn initialize_page_table(root_table_start_addr: HostPhysicalAddress) { let first_lv_page_table: &mut [PageTableEntry] = unsafe { From a4864a69ffc4c97da75395fd01ffde50da288e4f Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 13:25:16 +0900 Subject: [PATCH 41/99] [add] add `AddressFieldSv39` and `AddressFieldSv39x4` trait --- src/memmap/page_table.rs | 21 +-------------------- src/memmap/page_table/sv39.rs | 18 ++++++++++++++++++ src/memmap/page_table/sv39x4.rs | 18 ++++++++++++++++++ 3 files changed, 37 insertions(+), 20 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index 9cf880f..ef74255 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -114,16 +114,6 @@ impl PageTableAddress { } impl GuestVirtualAddress { - /// Return vpn value with index. - fn vpn(self, index: usize) -> usize { - match index { - 2 => (self.0 >> 30) & 0x1ff, - 1 => (self.0 >> 21) & 0x1ff, - 0 => (self.0 >> 12) & 0x1ff, - _ => unreachable!(), - } - } - /// Return page offset. fn page_offset(self) -> usize { self.0 & 0xfff @@ -131,16 +121,6 @@ impl GuestVirtualAddress { } impl GuestPhysicalAddress { - /// Return vpn value with index. - fn vpn(self, index: usize) -> usize { - match index { - 2 => (self.0 >> 30) & 0x7ff, - 1 => (self.0 >> 21) & 0x1ff, - 0 => (self.0 >> 12) & 0x1ff, - _ => unreachable!(), - } - } - /// Return page offset. fn page_offset(self) -> usize { self.0 & 0xfff @@ -148,6 +128,7 @@ impl GuestPhysicalAddress { } impl HostPhysicalAddress { + /// Return page number fn page_number(self) -> u64 { self.0 as u64 / constants::PAGE_SIZE as u64 } diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index 5f7b915..4cace6d 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -37,6 +37,24 @@ impl PteFieldSv39 for PageTableEntry { } } +/// Virtual address field for Sv39 +trait AddressFieldSv39 { + /// Return virtual page number + fn vpn(self, index: usize) -> usize; +} + +impl AddressFieldSv39 for GuestVirtualAddress { + /// Return vpn value with index. + fn vpn(self, index: usize) -> usize { + match index { + 2 => (self.0 >> 30) & 0x1ff, + 1 => (self.0 >> 21) & 0x1ff, + 0 => (self.0 >> 12) & 0x1ff, + _ => unreachable!(), + } + } +} + /// Translate gva to gpa in sv39 #[allow(clippy::cast_possible_truncation)] pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { diff --git a/src/memmap/page_table/sv39x4.rs b/src/memmap/page_table/sv39x4.rs index 2f86318..d793854 100644 --- a/src/memmap/page_table/sv39x4.rs +++ b/src/memmap/page_table/sv39x4.rs @@ -48,6 +48,24 @@ impl PteFieldSv39x4 for PageTableEntry { } } +/// Virtual address field for Sv39 +trait AddressFieldSv39x4 { + /// Return virtual page number + fn vpn(self, index: usize) -> usize; +} + +impl AddressFieldSv39x4 for GuestPhysicalAddress { + /// Return vpn value with index. + fn vpn(self, index: usize) -> usize { + match index { + 2 => (self.0 >> 30) & 0x7ff, + 1 => (self.0 >> 21) & 0x1ff, + 0 => (self.0 >> 12) & 0x1ff, + _ => unreachable!(), + } + } +} + /// Zero filling root page table pub fn initialize_page_table(root_table_start_addr: HostPhysicalAddress) { let first_lv_page_table: &mut [PageTableEntry] = unsafe { From 747554f78ae3b2a72b06bc3c412c0dc8bcb06872 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 13:49:32 +0900 Subject: [PATCH 42/99] [add] add new level to `PageTableLevel` --- src/memmap/page_table.rs | 12 ++++++------ src/memmap/page_table/sv39.rs | 4 ++++ src/memmap/page_table/sv39x4.rs | 3 +++ 3 files changed, 13 insertions(+), 6 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index ef74255..bb15544 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -20,16 +20,14 @@ pub mod constants { #[derive(Copy, Clone, PartialEq)] #[allow(clippy::module_name_repetitions)] enum PageTableLevel { - /// Page table level 0 - /// + /// 256TB = 48 bit = vpn\[3\] (9 bit) + vpn\[2\] (9 bit) + vpn\[1\] (9 bit) + vpn\[0\] (9 bit) + offset (12 bit) + Lv256TB = 4, + /// 512GB = 39 bit = vpn\[2\] (9 bit) + vpn\[1\] (9 bit) + vpn\[0\] (9 bit) + offset (12 bit) + Lv512GB = 3, /// 1GB = 30 bit = vpn\[1\] (9 bit) + vpn\[0\] (9 bit) + offset (12 bit) Lv1GB = 2, - /// Page table level 1 - /// /// 2MB = 21 bit = vpn\[0\] (9 bit) + offset (12 bit) Lv2MB = 1, - /// Page table level 2 - /// /// 4KB = 12 bit = offset (12 bit) Lv4KB = 0, } @@ -37,6 +35,8 @@ enum PageTableLevel { impl PageTableLevel { fn size(self) -> usize { match self { + Self::Lv256TB => 0x1_0000_0000_0000, + Self::Lv512GB => 0x80_0000_0000, Self::Lv1GB => 0x4000_0000, Self::Lv2MB => 0x0020_0000, Self::Lv4KB => 0x1000, diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index 4cace6d..1a3d197 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -1,3 +1,5 @@ +//! Sv39: Page-Based 39-bit Virtual-Memory System + use super::{ constants::{PAGE_SIZE, PAGE_TABLE_LEN}, PageTableAddress, PageTableEntry, PageTableLevel, @@ -67,6 +69,7 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { PageTableLevel::Lv4KB, ] { let page_table = match level { + PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), PageTableLevel::Lv1GB => unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), FIRST_LV_PAGE_TABLE_LEN) }, @@ -77,6 +80,7 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { let pte = page_table[gpa.vpn(level as usize)]; if pte.is_leaf() { match level { + PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), PageTableLevel::Lv1GB => { assert!( pte.ppn(0) == 0, diff --git a/src/memmap/page_table/sv39x4.rs b/src/memmap/page_table/sv39x4.rs index d793854..d4ae18b 100644 --- a/src/memmap/page_table/sv39x4.rs +++ b/src/memmap/page_table/sv39x4.rs @@ -121,6 +121,7 @@ pub fn generate_page_table(root_table_start_addr: HostPhysicalAddress, memmaps: ] { let vpn = v_start.vpn(current_level as usize); let current_page_table = match current_level { + PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), PageTableLevel::Lv1GB => &mut *first_lv_page_table, PageTableLevel::Lv2MB | PageTableLevel::Lv4KB => unsafe { from_raw_parts_mut(next_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) @@ -169,6 +170,7 @@ pub fn trans_addr(gpa: GuestPhysicalAddress) -> HostPhysicalAddress { PageTableLevel::Lv4KB, ] { let page_table = match level { + PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), PageTableLevel::Lv1GB => unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), FIRST_LV_PAGE_TABLE_LEN) }, @@ -179,6 +181,7 @@ pub fn trans_addr(gpa: GuestPhysicalAddress) -> HostPhysicalAddress { let pte = page_table[gpa.vpn(level as usize)]; if pte.is_leaf() { match level { + PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), PageTableLevel::Lv1GB => { assert!( pte.ppn(0) == 0, From ad4e2d6f8e1094bc770054ec1ceeea4887fff75e Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 13:51:41 +0900 Subject: [PATCH 43/99] [update] remove `FIRST_LV_PAGE_TABLE_LEN` from sv39.rs --- src/memmap/page_table/sv39.rs | 14 ++------------ 1 file changed, 2 insertions(+), 12 deletions(-) diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index 1a3d197..a3e9fe6 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -9,9 +9,6 @@ use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress}; use core::slice::from_raw_parts_mut; -/// First page table size -pub const FIRST_LV_PAGE_TABLE_LEN: usize = 512; - /// Pte field for Sv39x4 trait PteFieldSv39 { /// Return ppn @@ -68,15 +65,8 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { PageTableLevel::Lv2MB, PageTableLevel::Lv4KB, ] { - let page_table = match level { - PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), - PageTableLevel::Lv1GB => unsafe { - from_raw_parts_mut(page_table_addr.to_pte_ptr(), FIRST_LV_PAGE_TABLE_LEN) - }, - PageTableLevel::Lv2MB | PageTableLevel::Lv4KB => unsafe { - from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) - }, - }; + let page_table = + unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) }; let pte = page_table[gpa.vpn(level as usize)]; if pte.is_leaf() { match level { From 59c3a003d569edbbd99bc3285c4b3bb753d0b91c Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 13:56:15 +0900 Subject: [PATCH 44/99] [add] add sv57.rs --- src/memmap/page_table.rs | 1 + src/memmap/page_table/sv57.rs | 175 ++++++++++++++++++++++++++++++++++ 2 files changed, 176 insertions(+) create mode 100644 src/memmap/page_table/sv57.rs diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index bb15544..5dbccad 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -2,6 +2,7 @@ pub mod sv39; pub mod sv39x4; +pub mod sv57; use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress, HostPhysicalAddress}; diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs new file mode 100644 index 0000000..aa61fe4 --- /dev/null +++ b/src/memmap/page_table/sv57.rs @@ -0,0 +1,175 @@ +//! Sv57: Page-Based 57-bit Virtual-Memory System + +use super::{ + constants::{PAGE_SIZE, PAGE_TABLE_LEN}, + PageTableAddress, PageTableEntry, PageTableLevel, +}; +use crate::h_extension::csrs::vsatp; +use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress}; + +use core::slice::from_raw_parts_mut; + +/// Pte field for Sv57x4 +trait PteFieldSv57 { + /// Return ppn + fn entire_ppn(self) -> u64; + /// Return entire ppn field + fn ppn(self, index: usize) -> usize; +} + +impl PteFieldSv57 for PageTableEntry { + /// Return ppn + #[allow(clippy::cast_possible_truncation)] + fn ppn(self, index: usize) -> usize { + match index { + 4 => (self.0 as usize >> 46) & 0x0ff, // 8 bit + 3 => (self.0 as usize >> 37) & 0x1ff, // 9 bit + 2 => (self.0 as usize >> 28) & 0x1ff, // 9 bit + 1 => (self.0 as usize >> 19) & 0x1ff, // 9 bit + 0 => (self.0 as usize >> 10) & 0x1ff, // 9 bit + _ => unreachable!(), + } + } + + /// Return entire ppn field + fn entire_ppn(self) -> u64 { + (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit + } +} + +/// Virtual address field for Sv57 +trait AddressFieldSv57 { + /// Return virtual page number + fn vpn(self, index: usize) -> usize; +} + +impl AddressFieldSv57 for GuestVirtualAddress { + /// Return vpn value with index. + fn vpn(self, index: usize) -> usize { + match index { + 4 => (self.0 >> 48) & 0x1ff, // 9 bit + 3 => (self.0 >> 39) & 0x1ff, // 9 bit + 2 => (self.0 >> 30) & 0x1ff, // 9 bit + 1 => (self.0 >> 21) & 0x1ff, // 9 bit + 0 => (self.0 >> 12) & 0x1ff, // 9 bit + _ => unreachable!(), + } + } +} + +/// Translate gva to gpa in sv57 +#[allow(clippy::cast_possible_truncation)] +pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { + let vsatp = vsatp::read(); + let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); + assert!(matches!(vsatp.mode(), vsatp::Mode::Sv57)); + for level in [ + PageTableLevel::Lv256TB, + PageTableLevel::Lv512GB, + PageTableLevel::Lv1GB, + PageTableLevel::Lv2MB, + PageTableLevel::Lv4KB, + ] { + let page_table = + unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) }; + let pte = page_table[gpa.vpn(level as usize)]; + if pte.is_leaf() { + match level { + PageTableLevel::Lv256TB => { + assert!( + pte.ppn(3) == 0, + "Address translation failed: pte.ppn[3] != 0" + ); + assert!( + pte.ppn(2) == 0, + "Address translation failed: pte.ppn[2] != 0" + ); + assert!( + pte.ppn(1) == 0, + "Address translation failed: pte.ppn[1] != 0" + ); + assert!( + pte.ppn(0) == 0, + "Address translation failed: pte.ppn[0] != 0" + ); + return GuestPhysicalAddress( + pte.ppn(4) << 48 + | gpa.vpn(3) << 39 + | gpa.vpn(2) << 30 + | gpa.vpn(1) << 21 + | gpa.vpn(0) << 12 + | gpa.page_offset(), + ); + } + PageTableLevel::Lv512GB => { + assert!( + pte.ppn(2) == 0, + "Address translation failed: pte.ppn[2] != 0" + ); + assert!( + pte.ppn(1) == 0, + "Address translation failed: pte.ppn[1] != 0" + ); + assert!( + pte.ppn(0) == 0, + "Address translation failed: pte.ppn[0] != 0" + ); + return GuestPhysicalAddress( + pte.ppn(4) << 48 + | pte.ppn(3) << 39 + | gpa.vpn(2) << 30 + | gpa.vpn(1) << 21 + | gpa.vpn(0) << 12 + | gpa.page_offset(), + ); + } + PageTableLevel::Lv1GB => { + assert!( + pte.ppn(1) == 0, + "Address translation failed: pte.ppn[1] != 0" + ); + assert!( + pte.ppn(0) == 0, + "Address translation failed: pte.ppn[0] != 0" + ); + return GuestPhysicalAddress( + pte.ppn(4) << 48 + | pte.ppn(3) << 39 + | pte.ppn(2) << 30 + | gpa.vpn(1) << 21 + | gpa.vpn(0) << 12 + | gpa.page_offset(), + ); + } + PageTableLevel::Lv2MB => { + assert!( + pte.ppn(0) == 0, + "Address translation failed: pte.ppn[0] != 0" + ); + return GuestPhysicalAddress( + pte.ppn(4) << 48 + | pte.ppn(3) << 39 + | pte.ppn(2) << 30 + | pte.ppn(1) << 21 + | gpa.vpn(0) << 12 + | gpa.page_offset(), + ); + } + PageTableLevel::Lv4KB => { + return GuestPhysicalAddress( + pte.ppn(4) << 48 + | pte.ppn(3) << 39 + | pte.ppn(2) << 30 + | pte.ppn(1) << 21 + | pte.ppn(0) << 12 + | gpa.page_offset(), + ) + } + } + } + + page_table_addr = PageTableAddress(pte.entire_ppn() as usize * PAGE_SIZE); + } + + unreachable!(); +} From c0c6988a4f7ac12c4ad52a0a212cdfaf86e9c57e Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 14:08:31 +0900 Subject: [PATCH 45/99] [add] add `vs_stage_trans_addr` and `g_stage_trans_addr` --- src/memmap/page_table.rs | 25 +++++++++++++++++++++++++ src/memmap/page_table/sv57.rs | 34 +++++++++++++++++----------------- 2 files changed, 42 insertions(+), 17 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index 5dbccad..f15bbfa 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -134,3 +134,28 @@ impl HostPhysicalAddress { self.0 as u64 / constants::PAGE_SIZE as u64 } } + +/// VS-stage address translation. +pub fn vs_stage_trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { + use crate::h_extension::csrs::vsatp; + + let vsatp = vsatp::read(); + match vsatp.mode() { + vsatp::Mode::Bare => unreachable!("no trans addr"), + vsatp::Mode::Sv39 => sv39::trans_addr(gva), + vsatp::Mode::Sv57 => sv57::trans_addr(gva), + vsatp::Mode::Sv48 | vsatp::Mode::Sv64 => unimplemented!(), + } +} + +/// G-stage address translation. +pub fn g_stage_trans_addr(gpa: GuestPhysicalAddress) -> HostPhysicalAddress { + use crate::h_extension::csrs::hgatp::{self, HgatpMode}; + + let hgatp = hgatp::read(); + match hgatp.mode() { + HgatpMode::Bare => unreachable!("no trans addr"), + HgatpMode::Sv39x4 => sv39x4::trans_addr(gpa), + HgatpMode::Sv48x4 | HgatpMode::Sv57x4 => unimplemented!(), + } +} diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs index aa61fe4..0c56f16 100644 --- a/src/memmap/page_table/sv57.rs +++ b/src/memmap/page_table/sv57.rs @@ -59,7 +59,7 @@ impl AddressFieldSv57 for GuestVirtualAddress { /// Translate gva to gpa in sv57 #[allow(clippy::cast_possible_truncation)] -pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { +pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { let vsatp = vsatp::read(); let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); assert!(matches!(vsatp.mode(), vsatp::Mode::Sv57)); @@ -72,7 +72,7 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { ] { let page_table = unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) }; - let pte = page_table[gpa.vpn(level as usize)]; + let pte = page_table[gva.vpn(level as usize)]; if pte.is_leaf() { match level { PageTableLevel::Lv256TB => { @@ -94,11 +94,11 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { ); return GuestPhysicalAddress( pte.ppn(4) << 48 - | gpa.vpn(3) << 39 - | gpa.vpn(2) << 30 - | gpa.vpn(1) << 21 - | gpa.vpn(0) << 12 - | gpa.page_offset(), + | gva.vpn(3) << 39 + | gva.vpn(2) << 30 + | gva.vpn(1) << 21 + | gva.vpn(0) << 12 + | gva.page_offset(), ); } PageTableLevel::Lv512GB => { @@ -117,10 +117,10 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { return GuestPhysicalAddress( pte.ppn(4) << 48 | pte.ppn(3) << 39 - | gpa.vpn(2) << 30 - | gpa.vpn(1) << 21 - | gpa.vpn(0) << 12 - | gpa.page_offset(), + | gva.vpn(2) << 30 + | gva.vpn(1) << 21 + | gva.vpn(0) << 12 + | gva.page_offset(), ); } PageTableLevel::Lv1GB => { @@ -136,9 +136,9 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { pte.ppn(4) << 48 | pte.ppn(3) << 39 | pte.ppn(2) << 30 - | gpa.vpn(1) << 21 - | gpa.vpn(0) << 12 - | gpa.page_offset(), + | gva.vpn(1) << 21 + | gva.vpn(0) << 12 + | gva.page_offset(), ); } PageTableLevel::Lv2MB => { @@ -151,8 +151,8 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { | pte.ppn(3) << 39 | pte.ppn(2) << 30 | pte.ppn(1) << 21 - | gpa.vpn(0) << 12 - | gpa.page_offset(), + | gva.vpn(0) << 12 + | gva.page_offset(), ); } PageTableLevel::Lv4KB => { @@ -162,7 +162,7 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { | pte.ppn(2) << 30 | pte.ppn(1) << 21 | pte.ppn(0) << 12 - | gpa.page_offset(), + | gva.page_offset(), ) } } From 7a0f8c2eae4fd3cbe1710eee37005d56091c3167 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 14:11:22 +0900 Subject: [PATCH 46/99] [update] rename `hgatp::HgatpMode` to `hgatp::Mode` --- src/h_extension/csrs.rs | 14 +++++++------- src/hypervisor_init.rs | 6 ++---- src/memmap/page_table.rs | 8 ++++---- src/memmap/page_table/sv39x4.rs | 4 ++-- 4 files changed, 15 insertions(+), 17 deletions(-) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index 49ae51b..937c21e 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -420,12 +420,12 @@ pub mod hgatp { } /// Return translation mode. - pub fn mode(&self) -> HgatpMode { + pub fn mode(&self) -> Mode { match (self.bits >> 60) & 0b1111 { - 0 => HgatpMode::Bare, - 8 => HgatpMode::Sv39x4, - 9 => HgatpMode::Sv48x4, - 10 => HgatpMode::Sv57x4, + 0 => Mode::Bare, + 8 => Mode::Sv39x4, + 9 => Mode::Sv48x4, + 10 => Mode::Sv57x4, _ => unreachable!(), } } @@ -433,14 +433,14 @@ pub mod hgatp { /// Translation mode in G-stage. #[allow(clippy::module_name_repetitions)] - pub enum HgatpMode { + pub enum Mode { Bare = 0, Sv39x4 = 8, Sv48x4 = 9, Sv57x4 = 10, } - pub fn set(mode: HgatpMode, vmid: usize, ppn: usize) { + pub fn set(mode: Mode, vmid: usize, ppn: usize) { write((0xF & (mode as usize)) << 60 | (0x3FFF & vmid) << 44 | 0x0FFF_FFFF_FFFF & ppn); } diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index 5cdcd33..8f2a134 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -5,9 +5,7 @@ use crate::guest::Guest; use crate::h_extension::csrs::{ hcounteren, hedeleg, hedeleg::ExceptionKind, - henvcfg, hgatp, - hgatp::HgatpMode, - hideleg, hie, + henvcfg, hgatp, hideleg, hie, hstateen0::{self, StateEnField}, hstatus, hvip, vsatp, VsInterruptKind, }; @@ -144,7 +142,7 @@ fn vsmode_setup(hart_id: usize, dtb_addr: HostPhysicalAddress) -> ! { .device_mapping_g_stage(root_page_table_addr); // enable two-level address translation - hgatp::set(HgatpMode::Sv39x4, 0, root_page_table_addr.raw() >> 12); + hgatp::set(hgatp::Mode::Sv39x4, 0, root_page_table_addr.raw() >> 12); hfence_gvma_all(); // initialize IOMMU diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index f15bbfa..b475ddc 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -150,12 +150,12 @@ pub fn vs_stage_trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { /// G-stage address translation. pub fn g_stage_trans_addr(gpa: GuestPhysicalAddress) -> HostPhysicalAddress { - use crate::h_extension::csrs::hgatp::{self, HgatpMode}; + use crate::h_extension::csrs::hgatp; let hgatp = hgatp::read(); match hgatp.mode() { - HgatpMode::Bare => unreachable!("no trans addr"), - HgatpMode::Sv39x4 => sv39x4::trans_addr(gpa), - HgatpMode::Sv48x4 | HgatpMode::Sv57x4 => unimplemented!(), + hgatp::Mode::Bare => unreachable!("no trans addr"), + hgatp::Mode::Sv39x4 => sv39x4::trans_addr(gpa), + hgatp::Mode::Sv48x4 | hgatp::Mode::Sv57x4 => unimplemented!(), } } diff --git a/src/memmap/page_table/sv39x4.rs b/src/memmap/page_table/sv39x4.rs index d4ae18b..fd26d5b 100644 --- a/src/memmap/page_table/sv39x4.rs +++ b/src/memmap/page_table/sv39x4.rs @@ -7,7 +7,7 @@ use super::{ constants::{PAGE_SIZE, PAGE_TABLE_LEN}, PageTableAddress, PageTableEntry, PageTableLevel, PteFlag, }; -use crate::h_extension::csrs::{hgatp, hgatp::HgatpMode}; +use crate::h_extension::csrs::hgatp; use crate::memmap::{GuestPhysicalAddress, HostPhysicalAddress, MemoryMap}; use alloc::boxed::Box; @@ -163,7 +163,7 @@ pub fn generate_page_table(root_table_start_addr: HostPhysicalAddress, memmaps: pub fn trans_addr(gpa: GuestPhysicalAddress) -> HostPhysicalAddress { let hgatp = hgatp::read(); let mut page_table_addr = PageTableAddress(hgatp.ppn() << 12); - assert!(matches!(hgatp.mode(), HgatpMode::Sv39x4)); + assert!(matches!(hgatp.mode(), hgatp::Mode::Sv39x4)); for level in [ PageTableLevel::Lv1GB, PageTableLevel::Lv2MB, From 76569a7862d37fb056443302233ab5824ea4adad Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 14:12:19 +0900 Subject: [PATCH 47/99] [update] add `ssp_hp_ptr` to convert ssp value to hypervisor physical pointer --- src/emulate_extension/zicfiss.rs | 24 +++++++++++++++++------- 1 file changed, 17 insertions(+), 7 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index a0eb912..f820b14 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -2,6 +2,10 @@ //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) use super::{pseudo_vs_exception, CsrData, EmulateExtension}; +use crate::memmap::{ + page_table::{g_stage_trans_addr, vs_stage_trans_addr}, + GuestVirtualAddress, +}; use crate::HYPERVISOR_DATA; use core::cell::OnceCell; @@ -36,24 +40,30 @@ impl Zicfiss { } } - /// Return shadow stack pointer as `*mut usize`. - fn ssp_ptr(&self) -> *mut usize { - self.ssp.0 as *mut usize + /// Return host physical shadow stack pointer as `*mut usize`. + fn ssp_hp_ptr(&self) -> *mut usize { + let gpa = vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)); + let hpa = g_stage_trans_addr(gpa); + hpa.0 as *mut usize } /// Push value to shadow stack pub fn ss_push(&mut self, value: usize) { unsafe { - self.ssp = CsrData(self.ssp_ptr().byte_sub(core::mem::size_of::()) as u64); - self.ssp_ptr().write_volatile(value); + self.ssp = CsrData( + (self.ssp.0 as *const usize).byte_sub(core::mem::size_of::()) as u64, + ); + self.ssp_hp_ptr().write_volatile(value); } } /// Pop value from shadow stack pub fn ss_pop(&mut self) -> usize { unsafe { - let pop_value = self.ssp_ptr().read_volatile(); - self.ssp = CsrData(self.ssp_ptr().byte_add(core::mem::size_of::()) as u64); + let pop_value = self.ssp_hp_ptr().read_volatile(); + self.ssp = CsrData( + (self.ssp.0 as *const usize).byte_add(core::mem::size_of::()) as u64, + ); pop_value } From 86f58f03ad61a421eb0a269e93833d39ba60cb4f Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 14:37:06 +0900 Subject: [PATCH 48/99] [add] add `PageTableAddress::to_host_physical_ptr` --- src/memmap/page_table.rs | 5 +++++ src/memmap/page_table/sv39.rs | 2 +- src/memmap/page_table/sv57.rs | 2 +- 3 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index b475ddc..d673794 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -112,6 +112,11 @@ impl PageTableAddress { fn to_pte_ptr(self) -> *mut PageTableEntry { self.0 as *mut PageTableEntry } + + fn to_host_physical_ptr(self) -> *mut PageTableEntry { + let hpa = g_stage_trans_addr(GuestPhysicalAddress(self.0)); + hpa.0 as *mut PageTableEntry + } } impl GuestVirtualAddress { diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index a3e9fe6..25ce5a5 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -66,7 +66,7 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { PageTableLevel::Lv4KB, ] { let page_table = - unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) }; + unsafe { from_raw_parts_mut(page_table_addr.to_host_physical_ptr(), PAGE_TABLE_LEN) }; let pte = page_table[gpa.vpn(level as usize)]; if pte.is_leaf() { match level { diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs index 0c56f16..afc503b 100644 --- a/src/memmap/page_table/sv57.rs +++ b/src/memmap/page_table/sv57.rs @@ -71,7 +71,7 @@ pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { PageTableLevel::Lv4KB, ] { let page_table = - unsafe { from_raw_parts_mut(page_table_addr.to_pte_ptr(), PAGE_TABLE_LEN) }; + unsafe { from_raw_parts_mut(page_table_addr.to_host_physical_ptr(), PAGE_TABLE_LEN) }; let pte = page_table[gva.vpn(level as usize)]; if pte.is_leaf() { match level { From ad03547396e8e8c5135387db3fc634d136e4cfbf Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 14:41:25 +0900 Subject: [PATCH 49/99] [update] remove `entire_ppn` fro each PteField trait --- src/memmap/page_table.rs | 5 +++++ src/memmap/page_table/sv39.rs | 7 ------- src/memmap/page_table/sv39x4.rs | 7 ------- src/memmap/page_table/sv57.rs | 7 ------- 4 files changed, 5 insertions(+), 21 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index d673794..0fceb99 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -90,6 +90,11 @@ impl PageTableEntry { fn already_created(self) -> bool { self.0 & PteFlag::Valid as u64 == 1 } + + /// Return entire ppn field + fn entire_ppn(self) -> u64 { + (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit + } } /// Page table address diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index 25ce5a5..e4abcc1 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -11,8 +11,6 @@ use core::slice::from_raw_parts_mut; /// Pte field for Sv39x4 trait PteFieldSv39 { - /// Return ppn - fn entire_ppn(self) -> u64; /// Return entire ppn field fn ppn(self, index: usize) -> usize; } @@ -29,11 +27,6 @@ impl PteFieldSv39 for PageTableEntry { _ => unreachable!(), } } - - /// Return entire ppn field - fn entire_ppn(self) -> u64 { - (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit - } } /// Virtual address field for Sv39 diff --git a/src/memmap/page_table/sv39x4.rs b/src/memmap/page_table/sv39x4.rs index fd26d5b..1164a08 100644 --- a/src/memmap/page_table/sv39x4.rs +++ b/src/memmap/page_table/sv39x4.rs @@ -23,8 +23,6 @@ pub static ROOT_PAGE_TABLE: [PageTableEntry; FIRST_LV_PAGE_TABLE_LEN] = /// Pte field for Sv39x4 trait PteFieldSv39x4 { - /// Return ppn - fn entire_ppn(self) -> u64; /// Return entire ppn field fn ppn(self, index: usize) -> usize; } @@ -41,11 +39,6 @@ impl PteFieldSv39x4 for PageTableEntry { _ => unreachable!(), } } - - /// Return entire ppn field - fn entire_ppn(self) -> u64 { - (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit - } } /// Virtual address field for Sv39 diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs index afc503b..c433b43 100644 --- a/src/memmap/page_table/sv57.rs +++ b/src/memmap/page_table/sv57.rs @@ -11,8 +11,6 @@ use core::slice::from_raw_parts_mut; /// Pte field for Sv57x4 trait PteFieldSv57 { - /// Return ppn - fn entire_ppn(self) -> u64; /// Return entire ppn field fn ppn(self, index: usize) -> usize; } @@ -30,11 +28,6 @@ impl PteFieldSv57 for PageTableEntry { _ => unreachable!(), } } - - /// Return entire ppn field - fn entire_ppn(self) -> u64 { - (self.0 >> 10) & 0xfff_ffff_ffff // 44 bit - } } /// Virtual address field for Sv57 From bf2ea41709781024a8249a8121110a3c306cbb72 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 21:18:29 +0900 Subject: [PATCH 50/99] [update] change return type of `trans_addr` to `Result` to handle page fault --- src/memmap/page_table.rs | 2 +- src/memmap/page_table/sv39.rs | 22 +++++++++++----------- src/memmap/page_table/sv57.rs | 27 ++++++++++++++------------- 3 files changed, 26 insertions(+), 25 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index 0fceb99..e40c0df 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -146,7 +146,7 @@ impl HostPhysicalAddress { } /// VS-stage address translation. -pub fn vs_stage_trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { +pub fn vs_stage_trans_addr(gva: GuestVirtualAddress) -> Result { use crate::h_extension::csrs::vsatp; let vsatp = vsatp::read(); diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index e4abcc1..1a3b170 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -49,7 +49,7 @@ impl AddressFieldSv39 for GuestVirtualAddress { /// Translate gva to gpa in sv39 #[allow(clippy::cast_possible_truncation)] -pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { +pub fn trans_addr(gva: GuestVirtualAddress) -> Result { let vsatp = vsatp::read(); let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); assert!(matches!(vsatp.mode(), vsatp::Mode::Sv39)); @@ -60,7 +60,7 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { ] { let page_table = unsafe { from_raw_parts_mut(page_table_addr.to_host_physical_ptr(), PAGE_TABLE_LEN) }; - let pte = page_table[gpa.vpn(level as usize)]; + let pte = page_table[gva.vpn(level as usize)]; if pte.is_leaf() { match level { PageTableLevel::Lv256TB | PageTableLevel::Lv512GB => unreachable!(), @@ -73,23 +73,23 @@ pub fn trans_addr(gpa: GuestVirtualAddress) -> GuestPhysicalAddress { pte.ppn(1) == 0, "Address translation failed: pte.ppn[1] != 0" ); - return GuestPhysicalAddress( - pte.ppn(2) << 30 | gpa.vpn(1) << 21 | gpa.vpn(0) << 12 | gpa.page_offset(), - ); + return Ok(GuestPhysicalAddress( + pte.ppn(2) << 30 | gva.vpn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), + )); } PageTableLevel::Lv2MB => { assert!( pte.ppn(0) == 0, "Address translation failed: pte.ppn[0] != 0" ); - return GuestPhysicalAddress( - pte.ppn(2) << 30 | pte.ppn(1) << 21 | gpa.vpn(0) << 12 | gpa.page_offset(), - ); + return Ok(GuestPhysicalAddress( + pte.ppn(2) << 30 | pte.ppn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), + )); } PageTableLevel::Lv4KB => { - return GuestPhysicalAddress( - pte.ppn(2) << 30 | pte.ppn(1) << 21 | pte.ppn(0) << 12 | gpa.page_offset(), - ) + return Ok(GuestPhysicalAddress( + pte.ppn(2) << 30 | pte.ppn(1) << 21 | pte.ppn(0) << 12 | gva.page_offset(), + )); } } } diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs index c433b43..4d3b21f 100644 --- a/src/memmap/page_table/sv57.rs +++ b/src/memmap/page_table/sv57.rs @@ -52,10 +52,11 @@ impl AddressFieldSv57 for GuestVirtualAddress { /// Translate gva to gpa in sv57 #[allow(clippy::cast_possible_truncation)] -pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { +pub fn trans_addr(gva: GuestVirtualAddress) -> Result { let vsatp = vsatp::read(); - let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); assert!(matches!(vsatp.mode(), vsatp::Mode::Sv57)); + let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); + for level in [ PageTableLevel::Lv256TB, PageTableLevel::Lv512GB, @@ -85,14 +86,14 @@ pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { pte.ppn(0) == 0, "Address translation failed: pte.ppn[0] != 0" ); - return GuestPhysicalAddress( + return Ok(GuestPhysicalAddress( pte.ppn(4) << 48 | gva.vpn(3) << 39 | gva.vpn(2) << 30 | gva.vpn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), - ); + )); } PageTableLevel::Lv512GB => { assert!( @@ -107,14 +108,14 @@ pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { pte.ppn(0) == 0, "Address translation failed: pte.ppn[0] != 0" ); - return GuestPhysicalAddress( + return Ok(GuestPhysicalAddress( pte.ppn(4) << 48 | pte.ppn(3) << 39 | gva.vpn(2) << 30 | gva.vpn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), - ); + )); } PageTableLevel::Lv1GB => { assert!( @@ -125,38 +126,38 @@ pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { pte.ppn(0) == 0, "Address translation failed: pte.ppn[0] != 0" ); - return GuestPhysicalAddress( + return Ok(GuestPhysicalAddress( pte.ppn(4) << 48 | pte.ppn(3) << 39 | pte.ppn(2) << 30 | gva.vpn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), - ); + )); } PageTableLevel::Lv2MB => { assert!( pte.ppn(0) == 0, "Address translation failed: pte.ppn[0] != 0" ); - return GuestPhysicalAddress( + return Ok(GuestPhysicalAddress( pte.ppn(4) << 48 | pte.ppn(3) << 39 | pte.ppn(2) << 30 | pte.ppn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), - ); + )); } PageTableLevel::Lv4KB => { - return GuestPhysicalAddress( + return Ok(GuestPhysicalAddress( pte.ppn(4) << 48 | pte.ppn(3) << 39 | pte.ppn(2) << 30 | pte.ppn(1) << 21 | pte.ppn(0) << 12 | gva.page_offset(), - ) + )); } } } @@ -164,5 +165,5 @@ pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { page_table_addr = PageTableAddress(pte.entire_ppn() as usize * PAGE_SIZE); } - unreachable!(); + Err(()) } From 7c877d5c0f6639cad718ecaf19d07ee5e0aa14cc Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 10 Oct 2024 22:11:59 +0900 Subject: [PATCH 51/99] [fix] fix `pseudo_vs_exception` to disable interrupt in VS-mode handler --- src/emulate_extension.rs | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 57aa687..7a65f3e 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -67,10 +67,17 @@ pub fn pseudo_vs_exception(exception_num: usize, trap_value: usize) -> ! { let spp = sstatus::read().spp(); let vsstatus: usize; asm!("csrr {status}, vsstatus", status = out(reg) vsstatus); + let sie = vsstatus >> 1 & 0x1; asm!( "csrw vsstatus, {status}", status = in(reg) (vsstatus & !(1 << 8)) | (spp as usize) << 8 ); + // disable interrupt + asm!( + "csrs vsstatus, {status}", + "csrci vsstatus, 0b10", + status = in(reg) sie << 5, + ); context.set_sstatus(context.sstatus() | 1 << 8); context.set_sepc(vstvec::read().bits()); From 59ae01596cb1d29fb3e81e8a0f6c61ad8d875e45 Mon Sep 17 00:00:00 2001 From: Alingof Date: Sat, 12 Oct 2024 23:58:09 +0900 Subject: [PATCH 52/99] [update] modify `ssp_hp_ptr` to handle VS-stage address translation failure --- src/emulate_extension/zicfiss.rs | 35 +++++++++++++++++++++++++------- 1 file changed, 28 insertions(+), 7 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index f820b14..612d917 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -18,6 +18,8 @@ pub static mut ZICFISS_DATA: Mutex> = Mutex::new(OnceCell::new /// Software-check exception. (cause value) const SOFTWARE_CHECK_EXCEPTION: usize = 18; +/// Store/AMO page fault +const STORE_AMO_PAGE_FAULT: usize = 15; /// Shadow stack fault. (tval value) const SHADOW_STACK_FAULT: usize = 3; @@ -42,9 +44,19 @@ impl Zicfiss { /// Return host physical shadow stack pointer as `*mut usize`. fn ssp_hp_ptr(&self) -> *mut usize { - let gpa = vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)); - let hpa = g_stage_trans_addr(gpa); - hpa.0 as *mut usize + match vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)) { + Ok(gpa) => { + let hpa = g_stage_trans_addr(gpa); + hpa.0 as *mut usize + } + Err(()) => { + unsafe { + HYPERVISOR_DATA.force_unlock(); + ZICFISS_DATA.force_unlock(); + } + pseudo_vs_exception(STORE_AMO_PAGE_FAULT, self.ssp.0 as usize); + } + } } /// Push value to shadow stack @@ -82,8 +94,11 @@ impl Zicfiss { impl EmulateExtension for Zicfiss { /// Emulate Zicfiss instruction. fn instruction(&mut self, inst: Instruction) { - let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; - let mut context = hypervisor_data.get().unwrap().guest().context; + let mut context = unsafe { HYPERVISOR_DATA.lock() } + .get() + .unwrap() + .guest() + .context; let sstatus = context.sstatus(); match inst.opc { @@ -104,7 +119,10 @@ impl EmulateExtension for Zicfiss { let pop_value = self.ss_pop(); let expected_value = context.xreg(inst.rs1.unwrap()) as usize; if pop_value != expected_value { - drop(hypervisor_data); + unsafe { + HYPERVISOR_DATA.force_unlock(); + ZICFISS_DATA.force_unlock(); + } pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) } } @@ -114,7 +132,10 @@ impl EmulateExtension for Zicfiss { let pop_value = self.ss_pop(); let expected_value = context.xreg(inst.rd.unwrap()) as usize; if pop_value != expected_value { - drop(hypervisor_data); + unsafe { + HYPERVISOR_DATA.force_unlock(); + ZICFISS_DATA.force_unlock(); + } pseudo_vs_exception(SOFTWARE_CHECK_EXCEPTION, SHADOW_STACK_FAULT) } } From 47b3630d8737fcb39807792f19b3e010dfa7cecf Mon Sep 17 00:00:00 2001 From: Alingof Date: Sun, 13 Oct 2024 23:03:11 +0900 Subject: [PATCH 53/99] [wip][update] allow write only leaf pte for Zicfiss --- src/memmap/page_table.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index e40c0df..0de2d64 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -78,12 +78,13 @@ impl PageTableEntry { } /// Is leaf page table entry - #[allow(dead_code)] fn is_leaf(self) -> bool { let pte_r = self.0 >> 1 & 0x1; + let pte_w = self.0 >> 2 & 0x1; let pte_x = self.0 >> 3 & 0x1; - pte_r == 1 || pte_x == 1 + // For Zicfilp (TODO: remove it) + pte_r == 1 || pte_x == 1 || (pte_r == 0 && pte_w == 1 && pte_x == 0) } /// Is it has already been created From 2f3f89569704cc15fbaa922c6424eee03a941e3c Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 01:25:15 +0900 Subject: [PATCH 54/99] [update] change argument type of `EmulateExtension` to reference --- src/emulate_extension.rs | 4 ++-- src/emulate_extension/zicfiss.rs | 4 ++-- src/trap/hypervisor_supervisor/exception.rs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 7a65f3e..89237e2 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -13,9 +13,9 @@ use riscv::register::sstatus; /// Trait for extention emulation. pub trait EmulateExtension { /// Emulate instruction - fn instruction(&mut self, inst: Instruction); + fn instruction(&mut self, inst: &Instruction); /// Emulate CSR - fn csr(&mut self, inst: Instruction); + fn csr(&mut self, inst: &Instruction); /// Emulate CSR field that already exists. fn csr_field(&mut self, inst: &Instruction, write_to_csr_value: u64, read_csr_value: &mut u64); } diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 612d917..69da7b3 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -93,7 +93,7 @@ impl Zicfiss { impl EmulateExtension for Zicfiss { /// Emulate Zicfiss instruction. - fn instruction(&mut self, inst: Instruction) { + fn instruction(&mut self, inst: &Instruction) { let mut context = unsafe { HYPERVISOR_DATA.lock() } .get() .unwrap() @@ -153,7 +153,7 @@ impl EmulateExtension for Zicfiss { } /// Emulate Zicfiss CSRs access. - fn csr(&mut self, inst: Instruction) { + fn csr(&mut self, inst: &Instruction) { const CSR_SSP: usize = 0x11; let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index c654a03..9f22060 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -85,13 +85,13 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { OpcodeKind::Zicfiss(_) => unsafe { ZICFISS_DATA.lock() } .get_mut() .unwrap() - .instruction(fault_inst), + .instruction(&fault_inst), OpcodeKind::Zicsr(_) => match fault_inst.rs2.unwrap() { // ssp 0x11 => unsafe { ZICFISS_DATA.lock() } .get_mut() .unwrap() - .csr(fault_inst), + .csr(&fault_inst), unsupported_csr_num => { unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") } From f04665a83a1f681d54141dc3d842f00877e89bc6 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 01:37:59 +0900 Subject: [PATCH 55/99] [wip][add] add `Context::update_sepc_by_inst` --- src/guest/context.rs | 13 ++++++ src/trap/hypervisor_supervisor/exception.rs | 46 +++++---------------- 2 files changed, 23 insertions(+), 36 deletions(-) diff --git a/src/guest/context.rs b/src/guest/context.rs index 2e01ab7..1dc3853 100644 --- a/src/guest/context.rs +++ b/src/guest/context.rs @@ -2,6 +2,8 @@ use crate::memmap::HostPhysicalAddress; +use raki::Instruction; + /// Guest context on memory /// /// It place to hypervisor stack top. @@ -60,6 +62,17 @@ impl Context { self.get_context().sepc = value; } + /// Update sepc address according to instruction. + pub fn update_sepc_by_inst(&mut self, inst: &Instruction) { + if inst.is_compressed { + // compressed instruction + self.set_sepc(self.sepc() + 2); + } else { + // normal size instruction + self.set_sepc(self.sepc() + 4); + } + } + /// Return sstatus value. pub fn sstatus(self) -> usize { self.get_context().sstatus diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 9f22060..2b16939 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -104,13 +104,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { } let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; - if (fault_inst_value & 0b10) >> 1 == 0 { - // compressed instruction - context.set_sepc(context.sepc() + 2); - } else { - // normal size instruction - context.set_sepc(context.sepc() + 4); - } + context.update_sepc_by_inst(&fault_inst); } Exception::SupervisorEnvCall => panic!("SupervisorEnvCall should be handled by M-mode"), // Enum not found in `riscv` crate. @@ -143,13 +137,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { Ok(value) => { let mut context = hypervisor_data.get().unwrap().guest().context; context.set_xreg(fault_inst.rd.expect("rd is not found"), u64::from(value)); - if (fault_inst_value & 0b10) >> 1 == 0 { - // compressed instruction - context.set_sepc(context.sepc() + 2); - } else { - // normal size instruction - context.set_sepc(context.sepc() + 4); - } + context.update_sepc_by_inst(&fault_inst); } Err( DeviceEmulateError::InvalidAddress @@ -168,16 +156,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { .expect("decoding load fault instruction failed"); let mut hypervisor_data = HYPERVISOR_DATA.lock(); - let context = hypervisor_data.get().unwrap().guest().context; - let update_epc = |fault_inst_value: usize, mut context: guest::context::Context| { - if (fault_inst_value & 0b10) >> 1 == 0 { - // compressed instruction - context.set_sepc(context.sepc() + 2); - } else { - // normal size instruction - context.set_sepc(context.sepc() + 4); - } - }; + let mut context = hypervisor_data.get().unwrap().guest().context; let store_value = context.xreg(fault_inst.rs2.expect("rs2 is not found")); if let Ok(()) = hypervisor_data @@ -187,7 +166,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { .plic .emulate_write(fault_addr, store_value.try_into().unwrap()) { - update_epc(fault_inst_value, context); + context.update_sepc_by_inst(&fault_inst); drop(hypervisor_data); hstrap_exit(); // exit handler } @@ -198,6 +177,11 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { let fault_inst_value = stval::read(); let fault_inst = Instruction::try_from(fault_inst_value) .expect("decoding load fault instruction failed"); + let mut context = unsafe { HYPERVISOR_DATA.lock() } + .get() + .unwrap() + .guest() + .context; // emulate CSR set match fault_inst.opc { @@ -210,9 +194,6 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { asm!("csrr {0}, senvcfg", out(reg) read_from_csr_value); } - let mut context = unsafe { - HYPERVISOR_DATA.lock().get().unwrap().guest().context - }; let write_to_csr_value = context.xreg(fault_inst.rs1.unwrap()); // update emulated CSR field. @@ -236,14 +217,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { _ => unreachable!(), } - let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; - if (fault_inst_value & 0b10) >> 1 == 0 { - // compressed instruction - context.set_sepc(context.sepc() + 2); - } else { - // normal size instruction - context.set_sepc(context.sepc() + 4); - } + context.update_sepc_by_inst(&fault_inst); } }, _ => hs_forward_exception(), From 4ec54c2eb5828f28e77bd65c4799440128177dbe Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 14:35:35 +0900 Subject: [PATCH 56/99] [add] add `update_sepc_by_htinst_value` --- src/trap/hypervisor_supervisor/exception.rs | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 2b16939..f352bf8 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -68,6 +68,17 @@ fn sbi_vs_mode_handler(context: &mut guest::context::Context) { context.set_xreg(11, sbiret.value as u64); } +/// Update sepc by htinst value. +fn update_sepc_by_htinst_value(htinst_inst_value: usize, context: &mut guest::context::Context) { + if (htinst_inst_value & 0b10) >> 1 == 0 { + // compressed instruction + context.set_sepc(context.sepc() + 2); + } else { + // normal size instruction + context.set_sepc(context.sepc() + 4); + } +} + /// Trap handler for exception #[allow(clippy::cast_possible_truncation, clippy::module_name_repetitions)] pub unsafe fn trap_exception(exception_cause: Exception) -> ! { @@ -137,7 +148,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { Ok(value) => { let mut context = hypervisor_data.get().unwrap().guest().context; context.set_xreg(fault_inst.rd.expect("rd is not found"), u64::from(value)); - context.update_sepc_by_inst(&fault_inst); + update_sepc_by_htinst_value(fault_inst_value, &mut context); } Err( DeviceEmulateError::InvalidAddress @@ -166,7 +177,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { .plic .emulate_write(fault_addr, store_value.try_into().unwrap()) { - context.update_sepc_by_inst(&fault_inst); + update_sepc_by_htinst_value(fault_inst_value, &mut context); drop(hypervisor_data); hstrap_exit(); // exit handler } From 9256392639fc133a28f4275e34c6971130825b4a Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 14:45:13 +0900 Subject: [PATCH 57/99] [add] add `exception/instruction_handler.rs` --- src/trap/hypervisor_supervisor/exception.rs | 86 +---------------- .../exception/instruction_handler.rs | 92 +++++++++++++++++++ 2 files changed, 97 insertions(+), 81 deletions(-) create mode 100644 src/trap/hypervisor_supervisor/exception/instruction_handler.rs diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index f352bf8..c53b5bb 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -1,5 +1,6 @@ //! Trap VS-mode exception. +mod instruction_handler; mod sbi_handler; use super::hstrap_exit; @@ -13,10 +14,10 @@ use crate::memmap::HostPhysicalAddress; use crate::HYPERVISOR_DATA; use core::arch::asm; -use raki::{Instruction, OpcodeKind}; +use raki::Instruction; use riscv::register::{ scause::{self, Exception}, - sepc, stval, + stval, }; use sbi_handler::{sbi_base_handler, sbi_fwft_handler, sbi_rfnc_handler}; @@ -82,41 +83,9 @@ fn update_sepc_by_htinst_value(htinst_inst_value: usize, context: &mut guest::co /// Trap handler for exception #[allow(clippy::cast_possible_truncation, clippy::module_name_repetitions)] pub unsafe fn trap_exception(exception_cause: Exception) -> ! { - use crate::emulate_extension::zicfiss::ZICFISS_DATA; - use crate::emulate_extension::EmulateExtension; - match exception_cause { - Exception::IllegalInstruction => { - let fault_inst_value = stval::read(); - let fault_inst = Instruction::try_from(fault_inst_value) - .expect("decoding load fault instruction failed"); - - // emulate the instruction - match fault_inst.opc { - OpcodeKind::Zicfiss(_) => unsafe { ZICFISS_DATA.lock() } - .get_mut() - .unwrap() - .instruction(&fault_inst), - OpcodeKind::Zicsr(_) => match fault_inst.rs2.unwrap() { - // ssp - 0x11 => unsafe { ZICFISS_DATA.lock() } - .get_mut() - .unwrap() - .csr(&fault_inst), - unsupported_csr_num => { - unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") - } - }, - _ => unimplemented!( - "unsupported illegal instruction: {:#?}, at {:#x}", - fault_inst, - sepc::read() - ), - } + Exception::IllegalInstruction => instruction_handler::illegal_instruction(), - let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; - context.update_sepc_by_inst(&fault_inst); - } Exception::SupervisorEnvCall => panic!("SupervisorEnvCall should be handled by M-mode"), // Enum not found in `riscv` crate. Exception::Unknown => match HvException::from(scause::read().code()) { @@ -184,52 +153,7 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { hs_forward_exception(); } - HvException::VirtualInstruction => { - let fault_inst_value = stval::read(); - let fault_inst = Instruction::try_from(fault_inst_value) - .expect("decoding load fault instruction failed"); - let mut context = unsafe { HYPERVISOR_DATA.lock() } - .get() - .unwrap() - .guest() - .context; - - // emulate CSR set - match fault_inst.opc { - OpcodeKind::Zicsr(_) => { - match fault_inst.rs2.unwrap() { - // senvcfg - 0x10a => { - let mut read_from_csr_value: u64; - unsafe { - asm!("csrr {0}, senvcfg", out(reg) read_from_csr_value); - } - - let write_to_csr_value = context.xreg(fault_inst.rs1.unwrap()); - - // update emulated CSR field. - unsafe { ZICFISS_DATA.lock() }.get_mut().unwrap().csr_field( - &fault_inst, - write_to_csr_value, - &mut read_from_csr_value, - ); - - // commit result - unsafe { - asm!("csrw senvcfg, {0}", in(reg) write_to_csr_value); - } - context.set_xreg(fault_inst.rd.unwrap(), read_from_csr_value); - } - unsupported_csr_num => { - unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") - } - } - } - _ => unreachable!(), - } - - context.update_sepc_by_inst(&fault_inst); - } + HvException::VirtualInstruction => instruction_handler::virtual_instruction(), }, _ => hs_forward_exception(), } diff --git a/src/trap/hypervisor_supervisor/exception/instruction_handler.rs b/src/trap/hypervisor_supervisor/exception/instruction_handler.rs new file mode 100644 index 0000000..a9d5ada --- /dev/null +++ b/src/trap/hypervisor_supervisor/exception/instruction_handler.rs @@ -0,0 +1,92 @@ +//! Handle instruction exceptions. + +use crate::emulate_extension::zicfiss::ZICFISS_DATA; +use crate::emulate_extension::EmulateExtension; +use crate::HYPERVISOR_DATA; + +use core::arch::asm; +use raki::{Instruction, OpcodeKind}; +use riscv::register::{sepc, stval}; + +/// Trap `Illegal instruction` exception. +#[inline] +pub fn illegal_instruction() { + let fault_inst_value = stval::read(); + let fault_inst = + Instruction::try_from(fault_inst_value).expect("decoding load fault instruction failed"); + + // emulate the instruction + match fault_inst.opc { + OpcodeKind::Zicfiss(_) => unsafe { ZICFISS_DATA.lock() } + .get_mut() + .unwrap() + .instruction(&fault_inst), + OpcodeKind::Zicsr(_) => match fault_inst.rs2.unwrap() { + // ssp + 0x11 => unsafe { ZICFISS_DATA.lock() } + .get_mut() + .unwrap() + .csr(&fault_inst), + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + } + }, + _ => unimplemented!( + "unsupported illegal instruction: {:#?}, at {:#x}", + fault_inst, + sepc::read() + ), + } + + let mut context = unsafe { HYPERVISOR_DATA.lock().get().unwrap().guest().context }; + context.update_sepc_by_inst(&fault_inst); +} + +/// Trap `Virtual instruction` exception. +#[inline] +pub fn virtual_instruction() { + let fault_inst_value = stval::read(); + let fault_inst = + Instruction::try_from(fault_inst_value).expect("decoding load fault instruction failed"); + let mut context = unsafe { HYPERVISOR_DATA.lock() } + .get() + .unwrap() + .guest() + .context; + + // emulate CSR set + match fault_inst.opc { + OpcodeKind::Zicsr(_) => { + match fault_inst.rs2.unwrap() { + // senvcfg + 0x10a => { + let mut read_from_csr_value: u64; + unsafe { + asm!("csrr {0}, senvcfg", out(reg) read_from_csr_value); + } + + let write_to_csr_value = context.xreg(fault_inst.rs1.unwrap()); + + // update emulated CSR field. + unsafe { ZICFISS_DATA.lock() }.get_mut().unwrap().csr_field( + &fault_inst, + write_to_csr_value, + &mut read_from_csr_value, + ); + + // commit result + unsafe { + asm!("csrw senvcfg, {0}", in(reg) write_to_csr_value); + } + context.set_xreg(fault_inst.rd.unwrap(), read_from_csr_value); + } + unsupported_csr_num => { + unimplemented!("unsupported CSRs: {unsupported_csr_num:#x}") + } + } + } + _ => unreachable!(), + } + + context.update_sepc_by_inst(&fault_inst); +} From ca4bcdca919001b6743566600733ae27f9aee49f Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 14:55:04 +0900 Subject: [PATCH 58/99] [add] add exception/page_fault_handler.rs --- src/trap/hypervisor_supervisor/exception.rs | 68 +---------------- .../exception/instruction_handler.rs | 3 + .../exception/page_fault_handler.rs | 74 +++++++++++++++++++ 3 files changed, 81 insertions(+), 64 deletions(-) create mode 100644 src/trap/hypervisor_supervisor/exception/page_fault_handler.rs diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index c53b5bb..66c835d 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -1,20 +1,15 @@ //! Trap VS-mode exception. mod instruction_handler; +mod page_fault_handler; mod sbi_handler; use super::hstrap_exit; -use crate::device::DeviceEmulateError; use crate::guest; -use crate::h_extension::{ - csrs::{htinst, htval, vstvec}, - HvException, -}; -use crate::memmap::HostPhysicalAddress; +use crate::h_extension::{csrs::vstvec, HvException}; use crate::HYPERVISOR_DATA; use core::arch::asm; -use raki::Instruction; use riscv::register::{ scause::{self, Exception}, stval, @@ -85,7 +80,6 @@ fn update_sepc_by_htinst_value(htinst_inst_value: usize, context: &mut guest::co pub unsafe fn trap_exception(exception_cause: Exception) -> ! { match exception_cause { Exception::IllegalInstruction => instruction_handler::illegal_instruction(), - Exception::SupervisorEnvCall => panic!("SupervisorEnvCall should be handled by M-mode"), // Enum not found in `riscv` crate. Exception::Unknown => match HvException::from(scause::read().code()) { @@ -97,62 +91,8 @@ pub unsafe fn trap_exception(exception_cause: Exception) -> ! { HvException::InstructionGuestPageFault => { panic!("Instruction guest-page fault"); } - HvException::LoadGuestPageFault => { - let fault_addr = HostPhysicalAddress(htval::read().bits << 2); - let fault_inst_value = htinst::read().bits; - // htinst bit 1 replaced with a 0. - // thus it needed to flip bit 1. - // ref: vol. II p.161 - let fault_inst = Instruction::try_from(fault_inst_value | 0b10) - .expect("decoding load fault instruction failed"); - - let mut hypervisor_data = HYPERVISOR_DATA.lock(); - match hypervisor_data - .get_mut() - .unwrap() - .devices() - .plic - .emulate_read(fault_addr) - { - Ok(value) => { - let mut context = hypervisor_data.get().unwrap().guest().context; - context.set_xreg(fault_inst.rd.expect("rd is not found"), u64::from(value)); - update_sepc_by_htinst_value(fault_inst_value, &mut context); - } - Err( - DeviceEmulateError::InvalidAddress - | DeviceEmulateError::InvalidContextId - | DeviceEmulateError::ReservedRegister, - ) => hs_forward_exception(), - } - } - HvException::StoreAmoGuestPageFault => { - let fault_addr = HostPhysicalAddress(htval::read().bits << 2); - let fault_inst_value = htinst::read().bits; - // htinst bit 1 replaced with a 0. - // thus it needed to flip bit 1. - // ref: vol. II p.161 - let fault_inst = Instruction::try_from(fault_inst_value | 0b10) - .expect("decoding load fault instruction failed"); - - let mut hypervisor_data = HYPERVISOR_DATA.lock(); - let mut context = hypervisor_data.get().unwrap().guest().context; - let store_value = context.xreg(fault_inst.rs2.expect("rs2 is not found")); - - if let Ok(()) = hypervisor_data - .get_mut() - .unwrap() - .devices() - .plic - .emulate_write(fault_addr, store_value.try_into().unwrap()) - { - update_sepc_by_htinst_value(fault_inst_value, &mut context); - drop(hypervisor_data); - hstrap_exit(); // exit handler - } - - hs_forward_exception(); - } + HvException::LoadGuestPageFault => page_fault_handler::load_guest_page_fault(), + HvException::StoreAmoGuestPageFault => page_fault_handler::store_guest_page_fault(), HvException::VirtualInstruction => instruction_handler::virtual_instruction(), }, _ => hs_forward_exception(), diff --git a/src/trap/hypervisor_supervisor/exception/instruction_handler.rs b/src/trap/hypervisor_supervisor/exception/instruction_handler.rs index a9d5ada..37716ad 100644 --- a/src/trap/hypervisor_supervisor/exception/instruction_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/instruction_handler.rs @@ -1,4 +1,7 @@ //! Handle instruction exceptions. +//! +//! - Illegal Instruction +//! - Virtual Instruction use crate::emulate_extension::zicfiss::ZICFISS_DATA; use crate::emulate_extension::EmulateExtension; diff --git a/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs b/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs new file mode 100644 index 0000000..e889d36 --- /dev/null +++ b/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs @@ -0,0 +1,74 @@ +//! Handle page fault exceptions. +//! +//! - Load guest page fault +//! - Store AMO guest page fault + +use super::{hs_forward_exception, hstrap_exit, update_sepc_by_htinst_value}; +use crate::device::DeviceEmulateError; +use crate::h_extension::csrs::{htinst, htval}; +use crate::memmap::HostPhysicalAddress; +use crate::HYPERVISOR_DATA; + +use raki::Instruction; + +/// Trap `Load guest page fault` exception. +pub fn load_guest_page_fault() { + let fault_addr = HostPhysicalAddress(htval::read().bits << 2); + let fault_inst_value = htinst::read().bits; + // htinst bit 1 replaced with a 0. + // thus it needed to flip bit 1. + // ref: vol. II p.161 + let fault_inst = Instruction::try_from(fault_inst_value | 0b10) + .expect("decoding load fault instruction failed"); + + let mut hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + match hypervisor_data + .get_mut() + .unwrap() + .devices() + .plic + .emulate_read(fault_addr) + { + Ok(value) => { + let mut context = hypervisor_data.get().unwrap().guest().context; + context.set_xreg(fault_inst.rd.expect("rd is not found"), u64::from(value)); + update_sepc_by_htinst_value(fault_inst_value, &mut context); + } + Err( + DeviceEmulateError::InvalidAddress + | DeviceEmulateError::InvalidContextId + | DeviceEmulateError::ReservedRegister, + ) => hs_forward_exception(), + } +} + +/// Trap `Store guest page fault` exception. +pub fn store_guest_page_fault() { + let fault_addr = HostPhysicalAddress(htval::read().bits << 2); + let fault_inst_value = htinst::read().bits; + // htinst bit 1 replaced with a 0. + // thus it needed to flip bit 1. + // ref: vol. II p.161 + let fault_inst = Instruction::try_from(fault_inst_value | 0b10) + .expect("decoding load fault instruction failed"); + + let mut hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; + let mut context = hypervisor_data.get().unwrap().guest().context; + let store_value = context.xreg(fault_inst.rs2.expect("rs2 is not found")); + + if let Ok(()) = hypervisor_data + .get_mut() + .unwrap() + .devices() + .plic + .emulate_write(fault_addr, store_value.try_into().unwrap()) + { + update_sepc_by_htinst_value(fault_inst_value, &mut context); + drop(hypervisor_data); + unsafe { + hstrap_exit(); // exit handler + } + } + + hs_forward_exception(); +} From 5706bbb8f343cde3866c0898af7c60527380db94 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 15:24:29 +0900 Subject: [PATCH 59/99] [update] update version of `raki` crate --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index 62887b8..be76b32 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -10,7 +10,7 @@ pedantic = "warn" elf = { version = "0.7.2", default-features = false } fdt = "0.1.5" linked_list_allocator = "0.10.5" -raki = { version = "1.1.0" } +raki = "1.2.0" riscv = "0.11.1" riscv-rt = "0.11.0" rustsbi = { version = "0.4.0-alpha.1", features = ["machine"] } From 881a6b0481d395baadff6786a6841a3c93677815 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 15:43:23 +0900 Subject: [PATCH 60/99] [add] add build instruction for Zicfiss guest image --- guest_image/README.md | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/guest_image/README.md b/guest_image/README.md index 5e1a6fd..c6de4a8 100644 --- a/guest_image/README.md +++ b/guest_image/README.md @@ -1,7 +1,7 @@ # Build guest image ## device tree -``` +```sh $ ./build_dtb.sh create $ vim guest.dts # edit dts $ ./build_dtb.sh build @@ -9,7 +9,7 @@ $ ./build_dtb.sh build ``` ## Linux (with debug info) -``` +```sh $ git clone https://github.com/torvalds/linux -b v6.9 $ cd /path/to/this/repository @@ -22,3 +22,23 @@ $ DEBUG_KERNEL [=y], DEBUG_INFO [=y], EFI [=n], RELOCATABLE [=n] $ make ARCH=riscv CROSS_COMPILE=riscv64-unknown-linux-gnu- -j$(nproc) $ mv vmlinux /path/to/linux/vmlinx_debug ``` + +## Linux (For Zicfiss) +See [https://lwn.net/Articles/992578/](https://lwn.net/Articles/992578/). +```sh +# Toolchain +$ git clone git@github.com:sifive/riscv-gnu-toolchain.git -b cfi-dev +$ riscv-gnu-toolchain/configure --prefix= --with-arch=rv64gc_zicfilp_zicfiss --enable-linux --disable-gdb --with-extra-multilib-test="rv64gc_zicfilp_zicfiss-lp64d:-static" +$ make -j$(nproc) + +# Opensbi +$ git clone git@github.com:deepak0414/opensbi.git -b v6_cfi_spec_split_opensbi +$ make CROSS_COMPILE= -j$(nproc) PLATFORM=generic + +# Linux +$ git clone https://github.com/torvalds/linux -b v6.12-rc1 +$ wget https://patchwork.kernel.org/series/896898/mbox/ --output-document riscv-control-flow-integrity-for-usermode.patch +$ git am riscv-control-flow-integrity-for-usermode.patch +$ make ARCH=riscv CROSS_COMPILE=/build/bin/riscv64-unknown-linux-gnu- -j$(nproc) defconfig +$ make ARCH=riscv CROSS_COMPILE=/build/bin/riscv64-unknown-linux-gnu- -j$(nproc) +``` From 1791f89e2a30da359d7274ee45f2ac68355b0059 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 15:47:50 +0900 Subject: [PATCH 61/99] [update] update cargo runner command --- .cargo/config.toml | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/.cargo/config.toml b/.cargo/config.toml index 1c6d81d..e1b6672 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -1,17 +1,19 @@ [target.riscv64imac-unknown-none-elf] runner = """ qemu-system-riscv64 +-cpu rv64,smstateen=true -machine virt -bios none -nographic -m 2G --initrd vmlinux --drive file=rootfs.img,format=raw,id=hd0,if=none +-initrd vmlinux_debug +-drive file=rootfs.ext2,format=raw,id=hd0,if=none -device virtio-blk-pci,drive=hd0,iommu_platform=true,disable-legacy=on -append root=/dev/vda,rw,console=ttyS0 -device riscv-iommu-pci -kernel """ + # for debug # runner = "../../qemu/build/qemu-system-riscv64 -S -gdb tcp::10000 -d int,in_asm,cpu_reset,mmu,page,guest_errors -machine virt -bios none -nographic -m 2G -initrd vmlinux_debug -drive file=rootfs.img,format=raw,id=hd0,if=none -device virtio-blk-pci,drive=hd0,iommu_platform=true,disable-legacy=on -append root=/dev/vda,rw,console=ttyS0 -device riscv-iommu-pci -kernel" # memo: maintenance packet Qqemu.PhyMemMode:1 @@ -24,4 +26,3 @@ rustflags = [ [build] target = "riscv64imac-unknown-none-elf" - From ac8d24f6dbd2007986796994ed8abada346bd3ad Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 15:48:36 +0900 Subject: [PATCH 62/99] [refactor] apply `cargo clippy --fix` --- src/emulate_extension/zicfiss.rs | 4 ++-- src/hypervisor_init.rs | 2 +- src/trap/hypervisor_supervisor/exception.rs | 2 +- src/trap/hypervisor_supervisor/exception/sbi_handler.rs | 2 +- 4 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 69da7b3..c07687c 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -142,7 +142,7 @@ impl EmulateExtension for Zicfiss { } OpcodeKind::Zicfiss(ZicfissOpcode::SSRDP) => { if self.is_ss_enable(sstatus) { - context.set_xreg(inst.rd.unwrap(), self.ssp.0 as u64); + context.set_xreg(inst.rd.unwrap(), self.ssp.0); } else { context.set_xreg(inst.rd.unwrap(), 0); } @@ -205,7 +205,7 @@ impl EmulateExtension for Zicfiss { match csr_num { CSR_SENVCFG => { // overwritten emulated csr field - *read_csr_value |= (self.senv_sse as u64) << 3; + *read_csr_value |= u64::from(self.senv_sse) << 3; // update emulated csr field match inst.opc { diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index 8f2a134..ac54ab7 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -65,7 +65,7 @@ pub extern "C" fn hstart(hart_id: usize, dtb_addr: usize) -> ! { hcounteren::set(0xffff_ffff); // enable supervisor counter unsafe { - asm!("csrw scounteren, {bits}", bits = in(reg) 0xffff_ffff as u32); + asm!("csrw scounteren, {bits}", bits = in(reg) 0xffff_ffff_u32); } // specify delegation exception kinds. diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index 66c835d..c25527b 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -39,7 +39,7 @@ pub extern "C" fn hs_forward_exception() { /// Handler for Ecall from VS-mode exception #[allow(clippy::cast_possible_truncation)] fn sbi_vs_mode_handler(context: &mut guest::context::Context) { - const EID_FWFT: usize = 0x46574654; + const EID_FWFT: usize = 0x4657_4654; let ext_id: usize = context.xreg(17) as usize; let func_id: usize = context.xreg(16) as usize; let arguments: &[u64; 5] = &[ diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index ba04aa5..71352b7 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -99,7 +99,7 @@ pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { // TODO remove it. use crate::emulate_extension::zicfiss::Zicfiss; - unsafe { ZICFISS_DATA.lock().get_or_init(|| Zicfiss::new()) }; + unsafe { ZICFISS_DATA.lock().get_or_init(Zicfiss::new) }; match func_id { FWFT_SET => match FwftFeature::try_from(feature).unwrap() { From a55968e590ecc517093ecee7293f8a426e0cdf67 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:02:13 +0900 Subject: [PATCH 63/99] [refactor][update] remove result type from `sv39::trans_addr` --- src/memmap/page_table.rs | 2 +- src/memmap/page_table/sv39.rs | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index 0de2d64..f7918b9 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -153,7 +153,7 @@ pub fn vs_stage_trans_addr(gva: GuestVirtualAddress) -> Result unreachable!("no trans addr"), - vsatp::Mode::Sv39 => sv39::trans_addr(gva), + vsatp::Mode::Sv39 => Ok(sv39::trans_addr(gva)), vsatp::Mode::Sv57 => sv57::trans_addr(gva), vsatp::Mode::Sv48 | vsatp::Mode::Sv64 => unimplemented!(), } diff --git a/src/memmap/page_table/sv39.rs b/src/memmap/page_table/sv39.rs index 1a3b170..804281b 100644 --- a/src/memmap/page_table/sv39.rs +++ b/src/memmap/page_table/sv39.rs @@ -49,7 +49,7 @@ impl AddressFieldSv39 for GuestVirtualAddress { /// Translate gva to gpa in sv39 #[allow(clippy::cast_possible_truncation)] -pub fn trans_addr(gva: GuestVirtualAddress) -> Result { +pub fn trans_addr(gva: GuestVirtualAddress) -> GuestPhysicalAddress { let vsatp = vsatp::read(); let mut page_table_addr = PageTableAddress(vsatp.ppn() << 12); assert!(matches!(vsatp.mode(), vsatp::Mode::Sv39)); @@ -73,23 +73,23 @@ pub fn trans_addr(gva: GuestVirtualAddress) -> Result pte.ppn(1) == 0, "Address translation failed: pte.ppn[1] != 0" ); - return Ok(GuestPhysicalAddress( + return GuestPhysicalAddress( pte.ppn(2) << 30 | gva.vpn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), - )); + ); } PageTableLevel::Lv2MB => { assert!( pte.ppn(0) == 0, "Address translation failed: pte.ppn[0] != 0" ); - return Ok(GuestPhysicalAddress( + return GuestPhysicalAddress( pte.ppn(2) << 30 | pte.ppn(1) << 21 | gva.vpn(0) << 12 | gva.page_offset(), - )); + ); } PageTableLevel::Lv4KB => { - return Ok(GuestPhysicalAddress( + return GuestPhysicalAddress( pte.ppn(2) << 30 | pte.ppn(1) << 21 | pte.ppn(0) << 12 | gva.page_offset(), - )); + ); } } } From 51b618434a37e4b9a5915a3989b34de886989e1e Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:09:02 +0900 Subject: [PATCH 64/99] [refactor][update] remove `StateEnField` and add `hstateen0::clear_envcfg` --- src/h_extension/csrs.rs | 10 +++++----- src/hypervisor_init.rs | 9 +++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index 937c21e..8207025 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -354,12 +354,12 @@ pub mod hstateen0 { } } - /// Hypervisor State Enable 0 Register. - pub enum StateEnField { - /// It controls access to the senvcfg CSRs. - EnvCfg = 1 << 62, + /// Clear `ENVCFG` (62 bit) + pub fn clear_envcfg() { + unsafe { + core::arch::asm!("csrs hstateen0, {bits}", bits = in(reg) 1u64 << 62); + } } - clear_csr_from_enum!(StateEnField, 0x60c); } pub mod htval { diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index ac54ab7..b7c82fb 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -3,11 +3,8 @@ use crate::device::MmioDevice; use crate::guest::Guest; use crate::h_extension::csrs::{ - hcounteren, hedeleg, - hedeleg::ExceptionKind, - henvcfg, hgatp, hideleg, hie, - hstateen0::{self, StateEnField}, - hstatus, hvip, vsatp, VsInterruptKind, + hcounteren, hedeleg, hedeleg::ExceptionKind, henvcfg, hgatp, hideleg, hie, hstateen0, hstatus, + hvip, vsatp, VsInterruptKind, }; use crate::h_extension::instruction::hfence_gvma_all; use crate::memmap::{ @@ -59,7 +56,7 @@ pub extern "C" fn hstart(hart_id: usize, dtb_addr: usize) -> ! { // disable `ENVCFG` state hstateen0::all_state_set(); - hstateen0::clear(StateEnField::EnvCfg); + hstateen0::clear_envcfg(); // enable hypervisor counter hcounteren::set(0xffff_ffff); From 4f42e8d068ac1b9a981aaa8ffe4343d302dfc5c4 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:12:39 +0900 Subject: [PATCH 65/99] [refactor] fix cargo clippy warnings --- src/emulate_extension/zicfiss.rs | 77 +++++++------------ src/memmap/page_table/sv57.rs | 2 +- .../exception/sbi_handler.rs | 3 +- 3 files changed, 31 insertions(+), 51 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index c07687c..96c3190 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -43,19 +43,17 @@ impl Zicfiss { } /// Return host physical shadow stack pointer as `*mut usize`. + #[allow(clippy::similar_names, clippy::cast_possible_truncation)] fn ssp_hp_ptr(&self) -> *mut usize { - match vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)) { - Ok(gpa) => { - let hpa = g_stage_trans_addr(gpa); - hpa.0 as *mut usize - } - Err(()) => { - unsafe { - HYPERVISOR_DATA.force_unlock(); - ZICFISS_DATA.force_unlock(); - } - pseudo_vs_exception(STORE_AMO_PAGE_FAULT, self.ssp.0 as usize); + if let Ok(gpa) = vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)) { + let hpa = g_stage_trans_addr(gpa); + hpa.0 as *mut usize + } else { + unsafe { + HYPERVISOR_DATA.force_unlock(); + ZICFISS_DATA.force_unlock(); } + pseudo_vs_exception(STORE_AMO_PAGE_FAULT, self.ssp.0 as usize); } } @@ -93,6 +91,7 @@ impl Zicfiss { impl EmulateExtension for Zicfiss { /// Emulate Zicfiss instruction. + #[allow(clippy::cast_possible_truncation)] fn instruction(&mut self, inst: &Instruction) { let mut context = unsafe { HYPERVISOR_DATA.lock() } .get() @@ -202,47 +201,29 @@ impl EmulateExtension for Zicfiss { const CSR_SENVCFG: usize = 0x10a; let csr_num = inst.rs2.unwrap(); - match csr_num { - CSR_SENVCFG => { - // overwritten emulated csr field - *read_csr_value |= u64::from(self.senv_sse) << 3; - - // update emulated csr field - match inst.opc { - OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = false; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } + if csr_num == CSR_SENVCFG { + // overwritten emulated csr field + *read_csr_value |= u64::from(self.senv_sse) << 3; + + // update emulated csr field + match inst.opc { + OpcodeKind::Zicsr( + ZicsrOpcode::CSRRW + | ZicsrOpcode::CSRRS + | ZicsrOpcode::CSRRWI + | ZicsrOpcode::CSRRSI, + ) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = true; } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = false; - } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC | ZicsrOpcode::CSRRCI) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = false; } - _ => unreachable!(), } + _ => unreachable!(), } - _ => (), } } } diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs index 4d3b21f..d4a4c56 100644 --- a/src/memmap/page_table/sv57.rs +++ b/src/memmap/page_table/sv57.rs @@ -51,7 +51,7 @@ impl AddressFieldSv57 for GuestVirtualAddress { } /// Translate gva to gpa in sv57 -#[allow(clippy::cast_possible_truncation)] +#[allow(clippy::cast_possible_truncation, clippy::too_many_lines)] pub fn trans_addr(gva: GuestVirtualAddress) -> Result { let vsatp = vsatp::read(); assert!(matches!(vsatp.mode(), vsatp::Mode::Sv57)); diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 71352b7..e906c02 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -89,13 +89,12 @@ impl TryFrom for FwftFeature { /// SBI ecall handler for Firmware Features Extension (EID #0x46574654) /// /// FWFT ecall will be emulated because `sbi_rt` is not supported. +#[allow(clippy::items_after_statements, clippy::cast_possible_truncation)] // TODO pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { const FWFT_SET: usize = 0; const FWFT_GET: usize = 1; let feature = args[0] as usize; - let _value = args[1]; - let _flags = args[2]; // TODO remove it. use crate::emulate_extension::zicfiss::Zicfiss; From e883ec850e1d44204980a2d54178fc49845e5f3d Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:39:24 +0900 Subject: [PATCH 66/99] [doc] add doc comment to `FwftFeature` --- src/trap/hypervisor_supervisor/exception/sbi_handler.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index e906c02..2615768 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -63,11 +63,17 @@ pub fn sbi_rfnc_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { /// Ref: [https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/vv3.0-rc1/riscv-sbi.pdf](https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/vv3.0-rc1/riscv-sbi.pdf) p.78 #[derive(Debug)] enum FwftFeature { + /// Control misaligned access exception delegation to supervisor-mode if medeleg is present. MisalignedExcDeleg, + /// Control landing pad support for supervisor-mode. LandingPad, + /// Control shadow stack support for supervisor-mode. ShadowStack, + /// Control double trap support for supervisor-mode. DoubleTrap, + /// Control hardware updating of PTE A/D bits for supervisor-mode. PteAdHwUpdating, + /// Control the pointer masking tag length for supervisor-mode. PointerMaskingPmlen, } From dad054340b60e1758be24632701d7fe79caab969 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 17:20:06 +0900 Subject: [PATCH 67/99] [fix] fix linking probrem in `riscv-rt` by fork repo --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index be76b32..e30c7f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ fdt = "0.1.5" linked_list_allocator = "0.10.5" raki = "1.2.0" riscv = "0.11.1" -riscv-rt = "0.11.0" +riscv-rt = { git = "https://github.com/Alignof/riscv", branch = "fix/link_error_on_latest_rust" } rustsbi = { version = "0.4.0-alpha.1", features = ["machine"] } sbi-rt = "0.0.3" sbi-spec = { version = "0.0.7", features = [ "legacy" ] } From 5193e3bb706c33f40fbded5505eaf236e033a33e Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 17:20:22 +0900 Subject: [PATCH 68/99] [update] update rust toolchain version --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d9f4b4c..adbe447 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.76.0" +channel = "1.81.0" components = [ "rustfmt", "clippy" ] targets = [ "riscv64imac-unknown-none-elf" ] From b18ac3e78dd3af36be2f938f582e0906bfba3f72 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:09:02 +0900 Subject: [PATCH 69/99] [refactor][update] remove `StateEnField` and add `hstateen0::clear_envcfg` --- src/h_extension/csrs.rs | 10 +++++----- src/hypervisor_init.rs | 9 +++------ 2 files changed, 8 insertions(+), 11 deletions(-) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index 937c21e..94f815e 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -354,12 +354,12 @@ pub mod hstateen0 { } } - /// Hypervisor State Enable 0 Register. - pub enum StateEnField { - /// It controls access to the senvcfg CSRs. - EnvCfg = 1 << 62, + /// Clear `ENVCFG` (62 bit) + pub fn clear_envcfg() { + unsafe { + core::arch::asm!("csrc hstateen0, {bits}", bits = in(reg) 1u64 << 62); + } } - clear_csr_from_enum!(StateEnField, 0x60c); } pub mod htval { diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index ac54ab7..b7c82fb 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -3,11 +3,8 @@ use crate::device::MmioDevice; use crate::guest::Guest; use crate::h_extension::csrs::{ - hcounteren, hedeleg, - hedeleg::ExceptionKind, - henvcfg, hgatp, hideleg, hie, - hstateen0::{self, StateEnField}, - hstatus, hvip, vsatp, VsInterruptKind, + hcounteren, hedeleg, hedeleg::ExceptionKind, henvcfg, hgatp, hideleg, hie, hstateen0, hstatus, + hvip, vsatp, VsInterruptKind, }; use crate::h_extension::instruction::hfence_gvma_all; use crate::memmap::{ @@ -59,7 +56,7 @@ pub extern "C" fn hstart(hart_id: usize, dtb_addr: usize) -> ! { // disable `ENVCFG` state hstateen0::all_state_set(); - hstateen0::clear(StateEnField::EnvCfg); + hstateen0::clear_envcfg(); // enable hypervisor counter hcounteren::set(0xffff_ffff); From 025be4bb00a7ca5c8850bfa3be6aa6d29a4c966b Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:12:39 +0900 Subject: [PATCH 70/99] [refactor] fix cargo clippy warnings --- src/emulate_extension/zicfiss.rs | 77 +++++++------------ src/memmap/page_table/sv57.rs | 2 +- .../exception/sbi_handler.rs | 3 +- 3 files changed, 31 insertions(+), 51 deletions(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index c07687c..96c3190 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -43,19 +43,17 @@ impl Zicfiss { } /// Return host physical shadow stack pointer as `*mut usize`. + #[allow(clippy::similar_names, clippy::cast_possible_truncation)] fn ssp_hp_ptr(&self) -> *mut usize { - match vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)) { - Ok(gpa) => { - let hpa = g_stage_trans_addr(gpa); - hpa.0 as *mut usize - } - Err(()) => { - unsafe { - HYPERVISOR_DATA.force_unlock(); - ZICFISS_DATA.force_unlock(); - } - pseudo_vs_exception(STORE_AMO_PAGE_FAULT, self.ssp.0 as usize); + if let Ok(gpa) = vs_stage_trans_addr(GuestVirtualAddress(self.ssp.0 as usize)) { + let hpa = g_stage_trans_addr(gpa); + hpa.0 as *mut usize + } else { + unsafe { + HYPERVISOR_DATA.force_unlock(); + ZICFISS_DATA.force_unlock(); } + pseudo_vs_exception(STORE_AMO_PAGE_FAULT, self.ssp.0 as usize); } } @@ -93,6 +91,7 @@ impl Zicfiss { impl EmulateExtension for Zicfiss { /// Emulate Zicfiss instruction. + #[allow(clippy::cast_possible_truncation)] fn instruction(&mut self, inst: &Instruction) { let mut context = unsafe { HYPERVISOR_DATA.lock() } .get() @@ -202,47 +201,29 @@ impl EmulateExtension for Zicfiss { const CSR_SENVCFG: usize = 0x10a; let csr_num = inst.rs2.unwrap(); - match csr_num { - CSR_SENVCFG => { - // overwritten emulated csr field - *read_csr_value |= u64::from(self.senv_sse) << 3; - - // update emulated csr field - match inst.opc { - OpcodeKind::Zicsr(ZicsrOpcode::CSRRW) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRS) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRC) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = false; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRWI) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } - } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRSI) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = true; - } + if csr_num == CSR_SENVCFG { + // overwritten emulated csr field + *read_csr_value |= u64::from(self.senv_sse) << 3; + + // update emulated csr field + match inst.opc { + OpcodeKind::Zicsr( + ZicsrOpcode::CSRRW + | ZicsrOpcode::CSRRS + | ZicsrOpcode::CSRRWI + | ZicsrOpcode::CSRRSI, + ) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = true; } - OpcodeKind::Zicsr(ZicsrOpcode::CSRRCI) => { - if write_to_csr_value >> 3 & 0x1 == 1 { - self.senv_sse = false; - } + } + OpcodeKind::Zicsr(ZicsrOpcode::CSRRC | ZicsrOpcode::CSRRCI) => { + if write_to_csr_value >> 3 & 0x1 == 1 { + self.senv_sse = false; } - _ => unreachable!(), } + _ => unreachable!(), } - _ => (), } } } diff --git a/src/memmap/page_table/sv57.rs b/src/memmap/page_table/sv57.rs index 4d3b21f..d4a4c56 100644 --- a/src/memmap/page_table/sv57.rs +++ b/src/memmap/page_table/sv57.rs @@ -51,7 +51,7 @@ impl AddressFieldSv57 for GuestVirtualAddress { } /// Translate gva to gpa in sv57 -#[allow(clippy::cast_possible_truncation)] +#[allow(clippy::cast_possible_truncation, clippy::too_many_lines)] pub fn trans_addr(gva: GuestVirtualAddress) -> Result { let vsatp = vsatp::read(); assert!(matches!(vsatp.mode(), vsatp::Mode::Sv57)); diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 71352b7..e906c02 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -89,13 +89,12 @@ impl TryFrom for FwftFeature { /// SBI ecall handler for Firmware Features Extension (EID #0x46574654) /// /// FWFT ecall will be emulated because `sbi_rt` is not supported. +#[allow(clippy::items_after_statements, clippy::cast_possible_truncation)] // TODO pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { const FWFT_SET: usize = 0; const FWFT_GET: usize = 1; let feature = args[0] as usize; - let _value = args[1]; - let _flags = args[2]; // TODO remove it. use crate::emulate_extension::zicfiss::Zicfiss; From ca28ebd6c2a76754b771d7d4940c63b303e22327 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 16:39:24 +0900 Subject: [PATCH 71/99] [doc] add doc comment to `FwftFeature` --- src/trap/hypervisor_supervisor/exception/sbi_handler.rs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index e906c02..2615768 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -63,11 +63,17 @@ pub fn sbi_rfnc_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { /// Ref: [https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/vv3.0-rc1/riscv-sbi.pdf](https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/vv3.0-rc1/riscv-sbi.pdf) p.78 #[derive(Debug)] enum FwftFeature { + /// Control misaligned access exception delegation to supervisor-mode if medeleg is present. MisalignedExcDeleg, + /// Control landing pad support for supervisor-mode. LandingPad, + /// Control shadow stack support for supervisor-mode. ShadowStack, + /// Control double trap support for supervisor-mode. DoubleTrap, + /// Control hardware updating of PTE A/D bits for supervisor-mode. PteAdHwUpdating, + /// Control the pointer masking tag length for supervisor-mode. PointerMaskingPmlen, } From 06a469da807eed7342c108a2f1cb8f611988b425 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 17:20:06 +0900 Subject: [PATCH 72/99] [fix] fix linking probrem in `riscv-rt` by fork repo --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index be76b32..e30c7f0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ fdt = "0.1.5" linked_list_allocator = "0.10.5" raki = "1.2.0" riscv = "0.11.1" -riscv-rt = "0.11.0" +riscv-rt = { git = "https://github.com/Alignof/riscv", branch = "fix/link_error_on_latest_rust" } rustsbi = { version = "0.4.0-alpha.1", features = ["machine"] } sbi-rt = "0.0.3" sbi-spec = { version = "0.0.7", features = [ "legacy" ] } From 7ab118b46da57c22929081b19a0463e82002f6a2 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 17:20:22 +0900 Subject: [PATCH 73/99] [update] update rust toolchain version --- rust-toolchain.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain.toml b/rust-toolchain.toml index d9f4b4c..adbe447 100644 --- a/rust-toolchain.toml +++ b/rust-toolchain.toml @@ -1,4 +1,4 @@ [toolchain] -channel = "1.76.0" +channel = "1.81.0" components = [ "rustfmt", "clippy" ] targets = [ "riscv64imac-unknown-none-elf" ] From a0d629fdf7f8a539817269466284f8bef3469e85 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 18:36:55 +0900 Subject: [PATCH 74/99] [add] add `emulate_extension::initialize` --- src/emulate_extension.rs | 7 +++++++ src/emulate_extension/zicfiss.rs | 2 +- src/hypervisor_init.rs | 4 ++++ src/trap/hypervisor_supervisor/exception/sbi_handler.rs | 8 +------- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index 89237e2..b98f465 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -48,6 +48,13 @@ impl CsrData { } } +/// Initialize singletons for extension emulation. +/// TODO: Remove it when `OnceCell` is replaced to `LazyCell`. +pub fn initialize() { + use zicfiss::{Zicfiss, ZICFISS_DATA}; + unsafe { ZICFISS_DATA.lock() }.get_or_init(Zicfiss::new); +} + /// Throw an VS-level exception. /// * `exception_num`: Exception number. (store to vscause) /// * `trap_value`: Trap value. (store to vstval) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 96c3190..f7189d4 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -13,7 +13,7 @@ use raki::{Instruction, OpcodeKind, ZicfissOpcode, ZicsrOpcode}; use spin::Mutex; /// Singleton for Zicfiss. -/// TODO: change `OnceCell` to `LazyCell`. +/// TODO: change `OnceCell` to `LazyCell` when stable `LazyCell::force_mut`. pub static mut ZICFISS_DATA: Mutex> = Mutex::new(OnceCell::new()); /// Software-check exception. (cause value) diff --git a/src/hypervisor_init.rs b/src/hypervisor_init.rs index b7c82fb..bc2ca95 100644 --- a/src/hypervisor_init.rs +++ b/src/hypervisor_init.rs @@ -1,6 +1,7 @@ //! HS-mode level initialization. use crate::device::MmioDevice; +use crate::emulate_extension; use crate::guest::Guest; use crate::h_extension::csrs::{ hcounteren, hedeleg, hedeleg::ExceptionKind, henvcfg, hgatp, hideleg, hie, hstateen0, hstatus, @@ -148,6 +149,9 @@ fn vsmode_setup(hart_id: usize, dtb_addr: HostPhysicalAddress) -> ! { // set new guest data hypervisor_data.get_mut().unwrap().register_guest(new_guest); + // initialize emulate_extension data + emulate_extension::initialize(); + unsafe { // sstatus.SUM = 1, sstatus.SPP = 0 sstatus::set_sum(); diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 2615768..274a85c 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -1,8 +1,6 @@ //! Handle VS-mode Ecall exception //! See [https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/v2.0/riscv-sbi.pdf](https://github.com/riscv-non-isa/riscv-sbi-doc/releases/download/v2.0/riscv-sbi.pdf) -use crate::emulate_extension::zicfiss::ZICFISS_DATA; - use sbi_rt::SbiRet; /// SBI ecall handler for Base Extension (EID: #0x10) @@ -95,17 +93,13 @@ impl TryFrom for FwftFeature { /// SBI ecall handler for Firmware Features Extension (EID #0x46574654) /// /// FWFT ecall will be emulated because `sbi_rt` is not supported. -#[allow(clippy::items_after_statements, clippy::cast_possible_truncation)] // TODO +#[allow(clippy::cast_possible_truncation)] pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { const FWFT_SET: usize = 0; const FWFT_GET: usize = 1; let feature = args[0] as usize; - // TODO remove it. - use crate::emulate_extension::zicfiss::Zicfiss; - unsafe { ZICFISS_DATA.lock().get_or_init(Zicfiss::new) }; - match func_id { FWFT_SET => match FwftFeature::try_from(feature).unwrap() { FwftFeature::ShadowStack => { From caef788ed9c3127cb5c22b85da9796e5bd6d376f Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 18:54:25 +0900 Subject: [PATCH 75/99] [add] add rules to force documentation --- Cargo.toml | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index e30c7f0..49584ff 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,6 +6,12 @@ edition = "2021" [lints.clippy] pedantic = "warn" +[lints.rust] +missing_docs = "warn" + +[lints.rustdoc] +missing_crate_level_docs = "warn" + [dependencies] elf = { version = "0.7.2", default-features = false } fdt = "0.1.5" From c6167d6f9ad189c6af5b2b4e3de861cd4487d239 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 18:54:41 +0900 Subject: [PATCH 76/99] [add] add crate level docs to main.rs --- src/main.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/main.rs b/src/main.rs index 5679bf1..b9bee71 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,16 @@ +//! hikami - Light weight type-1 hypervisor for RISC-V H-extension. +//! +//! ## Run +//! ```no_run +//! # The actual command to be executed is written in .cargo/config.toml. +//! $ cargo r +//! ``` +//! +//! ## Documents +//! ```no_run +//! $ cargo doc --open +//! ``` + #![no_main] #![no_std] From fb09b9721ca9f56afefe996d913b7ca231af8359 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 18:58:15 +0900 Subject: [PATCH 77/99] [add] add doc comment to build.rs --- build.rs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build.rs b/build.rs index 143e014..a1df5b1 100644 --- a/build.rs +++ b/build.rs @@ -1,7 +1,10 @@ +//! build.rs - For build script for cargo project. + use std::env; use std::fs; use std::path::PathBuf; +/// Build script for cargo project fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); From 107376a620d86981759d0c068e84745307da07ac Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 19:14:18 +0900 Subject: [PATCH 78/99] [add] add clippy rules to force private object's documentation --- Cargo.toml | 1 + 1 file changed, 1 insertion(+) diff --git a/Cargo.toml b/Cargo.toml index 49584ff..7dccfa6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,6 +5,7 @@ edition = "2021" [lints.clippy] pedantic = "warn" +missing_docs_in_private_items = "warn" [lints.rust] missing_docs = "warn" From 7d9cde28479bdd529d0bc1d2e400aae9b1d1c86d Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 21:15:37 +0900 Subject: [PATCH 79/99] [fix] replace constant to `const { None }` --- src/main.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main.rs b/src/main.rs index b9bee71..577099b 100644 --- a/src/main.rs +++ b/src/main.rs @@ -113,10 +113,9 @@ impl HypervisorData { /// It will be panic when parsing device tree failed. #[must_use] pub fn new(device_tree: Fdt) -> Self { - const ARRAY_INIT_VALUE: Option = None; HypervisorData { current_hart: 0, - guests: [ARRAY_INIT_VALUE; MAX_HART_NUM], + guests: [const { None }; MAX_HART_NUM], devices: Devices::new(device_tree), } } From b381028f8404de9bfc433fcc4171b136db10f93a Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 21:53:16 +0900 Subject: [PATCH 80/99] [doc][add] add missing documents in h_extension/csrs.rs --- src/h_extension/csrs.rs | 44 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index 94f815e..fc59a1b 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -101,8 +101,11 @@ pub mod vstvec { //! Virtual supervisor trap handler base address. #![allow(dead_code)] + /// vstvec register number. const VSTVEC: usize = 0x205; + /// Virtual supervisor trap handler base address. pub struct Vstvec { + /// bitmap bits: usize, } @@ -116,8 +119,11 @@ pub mod vsip { //! Virtual supervisor interrupt pending. #![allow(dead_code)] + /// vsip register number. const VSIP: usize = 0x244; + /// Virtual supervisor interrupt pending. pub struct Vsip { + /// bitmap bits: usize, } @@ -149,8 +155,11 @@ pub mod vsatp { //! Virtual supervisor address translation and protection. #![allow(dead_code)] + /// vsatp register number. const VSATP: usize = 0x280; + /// Virtual supervisor address translation and protection. pub struct Vsatp { + /// bitmap bits: usize, } @@ -192,8 +201,11 @@ pub mod hstatus { //! hstatus util functions. #![allow(dead_code)] + /// hstatus register number. const HSTATUS: usize = 0x600; + /// hstatus util functions. pub struct Hstatus { + /// bitmap bits: usize, } @@ -215,8 +227,11 @@ pub mod hedeleg { //! Hypervisor exception delegation register. #![allow(dead_code)] + /// hedeleg register number. const HEDELEG: usize = 0x602; + /// Hypervisor exception delegation register. pub struct Hedeleg { + /// bitmap bits: usize, } @@ -246,8 +261,11 @@ pub mod hideleg { //! Hypervisor interrupt delegation register. #![allow(dead_code)] + /// hideleg register number. const HIDELEG: usize = 0x603; + /// Hypervisor interrupt delegation register. pub struct Hideleg { + /// bitmap bits: usize, } @@ -260,8 +278,11 @@ pub mod hie { #![allow(dead_code)] use super::VsInterruptKind; + /// hie register number. const HIE: usize = 0x604; + /// Hypervisor interrupt-enable register. pub struct Hie { + /// bitmap bits: usize, } @@ -272,8 +293,11 @@ pub mod hcounteren { //! Hypervisor counter enable. #![allow(dead_code)] + /// hcounteren register number. const HCOUNTEREN: usize = 0x606; + /// Hypervisor counter enable. pub struct Hcounteren { + /// bitmap bits: usize, } @@ -284,8 +308,11 @@ pub mod henvcfg { //! Hypervisor environment configuration register. #![allow(dead_code)] + /// henvcfg register number. const HENVCFG: usize = 0x60a; + /// Hypervisor environment configuration register. pub struct Henvcfg { + /// bitmap bits: usize, } @@ -342,8 +369,11 @@ pub mod hstateen0 { //! Hypervisor State Enable 0 Register. #![allow(dead_code)] + /// hstateen0 register number. const HSTATEEN0: usize = 0x60c; + /// Hypervisor State Enable 0 Register. pub struct HstateEn0 { + /// bitmap pub bits: usize, } @@ -366,8 +396,11 @@ pub mod htval { //! Hypervisor bad guest physical address. #![allow(dead_code)] + /// htval register number. const HTVAL: usize = 0x643; + /// Hypervisor bad guest physical address. pub struct Htval { + /// bitmap pub bits: usize, } @@ -377,10 +410,14 @@ pub mod htval { pub mod hvip { //! Hypervisor virtual interrupt pending. #![allow(dead_code)] + use super::VsInterruptKind; + /// hvip register number. const HVIP: usize = 0x645; + /// Hypervisor virtual interrupt pending. pub struct Hvip { + /// bitmap bits: usize, } @@ -395,8 +432,11 @@ pub mod htinst { //! Hypervisor trap instruction (transformed). #![allow(dead_code)] + /// htinst register number. const HTINST: usize = 0x64a; + /// Hypervisor trap instruction (transformed). pub struct Htinst { + /// bitmap pub bits: usize, } @@ -408,8 +448,11 @@ pub mod hgatp { //! Hypervisor guest address translation and protection. #![allow(dead_code)] + /// hgatp register number. const HGATP: usize = 0x680; + /// Hypervisor guest address translation and protection. pub struct Hgatp { + /// bitmap pub bits: usize, } @@ -440,6 +483,7 @@ pub mod hgatp { Sv57x4 = 10, } + /// Set Hgatp fields. pub fn set(mode: Mode, vmid: usize, ppn: usize) { write((0xF & (mode as usize)) << 60 | (0x3FFF & vmid) << 44 | 0x0FFF_FFFF_FFFF & ppn); } From b792f36aff2ff5d0451aee285d1db2a0ab016d2c Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 21:53:32 +0900 Subject: [PATCH 81/99] [doc][add] add missing documents in trap/ --- src/trap/hypervisor_supervisor/exception.rs | 2 ++ src/trap/hypervisor_supervisor/exception/sbi_handler.rs | 2 ++ src/trap/machine.rs | 5 +++++ 3 files changed, 9 insertions(+) diff --git a/src/trap/hypervisor_supervisor/exception.rs b/src/trap/hypervisor_supervisor/exception.rs index c25527b..3c7a5a4 100644 --- a/src/trap/hypervisor_supervisor/exception.rs +++ b/src/trap/hypervisor_supervisor/exception.rs @@ -39,7 +39,9 @@ pub extern "C" fn hs_forward_exception() { /// Handler for Ecall from VS-mode exception #[allow(clippy::cast_possible_truncation)] fn sbi_vs_mode_handler(context: &mut guest::context::Context) { + /// Extension ID of FWFT(Firmware Features) Extension. const EID_FWFT: usize = 0x4657_4654; + let ext_id: usize = context.xreg(17) as usize; let func_id: usize = context.xreg(16) as usize; let arguments: &[u64; 5] = &[ diff --git a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs index 274a85c..6d517b0 100644 --- a/src/trap/hypervisor_supervisor/exception/sbi_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/sbi_handler.rs @@ -95,7 +95,9 @@ impl TryFrom for FwftFeature { /// FWFT ecall will be emulated because `sbi_rt` is not supported. #[allow(clippy::cast_possible_truncation)] pub fn sbi_fwft_handler(func_id: usize, args: &[u64; 5]) -> SbiRet { + /// Firmware Features Set (FID #0) const FWFT_SET: usize = 0; + /// Firmware Features Get (FID #1) const FWFT_GET: usize = 1; let feature = args[0] as usize; diff --git a/src/trap/machine.rs b/src/trap/machine.rs index 2c7b06f..333476d 100644 --- a/src/trap/machine.rs +++ b/src/trap/machine.rs @@ -9,6 +9,7 @@ use interrupt::trap_interrupt; use core::arch::asm; use riscv::register::mcause::{self, Trap}; +/// Epilogue of Machine trap vector #[inline(always)] #[allow(clippy::inline_always)] unsafe fn mtrap_exit() -> ! { @@ -63,6 +64,10 @@ unsafe fn mtrap_exit() -> ! { ); } +/// Epilogue of Machine trap vector with SBI return value. +/// +/// - error: Error code (store to `a0`). +/// - value: Return value (store to `a1`). #[inline(always)] #[allow(clippy::inline_always)] unsafe fn mtrap_exit_sbi(error: usize, value: usize) -> ! { From 2a8f45e3a8d7e83a860e4f2218c465da64b05a18 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 21:53:46 +0900 Subject: [PATCH 82/99] [doc][add] add missing documents in memmap/ --- src/memmap/page_table.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/memmap/page_table.rs b/src/memmap/page_table.rs index f7918b9..a82b612 100644 --- a/src/memmap/page_table.rs +++ b/src/memmap/page_table.rs @@ -7,6 +7,8 @@ pub mod sv57; use crate::memmap::{GuestPhysicalAddress, GuestVirtualAddress, HostPhysicalAddress}; pub mod constants { + //! Constants of page table. + /// Size of memory areathat a page can point to. pub const PAGE_SIZE: usize = 4096; /// Second or Third page table size @@ -34,6 +36,7 @@ enum PageTableLevel { } impl PageTableLevel { + /// Return usize. fn size(self) -> usize { match self { Self::Lv256TB => 0x1_0000_0000_0000, @@ -73,6 +76,7 @@ pub enum PteFlag { pub struct PageTableEntry(u64); impl PageTableEntry { + /// Constructor for `PageTableEntry`. fn new(ppn: u64, flags: u8) -> Self { Self(ppn << 10 | u64::from(flags)) } @@ -119,6 +123,7 @@ impl PageTableAddress { self.0 as *mut PageTableEntry } + /// Convert guest physical page table address to host physical one. fn to_host_physical_ptr(self) -> *mut PageTableEntry { let hpa = g_stage_trans_addr(GuestPhysicalAddress(self.0)); hpa.0 as *mut PageTableEntry From 185046fb1f52c5de19c4ac349b5e31258cc25b2c Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 21:53:55 +0900 Subject: [PATCH 83/99] [doc][add] add missing documents in guest module --- src/guest/context.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/guest/context.rs b/src/guest/context.rs index 1dc3853..c3dda1d 100644 --- a/src/guest/context.rs +++ b/src/guest/context.rs @@ -22,10 +22,12 @@ pub struct ContextData { /// Guest context #[derive(Debug, Copy, Clone)] pub struct Context { + /// Address of context storing. address: HostPhysicalAddress, } impl Context { + /// Constructor for `Context`. pub fn new(address: HostPhysicalAddress) -> Self { Context { address } } From 2fd3960e607bced9202495a26dba23bcead36094 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 22:44:52 +0900 Subject: [PATCH 84/99] [doc][add] add missing documents in device module --- src/device.rs | 18 ++++++++++++++++++ src/device/clint.rs | 18 ++++++++++++------ src/device/initrd.rs | 2 ++ src/device/iommu.rs | 6 ++++++ src/device/iommu/register_map.rs | 20 ++++++++++++++++++-- src/device/pci.rs | 5 +++++ src/device/plic.rs | 9 +++++++++ src/device/rtc.rs | 2 ++ src/device/uart.rs | 3 +++ src/device/virtio.rs | 5 +++++ 10 files changed, 80 insertions(+), 8 deletions(-) diff --git a/src/device.rs b/src/device.rs index ad16f46..539006a 100644 --- a/src/device.rs +++ b/src/device.rs @@ -68,19 +68,37 @@ pub trait MmioDevice { /// `memory_map` has memory region data of each devices. /// Each devices **must** be implemented Device trait. #[derive(Debug)] +#[allow(clippy::doc_markdown)] pub struct Devices { + /// UART: Universal Asynchronous Receiver-Transmitter pub uart: uart::Uart, + + /// Lists of Virtio. pub virtio_list: virtio::VirtIoList, + + /// initrd: INITial RamDisk pub initrd: initrd::Initrd, + + /// PLIC: Platform-Level Interrupt Controller pub plic: plic::Plic, + /// TODO: It is unused? pub plic_context: usize, + + /// clint: Core Local INTerrupt pub clint: clint::Clint, + + /// RTC: Real Time Clock. pub rtc: rtc::Rtc, + + /// PCI: Peripheral Component Interconnect pub pci: pci::Pci, + + /// IOMMU: I/O memory management unit. pub iommu: Option, } impl Devices { + /// Constructor for `Devices`. pub fn new(device_tree: Fdt) -> Self { Devices { uart: uart::Uart::new(&device_tree, "/soc/serial"), diff --git a/src/device/clint.rs b/src/device/clint.rs index bfc92f2..3ebe77d 100644 --- a/src/device/clint.rs +++ b/src/device/clint.rs @@ -1,4 +1,4 @@ -//! CLINT: Core Local `INTerrupt` +//! CLINT: *C*ore *L*ocal *Int*errupt use super::{MmioDevice, PTE_FLAGS_FOR_DEVICE}; use crate::memmap::{constant, GuestPhysicalAddress, HostPhysicalAddress, MemoryMap}; @@ -7,15 +7,19 @@ use rustsbi::{HartMask, SbiRet}; mod register { //! Ref: [https://chromitem-soc.readthedocs.io/en/latest/clint.html](https://chromitem-soc.readthedocs.io/en/latest/clint.html) + //! + //! | Register-Name | Offset(hex) | Size(Bits) | Reset(hex) | Description | + //! | ------------- | ----------- | ---------- | ---------- | ----------- | + //! | msip | 0x0 | 32 | 0x0 | This register generates machine mode software interrupts when set. | + //! | mtimecmp | 0x4000 | 64 | 0x0 | This register holds the compare value for the timer. | + //! | mtime | 0xBFF8 | 64 | 0x0 | Provides the current timer value. | - /// | Register-Name | Offset(hex) | Size(Bits) | Reset(hex) | Description | - /// | ------------- | ----------- | ---------- | ---------- | ----------- | - /// | msip | 0x0 | 32 | 0x0 | This register generates machine mode software interrupts when set. | - /// | mtimecmp | 0x4000 | 64 | 0x0 | This register holds the compare value for the timer. | - /// | mtime | 0xBFF8 | 64 | 0x0 | Provides the current timer value. | + /// Offset of `MISP` register pub const MSIP_OFFSET: usize = 0x0; + /// Offset of `MTIMECMP` register pub const MTIMECMP_OFFSET: usize = 0x4000; #[allow(dead_code)] + /// Offset of `MTIME` register pub const MTIME_OFFSET: usize = 0xbff8; } @@ -24,7 +28,9 @@ mod register { /// Local interrupt controller #[derive(Debug)] pub struct Clint { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, } diff --git a/src/device/initrd.rs b/src/device/initrd.rs index b2199d5..3c58d59 100644 --- a/src/device/initrd.rs +++ b/src/device/initrd.rs @@ -9,7 +9,9 @@ use fdt::Fdt; /// to be used as part of the Linux startup process. #[derive(Debug)] pub struct Initrd { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, } diff --git a/src/device/iommu.rs b/src/device/iommu.rs index 52c381f..34c190b 100644 --- a/src/device/iommu.rs +++ b/src/device/iommu.rs @@ -17,16 +17,22 @@ use fdt::Fdt; /// IOMMU: I/O memory management unit. #[derive(Debug)] pub struct IoMmu { + /// PCI Bus number bus: u32, + /// PCI Device number device: u32, + /// PCI Function number function: u32, } impl IoMmu { /// Set page table in IOMMU. fn init_page_table(ddt_addr: HostPhysicalAddress) { + /// Offset of `iohgatp` register. const OFFSET_IOHGATP: usize = 8; + /// Size of leaf ddt entry. const LEAF_DDT_ENTRY_SIZE: usize = 512; + // set all ddt entry for offset in (0..PAGE_SIZE).step_by(LEAF_DDT_ENTRY_SIZE) { let tc_addr = ddt_addr + offset; diff --git a/src/device/iommu/register_map.rs b/src/device/iommu/register_map.rs index ecd6dc5..f13d65b 100644 --- a/src/device/iommu/register_map.rs +++ b/src/device/iommu/register_map.rs @@ -52,14 +52,19 @@ impl Capabilities { ((version_reg >> 4 & 0xf) as u8, (version_reg & 0xf) as u8) } - /// Return + /// Is base format? + /// + /// true -> base format + /// false -> extended format pub fn is_base_format(&self) -> bool { (self.0 >> 22) & 0x1 == 0 } /// Is sv39x4 supported? pub fn is_sv39x4_supported(&self) -> bool { + /// Field `Sv39x4` of `capabilities` register. const FIELD_CAPABILITIES_SV39X4: usize = 17; + self.0 >> FIELD_CAPABILITIES_SV39X4 & 0x1 == 1 } } @@ -80,6 +85,7 @@ impl Cqb { /// Command-queue tail pub struct Cqt(u32); impl Cqt { + /// Write a value. pub fn write(&mut self, value: u32) { self.0 = value; } @@ -93,9 +99,11 @@ impl CqCsr { self.0 |= 1; } - /// cqon (offset: 16) + /// Return `cqon` field value. (offset: 16) pub fn cqon(&self) -> bool { + /// Field `cqon` of `cqcsr` register. (16 bit) const FIELD_CQCSR_CQON: usize = 0x10; + let cqcsr = self.0; (cqcsr >> FIELD_CQCSR_CQON) & 0x1 == 1 } @@ -117,6 +125,7 @@ impl Fqb { /// Fault-queue tail pub struct Fqt(u32); impl Fqt { + /// Write a value. pub fn write(&mut self, value: u32) { self.0 = value; } @@ -132,6 +141,7 @@ impl FqCsr { /// fqon (offset: 16) pub fn fqon(&self) -> bool { + /// Field `fqon` of `fqcsr` register. (16 bit) const FIELD_FQCSR_FQON: usize = 0x10; let fqcsr = self.0; fqcsr >> FIELD_FQCSR_FQON & 0x1 == 1 @@ -154,6 +164,7 @@ impl Pqb { /// Page-request-queue tail pub struct Pqt(u32); impl Pqt { + /// Write a value. pub fn write(&mut self, value: u32) { self.0 = value; } @@ -169,7 +180,9 @@ impl PqCsr { /// pqon (offset: 16) pub fn pqon(&self) -> bool { + /// Field `pqon` of `pqcsr` register. (16 bit) const FIELD_PQCSR_PQON: usize = 0x10; + let pqcsr = self.0; pqcsr >> FIELD_PQCSR_PQON & 0x1 == 1 } @@ -193,8 +206,11 @@ pub enum IoMmuMode { /// Device-directory-table pointer pub struct Ddtp(u64); impl Ddtp { + /// set ppn and mode (defined in `IoMmuMode`). pub fn set(&mut self, mode: IoMmuMode, ddt_addr: HostPhysicalAddress) { + /// Field `ppn` of `ddtp` register. (16 bit) const FIELD_DDTP_PPN: usize = 10; + self.0 = (ddt_addr.0 as u64 >> 12) << FIELD_DDTP_PPN | mode as u64; } } diff --git a/src/device/pci.rs b/src/device/pci.rs index d63e022..9b61cb8 100644 --- a/src/device/pci.rs +++ b/src/device/pci.rs @@ -31,7 +31,9 @@ pub enum ConfigSpaceRegister { /// Local computer bus. #[derive(Debug)] pub struct Pci { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, /// Memory maps for pci devices memory_maps: Vec, @@ -106,7 +108,10 @@ impl Pci { impl MmioDevice for Pci { fn new(device_tree: &Fdt, node_path: &str) -> Self { + /// Bytes size of u32. const BYTES_U32: usize = 4; + /// Number of bytes in each range chunks. + /// `BUS_ADDRESS(3)` - `CPU_PHYSICAL(2)` - `SIZE(2)` const RANGE_NUM: usize = 7; let region = device_tree diff --git a/src/device/plic.rs b/src/device/plic.rs index 63fb325..bb05724 100644 --- a/src/device/plic.rs +++ b/src/device/plic.rs @@ -23,10 +23,14 @@ const CONTEXT_END: usize = CONTEXT_BASE * CONTEXT_REGS_SIZE * MAX_CONTEXT_NUM; pub struct ContextId(usize); impl ContextId { + /// Create new `ContextId` from hart id. + /// + /// Each hart has two id for machine and supervisor. pub fn new(hart_id: usize, is_supervisor: bool) -> Self { ContextId(2 * hart_id + usize::from(is_supervisor)) } + /// Return raw usize value. pub fn raw(&self) -> usize { self.0 } @@ -36,8 +40,13 @@ impl ContextId { /// Interrupt controller for global interrupts. #[derive(Debug)] pub struct Plic { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, + /// Claim complete flags for external interrupts emulation. + /// + /// Each bit indicates whether interrupts are claimed in context. claim_complete: [u32; MAX_CONTEXT_NUM], } diff --git a/src/device/rtc.rs b/src/device/rtc.rs index 9da908a..de8430d 100644 --- a/src/device/rtc.rs +++ b/src/device/rtc.rs @@ -8,7 +8,9 @@ use fdt::Fdt; /// An electronic device that measures the passage of time. #[derive(Debug)] pub struct Rtc { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, } diff --git a/src/device/uart.rs b/src/device/uart.rs index 4aac560..b520f96 100644 --- a/src/device/uart.rs +++ b/src/device/uart.rs @@ -59,11 +59,14 @@ impl Write for UartWriter { /// UART: Universal asynchronous receiver-transmitter #[derive(Debug)] pub struct Uart { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, } impl Uart { + /// Return address of LSR register. pub fn lsr_addr(&self) -> HostPhysicalAddress { self.base_addr + register::LSR_OFFSET } diff --git a/src/device/virtio.rs b/src/device/virtio.rs index 0d76de3..1100545 100644 --- a/src/device/virtio.rs +++ b/src/device/virtio.rs @@ -36,14 +36,19 @@ impl VirtIoList { } } +/// Virtualization standard for IO device. #[derive(Debug)] pub struct VirtIo { + /// Base address of memory map. base_addr: HostPhysicalAddress, + /// Memory map size. size: usize, + /// Interrupt Reqeust bit. irq: u8, } impl VirtIo { + /// Return `irq`. pub fn irq(&self) -> u8 { self.irq } From 826f6f7ff66e4495f9068a63099b09d6b1fd4ce5 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 22:45:22 +0900 Subject: [PATCH 85/99] [doc][add] add missing documents --- src/emulate_extension/zicfiss.rs | 6 ++++++ src/guest.rs | 6 +++++- src/main.rs | 9 +++++++++ src/memmap.rs | 5 +++++ src/sbi.rs | 2 ++ 5 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index f7189d4..8284126 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -34,6 +34,7 @@ pub struct Zicfiss { } impl Zicfiss { + /// Constructor for `Zicfiss`. pub fn new() -> Self { Zicfiss { ssp: CsrData(0), @@ -79,6 +80,9 @@ impl Zicfiss { } } + /// Is shadow stack enabled? + /// + /// Chack corresponding `SSE` bit of xenvcfg. fn is_ss_enable(&self, sstatus: usize) -> bool { let spp = sstatus >> 8 & 0x1; if spp == 0 { @@ -153,6 +157,7 @@ impl EmulateExtension for Zicfiss { /// Emulate Zicfiss CSRs access. fn csr(&mut self, inst: &Instruction) { + /// Register number of `Shadow Stack Pointer`. const CSR_SSP: usize = 0x11; let hypervisor_data = unsafe { HYPERVISOR_DATA.lock() }; @@ -198,6 +203,7 @@ impl EmulateExtension for Zicfiss { /// Emulate CSR field that already exists. fn csr_field(&mut self, inst: &Instruction, write_to_csr_value: u64, read_csr_value: &mut u64) { + /// Register number of `Supervisor Environment Configuration Register`. const CSR_SENVCFG: usize = 0x10a; let csr_num = inst.rs2.unwrap(); diff --git a/src/guest.rs b/src/guest.rs index f49a7dd..098b9ac 100644 --- a/src/guest.rs +++ b/src/guest.rs @@ -143,6 +143,11 @@ impl Guest { guest_elf: &ElfBytes, elf_addr: *mut u8, ) -> (GuestPhysicalAddress, GuestPhysicalAddress) { + /// Segment type `PT_LOAD` + /// + /// The array element specifies a loadable segment, described by `p_filesz` and `p_memsz`. + const PT_LOAD: u32 = 1; + use PteFlag::{Accessed, Dirty, Exec, Read, User, Valid, Write}; let align_size = @@ -154,7 +159,6 @@ impl Guest { .expect("failed to get segments from elf") .iter() { - const PT_LOAD: u32 = 1; if prog_header.p_type == PT_LOAD && prog_header.p_filesz > 0 { assert!(prog_header.p_align >= PAGE_SIZE as u64); let aligned_segment_size = align_size(prog_header.p_filesz, prog_header.p_align); diff --git a/src/main.rs b/src/main.rs index 577099b..782f537 100644 --- a/src/main.rs +++ b/src/main.rs @@ -101,8 +101,11 @@ impl PageBlock { /// FIXME: Rename me! #[derive(Debug)] pub struct HypervisorData { + /// Current hart id (zero indexed). current_hart: usize, + /// Guests data guests: [Option; MAX_HART_NUM], + /// Devices data. devices: device::Devices, } @@ -120,6 +123,8 @@ impl HypervisorData { } } + /// Return Device objects. + /// /// # Panics /// It will be panic if devices are uninitialized. #[must_use] @@ -127,6 +132,8 @@ impl HypervisorData { &mut self.devices } + /// Return current hart's guest. + /// /// # Panics /// It will be panic if current HART's guest data is empty. #[must_use] @@ -136,6 +143,8 @@ impl HypervisorData { .expect("guest data not found") } + /// Add new guest data. + /// /// # Panics /// It will be panic if `hart_id` is greater than `MAX_HART_NUM`. pub fn register_guest(&mut self, new_guest: Guest) { diff --git a/src/memmap.rs b/src/memmap.rs index f777767..052a153 100644 --- a/src/memmap.rs +++ b/src/memmap.rs @@ -21,6 +21,7 @@ pub struct GuestVirtualAddress(pub usize); pub struct GuestPhysicalAddress(pub usize); impl GuestPhysicalAddress { + /// Convert to usize. pub fn raw(self) -> usize { self.0 } @@ -51,6 +52,7 @@ impl AddressRangeUtil for Range { pub struct HostPhysicalAddress(pub usize); impl HostPhysicalAddress { + /// Convert to usize. pub fn raw(self) -> usize { self.0 } @@ -95,6 +97,9 @@ pub struct MemoryMap { } impl MemoryMap { + /// Create new `MemoryMap`. + /// + /// `flags` is mapped to bitmap. pub fn new( virt: Range, phys: Range, diff --git a/src/sbi.rs b/src/sbi.rs index 9a81347..fe2ddab 100644 --- a/src/sbi.rs +++ b/src/sbi.rs @@ -10,6 +10,7 @@ use rustsbi::RustSBI; /// Device reference for `RustSBI`. #[derive(RustSBI)] +#[allow(clippy::doc_markdown)] pub struct Sbi { /// Core Local INTerrupt #[rustsbi(ipi, timer)] @@ -26,6 +27,7 @@ pub struct Sbi { } impl Sbi { + /// Constructor for `Sbi` pub fn new(device_tree: Fdt) -> Self { Sbi { uart: uart::Uart::new(&device_tree, "/soc/serial"), From 9cb44fa0acba9a387316a238e5f5dcd81f91dd57 Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 22:58:45 +0900 Subject: [PATCH 86/99] [update] change struct type of hypervisor CSR to tuple struct --- src/device/iommu.rs | 2 +- src/h_extension/csrs.rs | 96 +++++-------------- .../exception/page_fault_handler.rs | 8 +- 3 files changed, 31 insertions(+), 75 deletions(-) diff --git a/src/device/iommu.rs b/src/device/iommu.rs index 34c190b..761b56e 100644 --- a/src/device/iommu.rs +++ b/src/device/iommu.rs @@ -40,7 +40,7 @@ impl IoMmu { unsafe { core::ptr::write_volatile(tc_addr.0 as *mut u64, 1); - core::ptr::write_volatile(iohgatp_addr.0 as *mut u64, hgatp::read().bits as u64); + core::ptr::write_volatile(iohgatp_addr.0 as *mut u64, hgatp::read().bits() as u64); } } } diff --git a/src/h_extension/csrs.rs b/src/h_extension/csrs.rs index fc59a1b..b16d235 100644 --- a/src/h_extension/csrs.rs +++ b/src/h_extension/csrs.rs @@ -9,7 +9,7 @@ macro_rules! impl_bits { #[allow(dead_code)] impl $register { pub fn bits(&self) -> usize { - self.bits + self.0 } } }; @@ -22,15 +22,11 @@ macro_rules! read_csr_as { #[inline] #[allow(dead_code)] pub fn read() -> $register { - $register { - bits: { - let csr_out; - unsafe { - core::arch::asm!(concat!("csrrs {0}, ", stringify!($csr_number), ", x0"), out(reg) csr_out); - } - csr_out - } + let csr_out; + unsafe { + core::arch::asm!(concat!("csrrs {0}, ", stringify!($csr_number), ", x0"), out(reg) csr_out); } + $register(csr_out) } }; } @@ -104,13 +100,9 @@ pub mod vstvec { /// vstvec register number. const VSTVEC: usize = 0x205; /// Virtual supervisor trap handler base address. - pub struct Vstvec { - /// bitmap - bits: usize, - } + pub struct Vstvec(usize); impl_bits!(Vstvec); - read_csr_as!(Vstvec, 0x205); write_csr_as!(0x205); } @@ -122,10 +114,7 @@ pub mod vsip { /// vsip register number. const VSIP: usize = 0x244; /// Virtual supervisor interrupt pending. - pub struct Vsip { - /// bitmap - bits: usize, - } + pub struct Vsip(usize); read_csr_as!(Vsip, 0x244); write_csr_as!(0x244); @@ -158,16 +147,13 @@ pub mod vsatp { /// vsatp register number. const VSATP: usize = 0x280; /// Virtual supervisor address translation and protection. - pub struct Vsatp { - /// bitmap - bits: usize, - } + pub struct Vsatp(usize); impl Vsatp { /// Current address-translation scheme #[inline] pub fn mode(&self) -> Mode { - match self.bits >> 60 { + match self.0 >> 60 { 0 => Mode::Bare, 8 => Mode::Sv39, 9 => Mode::Sv48, @@ -180,7 +166,7 @@ pub mod vsatp { /// Physical page number #[inline] pub fn ppn(&self) -> usize { - self.bits & 0xFFF_FFFF_FFFF // bits 0-43 + self.0 & 0xFFF_FFFF_FFFF // bits 0-43 } } @@ -204,10 +190,7 @@ pub mod hstatus { /// hstatus register number. const HSTATUS: usize = 0x600; /// hstatus util functions. - pub struct Hstatus { - /// bitmap - bits: usize, - } + pub struct Hstatus(usize); read_csr_as!(Hstatus, 0x600); write_csr_as!(0x600); @@ -230,10 +213,7 @@ pub mod hedeleg { /// hedeleg register number. const HEDELEG: usize = 0x602; /// Hypervisor exception delegation register. - pub struct Hedeleg { - /// bitmap - bits: usize, - } + pub struct Hedeleg(usize); /// Exception Kind that possible to delegate to lower privileged. /// @@ -264,10 +244,7 @@ pub mod hideleg { /// hideleg register number. const HIDELEG: usize = 0x603; /// Hypervisor interrupt delegation register. - pub struct Hideleg { - /// bitmap - bits: usize, - } + pub struct Hideleg(usize); read_csr_as!(Hideleg, 0x603); write_csr_as!(0x603); @@ -281,10 +258,7 @@ pub mod hie { /// hie register number. const HIE: usize = 0x604; /// Hypervisor interrupt-enable register. - pub struct Hie { - /// bitmap - bits: usize, - } + pub struct Hie(usize); set_csr_from_enum!(VsInterruptKind, 0x604); } @@ -296,10 +270,7 @@ pub mod hcounteren { /// hcounteren register number. const HCOUNTEREN: usize = 0x606; /// Hypervisor counter enable. - pub struct Hcounteren { - /// bitmap - bits: usize, - } + pub struct Hcounteren(usize); set_csr_as!(0x606); } @@ -311,10 +282,7 @@ pub mod henvcfg { /// henvcfg register number. const HENVCFG: usize = 0x60a; /// Hypervisor environment configuration register. - pub struct Henvcfg { - /// bitmap - bits: usize, - } + pub struct Henvcfg(usize); /// set STCE (63 bit) pub fn set_stce() { @@ -372,10 +340,7 @@ pub mod hstateen0 { /// hstateen0 register number. const HSTATEEN0: usize = 0x60c; /// Hypervisor State Enable 0 Register. - pub struct HstateEn0 { - /// bitmap - pub bits: usize, - } + pub struct HstateEn0(usize); /// Enable all state except `C` bit pub fn all_state_set() { @@ -399,11 +364,9 @@ pub mod htval { /// htval register number. const HTVAL: usize = 0x643; /// Hypervisor bad guest physical address. - pub struct Htval { - /// bitmap - pub bits: usize, - } + pub struct Htval(usize); + impl_bits!(Htval); read_csr_as!(Htval, 0x643); } @@ -416,10 +379,7 @@ pub mod hvip { /// hvip register number. const HVIP: usize = 0x645; /// Hypervisor virtual interrupt pending. - pub struct Hvip { - /// bitmap - bits: usize, - } + pub struct Hvip(usize); set_csr_from_enum!(VsInterruptKind, 0x645); clear_csr_from_enum!(VsInterruptKind, 0x645); @@ -435,11 +395,9 @@ pub mod htinst { /// htinst register number. const HTINST: usize = 0x64a; /// Hypervisor trap instruction (transformed). - pub struct Htinst { - /// bitmap - pub bits: usize, - } + pub struct Htinst(usize); + impl_bits!(Htinst); read_csr_as!(Htinst, 0x64a); write_csr_as!(0x64a); } @@ -451,20 +409,17 @@ pub mod hgatp { /// hgatp register number. const HGATP: usize = 0x680; /// Hypervisor guest address translation and protection. - pub struct Hgatp { - /// bitmap - pub bits: usize, - } + pub struct Hgatp(usize); impl Hgatp { /// Return ppn. pub fn ppn(&self) -> usize { - self.bits & 0xfff_ffff_ffff // 44 bit + self.0 & 0xfff_ffff_ffff // 44 bit } /// Return translation mode. pub fn mode(&self) -> Mode { - match (self.bits >> 60) & 0b1111 { + match (self.0 >> 60) & 0b1111 { 0 => Mode::Bare, 8 => Mode::Sv39x4, 9 => Mode::Sv48x4, @@ -488,6 +443,7 @@ pub mod hgatp { write((0xF & (mode as usize)) << 60 | (0x3FFF & vmid) << 44 | 0x0FFF_FFFF_FFFF & ppn); } + impl_bits!(Hgatp); read_csr_as!(Hgatp, 0x680); write_csr_as!(0x680); } diff --git a/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs b/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs index e889d36..a416888 100644 --- a/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs +++ b/src/trap/hypervisor_supervisor/exception/page_fault_handler.rs @@ -13,8 +13,8 @@ use raki::Instruction; /// Trap `Load guest page fault` exception. pub fn load_guest_page_fault() { - let fault_addr = HostPhysicalAddress(htval::read().bits << 2); - let fault_inst_value = htinst::read().bits; + let fault_addr = HostPhysicalAddress(htval::read().bits() << 2); + let fault_inst_value = htinst::read().bits(); // htinst bit 1 replaced with a 0. // thus it needed to flip bit 1. // ref: vol. II p.161 @@ -44,8 +44,8 @@ pub fn load_guest_page_fault() { /// Trap `Store guest page fault` exception. pub fn store_guest_page_fault() { - let fault_addr = HostPhysicalAddress(htval::read().bits << 2); - let fault_inst_value = htinst::read().bits; + let fault_addr = HostPhysicalAddress(htval::read().bits() << 2); + let fault_inst_value = htinst::read().bits(); // htinst bit 1 replaced with a 0. // thus it needed to flip bit 1. // ref: vol. II p.161 From 6fb9c4d2657b0493f4218cd951ebdce4a074571e Mon Sep 17 00:00:00 2001 From: Alingof Date: Mon, 14 Oct 2024 23:53:01 +0900 Subject: [PATCH 87/99] [update] update dts for network device --- guest.dtb | Bin 5108 -> 5112 bytes guest_image/build_dtb.sh | 6 ++++-- guest_image/guest.dts | 24 ++++++++++++------------ 3 files changed, 16 insertions(+), 14 deletions(-) diff --git a/guest.dtb b/guest.dtb index fc2c130a588c0049a319a282bbd374a2467f7104..72e09886f1a88b0995c98df4893635c20491c850 100644 GIT binary patch delta 139 zcmeyO{zF~h0`I@K3=G0Q7#J8V7#IXkOcW4joUl>j4-1p2`DQg%GbWZ9LYoXGC$PIH zoNT=z#k0V7!A;>$M^m#FJ03V$r+cZd@SeimT1Uyc7=_J8*o!$01b`+9GB7j%DG>et hJ&9c62`%><3-DBSzC%IpHqAA&`et gJCJ6~%+Jj&bpTqxz`zW|B0!wNz`(INU2q~30GVkiZU6uP diff --git a/guest_image/build_dtb.sh b/guest_image/build_dtb.sh index e3a1d29..f3fbdc9 100755 --- a/guest_image/build_dtb.sh +++ b/guest_image/build_dtb.sh @@ -17,10 +17,12 @@ if [ "$#" -eq 1 ]; then -bios none \ -m 256M \ -initrd ../vmlinux_debug \ - -device riscv-iommu-pci \ - -drive file=../rootfs.img,format=raw,id=hd0,if=none \ + -drive file=../rootfs.ext2,format=raw,id=hd0,if=none \ -device virtio-blk-device,drive=hd0 \ + -netdev user,id=n1 \ + -device virtio-net-pci,netdev=n1,rombar=0 \ -append "root=/dev/vda rw console=ttyS0" \ + -device riscv-iommu-pci \ -kernel ../target/riscv64imac-unknown-none-elf/debug/hikami \ -machine dumpdtb=qemu.dtb dtc -I dtb -O dts -o guest.dts qemu.dtb diff --git a/guest_image/guest.dts b/guest_image/guest.dts index 5aff2da..bcff46e 100644 --- a/guest_image/guest.dts +++ b/guest_image/guest.dts @@ -25,7 +25,7 @@ ranges = <0x00 0x00 0x4000000 0x2000000>; #address-cells = <0x01>; #size-cells = <0x01>; - compatible = "qemu,platform\0simple-bus"; + compatible = "qemu,platform", "simple-bus"; }; memory@90000000 { @@ -47,10 +47,10 @@ riscv,cbop-block-size = <0x40>; riscv,cboz-block-size = <0x40>; riscv,cbom-block-size = <0x40>; - riscv,isa-extensions = "i\0m\0a\0f\0d\0c\0h\0zic64b\0zicbom\0zicbop\0zicboz\0ziccamoa\0ziccif\0zicclsm\0ziccrse\0zicfiss\0zicntr\0zicsr\0zifencei\0zihintntl\0zihintpause\0zihpm\0zmmul\0za64rs\0zaamo\0zalrsc\0zawrs\0zfa\0zca\0zcd\0zba\0zbb\0zbc\0zbs\0ssccptr\0sscounterenw\0sstc\0sstvala\0sstvecd\0svadu"; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "h", "zic64b", "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicfiss", "zicntr", "zicsr", "zifencei", "zihintntl", "zihintpause", "zihpm", "zmmul", "za64rs", "zaamo", "zalrsc", "zawrs", "zfa", "zca", "zcd", "zba", "zbb", "zbc", "zbs", "ssccptr", "sscounterenw", "sstc", "sstvala", "sstvecd", "svadu"; riscv,isa-base = "rv64i"; riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicfiss_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zmmul_za64rs_zaamo_zalrsc_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu"; - mmu-type = "riscv,sv39"; + mmu-type = "riscv,sv57"; interrupt-controller { #interrupt-cells = <0x01>; @@ -90,10 +90,10 @@ chosen { bootargs = "root=/dev/vda rw console=ttyS0"; - linux,initrd-end = <0x00 0x97f67ce0>; + linux,initrd-end = <0x00 0x9812b230>; linux,initrd-start = <0x00 0x88000000>; stdout-path = "/soc/serial@10000000"; - rng-seed = <0xcaf53f7f 0x52fe6542 0xf3156947 0xa50b572d 0xc6f64192 0x47d6e429 0x1985224b 0xe8a94cc2>; + rng-seed = <0xc985d81a 0xca04da0 0xd913f2c5 0x656aa341 0xc0c97e2d 0xd28e71de 0x20dd7d41 0x197e5c20>; }; soc { @@ -112,7 +112,7 @@ serial@10000000 { interrupts = <0x0a>; interrupt-parent = <0x03>; - clock-frequency = "\08@"; + clock-frequency = "", "8@"; reg = <0x00 0x10000000 0x00 0x100>; compatible = "ns16550a"; }; @@ -120,7 +120,7 @@ test@100000 { phandle = <0x04>; reg = <0x00 0x100000 0x00 0x1000>; - compatible = "sifive,test1\0sifive,test0\0syscon"; + compatible = "sifive,test1", "sifive,test0", "syscon"; }; virtio_mmio@10008000 { @@ -185,7 +185,7 @@ reg = <0x00 0xc000000 0x00 0x600000>; interrupts-extended = <0x02 0x0b 0x02 0x09>; interrupt-controller; - compatible = "sifive,plic-1.0.0\0riscv,plic0"; + compatible = "sifive,plic-1.0.0", "riscv,plic0"; #address-cells = <0x00>; #interrupt-cells = <0x01>; }; @@ -193,7 +193,7 @@ clint@2000000 { interrupts-extended = <0x02 0x03 0x02 0x07>; reg = <0x00 0x2000000 0x00 0x10000>; - compatible = "sifive,clint0\0riscv,clint0"; + compatible = "sifive,clint0", "riscv,clint0"; }; pci@30000000 { @@ -213,10 +213,10 @@ #size-cells = <0x02>; #interrupt-cells = <0x01>; #address-cells = <0x03>; - iommu-map = <0x00 0x8000 0x00 0x08 0x09 0x8000 0x09 0xfff7>; + iommu-map = <0x00 0x8000 0x00 0x10 0x11 0x8000 0x11 0xffef>; - iommu@8 { - reg = <0x800 0x00 0x00 0x00 0x00>; + iommu@10 { + reg = <0x1000 0x00 0x00 0x00 0x00>; phandle = <0x8000>; #iommu-cells = <0x01>; compatible = "riscv,pci-iommu"; From 107de300a1c5e821ae71aa4edb5df9c64351b937 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 16:41:15 +0900 Subject: [PATCH 88/99] [fix] fix `LEAF_DDT_ENTRY_SIZE` --- src/device/iommu.rs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/device/iommu.rs b/src/device/iommu.rs index 761b56e..975cf42 100644 --- a/src/device/iommu.rs +++ b/src/device/iommu.rs @@ -30,8 +30,10 @@ impl IoMmu { fn init_page_table(ddt_addr: HostPhysicalAddress) { /// Offset of `iohgatp` register. const OFFSET_IOHGATP: usize = 8; - /// Size of leaf ddt entry. - const LEAF_DDT_ENTRY_SIZE: usize = 512; + /// Size of leaf ddt entry [byte]. + const LEAF_DDT_ENTRY_SIZE: usize = 64; // 512 / 8 = 64 [byte] + /// V field in TC regsiter. + const TC_V: u64 = 1; // set all ddt entry for offset in (0..PAGE_SIZE).step_by(LEAF_DDT_ENTRY_SIZE) { @@ -39,7 +41,7 @@ impl IoMmu { let iohgatp_addr = ddt_addr + offset + OFFSET_IOHGATP; unsafe { - core::ptr::write_volatile(tc_addr.0 as *mut u64, 1); + core::ptr::write_volatile(tc_addr.0 as *mut u64, TC_V); core::ptr::write_volatile(iohgatp_addr.0 as *mut u64, hgatp::read().bits() as u64); } } From 43fc5743d22f3e3decf6c3e39e6a1c3580b22ad3 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 16:42:06 +0900 Subject: [PATCH 89/99] [refator][update] replace some value to constants --- src/device/iommu.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/src/device/iommu.rs b/src/device/iommu.rs index 975cf42..2425720 100644 --- a/src/device/iommu.rs +++ b/src/device/iommu.rs @@ -28,7 +28,7 @@ pub struct IoMmu { impl IoMmu { /// Set page table in IOMMU. fn init_page_table(ddt_addr: HostPhysicalAddress) { - /// Offset of `iohgatp` register. + /// Offset of `iohgatp` register [byte]. const OFFSET_IOHGATP: usize = 8; /// Size of leaf ddt entry [byte]. const LEAF_DDT_ENTRY_SIZE: usize = 64; // 512 / 8 = 64 [byte] @@ -62,6 +62,7 @@ impl PciDevice for IoMmu { | u32::from(pci_reg.address[2]) << 8 | u32::from(pci_reg.address[3]); + // https://www.kernel.org/doc/Documentation/devicetree/bindings/pci/pci.txt Some(IoMmu { bus: pci_first_reg >> 16 & 0b1111_1111, // 8 bit device: pci_first_reg >> 11 & 0b1_1111, // 5 bit @@ -116,9 +117,9 @@ impl PciDevice for IoMmu { // Let k=log2(N) and B be the physical page number (PPN) of the allocated memory buffer. // CQB.PPN = B, CQB.LOG2SZ-1 = k - 1 let command_queue = PageBlock::alloc(); - let command_queue_ptr = command_queue.0 as *mut [u8; 0x1000]; + let command_queue_ptr = command_queue.0 as *mut u8; unsafe { - core::ptr::write_bytes(command_queue_ptr, 0u8, 1); + core::ptr::write_bytes(command_queue_ptr, 0u8, PAGE_SIZE); } registers.cqb.set(command_queue, 4096); // cqt = 0 @@ -134,9 +135,9 @@ impl PciDevice for IoMmu { // Let k=log2(N) and B be the PPN of the allocated memory buffer. // FQB.PPN = B, FQB.LOG2SZ-1 = k - 1 let fault_queue = PageBlock::alloc(); - let fault_queue_ptr = fault_queue.0 as *mut [u8; 0x1000]; + let fault_queue_ptr = fault_queue.0 as *mut u8; unsafe { - core::ptr::write_bytes(fault_queue_ptr, 0u8, 1); + core::ptr::write_bytes(fault_queue_ptr, 0u8, PAGE_SIZE); } registers.fqb.set(fault_queue, 4096); // fqt = 0 @@ -152,9 +153,9 @@ impl PciDevice for IoMmu { // Let k=log2(N) and B be the PPN of the allocated memory buffer. // PQB.PPN = B, PQB.LOG2SZ-1 = k - 1 let page_request_queue = PageBlock::alloc(); - let page_request_queue_ptr = page_request_queue.0 as *mut [u8; 0x1000]; + let page_request_queue_ptr = page_request_queue.0 as *mut u8; unsafe { - core::ptr::write_bytes(page_request_queue_ptr, 0u8, 1); + core::ptr::write_bytes(page_request_queue_ptr, 0u8, PAGE_SIZE); } registers.pqb.set(page_request_queue, 4096); // pqt = 0 @@ -166,9 +167,9 @@ impl PciDevice for IoMmu { // 15. To program the DDT pointer, first determine the supported device_id width Dw and the format of the device-context data structure. let ddt_addr = PageBlock::alloc(); - let ddt_ptr = ddt_addr.0 as *mut [u8; 0x1000]; + let ddt_ptr = ddt_addr.0 as *mut u8; unsafe { - core::ptr::write_bytes(ddt_ptr, 0u8, 1); + core::ptr::write_bytes(ddt_ptr, 0u8, PAGE_SIZE); } Self::init_page_table(ddt_addr); registers.ddtp.set(IoMmuMode::Lv1, ddt_addr); From bc9c27730d540a891eeaba924d741d14f4480b6f Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 16:56:50 +0900 Subject: [PATCH 90/99] [update] add host option to build_dtb.sh to create dtb for hypervisor --- guest_image/build_dtb.sh | 94 ++++++++++++++++++++++++++++++++-------- 1 file changed, 76 insertions(+), 18 deletions(-) diff --git a/guest_image/build_dtb.sh b/guest_image/build_dtb.sh index f3fbdc9..cd30928 100755 --- a/guest_image/build_dtb.sh +++ b/guest_image/build_dtb.sh @@ -1,8 +1,45 @@ #!/bin/bash +qemu_path="../../qemu_iommu/build/qemu-system-riscv64" + function help() { - echo "create: create dts from qemu dtb" - echo "build: build dtb from guest.dts" + echo "create [host/guest/all]: create host or guest dts from qemu dtb" + echo "build [host/guest/all]: build host or guest dtb from guest.dts" +} + +function create_host() { + $qemu_path -S -gdb tcp::10000 \ + -machine virt \ + -bios none \ + -m 256M \ + -initrd ../vmlinux_debug \ + -drive file=../rootfs.ext2,format=raw,id=hd0,if=none \ + -device virtio-blk-device,drive=hd0 \ + -netdev user,id=n1 \ + -device virtio-net-pci,netdev=n1 \ + -device riscv-iommu-pci \ + -append "root=/dev/vda rw console=ttyS0" \ + -kernel ../target/riscv64imac-unknown-none-elf/debug/hikami \ + -machine dumpdtb=qemu.dtb + dtc -I dtb -O dts -o host.dts qemu.dtb + rm -f qemu.dtb +} + +function create_guest() { + $qemu_path -S -gdb tcp::10000 \ + -machine virt \ + -bios none \ + -m 256M \ + -initrd ../vmlinux_debug \ + -drive file=../rootfs.ext2,format=raw,id=hd0,if=none \ + -device virtio-blk-device,drive=hd0 \ + -netdev user,id=n1 \ + -device virtio-net-pci,netdev=n1 \ + -append "root=/dev/vda rw console=ttyS0" \ + -kernel ../target/riscv64imac-unknown-none-elf/debug/hikami \ + -machine dumpdtb=qemu.dtb + dtc -I dtb -O dts -o guest.dts qemu.dtb + rm -f qemu.dtb } if [ "$#" -eq 0 ]; then @@ -10,26 +47,47 @@ if [ "$#" -eq 0 ]; then fi if [ "$#" -eq 1 ]; then + echo "specify target: host or guest or all" + help +fi + +if [ "$#" -eq 2 ]; then case "$1" in "create") - qemu-system-riscv64 -S -gdb tcp::10000 \ - -machine virt \ - -bios none \ - -m 256M \ - -initrd ../vmlinux_debug \ - -drive file=../rootfs.ext2,format=raw,id=hd0,if=none \ - -device virtio-blk-device,drive=hd0 \ - -netdev user,id=n1 \ - -device virtio-net-pci,netdev=n1,rombar=0 \ - -append "root=/dev/vda rw console=ttyS0" \ - -device riscv-iommu-pci \ - -kernel ../target/riscv64imac-unknown-none-elf/debug/hikami \ - -machine dumpdtb=qemu.dtb - dtc -I dtb -O dts -o guest.dts qemu.dtb - rm -f qemu.dtb + case "$2" in + "host") + create_host + ;; + "guest") + create_guest + ;; + "all") + create_host + create_guest + ;; + *) + echo "specify target: host or guest or all" + help + ;; + esac ;; "build") - dtc -I dts -O dtb -o ../guest.dtb guest.dts + case "$2" in + "host") + dtc -I dts -O dtb -o ../host.dtb guest.dts + ;; + "guest") + dtc -I dts -O dtb -o ../guest.dtb guest.dts + ;; + "all") + dtc -I dts -O dtb -o ../host.dtb guest.dts + dtc -I dts -O dtb -o ../guest.dtb guest.dts + ;; + *) + echo "specify target: host or guest or all" + help + ;; + esac ;; *) echo "command not found" From b2744971704870667165989215d088f436659eb5 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 17:09:38 +0900 Subject: [PATCH 91/99] [add] add host.dts and host.dtb --- guest.dtb | Bin 5112 -> 4933 bytes guest_image/build_dtb.sh | 4 +- guest_image/guest.dts | 16 +-- guest_image/host.dts | 222 +++++++++++++++++++++++++++++++++++++++ host.dtb | Bin 0 -> 4933 bytes 5 files changed, 226 insertions(+), 16 deletions(-) create mode 100644 guest_image/host.dts create mode 100644 host.dtb diff --git a/guest.dtb b/guest.dtb index 72e09886f1a88b0995c98df4893635c20491c850..67ca935ec7be542056c8d1c5787c7a3cc1d58334 100644 GIT binary patch delta 92 zcmeyNepF540`I@K3=G1q3=9kw3=D!gKw1Nc1%X%qh=G7f63G0rQKN=kL7R1f$#cv7 q+XHnKR6o3#{vy+IUYoq`)0L;rEm^gGt6S*iBka+fn|BMUF#!ND(HwFB delta 271 zcmX@A_CsCc0`I@K3=G0Q7#J8V7#IXk0BH>%76f7eAO->^10Z+8MvWSFg_Er}q<9wi zF1RWD>1b-!V#fm~>vS*m72Z?0Tk9xU7o)KG2zxYVJu^^~0#KhMNH+sR1DFI7AoGCc zg84xD|9c>xF*83mx75K9Xa^X8^ojs+3fy{#IE)0zvjA~5)Ep?ENf{`{2*g0X6xbr^ qqRistGM$3tOkJ=QKsg4c%`$?TOyXd^Zf;@$gEEAfoSKtU%m4tx%`-dz diff --git a/guest_image/build_dtb.sh b/guest_image/build_dtb.sh index cd30928..2774063 100755 --- a/guest_image/build_dtb.sh +++ b/guest_image/build_dtb.sh @@ -74,13 +74,13 @@ if [ "$#" -eq 2 ]; then "build") case "$2" in "host") - dtc -I dts -O dtb -o ../host.dtb guest.dts + dtc -I dts -O dtb -o ../host.dtb host.dts ;; "guest") dtc -I dts -O dtb -o ../guest.dtb guest.dts ;; "all") - dtc -I dts -O dtb -o ../host.dtb guest.dts + dtc -I dts -O dtb -o ../host.dtb host.dts dtc -I dts -O dtb -o ../guest.dtb guest.dts ;; *) diff --git a/guest_image/guest.dts b/guest_image/guest.dts index bcff46e..ffe6b00 100644 --- a/guest_image/guest.dts +++ b/guest_image/guest.dts @@ -93,7 +93,7 @@ linux,initrd-end = <0x00 0x9812b230>; linux,initrd-start = <0x00 0x88000000>; stdout-path = "/soc/serial@10000000"; - rng-seed = <0xc985d81a 0xca04da0 0xd913f2c5 0x656aa341 0xc0c97e2d 0xd28e71de 0x20dd7d41 0x197e5c20>; + rng-seed = <0x2b05a034 0xe739bfb7 0x512d2025 0xf0ec97e8 0x69399e86 0x1f2de5a9 0xcacea4aa 0xafb54655>; }; soc { @@ -199,11 +199,7 @@ pci@30000000 { interrupt-map-mask = <0x1800 0x00 0x00 0x07>; interrupt-map = <0x00 0x00 0x00 0x01 0x03 0x20 0x00 0x00 0x00 0x02 0x03 0x21 0x00 0x00 0x00 0x03 0x03 0x22 0x00 0x00 0x00 0x04 0x03 0x23 0x800 0x00 0x00 0x01 0x03 0x21 0x800 0x00 0x00 0x02 0x03 0x22 0x800 0x00 0x00 0x03 0x03 0x23 0x800 0x00 0x00 0x04 0x03 0x20 0x1000 0x00 0x00 0x01 0x03 0x22 0x1000 0x00 0x00 0x02 0x03 0x23 0x1000 0x00 0x00 0x03 0x03 0x20 0x1000 0x00 0x00 0x04 0x03 0x21 0x1800 0x00 0x00 0x01 0x03 0x23 0x1800 0x00 0x00 0x02 0x03 0x20 0x1800 0x00 0x00 0x03 0x03 0x21 0x1800 0x00 0x00 0x04 0x03 0x22>; - // BUS_ADDRESS(3) CPU_PHYSICAL(2) SIZE(2) - ranges = < - 0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 - 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 - 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; reg = <0x00 0x30000000 0x00 0x10000000>; dma-coherent; bus-range = <0x00 0xff>; @@ -213,14 +209,6 @@ #size-cells = <0x02>; #interrupt-cells = <0x01>; #address-cells = <0x03>; - iommu-map = <0x00 0x8000 0x00 0x10 0x11 0x8000 0x11 0xffef>; - - iommu@10 { - reg = <0x1000 0x00 0x00 0x00 0x00>; - phandle = <0x8000>; - #iommu-cells = <0x01>; - compatible = "riscv,pci-iommu"; - }; }; }; }; diff --git a/guest_image/host.dts b/guest_image/host.dts new file mode 100644 index 0000000..9c840f5 --- /dev/null +++ b/guest_image/host.dts @@ -0,0 +1,222 @@ +/dts-v1/; + +/ { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "riscv-virtio"; + model = "riscv-virtio,qemu"; + + poweroff { + value = <0x5555>; + offset = <0x00>; + regmap = <0x04>; + compatible = "syscon-poweroff"; + }; + + reboot { + value = <0x7777>; + offset = <0x00>; + regmap = <0x04>; + compatible = "syscon-reboot"; + }; + + platform-bus@4000000 { + interrupt-parent = <0x03>; + ranges = <0x00 0x00 0x4000000 0x2000000>; + #address-cells = <0x01>; + #size-cells = <0x01>; + compatible = "qemu,platform", "simple-bus"; + }; + + memory@80000000 { + device_type = "memory"; + reg = <0x00 0x80000000 0x00 0x10000000>; + }; + + cpus { + #address-cells = <0x01>; + #size-cells = <0x00>; + timebase-frequency = <0x989680>; + + cpu@0 { + phandle = <0x01>; + device_type = "cpu"; + reg = <0x00>; + status = "okay"; + compatible = "riscv"; + riscv,cbop-block-size = <0x40>; + riscv,cboz-block-size = <0x40>; + riscv,cbom-block-size = <0x40>; + riscv,isa-extensions = "i", "m", "a", "f", "d", "c", "h", "zic64b", "zicbom", "zicbop", "zicboz", "ziccamoa", "ziccif", "zicclsm", "ziccrse", "zicntr", "zicsr", "zifencei", "zihintntl", "zihintpause", "zihpm", "zmmul", "za64rs", "zaamo", "zalrsc", "zawrs", "zfa", "zca", "zcd", "zba", "zbb", "zbc", "zbs", "ssccptr", "sscounterenw", "sstc", "sstvala", "sstvecd", "svadu"; + riscv,isa-base = "rv64i"; + riscv,isa = "rv64imafdch_zic64b_zicbom_zicbop_zicboz_ziccamoa_ziccif_zicclsm_ziccrse_zicntr_zicsr_zifencei_zihintntl_zihintpause_zihpm_zmmul_za64rs_zaamo_zalrsc_zawrs_zfa_zca_zcd_zba_zbb_zbc_zbs_ssccptr_sscounterenw_sstc_sstvala_sstvecd_svadu"; + mmu-type = "riscv,sv57"; + + interrupt-controller { + #interrupt-cells = <0x01>; + interrupt-controller; + compatible = "riscv,cpu-intc"; + phandle = <0x02>; + }; + }; + + cpu-map { + + cluster0 { + + core0 { + cpu = <0x01>; + }; + }; + }; + }; + + pmu { + riscv,event-to-mhpmcounters = <0x01 0x01 0x7fff9 0x02 0x02 0x7fffc 0x10019 0x10019 0x7fff8 0x1001b 0x1001b 0x7fff8 0x10021 0x10021 0x7fff8>; + compatible = "riscv,pmu"; + }; + + fw-cfg@10100000 { + dma-coherent; + reg = <0x00 0x10100000 0x00 0x18>; + compatible = "qemu,fw-cfg-mmio"; + }; + + flash@20000000 { + bank-width = <0x04>; + reg = <0x00 0x20000000 0x00 0x2000000 0x00 0x22000000 0x00 0x2000000>; + compatible = "cfi-flash"; + }; + + chosen { + bootargs = "root=/dev/vda rw console=ttyS0"; + linux,initrd-end = <0x00 0x9812b230>; + linux,initrd-start = <0x00 0x88000000>; + stdout-path = "/soc/serial@10000000"; + rng-seed = <0x43b57d4e 0xc47d1e53 0xf72be401 0x8782f496 0x6b3aef66 0xccfa8bb3 0x710c4d0d 0x40c7b7c6>; + }; + + soc { + #address-cells = <0x02>; + #size-cells = <0x02>; + compatible = "simple-bus"; + ranges; + + rtc@101000 { + interrupts = <0x0b>; + interrupt-parent = <0x03>; + reg = <0x00 0x101000 0x00 0x1000>; + compatible = "google,goldfish-rtc"; + }; + + serial@10000000 { + interrupts = <0x0a>; + interrupt-parent = <0x03>; + clock-frequency = "", "8@"; + reg = <0x00 0x10000000 0x00 0x100>; + compatible = "ns16550a"; + }; + + test@100000 { + phandle = <0x04>; + reg = <0x00 0x100000 0x00 0x1000>; + compatible = "sifive,test1", "sifive,test0", "syscon"; + }; + + virtio_mmio@10008000 { + interrupts = <0x08>; + interrupt-parent = <0x03>; + reg = <0x00 0x10008000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10007000 { + interrupts = <0x07>; + interrupt-parent = <0x03>; + reg = <0x00 0x10007000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10006000 { + interrupts = <0x06>; + interrupt-parent = <0x03>; + reg = <0x00 0x10006000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10005000 { + interrupts = <0x05>; + interrupt-parent = <0x03>; + reg = <0x00 0x10005000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10004000 { + interrupts = <0x04>; + interrupt-parent = <0x03>; + reg = <0x00 0x10004000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10003000 { + interrupts = <0x03>; + interrupt-parent = <0x03>; + reg = <0x00 0x10003000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10002000 { + interrupts = <0x02>; + interrupt-parent = <0x03>; + reg = <0x00 0x10002000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + virtio_mmio@10001000 { + interrupts = <0x01>; + interrupt-parent = <0x03>; + reg = <0x00 0x10001000 0x00 0x1000>; + compatible = "virtio,mmio"; + }; + + plic@c000000 { + phandle = <0x03>; + riscv,ndev = <0x5f>; + reg = <0x00 0xc000000 0x00 0x600000>; + interrupts-extended = <0x02 0x0b 0x02 0x09>; + interrupt-controller; + compatible = "sifive,plic-1.0.0", "riscv,plic0"; + #address-cells = <0x00>; + #interrupt-cells = <0x01>; + }; + + clint@2000000 { + interrupts-extended = <0x02 0x03 0x02 0x07>; + reg = <0x00 0x2000000 0x00 0x10000>; + compatible = "sifive,clint0", "riscv,clint0"; + }; + + pci@30000000 { + interrupt-map-mask = <0x1800 0x00 0x00 0x07>; + interrupt-map = <0x00 0x00 0x00 0x01 0x03 0x20 0x00 0x00 0x00 0x02 0x03 0x21 0x00 0x00 0x00 0x03 0x03 0x22 0x00 0x00 0x00 0x04 0x03 0x23 0x800 0x00 0x00 0x01 0x03 0x21 0x800 0x00 0x00 0x02 0x03 0x22 0x800 0x00 0x00 0x03 0x03 0x23 0x800 0x00 0x00 0x04 0x03 0x20 0x1000 0x00 0x00 0x01 0x03 0x22 0x1000 0x00 0x00 0x02 0x03 0x23 0x1000 0x00 0x00 0x03 0x03 0x20 0x1000 0x00 0x00 0x04 0x03 0x21 0x1800 0x00 0x00 0x01 0x03 0x23 0x1800 0x00 0x00 0x02 0x03 0x20 0x1800 0x00 0x00 0x03 0x03 0x21 0x1800 0x00 0x00 0x04 0x03 0x22>; + ranges = <0x1000000 0x00 0x00 0x00 0x3000000 0x00 0x10000 0x2000000 0x00 0x40000000 0x00 0x40000000 0x00 0x40000000 0x3000000 0x04 0x00 0x04 0x00 0x04 0x00>; + reg = <0x00 0x30000000 0x00 0x10000000>; + dma-coherent; + bus-range = <0x00 0xff>; + linux,pci-domain = <0x00>; + device_type = "pci"; + compatible = "pci-host-ecam-generic"; + #size-cells = <0x02>; + #interrupt-cells = <0x01>; + #address-cells = <0x03>; + iommu-map = <0x00 0x8000 0x00 0x10 0x11 0x8000 0x11 0xffef>; + + iommu@10 { + reg = <0x1000 0x00 0x00 0x00 0x00>; + phandle = <0x8000>; + #iommu-cells = <0x01>; + compatible = "riscv,pci-iommu"; + }; + }; + }; +}; diff --git a/host.dtb b/host.dtb new file mode 100644 index 0000000000000000000000000000000000000000..67ca935ec7be542056c8d1c5787c7a3cc1d58334 GIT binary patch literal 4933 zcmbVQ%ZnUE7_W}THEMJd9~cJA#GoinC$n+0Nx;Bd6ucQUlG~)GyJn_MztYt+n_Vvf zLBxZ2(%?Y?deMV|px*SXi1-h9@F03n$-zSuN&Nll(bF?o6V?x^zej!by{fvps(;vh z?RO#We^v-_T!=j#;3v@bpe>^TcI*TBr=jPbp5<->zTMJ0fE|AyXvgmc-6~@hPW@?I zR&j3isk;~L@n&D=yi6xX!7K80S?0rGL!Z77=jqeH&exHJ{uAJ-$A0F~QX4AFGrwt$ zv3aE&ExTkUF~BY=y$XK5GbDRvSV zJOczcUDB+%<5^$FV~#|NW$QSnLd9v3Ncu(}LFb#wG%q)LCrmV5%4u&2?TqQ8NXuBa zh|Jr304M-xJ7H1Vb@8yz#l!F!AHnsH#ie&Hg7+}Cr#;X5UZuRDdj>jS>#;fx%kKn! zEk74*Pys;ucc7W|MagX3o1l9Q{_+CS=EHAv#KOgd=6z6${55r&Z?|REL8*(J!V|MLYht>57t&o z3=iN0&!ki#&^kp!I1Sk%u{i)9AjAQB2TCXvh6UUK=aa0GrOejBR3RVJAPF><7^$W~ zRM(jG`>C9+t;Qe#tmz+USF|h*hEX`~BL!502-PsCFlduVS3?u=P$N`BV^o8f)gVSS zh!mfu8X#;nETyYKx_|{%qi?DKglgc)Y5<`ceN>~5YM@1ZR09nm4$wPLeOnFUx*A}r zkPlWvV^pJGSHt9fH*)`5?@1jsJ$eir)+Z)RmgS_Vd~79EnJ0-Xbx*zCJl4&vW0DWx zK^fl#vpzdm**+|VkksP@*FWDY*Z7Y3X;4td3zLb0XZy;4&r3P~{&-JPuQ9&1Q<$BU zF+2km-|Bf{>H1%_{?he-FnXVEOV_Ugw{$b~0ni7ae--+)a~GP;#ag#}!f@RWhojy~ zcctFys1NX-$Ak1Tntqp;Nf~$;h<*I#m_5uG^3$~bPB0&Dm;`FvJJQ&?^f>G_-plCc zoRhlgeQn$HYhU3wS2EKA>g|V*pv0HrqGnGJXv1!EbaO~5yvUg{dEl5Go@I(0P5~SYh`L>?dZ{NKp{Zat&*y; z#iz{q;e5F@RoitRLHjkN?g2E^au`o#ho)BW>8+WrFeeY_5VSvY0_t;lYq!TS?WWuL z);VJxIesqZI+kT|(GJtuGM0PLTE>3Iy*^v|Jhrt@o&#L|Jxh~s_$S|HmhfdUmk&q36@BCE^|$``DONga)EV1lWF_PjBth z`M8Ns7wYzXawj(Nx?1Wyx!!Ev|CMLk4%@y@?vY#g+g>I!ob zp`fev>s$?2=U$&bXdmYWoHN|_ayG6R3;k2qz4vtv6l&1hr}ozZ?_$%YU0jx-y7pUy zagXbfplz7===Vn<__?pa`t>fN?@BE-gqzd$f}B1WH}~BpP{#IXQwW-CpYntH(>&{R z_F;!xZ4J&o?99oX{Y5*@e%r1sXUN%y9hS8QXCHRv-=7clKdt zPVVe4+Hv*~r>@gWz^7=u2^_2e9dtnG>E}GQdbCMc#O!9$5j(ql0BjZP(E6;1;(OPO zhPV#Qe%RaLCdKmN4AvXf$UlVE0`KGaR{0WF5`QE!oGn6X)HdeMLa-wjBcA1F_lF|Dy$tdo z8%ZT_qKre?uQm!vRZ+#M90W@G!&07~;J&yaigA!dFs`bg!o}O{2e^h6{vgT2b3Q|v zNjJBY;y=WqZma@dUZ`ZIVjN|y0Sf7U#tK})d>!7wSq`QM4Ssef;^p0hD5uENuW~=d zRnFeQkZ>B{3N_~Cv=W0LJLj**Q8gC)6%&*rC9rW#E_C87uFA-lSu`&|5y}dsi1JD0 zqwHf*W+Puo8O=(pM5vRUmCyu~q1X*AlYP`2$!iyyIyY0(H!=K3@%4n+V7SVnJPqPZ F{0nT@1kwNi literal 0 HcmV?d00001 From c44e3cfaffc9c48e40b7ae5501dc86f90b19337d Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 17:53:48 +0900 Subject: [PATCH 92/99] [add] add host.dtb and `HOST_DTB` --- host.dtb | Bin 4933 -> 5096 bytes memory.x | 6 ++++++ src/main.rs | 4 ++++ 3 files changed, 10 insertions(+) diff --git a/host.dtb b/host.dtb index 67ca935ec7be542056c8d1c5787c7a3cc1d58334..f8f70461627d4800c9679264974f6017c6f9aff4 100644 GIT binary patch delta 304 zcmX@A_Cj6b0`I@K3=G0A7#J8V7#IY10BH>%76f7eAO->^10c6yqsDngMvKWm7{w^QY#nyUHb`Rd()R`*;en<&iv}$ zT*%|g>u`MgvCT)=qdDuDfuRVLZHQ9K9K(Z9>{0R%+Jj&bua`v z0t`TUMSwU3?mmb(j0DNE0C6?c94Mbj87RgG#6Z3j*dpno%;MxSor2^{U9c5EIR>W9 ZGJ={+;$XgRZejt0GK86&nv+w^005CaKDPh> delta 135 zcmaE%epF540`I@K3=G1q3=9kw3=D!gKw1Nc1%X%qh=G7f63G0rQR6%#qvhluj5>@H zCaW?%WBf3ghdGcXEwi|IawPLE#&?rNSp31<&G9Uz%nI793rwC{?%y7$tDySf&GZ+U fmh;-=b)T+0b#BS3^;_LSH*aB&=G?qmP>l%yT+Axy diff --git a/memory.x b/memory.x index 167c9eb..caaa17b 100644 --- a/memory.x +++ b/memory.x @@ -33,6 +33,12 @@ SECTIONS _top_m_stack = .; } > MACHINE_RAM + .host_dtb : ALIGN(4K) + { + *(.host_dtb); + . = ALIGN(4K); + } > REGION_DATA + .guest_dtb : ALIGN(4K) { *(.guest_dtb); diff --git a/src/main.rs b/src/main.rs index 782f537..5da01bc 100644 --- a/src/main.rs +++ b/src/main.rs @@ -54,6 +54,10 @@ static mut HYPERVISOR_DATA: Mutex> = Mutex::new(OnceCel /// Singleton for SBI handler. static SBI: Mutex> = Mutex::new(OnceCell::new()); +/// Device tree blob that is passed to hypervisor +#[link_section = ".host_dtb"] +static HOST_DTB: [u8; include_bytes!("../host.dtb").len()] = *include_bytes!("../host.dtb"); + /// Device tree blob that is passed to guest #[link_section = ".guest_dtb"] static GUEST_DTB: [u8; include_bytes!("../guest.dtb").len()] = *include_bytes!("../guest.dtb"); From 637dcc66c59f305ce881d76c2ce606fae8073e18 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 18:09:47 +0900 Subject: [PATCH 93/99] [add] add `embedded_host_dtb` flag for embed host dtb data to binary to support environments other than QEMU --- Cargo.toml | 5 +++++ src/main.rs | 1 + 2 files changed, 6 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index 7dccfa6..ac3e49e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -13,6 +13,11 @@ missing_docs = "warn" [lints.rustdoc] missing_crate_level_docs = "warn" + +[features] +# for real device +embedded_host_dtb = [] + [dependencies] elf = { version = "0.7.2", default-features = false } fdt = "0.1.5" diff --git a/src/main.rs b/src/main.rs index 5da01bc..1c4ee0c 100644 --- a/src/main.rs +++ b/src/main.rs @@ -55,6 +55,7 @@ static mut HYPERVISOR_DATA: Mutex> = Mutex::new(OnceCel static SBI: Mutex> = Mutex::new(OnceCell::new()); /// Device tree blob that is passed to hypervisor +#[cfg(feature = "embedded_host_dtb")] #[link_section = ".host_dtb"] static HOST_DTB: [u8; include_bytes!("../host.dtb").len()] = *include_bytes!("../host.dtb"); From 1cb06ba218669a88821bca1d590638245a11245e Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 18:20:36 +0900 Subject: [PATCH 94/99] [add] add network device to qemu option --- .cargo/config.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.cargo/config.toml b/.cargo/config.toml index e1b6672..f071678 100644 --- a/.cargo/config.toml +++ b/.cargo/config.toml @@ -9,6 +9,8 @@ qemu-system-riscv64 -initrd vmlinux_debug -drive file=rootfs.ext2,format=raw,id=hd0,if=none -device virtio-blk-pci,drive=hd0,iommu_platform=true,disable-legacy=on +-netdev user,id=n1 +-device virtio-net-pci,netdev=n1,iommu_platform=true,disable-legacy=on -append root=/dev/vda,rw,console=ttyS0 -device riscv-iommu-pci -kernel From e9a39658c4802be1303fe9bd41b025ccc019acc3 Mon Sep 17 00:00:00 2001 From: Alingof Date: Tue, 15 Oct 2024 19:44:27 +0900 Subject: [PATCH 95/99] [doc] update crate doc comment to load from README.md --- README.md | 10 +++++----- src/main.rs | 14 +------------- 2 files changed, 6 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 8554c6e..8972350 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Poster in RISC-V Days Tokyo 2024 Summer: [PDF](https://riscv.or.jp/wp-content/up ## Run Linux ### Build QEMU We need to build manually the QEMU to support IOMMU. -``` +```sh $ git clone https://github.com/qemu/qemu.git -b staging $ cd qemu/ # https://patchwork.ozlabs.org/project/qemu-devel/list/?series=417654 @@ -21,7 +21,7 @@ $ make -j $(nproc) Ver. 9.2 or later should officially support IOMMU, so it should no longer be necessary to apply patches. ### Build Linux -``` +```sh $ git clone https://github.com/torvalds/linux -b v6.9 $ cd /path/to/this/repository @@ -35,7 +35,7 @@ $ mv vmlinux /path/to/this/repository See also for custom guest image: `guest_image/README.md`. ### Create rootfs -``` +```sh $ git clone https://gitee.com/mirrors/busyboxsource.git $ cd busyboxsource @@ -70,13 +70,13 @@ $ mv rootfs.img /path/to/this/repository ``` ### Run -``` +```sh # The actual command to be executed is written in .cargo/config.toml. $ cargo r ``` ## Documents -``` +```sh $ cargo doc --open ``` diff --git a/src/main.rs b/src/main.rs index 1c4ee0c..c92c991 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,4 @@ -//! hikami - Light weight type-1 hypervisor for RISC-V H-extension. -//! -//! ## Run -//! ```no_run -//! # The actual command to be executed is written in .cargo/config.toml. -//! $ cargo r -//! ``` -//! -//! ## Documents -//! ```no_run -//! $ cargo doc --open -//! ``` - +#![doc = include_str!("../README.md")] #![no_main] #![no_std] From 351a4b7814e0d9038edbea1d8c735c8133f8eefc Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 17 Oct 2024 15:01:42 +0900 Subject: [PATCH 96/99] [refactor] rename `CsrData` to `EmulatedCsr` --- src/emulate_extension.rs | 10 +++++----- src/emulate_extension/zicfiss.rs | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/emulate_extension.rs b/src/emulate_extension.rs index b98f465..290f7bf 100644 --- a/src/emulate_extension.rs +++ b/src/emulate_extension.rs @@ -20,10 +20,10 @@ pub trait EmulateExtension { fn csr_field(&mut self, inst: &Instruction, write_to_csr_value: u64, read_csr_value: &mut u64); } -/// CSR data for CSRs emulation. -pub struct CsrData(u64); +/// Holding a CSR value for CSRs emulation. +pub struct EmulatedCsr(u64); -impl CsrData { +impl EmulatedCsr { /// Return raw data. pub fn bits(&self) -> u64 { self.0 @@ -56,8 +56,8 @@ pub fn initialize() { } /// Throw an VS-level exception. -/// * `exception_num`: Exception number. (store to vscause) -/// * `trap_value`: Trap value. (store to vstval) +/// * `exception_num`: Exception number. (stored to vscause) +/// * `trap_value`: Trap value. (stored to vstval) pub fn pseudo_vs_exception(exception_num: usize, trap_value: usize) -> ! { unsafe { let hypervisor_data = HYPERVISOR_DATA.lock(); diff --git a/src/emulate_extension/zicfiss.rs b/src/emulate_extension/zicfiss.rs index 8284126..9a4eae8 100644 --- a/src/emulate_extension/zicfiss.rs +++ b/src/emulate_extension/zicfiss.rs @@ -1,7 +1,7 @@ //! Emulation Zicfiss (Shadow Stack) //! Ref: [https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf](https://github.com/riscv/riscv-cfi/releases/download/v1.0/riscv-cfi.pdf) -use super::{pseudo_vs_exception, CsrData, EmulateExtension}; +use super::{pseudo_vs_exception, EmulateExtension, EmulatedCsr}; use crate::memmap::{ page_table::{g_stage_trans_addr, vs_stage_trans_addr}, GuestVirtualAddress, @@ -26,7 +26,7 @@ const SHADOW_STACK_FAULT: usize = 3; /// Singleton for Zicfiss extension pub struct Zicfiss { /// Shadow stack pointer - pub ssp: CsrData, + pub ssp: EmulatedCsr, /// Shadow Stack Enable in henvcfg (for VS-mode) pub henv_sse: bool, /// Shadow Stack Enable in senvcfg (for VU-mode) @@ -37,7 +37,7 @@ impl Zicfiss { /// Constructor for `Zicfiss`. pub fn new() -> Self { Zicfiss { - ssp: CsrData(0), + ssp: EmulatedCsr(0), henv_sse: false, senv_sse: false, } @@ -61,7 +61,7 @@ impl Zicfiss { /// Push value to shadow stack pub fn ss_push(&mut self, value: usize) { unsafe { - self.ssp = CsrData( + self.ssp = EmulatedCsr( (self.ssp.0 as *const usize).byte_sub(core::mem::size_of::()) as u64, ); self.ssp_hp_ptr().write_volatile(value); @@ -72,7 +72,7 @@ impl Zicfiss { pub fn ss_pop(&mut self) -> usize { unsafe { let pop_value = self.ssp_hp_ptr().read_volatile(); - self.ssp = CsrData( + self.ssp = EmulatedCsr( (self.ssp.0 as *const usize).byte_add(core::mem::size_of::()) as u64, ); From 6d236a36e547bbf68ca9ffc2a6b1995218c28686 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 17 Oct 2024 15:20:32 +0900 Subject: [PATCH 97/99] [!][refactor] remove `Device.plic_context` --- src/device.rs | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/src/device.rs b/src/device.rs index 539006a..da96c8f 100644 --- a/src/device.rs +++ b/src/device.rs @@ -81,8 +81,6 @@ pub struct Devices { /// PLIC: Platform-Level Interrupt Controller pub plic: plic::Plic, - /// TODO: It is unused? - pub plic_context: usize, /// clint: Core Local INTerrupt pub clint: clint::Clint, @@ -105,15 +103,6 @@ impl Devices { virtio_list: virtio::VirtIoList::new(&device_tree, "/soc/virtio_mmio"), initrd: initrd::Initrd::new(&device_tree, "/chosen"), plic: plic::Plic::new(&device_tree, "/soc/plic"), - plic_context: device_tree - .find_node("/cpus/cpu") - .unwrap() - .children() - .next() // interrupt-controller - .unwrap() - .property("phandle") - .unwrap() - .value[0] as usize, clint: clint::Clint::new(&device_tree, "/soc/clint"), rtc: rtc::Rtc::new(&device_tree, "/soc/rtc"), pci: pci::Pci::new(&device_tree, "/soc/pci"), From 5e5a088d3ee711706452b149c93ce42524c382d2 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 17 Oct 2024 15:35:41 +0900 Subject: [PATCH 98/99] [doc] update doc comment of `rustsbi::Console` implementation --- src/device/uart.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/device/uart.rs b/src/device/uart.rs index b520f96..ef666fc 100644 --- a/src/device/uart.rs +++ b/src/device/uart.rs @@ -112,7 +112,8 @@ impl MmioDevice for Uart { /// Ref: [https://docs.rs/rustsbi/0.4.0-alpha.1/rustsbi/trait.Console.html](https://docs.rs/rustsbi/0.4.0-alpha.1/rustsbi/trait.Console.html) /// -/// TODO: Checking target address range? +/// It doesn't seems to be used by linux. +/// TODO: Checking target address? impl rustsbi::Console for Uart { /// Write bytes to the debug console from input memory. fn write(&self, bytes: Physical<&[u8]>) -> SbiRet { From e2c0b6b04e7f21f8e3f6e8a21b04dc19a21259a7 Mon Sep 17 00:00:00 2001 From: Alingof Date: Thu, 17 Oct 2024 16:06:27 +0900 Subject: [PATCH 99/99] [update] update version (v1.0.0 -> v1.1.0) --- Cargo.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Cargo.toml b/Cargo.toml index ac3e49e..3f478a7 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "hikami" -version = "1.0.0" +version = "1.1.0" edition = "2021" [lints.clippy]