rsdp.rs 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596
  1. use super::AcpiError;
  2. use core::{mem, str};
  3. /// The first structure found in ACPI. It just tells us where the RSDT is.
  4. ///
  5. /// On BIOS systems, it is either found in the first 1KB of the Extended Bios Data Area, or between
  6. /// 0x000E0000 and 0x000FFFFF. The signature is always on a 16 byte boundary. On (U)EFI, it may not
  7. /// be located in these locations, and so an address should be found in the EFI_SYSTEM_TABLE
  8. /// instead.
  9. ///
  10. /// The recommended way of locating the RSDP is to let the bootloader do it - Multiboot2 can pass a
  11. /// tag with the physical address of it. If this is not possible, a manual scan can be done.
  12. ///
  13. /// If `revision > 0`, (the hardware ACPI version is Version 2.0 or greater), the RSDP contains
  14. /// some new fields. For ACPI Version 1.0, these fields are not valid and should not be accessed.
  15. /// For ACPI Version 2.0+, `xsdt_address` should be used (truncated to `u32` on x86) instead of
  16. /// `rsdt_address`.
  17. #[repr(C, packed)]
  18. pub(crate) struct Rsdp {
  19. signature: [u8; 8],
  20. checksum: u8,
  21. oem_id: [u8; 6],
  22. revision: u8,
  23. rsdt_address: u32,
  24. /*
  25. * These fields are only valid for ACPI Version 2.0 and greater
  26. */
  27. length: u32,
  28. xsdt_address: u64,
  29. ext_checksum: u8,
  30. reserved: [u8; 3],
  31. }
  32. impl Rsdp {
  33. /// Checks that:
  34. /// 1) The signature is correct
  35. /// 2) The checksum is correct
  36. /// 3) For Version 2.0+, that the extension checksum is correct
  37. pub(crate) fn validate(&self) -> Result<(), AcpiError> {
  38. // Check the signature
  39. if &self.signature != b"RSD PTR " {
  40. return Err(AcpiError::RsdpIncorrectSignature);
  41. }
  42. // Check the OEM id is valid UTF8 (allows use of unwrap)
  43. if str::from_utf8(&self.oem_id).is_err() {
  44. return Err(AcpiError::RsdpInvalidOemId);
  45. }
  46. /*
  47. * `self.length` doesn't exist on ACPI version 1.0, so we mustn't rely on it. Instead,
  48. * check for version 1.0 and use a hard-coded length instead.
  49. */
  50. let length = if self.revision > 0 {
  51. // For Version 2.0+, check ALL the fields
  52. mem::size_of::<Self>()
  53. } else {
  54. // For Version 1, only check fields up to v1 length only
  55. mem::size_of::<[u8; 8]>()
  56. + mem::size_of::<u8>()
  57. + mem::size_of::<[u8; 6]>()
  58. + mem::size_of::<u8>()
  59. + mem::size_of::<u32>()
  60. };
  61. let self_ptr = self as *const Rsdp as *const u8;
  62. let mut sum: u8 = 0;
  63. for i in 0..length {
  64. sum = sum.wrapping_add(unsafe { *(self_ptr.offset(i as isize)) });
  65. }
  66. if sum != 0 {
  67. return Err(AcpiError::RsdpInvalidChecksum);
  68. }
  69. Ok(())
  70. }
  71. pub(crate) fn oem_id<'a>(&'a self) -> &'a str {
  72. str::from_utf8(&self.oem_id).unwrap()
  73. }
  74. pub(crate) fn revision(&self) -> u8 {
  75. self.revision
  76. }
  77. pub(crate) fn rsdt_address(&self) -> u32 {
  78. self.rsdt_address
  79. }
  80. pub(crate) fn xsdt_address(&self) -> u64 {
  81. assert!(self.revision > 0, "Tried to read extended RSDP field with ACPI Version 1.0");
  82. self.xsdt_address
  83. }
  84. }