Skip to content

Commit 95da2c9

Browse files
authored
Merge pull request #62 from ntegan/54-xsdt-v2
acpi: add support for the xsdt
2 parents a9b44b8 + cc374c1 commit 95da2c9

File tree

4 files changed

+113
-59
lines changed

4 files changed

+113
-59
lines changed

mythril_core/src/acpi/rsdp.rs

Lines changed: 7 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -30,8 +30,6 @@ mod offsets {
3030
pub const REVISION: usize = 15;
3131
/// 32-bit physical address of the RSDT.
3232
pub const RSDT_ADDR: Range<usize> = 16..20;
33-
/// Length of the XSDT table in bytes (ACPI 2.0 only).
34-
pub const LENGTH: Range<usize> = 20..24;
3533
/// 64-bit physical address of the XSDT (ACPI 2.0 only).
3634
pub const XSDT_ADDR: Range<usize> = 24..32;
3735
/// Checksum of entire structure (ACPI 2.0 only).
@@ -60,12 +58,10 @@ pub enum RSDP {
6058
V2 {
6159
/// OEM Supplied string.
6260
oemid: [u8; 6],
63-
/// 32-bit physical address of the RSDT.
64-
rsdt_addr: u32,
65-
/// Length of the XSDT table in bytes.
66-
length: u32,
6761
/// 64-bit physical address of the XSDT.
6862
xsdt_addr: u64,
63+
// TODO(ntegan) multiboot2 doesn't give us a length for rsdpv2tag,
64+
// so we can't calculate the rsdp checksum
6965
},
7066
}
7167

@@ -75,15 +71,9 @@ impl fmt::Debug for RSDP {
7571
&RSDP::V1 { rsdt_addr, .. } => {
7672
write!(f, "RSDP: revision=1.0 rsdt=0x{:x}", rsdt_addr)
7773
}
78-
&RSDP::V2 {
79-
rsdt_addr,
80-
xsdt_addr,
81-
..
82-
} => write!(
83-
f,
84-
"RSDP: revision=2.0 rsdt=0x{:x} xsdt_addr=0x{:x}",
85-
rsdt_addr, xsdt_addr
86-
),
74+
&RSDP::V2 { xsdt_addr, .. } => {
75+
write!(f, "RSDP: revision=2.0 xsdt_addr=0x{:x}", xsdt_addr)
76+
}
8777
}
8878
}
8979
}
@@ -125,8 +115,6 @@ impl RSDP {
125115
// This is ACPI 2.0. Extract the addrss and length of the XSDT.
126116
2 => RSDP::V2 {
127117
oemid,
128-
rsdt_addr,
129-
length: NativeEndian::read_u32(&bytes[offsets::LENGTH]),
130118
xsdt_addr: NativeEndian::read_u64(&bytes[offsets::XSDT_ADDR]),
131119
},
132120
_ => {
@@ -202,8 +190,8 @@ impl RSDP {
202190
/// Return the RSDT pointed to by this structure.
203191
pub fn rsdt(&self) -> Result<RSDT> {
204192
match self {
205-
&RSDP::V1 { rsdt_addr, .. } => RSDT::new(rsdt_addr),
206-
&RSDP::V2 { .. } => Err(Error::NotSupported),
193+
&RSDP::V1 { rsdt_addr, .. } => RSDT::new_rsdt(rsdt_addr as usize),
194+
&RSDP::V2 { xsdt_addr, .. } => RSDT::new_xsdt(xsdt_addr as usize),
207195
}
208196
}
209197
}

mythril_core/src/acpi/rsdt.rs

Lines changed: 82 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -101,27 +101,45 @@ impl<'a> SDT<'a> {
101101
}
102102
}
103103

104-
/// The Root System Descriptor Table.
105-
pub struct RSDT<'a>(SDT<'a>);
104+
/// The Root System Description Table.
105+
/// Two variants to support 32 bit RSDT and 64 bit XSDT.
106+
pub enum RSDT<'a> {
107+
/// Root System Description Table.
108+
RSDT(SDT<'a>),
109+
/// Extended System Description Table.
110+
XSDT(SDT<'a>),
111+
}
106112

107113
impl<'a> RSDT<'a> {
108-
/// Create a new SDT.
109-
pub fn new(rsdt_addr: u32) -> Result<RSDT<'a>> {
114+
/// Create a new RSDT.
115+
pub fn new_rsdt(rsdt_addr: usize) -> Result<RSDT<'a>> {
110116
let sdt = unsafe { SDT::new(rsdt_addr as *const u8)? };
111-
Ok(RSDT(sdt))
117+
Ok(RSDT::RSDT(sdt))
118+
}
119+
120+
/// Create a new XSDT.
121+
pub fn new_xsdt(xsdt_addr: usize) -> Result<RSDT<'a>> {
122+
let sdt = unsafe { SDT::new(xsdt_addr as *const u8)? };
123+
Ok(RSDT::XSDT(sdt))
112124
}
113125

