From b3cd92dc4118f64f300a110195da3f0de2847252 Mon Sep 17 00:00:00 2001 From: Stephen Marz Date: Sun, 10 Nov 2019 09:20:40 -0500 Subject: [PATCH] Added comments --- risc_v/ch5/src/cpu.rs | 34 ++++++++++++++++++++++++++++++++++ risc_v/ch5/src/plic.rs | 28 ++++++++++++++-------------- risc_v/ch5/src/trap.rs | 4 ++++ 3 files changed, 52 insertions(+), 14 deletions(-) diff --git a/risc_v/ch5/src/cpu.rs b/risc_v/ch5/src/cpu.rs index 84b95ee..0bd1714 100755 --- a/risc_v/ch5/src/cpu.rs +++ b/risc_v/ch5/src/cpu.rs @@ -6,6 +6,10 @@ use core::ptr::null_mut; +/// In 64-bit mode, we're given three different modes for the MMU: +/// 0 - The MMU is off -- no protection and no translation PA = VA +/// 8 - This is Sv39 mode -- 39-bit virtual addresses +/// 9 - This is Sv48 mode -- 48-bit virtual addresses #[repr(usize)] pub enum SatpMode { Off = 0, @@ -13,6 +17,10 @@ pub enum SatpMode { Sv48 = 9, } +/// The trap frame is set into a structure +/// and packed into each hart's mscratch register. +/// This allows for quick reference and full +/// context switch handling. #[repr(C)] #[derive(Clone, Copy)] pub struct TrapFrame { @@ -23,6 +31,14 @@ pub struct TrapFrame { pub hartid: usize, // 528 } +/// Rust requires that we initialize our structures +/// because of the move semantics. What'll happen below +/// is Rust will construct a new TrapFrame and move it +/// out of the zero() function below. Rust contains two +/// different "selfs" where self can refer to the object +/// in memory or Self (capital S) which refers to the +/// data type of the structure. In the case below, this +/// is TrapFrame. impl TrapFrame { pub const fn zero() -> Self { TrapFrame { regs: [0; 32], @@ -33,9 +49,17 @@ impl TrapFrame { } } +/// The global kernel trap frame stores 8 separate +/// frames -- one per CPU hart. We will switch these +/// in and out and store a dormant trap frame with +/// the process itself. pub static mut KERNEL_TRAP_FRAME: [TrapFrame; 8] = [TrapFrame::zero(); 8]; +/// The SATP register contains three fields: mode, address space id, and +/// the first level table address (level 2 for Sv39). This function +/// helps make the 64-bit register contents based on those three +/// fields. pub const fn build_satp(mode: SatpMode, asid: usize, addr: usize) -> usize { (mode as usize) << 60 | (asid & 0xffff) << 44 @@ -150,12 +174,22 @@ pub fn satp_read() -> usize { } } +/// Take a hammer to the page tables and synchronize +/// all of them. This essentially flushes the entire +/// TLB. pub fn satp_fence(vaddr: usize, asid: usize) { unsafe { asm!("sfence.vma $0, $1" :: "r"(vaddr), "r"(asid)); } } +/// Synchronize based on the address space identifier +/// This allows us to fence a particular process rather +/// than the entire TLB. +/// The RISC-V documentation calls this a TLB flush +. +/// Since there are other memory routines involved, they +/// didn't call it a TLB flush, but it is much like +/// Intel/AMD's invtlb [] instruction. pub fn satp_fence_asid(asid: usize) { unsafe { asm!("sfence.vma zero, $0" :: "r"(asid)); diff --git a/risc_v/ch5/src/plic.rs b/risc_v/ch5/src/plic.rs index fb38724..5fbd01f 100644 --- a/risc_v/ch5/src/plic.rs +++ b/risc_v/ch5/src/plic.rs @@ -23,10 +23,10 @@ const PLIC_CLAIM: usize = 0x0c20_0004; // PCIE = [32..35] -// Get the next available interrupt. This is the "claim" process. -// The plic will automatically sort by priority and hand us the -// ID of the interrupt. For example, if the UART is interrupting -// and it's next, we will get the value 10. +/// Get the next available interrupt. This is the "claim" process. +/// The plic will automatically sort by priority and hand us the +/// ID of the interrupt. For example, if the UART is interrupting +/// and it's next, we will get the value 10. pub fn next() -> Option { let claim_reg = PLIC_CLAIM as *const u32; let claim_no; @@ -41,8 +41,8 @@ pub fn next() -> Option { } } -// Complete a pending interrupt by id. The id should come -// from the next() function above. +/// Complete a pending interrupt by id. The id should come +/// from the next() function above. pub fn complete(id: u32) { let complete_reg = PLIC_CLAIM as *mut u32; unsafe { @@ -50,10 +50,10 @@ pub fn complete(id: u32) { } } -// Set the global threshold. The threshold can be a value [0..7]. -// The PLIC will mask any interrupts at or below the given threshold. -// This means that a threshold of 7 will mask ALL interrupts and -// a threshold of 0 will allow ALL interrupts. +/// Set the global threshold. The threshold can be a value [0..7]. +/// The PLIC will mask any interrupts at or below the given threshold. +/// This means that a threshold of 7 will mask ALL interrupts and +/// a threshold of 0 will allow ALL interrupts. pub fn set_threshold(tsh: u8) { let actual_tsh = tsh & 7; let tsh_reg = PLIC_THRESHOLD as *mut u32; @@ -62,7 +62,7 @@ pub fn set_threshold(tsh: u8) { } } -// See if a given interrupt id is pending. +/// See if a given interrupt id is pending. pub fn is_pending(id: u32) -> bool { let pend = PLIC_PENDING as *const u32; let actual_id = 1 << id; @@ -73,7 +73,7 @@ pub fn is_pending(id: u32) -> bool { actual_id & pend_ids != 0 } -// Enable a given interrupt id +/// Enable a given interrupt id pub fn enable(id: u32) { let enables = PLIC_INT_ENABLE as *mut u32; let actual_id = 1 << id; @@ -82,8 +82,8 @@ pub fn enable(id: u32) { } } -// Set a given interrupt priority to the given priority. -// The priority must be [0..7] +/// Set a given interrupt priority to the given priority. +/// The priority must be [0..7] pub fn set_priority(id: u32, prio: u8) { let actual_prio = prio as u32 & 7; let prio_reg = PLIC_PRIORITY as *mut u32; diff --git a/risc_v/ch5/src/trap.rs b/risc_v/ch5/src/trap.rs index db3b32e..bfe4523 100755 --- a/risc_v/ch5/src/trap.rs +++ b/risc_v/ch5/src/trap.rs @@ -6,6 +6,10 @@ use crate::cpu::TrapFrame; #[no_mangle] +/// The m_trap stands for "machine trap". Right now, we are handling +/// all traps at machine mode. In this mode, we can figure out what's +/// going on and send a trap where it needs to be. Remember, in machine +/// mode and in this trap, interrupts are disabled and the MMU is off. extern "C" fn m_trap(epc: usize, tval: usize, cause: usize,