mirror of
https://github.com/sgmarz/osblog.git
synced 2024-11-24 02:16:19 +04:00
Added comments
This commit is contained in:
parent
e2dfa8661f
commit
b3cd92dc41
@ -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));
|
||||||
|
@ -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;
|
||||||
|
@ -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,
|
||||||
|
Loading…
Reference in New Issue
Block a user