1
0
mirror of https://github.com/sgmarz/osblog.git synced 2024-11-24 02:16:19 +04:00

Added comments

This commit is contained in:
Stephen Marz 2019-11-10 09:20:40 -05:00
parent e2dfa8661f
commit b3cd92dc41
3 changed files with 52 additions and 14 deletions

View File

@ -6,6 +6,10 @@
use core::ptr::null_mut; 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)] #[repr(usize)]
pub enum SatpMode { pub enum SatpMode {
Off = 0, Off = 0,
@ -13,6 +17,10 @@ pub enum SatpMode {
Sv48 = 9, 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)] #[repr(C)]
#[derive(Clone, Copy)] #[derive(Clone, Copy)]
pub struct TrapFrame { pub struct TrapFrame {
@ -23,6 +31,14 @@ pub struct TrapFrame {
pub hartid: usize, // 528 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 { impl TrapFrame {
pub const fn zero() -> Self { pub const fn zero() -> Self {
TrapFrame { regs: [0; 32], 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] = pub static mut KERNEL_TRAP_FRAME: [TrapFrame; 8] =
[TrapFrame::zero(); 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 { pub const fn build_satp(mode: SatpMode, asid: usize, addr: usize) -> usize {
(mode as usize) << 60 (mode as usize) << 60
| (asid & 0xffff) << 44 | (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) { pub fn satp_fence(vaddr: usize, asid: usize) {
unsafe { unsafe {
asm!("sfence.vma $0, $1" :: "r"(vaddr), "r"(asid)); 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) { pub fn satp_fence_asid(asid: usize) {
unsafe { unsafe {
asm!("sfence.vma zero, $0" :: "r"(asid)); asm!("sfence.vma zero, $0" :: "r"(asid));

View File

@ -23,10 +23,10 @@ const PLIC_CLAIM: usize = 0x0c20_0004;
// PCIE = [32..35] // PCIE = [32..35]
// Get the next available interrupt. This is the "claim" process. /// Get the next available interrupt. This is the "claim" process.
// The plic will automatically sort by priority and hand us the /// The plic will automatically sort by priority and hand us the
// ID of the interrupt. For example, if the UART is interrupting /// ID of the interrupt. For example, if the UART is interrupting
// and it's next, we will get the value 10. /// and it's next, we will get the value 10.
pub fn next() -> Option<u32> { pub fn next() -> Option<u32> {
let claim_reg = PLIC_CLAIM as *const u32; let claim_reg = PLIC_CLAIM as *const u32;
let claim_no; let claim_no;
@ -41,8 +41,8 @@ pub fn next() -> Option<u32> {
} }
} }
// Complete a pending interrupt by id. The id should come /// Complete a pending interrupt by id. The id should come
// from the next() function above. /// from the next() function above.
pub fn complete(id: u32) { pub fn complete(id: u32) {
let complete_reg = PLIC_CLAIM as *mut u32; let complete_reg = PLIC_CLAIM as *mut u32;
unsafe { unsafe {
@ -50,10 +50,10 @@ pub fn complete(id: u32) {
} }
} }
// Set the global threshold. The threshold can be a value [0..7]. /// Set the global threshold. The threshold can be a value [0..7].
// The PLIC will mask any interrupts at or below the given threshold. /// The PLIC will mask any interrupts at or below the given threshold.
// This means that a threshold of 7 will mask ALL interrupts and /// This means that a threshold of 7 will mask ALL interrupts and
// a threshold of 0 will allow ALL interrupts. /// a threshold of 0 will allow ALL interrupts.
pub fn set_threshold(tsh: u8) { pub fn set_threshold(tsh: u8) {
let actual_tsh = tsh & 7; let actual_tsh = tsh & 7;
let tsh_reg = PLIC_THRESHOLD as *mut u32; 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 { pub fn is_pending(id: u32) -> bool {
let pend = PLIC_PENDING as *const u32; let pend = PLIC_PENDING as *const u32;
let actual_id = 1 << id; let actual_id = 1 << id;
@ -73,7 +73,7 @@ pub fn is_pending(id: u32) -> bool {
actual_id & pend_ids != 0 actual_id & pend_ids != 0
} }
// Enable a given interrupt id /// Enable a given interrupt id
pub fn enable(id: u32) { pub fn enable(id: u32) {
let enables = PLIC_INT_ENABLE as *mut u32; let enables = PLIC_INT_ENABLE as *mut u32;
let actual_id = 1 << id; let actual_id = 1 << id;
@ -82,8 +82,8 @@ pub fn enable(id: u32) {
} }
} }
// Set a given interrupt priority to the given priority. /// Set a given interrupt priority to the given priority.
// The priority must be [0..7] /// The priority must be [0..7]
pub fn set_priority(id: u32, prio: u8) { pub fn set_priority(id: u32, prio: u8) {
let actual_prio = prio as u32 & 7; let actual_prio = prio as u32 & 7;
let prio_reg = PLIC_PRIORITY as *mut u32; let prio_reg = PLIC_PRIORITY as *mut u32;

View File

@ -6,6 +6,10 @@
use crate::cpu::TrapFrame; use crate::cpu::TrapFrame;
#[no_mangle] #[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, extern "C" fn m_trap(epc: usize,
tval: usize, tval: usize,
cause: usize, cause: usize,