1use std::num::Wrapping;
5use zerocopy::IntoBytes;
6
7#[derive(Copy, Clone)]
8pub struct OemInfo {
9 pub oem_id: [u8; 6],
10 pub oem_tableid: [u8; 8],
11 pub oem_revision: u32,
12 pub creator_id: [u8; 4],
13 pub creator_revision: u32,
14}
15
16pub struct Table<'a> {
17 revision: u8,
18 oem_tableid: Option<[u8; 8]>,
19 signature: [u8; 4],
20 base: &'a [u8],
21 extra: &'a [&'a [u8]],
22}
23
24impl<'a> Table<'a> {
25 pub fn new<T: acpi_spec::Table>(revision: u8, oem_tableid: Option<[u8; 8]>, t: &'a T) -> Self {
26 Self {
27 revision,
28 oem_tableid,
29 signature: T::SIGNATURE,
30 base: t.as_bytes(),
31 extra: &[],
32 }
33 }
34
35 pub fn new_dyn<T: acpi_spec::Table>(
36 revision: u8,
37 oem_tableid: Option<[u8; 8]>,
38 t: &'a T,
39 extra: &'a [&'a [u8]],
40 ) -> Self {
41 Self {
42 revision,
43 oem_tableid,
44 signature: T::SIGNATURE,
45 base: t.as_bytes(),
46 extra,
47 }
48 }
49
50 pub fn append_to_vec(&self, oem: &OemInfo, v: &mut Vec<u8>) -> usize {
51 let len = size_of::<acpi_spec::Header>()
52 + self.base.len()
53 + self.extra.iter().fold(0, |x, y| x + y.len());
54 let mut header = acpi_spec::Header {
55 signature: self.signature,
56 length: (len as u32).into(),
57 revision: self.revision,
58 checksum: 0,
59 oem_id: oem.oem_id,
60 oem_tableid: self.oem_tableid.unwrap_or(oem.oem_tableid),
61 oem_revision: oem.oem_revision.into(),
62 creator_id: u32::from_le_bytes(oem.creator_id).into(),
63 creator_revision: oem.creator_revision.into(),
64 };
65 let sum = checksum(header.as_bytes())
66 + checksum(self.base.as_bytes())
67 + self.extra.iter().fold(Wrapping(0), |x, y| x + checksum(y));
68 header.checksum = (-sum).0;
69 let orig_len = v.len();
70 v.extend_from_slice(header.as_bytes());
71 v.extend_from_slice(self.base.as_bytes());
72 for x in self.extra.iter() {
73 v.extend_from_slice(x);
74 }
75 assert_eq!(checksum(&v[orig_len..]), Wrapping(0));
76 len
77 }
78
79 pub fn to_vec(&self, oem: &OemInfo) -> Vec<u8> {
80 let mut v = Vec::new();
81 self.append_to_vec(oem, &mut v);
82 v
83 }
84}
85
86pub struct Builder {
87 v: Vec<u8>,
88 tables: Vec<u64>,
89 base_addr: u64,
90 oem: OemInfo,
91}
92
93fn checksum(data: &[u8]) -> Wrapping<u8> {
94 let mut sum = Wrapping(0u8);
95 for i in data.iter() {
96 sum += Wrapping(*i);
97 }
98 sum
99}
100
101impl Builder {
102 pub fn new(base_addr: u64, oem: OemInfo) -> Self {
103 Builder {
104 v: Vec::new(),
105 tables: Vec::new(),
106 base_addr,
107 oem,
108 }
109 }
110
111 pub fn append(&mut self, table: &Table<'_>) -> u64 {
112 let addr = self.base_addr + self.v.len() as u64;
113 let len = table.append_to_vec(&self.oem, &mut self.v);
114 if len % 8 != 0 {
115 self.v.extend_from_slice(&[0; 8][..8 - len % 8]);
116 }
117 if table.signature != *b"XSDT" && table.signature != *b"DSDT" {
118 self.tables.push(addr);
119 }
120 addr
121 }
122
123 pub fn append_raw(&mut self, data: &[u8]) -> u64 {
124 let offset = self.v.len() as u64;
125 let signature = &data[0..4];
126 if signature != *b"XSDT" && signature != *b"DSDT" {
127 self.tables.push(self.base_addr + offset);
128 }
129 self.v.extend_from_slice(data);
130 if data.len() % 8 != 0 {
131 self.v.extend_from_slice(&[0; 8][..8 - data.len() % 8]);
132 }
133 self.base_addr + offset
134 }
135
136 fn rsdp(&self, xsdt: u64) -> acpi_spec::Rsdp {
137 let mut r = acpi_spec::Rsdp {
138 signature: *b"RSD PTR ", checksum: 0, oem_id: self.oem.oem_id, revision: 2, rsdt: 0, length: size_of::<acpi_spec::Rsdp>() as u32, xsdt, xchecksum: 0, rsvd: [0, 0, 0], };
148 let sum = checksum(&r.as_bytes()[0..20]);
149 r.checksum = (-sum).0;
150 let xsum = checksum(r.as_bytes());
151 r.xchecksum = (-xsum).0;
152 assert_eq!(checksum(&r.as_bytes()[0..20]), Wrapping(0));
153 assert_eq!(checksum(r.as_bytes()), Wrapping(0));
154 r
155 }
156
157 pub fn build(mut self) -> (Vec<u8>, Vec<u8>) {
158 let tables = std::mem::take(&mut self.tables);
159 let xsdt = self.append(&Table {
160 signature: *b"XSDT",
161 revision: 1,
162 oem_tableid: None,
163 base: tables.as_slice().as_bytes(),
164 extra: &[],
165 });
166 let rsdp = self.rsdp(xsdt);
167 (rsdp.as_bytes().to_vec(), self.v)
168 }
169}