dynamic.rs 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. //! Frequently used first boot stage dynamic information on RISC-V.
  2. use core::ops::Range;
  3. use riscv::register::mstatus;
  4. /// M-mode firmware dynamic information.
  5. #[derive(Clone, Copy)]
  6. #[repr(C)]
  7. pub struct DynamicInfo {
  8. /// Dynamic information magic value.
  9. pub magic: usize,
  10. /// Version of dynamic information.
  11. pub version: usize,
  12. /// Address of the next boot-loading stage.
  13. pub next_addr: usize,
  14. /// RISC-V privilege mode of the next boot-loading stage.
  15. pub next_mode: usize,
  16. /// M-mode firmware options; its definition varies between SBI implementations.
  17. pub options: usize,
  18. /// Boot hart ID of current environment.
  19. pub boot_hart: usize,
  20. }
  21. // Definition of `boot_hart` can be found at:
  22. // https://github.com/riscv-software-src/opensbi/blob/019a8e69a1dc0c0f011fabd0372e1ba80e40dd7c/include/sbi/fw_dynamic.h#L75
  23. const DYNAMIC_INFO_INVALID_ADDRESSES: usize = 0x00000000;
  24. const NEXT_ADDR_VALID_ADDRESSES: Range<usize> = 0x80000000..0x90000000;
  25. pub(crate) const MAGIC: usize = 0x4942534f;
  26. const SUPPORTED_VERSION: Range<usize> = 2..3;
  27. pub struct DynamicReadError {
  28. pub bad_paddr: Option<usize>,
  29. pub bad_magic: Option<usize>,
  30. pub bad_version: Option<usize>,
  31. }
  32. // TODO unconstrained lifetime
  33. pub fn read_paddr(paddr: usize) -> Result<DynamicInfo, DynamicReadError> {
  34. let mut error = DynamicReadError {
  35. bad_paddr: None,
  36. bad_magic: None,
  37. bad_version: None,
  38. };
  39. // check pointer before dereference
  40. if DYNAMIC_INFO_INVALID_ADDRESSES == paddr
  41. {
  42. error.bad_paddr = Some(paddr);
  43. return Err(error);
  44. }
  45. let ans = unsafe { *(paddr as *const DynamicInfo) };
  46. if ans.magic != MAGIC {
  47. error.bad_magic = Some(ans.magic);
  48. }
  49. if !SUPPORTED_VERSION.contains(&ans.version) {
  50. error.bad_version = Some(ans.version);
  51. }
  52. if error.bad_magic.is_some() || error.bad_version.is_some() {
  53. return Err(error);
  54. }
  55. Ok(ans)
  56. }
  57. pub struct DynamicError<'a> {
  58. pub invalid_mpp: bool,
  59. pub invalid_next_addr: bool,
  60. pub bad_info: &'a DynamicInfo,
  61. }
  62. pub fn mpp_next_addr(info: &DynamicInfo) -> Result<(mstatus::MPP, usize), DynamicError> {
  63. let mut error = DynamicError {
  64. invalid_mpp: false,
  65. invalid_next_addr: false,
  66. bad_info: info,
  67. };
  68. // fail safe, errors will be aggregated after whole checking process.
  69. let next_addr_valid = NEXT_ADDR_VALID_ADDRESSES.contains(&info.next_addr);
  70. let mpp_valid = matches!(info.next_mode, 0 | 1 | 3);
  71. if !next_addr_valid {
  72. error.invalid_next_addr = true;
  73. }
  74. if !mpp_valid {
  75. error.invalid_mpp = true;
  76. }
  77. if !next_addr_valid || !mpp_valid {
  78. return Err(error);
  79. }
  80. let mpp = match info.next_mode {
  81. 3 => mstatus::MPP::Machine,
  82. 1 => mstatus::MPP::Supervisor,
  83. // pattern `_` avoids `unreachable!`` which introduces panic handler.
  84. 0 | _ => mstatus::MPP::User,
  85. };
  86. Ok((mpp, info.next_addr))
  87. }