rsdp.rs 2.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  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 instead.
  8. ///
  9. /// The recommended way of locating the RSDP is to let the bootloader do it - Multiboot2 can pass a
  10. /// tag with the physical address of it. If this is not possible, a manual scan can be done.
  11. ///
  12. /// If `revision > 0`, (the hardware ACPI version is Version 2.0 or greater), the RSDP contains
  13. /// some new fields. For ACPI Version 1.0, these fields are not valid and should not be accessed.
  14. /// For ACPI Version 2.0+, `xsdt_address` should be used (truncated to `u32` on x86) instead of
  15. /// `rsdt_address`.
  16. #[repr(C, packed)]
  17. pub(crate) struct Rsdp {
  18. signature: [u8; 8],
  19. checksum: u8,
  20. oem_id: [u8; 6],
  21. revision: u8,
  22. rsdt_address: u32,
  23. /*
  24. * These fields are only valid for ACPI Version 2.0 and greater
  25. */
  26. length: u32,
  27. xsdt_address: u64,
  28. ext_checksum: u8,
  29. reserved: [u8; 3],
  30. }
  31. impl Rsdp {
  32. /// Checks that:
  33. /// 1) The signature is correct
  34. /// 2) The checksum is correct
  35. /// 3) For Version 2.0+, that the extension checksum is correct
  36. pub(crate) fn validate(&self) -> Result<(), AcpiError> {
  37. // Check the signature
  38. if &self.signature != b"RSD PTR " {
  39. return Err(AcpiError::RsdpIncorrectSignature);
  40. }
  41. // Check the OEM id is valid UTF8 (allows use of unwrap)
  42. if str::from_utf8(&self.oem_id).is_err() {
  43. return Err(AcpiError::RsdpInvalidOemId);
  44. }
  45. let len = if self.revision > 0 {
  46. // For Version 2.0+, check ALL the fields
  47. mem::size_of::<Self>()
  48. } else {
  49. // For Version 1, only check fields up to v1 length only
  50. 20
  51. };
  52. let self_ptr = self as *const Rsdp as *const u8;
  53. let mut sum: u8 = 0;
  54. for i in 0..self.length {
  55. sum = sum.wrapping_add(unsafe { *(self_ptr.offset(i as isize)) } as u8);
  56. }
  57. if sum != 0 {
  58. return Err(AcpiError::RsdpInvalidChecksum);
  59. }
  60. Ok(())
  61. }
  62. pub(crate) fn oem_id<'a>(&'a self) -> &'a str {
  63. str::from_utf8(&self.oem_id).unwrap()
  64. }
  65. pub(crate) fn revision(&self) -> u8 {
  66. self.revision
  67. }
  68. pub(crate) fn rsdt_address(&self) -> u32 {
  69. self.rsdt_address
  70. }
  71. pub(crate) fn xsdt_address(&self) -> u64 {
  72. assert!(
  73. self.revision > 0,
  74. "Tried to read extended RSDP field with ACPI Version 1.0"
  75. );
  76. self.xsdt_address
  77. }
  78. }