114126
/// Return the number of entries in the table.
115127
///
116128
/// Note: This is not the same as the length value of the header.
117129
/// the the length value _includes_ the header.
118130
pub fn num_entries(&self) -> usize {
119-
self.0.len() / 4
131+
match self {
132+
RSDT::XSDT(sdt) => sdt.len() / 8,
133+
RSDT::RSDT(sdt) => sdt.len() / 4,
134+
}
120135
}
121136

122137
/// Return an iterator for the SDT entries.
123138
pub fn entries(&self) -> RSDTIterator<'a> {
124-
RSDTIterator::new(self.0.table)
139+
match self {
140+
RSDT::RSDT(sdt) => RSDTIterator::new_rsdt(sdt.table),
141+
RSDT::XSDT(sdt) => RSDTIterator::new_xsdt(sdt.table),
142+
}
125143
}
126144

127145
/// Returns the first matching SDT for a given signature.
@@ -137,41 +155,77 @@ impl<'a> RSDT<'a> {
137155

138156
impl<'a> fmt::Debug for RSDT<'a> {
139157
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
140-
write!(f, "{:?}", self.0)
158+
let my_sdt = match self {
159+
RSDT::RSDT(the_sdt) => the_sdt,
160+
RSDT::XSDT(the_sdt) => the_sdt,
161+
};
162+
write!(f, "{:?}", my_sdt)
141163
}
142164
}
143165

144-
/// Iterator for the SDT entries found in the RSDT.
145-
pub struct RSDTIterator<'a> {
146-
table: &'a [u8],
147-
offset: usize,
166+
/// Iterator for the SDT entries found in the RSDT/XSDT.
167+
pub enum RSDTIterator<'a> {
168+
/// Iterates through 32 bit RSDT.
169+
RSDTIterator {
170+
/// Table of 32 bit SDT pointers.
171+
table: &'a [u8],
172+
/// Current offset to keep track of iteration.
173+
offset: usize,
174+
},
175+
/// Iterates through 64 bit XSDT.
176+
XSDTIterator {
177+
/// Table of 64 bit SDT pointers.
178+
table: &'a [u8],
179+
/// Current offset to keep track of iteration.
180+
offset: usize,
181+
},
148182
}
149183

