mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-23 18:06:20 +04:00
Added comments
This commit is contained in:
parent
e2dfa8661f
commit
b3cd92dc41
@ -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));
|
||||
|
@ -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<u32> {
|
||||
let claim_reg = PLIC_CLAIM as *const u32;
|
||||
let claim_no;
|
||||
@ -41,8 +41,8 @@ pub fn next() -> Option<u32> {
|
||||
}
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
@ -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,
|
||||
|
Loading…
Reference in New Issue
Block a user