1use crate::{PhysMapRo, sum};
4
5pub struct AcpiRoots {
6    pub rsdp_addr: u64,
7    pub xsdt_addr: Option<u64>,
8    pub rsdt_addr: Option<u64>,
9}
10
11#[derive(Clone)]
13#[repr(C, packed)]
14struct Rsdp {
15    pub(crate) signature: [u8; 8], checksum: u8,                  oem_id: [u8; 6],
18    pub(crate) revision: u8, pub(crate) rsdt_addr: u32,
20}
21
22#[derive(Clone)]
24#[repr(C, packed)]
25struct Xsdp {
26    signature: [u8; 8], checksum: u8,       oem_id: [u8; 6],
29    revision: u8, _deprecated: u32,
31    pub(crate) length: u32,
32    pub(crate) xsdt_addr: u64,
33    ext_checksum: u8, reserved: [u8; 3],
35}
36
37impl AcpiRoots {
38    #[must_use]
44    #[allow(clippy::similar_names)]
45    pub unsafe fn parse(map: &impl PhysMapRo, rsdp_addr: u64) -> Option<Self> {
46        if rsdp_addr == 0 {
47            return None;
48        }
49
50        unsafe {
51            let v1 = map.map_ro(rsdp_addr, size_of::<Rsdp>());
52            if &v1[0..8] != b"RSD PTR " {
53                return None;
54            }
55            if sum(&v1[0..20]) != 0 {
56                return None;
57            }
58
59            let v1p = &*v1.as_ptr().cast::<Rsdp>();
60            let rsdt_addr = Some(u64::from(v1p.rsdt_addr));
61
62            if v1p.revision >= 2 {
63                let min_v2 = core::mem::size_of::<Xsdp>();
65                let v2 = map.map_ro(rsdp_addr, min_v2);
66                let v2p = &*v2.as_ptr().cast::<Xsdp>();
67                let len = v2p.length as usize;
68                let full = map.map_ro(rsdp_addr, len);
69                if sum(full) != 0 {
70                    return None;
71                }
72                return Some(Self {
73                    rsdp_addr,
74                    xsdt_addr: Some(v2p.xsdt_addr),
75                    rsdt_addr,
76                });
77            }
78
79            Some(Self {
80                rsdp_addr,
81                xsdt_addr: None,
82                rsdt_addr,
83            })
84        }
85    }
86}