150184
impl<'a> RSDTIterator<'a> {
151185
/// Create an iterator for the SDT entries in an RSDT.
152-
pub fn new<'b: 'a>(table: &'b [u8]) -> RSDTIterator<'a> {
153-
RSDTIterator { table, offset: 0 }
186+
pub fn new_rsdt<'b: 'a>(table: &'b [u8]) -> RSDTIterator<'a> {
187+
RSDTIterator::RSDTIterator { table, offset: 0 }
188+
}
189+
190+
/// Create an iterator for the SDT entries in an XSDT.
191+
pub fn new_xsdt<'b: 'a>(table: &'b [u8]) -> RSDTIterator<'a> {
192+
RSDTIterator::XSDTIterator { table, offset: 0 }
154193
}
155194
}
156195

157196
impl<'a> Iterator for RSDTIterator<'a> {
158197
type Item = Result<SDT<'a>>;
159198

160199
fn next(&mut self) -> Option<Self::Item> {
161-
let next = self.offset + 4;
162-
if next <= self.table.len() {
163-
let item = unsafe {
164-
// TODO(dlrobertson): We currently only support the 32-bit RSDT.
165-
// When we support the 64-bit XSDT, the table may point to an
166-
// array of 64-bit pointers.
167-
let ptr =
168-
NativeEndian::read_u32(&self.table[self.offset..next]);
169-
self.offset = next;
170-
SDT::new(ptr as *const u8)
171-
};
172-
Some(item)
173-
} else {
174-
None
200+
match self {
201+
RSDTIterator::RSDTIterator { table, offset } => {
202+
let next = *offset + 4usize;
203+
if next <= table.len() {
204+
let item = unsafe {
205+
let ptr = NativeEndian::read_u32(&table[*offset..next])
206+
as usize;
207+
*offset = next;
208+
SDT::new(ptr as *const u8)
209+
};
210+
Some(item)
211+
} else {
212+
None
213+
}
214+
}
215+
RSDTIterator::XSDTIterator { table, offset } => {
216+
let next = *offset + 8usize;
217+
if next <= table.len() {
218+
let item = unsafe {
219+
let ptr = NativeEndian::read_u64(&table[*offset..next])
220+
as usize;
221+
*offset = next;
222+
SDT::new(ptr as *const u8)
223+
};
224+
Some(item)
225+
} else {
226+
None
227+
}
228+
}
175229
}
176230
}
177231
}

mythril_multiboot2/src/services.rs

Lines changed: 22 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -35,19 +35,30 @@ impl VmServices for Multiboot2Services {
3535
}
3636

3737
fn rsdp(&self) -> Result<acpi::rsdp::RSDP> {
38-
// Get a v1 tag if possible
39-
self.info
40-
.rsdp_v1_tag()
41-
.map(|tag| {
42-
// use empty string if no OEM id provided
43-
let id = tag.oem_id().unwrap_or(" ").as_bytes();
38+
let mut arr: [u8; 6] = [0; 6];
39+
self.info.rsdp_v2_tag().map_or_else(
40+
|| {
41+
self.info.rsdp_v1_tag().map_or_else(
42+
|| Err(Error::NotFound),
43+
move |tag_v1| {
44+
let id = tag_v1.oem_id().unwrap_or(" ").as_bytes();
45+
arr.copy_from_slice(&id[0..6]);
46+
Ok(acpi::rsdp::RSDP::V1 {
47+
oemid: arr,
48+
rsdt_addr: tag_v1.rsdt_address() as u32,
49+
})
50+
},
51+
)
52+
},
53+
move |tag_v2| {
54+
let id = tag_v2.oem_id().unwrap_or(" ").as_bytes();
4455
let mut arr: [u8; 6] = [0; 6];
4556
arr.copy_from_slice(&id[0..6]);
46-
acpi::rsdp::RSDP::V1 {
57+
Ok(acpi::rsdp::RSDP::V2 {
4758
oemid: arr,
48-
rsdt_addr: tag.rsdt_address() as u32,
49-
}
50-
})
51-
.ok_or(Error::NotFound)
59+
xsdt_addr: tag_v2.xsdt_address() as u64,
60+
})
61+
},
62+
)
5263
}
5364
}

scripts/grub.cfg

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,10 @@ set timeout=0
33

44
menuentry 'Mythril' {
55
echo 'Loading Mythril'
6+
acpi -2
67
multiboot2 /boot/mythril.bin
78
module2 /boot/seabios.bin seabios.bin
89
module2 /boot/linuxboot_dma.bin linuxboot_dma.bin
910
module2 /boot/vmlinuz kernel
1011
module2 /boot/initramfs initramfs
11-
}
12+
}

0 commit comments

Comments
 (0)