Переглянути джерело

dynamic: aggregate error on dynamic information parsing

Signed-off-by: Zhouqi Jiang <luojia@hust.edu.cn>
Zhouqi Jiang 11 місяців тому
батько
коміт
cb24cee970
2 змінених файлів з 37 додано та 31 видалено
  1. 30 13
      src/dynamic.rs
  2. 7 18
      src/main.rs

+ 30 - 13
src/dynamic.rs

@@ -24,7 +24,7 @@ const DYNAMIC_INFO_VALID_ADDRESSES: Range<usize> = 0x1000..0xf000;
 const NEXT_ADDR_VALID_ADDRESSES: Range<usize> = 0x80000000..0x90000000;
 
 // TODO unconstrained lifetime
-pub fn try_read_dynamic(paddr: usize) -> Result<DynamicInfo, ()> {
+pub fn read_paddr(paddr: usize) -> Result<DynamicInfo, ()> {
     // check pointer before dereference
     if !DYNAMIC_INFO_VALID_ADDRESSES.contains(&paddr)
         || !DYNAMIC_INFO_VALID_ADDRESSES.contains(&(paddr + size_of::<DynamicInfo>()))
@@ -35,19 +35,36 @@ pub fn try_read_dynamic(paddr: usize) -> Result<DynamicInfo, ()> {
     Ok(ans)
 }
 
-pub fn next_mode_mpp(info: &DynamicInfo) -> Result<mstatus::MPP, ()> {
-    match info.next_mode {
-        0 => Ok(mstatus::MPP::User),
-        1 => Ok(mstatus::MPP::Supervisor),
-        3 => Ok(mstatus::MPP::Machine),
-        _ => Err(()),
-    }
+#[derive(Default)]
+pub struct DynamicError {
+    invalid_mpp: bool,
+    invalid_next_addr: bool,
 }
 
-pub fn check_next_addr(info: &DynamicInfo) -> Result<usize, ()> {
-    if NEXT_ADDR_VALID_ADDRESSES.contains(&info.next_addr) {
-        Ok(info.next_addr)
-    } else {
-        Err(())
+pub fn mpp_next_addr(info: &DynamicInfo) -> Result<(mstatus::MPP, usize), DynamicError> {
+    let mut error = DynamicError::default();
+
+    // fail safe, errors will be aggregated after whole checking process.
+    let next_addr_valid = NEXT_ADDR_VALID_ADDRESSES.contains(&info.next_addr);
+    let mpp_valid = matches!(info.next_mode, 0 | 1 | 3);
+
+    if !next_addr_valid {
+        error.invalid_next_addr = true;
+    }
+    if !mpp_valid {
+        error.invalid_mpp = true;
+    }
+
+    if !next_addr_valid || !mpp_valid {
+        return Err(error);
     }
+
+    let mpp = match info.next_mode {
+        3 => mstatus::MPP::Machine,
+        1 => mstatus::MPP::Supervisor,
+        // pattern `_` avoids `unreachable!`` which introduces panic handler.
+        0 | _ => mstatus::MPP::User,
+    };
+
+    Ok((mpp, info.next_addr))
 }

+ 7 - 18
src/main.rs

@@ -10,35 +10,24 @@ use riscv::register::mstatus;
 extern "C" fn main(hart_id: usize, opaque: usize, nonstandard_a2: usize) -> usize {
     let _ = (hart_id, opaque);
 
-    if let Ok(info) = dynamic::try_read_dynamic(nonstandard_a2) {
-        let mpp = dynamic::next_mode_mpp(&info).unwrap_or_else(fail_invalid_next_privilege_mode);
-        let next_addr = dynamic::check_next_addr(&info).unwrap_or_else(fail_invalid_next_address);
+    let info = dynamic::read_paddr(nonstandard_a2).unwrap_or_else(fail_no_dynamic_info_available);
 
-        unsafe { mstatus::set_mpp(mpp) };
-        next_addr
-    } else {
-        fail_no_dynamic_info_available()
-    }
-}
+    let (mpp, next_addr) = dynamic::mpp_next_addr(&info).unwrap_or_else(fail_invalid_dynamic_info);
 
-#[cold]
-fn fail_invalid_next_privilege_mode(_err: ()) -> mstatus::MPP {
-    // TODO dynamic information contains invalid privilege mode
-    loop {
-        core::hint::spin_loop()
-    }
+    unsafe { mstatus::set_mpp(mpp) };
+    next_addr
 }
 
 #[cold]
-fn fail_invalid_next_address(_err: ()) -> usize {
-    // TODO dynamic information contains invalid next address
+fn fail_invalid_dynamic_info(_err: dynamic::DynamicError) -> (mstatus::MPP, usize) {
+    // TODO dynamic information contains invalid privilege mode or next address
     loop {
         core::hint::spin_loop()
     }
 }
 
 #[cold]
-fn fail_no_dynamic_info_available() -> ! {
+fn fail_no_dynamic_info_available(_err: ()) -> dynamic::DynamicInfo {
     // TODO no dynamic information available
     loop {
         core::hint::spin_loop()