Skip to content

Commit 21e8039

Browse files
Better infrastructure for regression/integration testing of ASL snippets (#269)
1 parent 4deb78d commit 21e8039

File tree

15 files changed

+1519
-309
lines changed

15 files changed

+1519
-309
lines changed

Cargo.toml

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
[workspace]
2-
members = ["tools/aml_tester", "tools/acpi_dumper"]
2+
members = ["tools/aml_tester", "tools/acpi_dumper", "tools/aml_test_tools"]
33
resolver = "2"
44

55
[package]
@@ -20,6 +20,10 @@ spinning_top = "0.3.0"
2020
pci_types = { version = "0.10.0", public = true }
2121
byteorder = { version = "1.5.0", default-features = false }
2222

23+
[dev-dependencies]
24+
aml_test_tools = { path = "tools/aml_test_tools" }
25+
pretty_env_logger = "0.5.0"
26+
2327
[features]
2428
default = ["alloc", "aml"]
2529
alloc = []

src/aml/mod.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,9 @@ impl<H> Interpreter<H>
9595
where
9696
H: Handler,
9797
{
98-
/// Construct a new `Interpreter`. This does not load any tables - if you have an `AcpiTables`
99-
/// already, use [`Interpreter::new_from_tables`] instead.
98+
/// Construct a new [`Interpreter`]. This does not load any tables - if you have an
99+
/// [`crate::AcpiTables`] already, construct an [`AcpiPlatform`] first and then use
100+
/// [`Interpreter::new_from_platform`]
100101
pub fn new(
101102
handler: H,
102103
dsdt_revision: u8,
@@ -120,8 +121,7 @@ where
120121
}
121122
}
122123

123-
/// Construct a new `Interpreter` with the given set of ACPI tables. This will automatically
124-
/// load the DSDT and any SSDTs in the supplied [`AcpiTables`].
124+
/// Construct a new [`Interpreter`] with the given [`AcpiPlatform`].
125125
pub fn new_from_platform(platform: &AcpiPlatform<H>) -> Result<Interpreter<H>, AcpiError> {
126126
fn load_table(interpreter: &Interpreter<impl Handler>, table: AmlTable) -> Result<(), AcpiError> {
127127
let mapping = unsafe {
@@ -158,7 +158,7 @@ where
158158
}
159159

160160
/// Load the supplied byte stream as an AML table. This should be only the encoded AML stream -
161-
/// not the header at the start of a table. If you've used [`Interpreter::new_from_tables`],
161+
/// not the header at the start of a table. If you've used [`Interpreter::new_from_platform`],
162162
/// you'll likely not need to load any tables manually.
163163
pub fn load_table(&self, stream: &[u8]) -> Result<(), AmlError> {
164164
let context = unsafe { MethodContext::new_from_table(stream) };

src/lib.rs

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
//!
2121
//! Next, you'll need to get the physical address of either the RSDP, or the RSDT/XSDT. The method
2222
//! for doing this depends on the platform you're running on and how you were booted. If you know
23-
//! the system was booted via the BIOS, you can use [`rsdp::Rsdp::search_for_on_bios`]. UEFI provides a
23+
//! the system was booted via the BIOS, you can use [`Rsdp::search_for_on_bios`]. UEFI provides a
2424
//! separate mechanism for getting the address of the RSDP.
2525
//!
2626
//! You then need to construct an instance of [`AcpiTables`], which can be done in a few ways
@@ -29,7 +29,18 @@
2929
//! * Use [`AcpiTables::from_rsdt`] if you have the physical address of the RSDT/XSDT
3030
//!
3131
//! Once you have an [`AcpiTables`], you can search for relevant tables, or use the higher-level
32-
//! interfaces, such as [`PlatformInfo`], [`PciConfigRegions`], or [`HpetInfo`].
32+
//! interfaces, such as [`PowerProfile`], or [`HpetInfo`].
33+
//!
34+
//! If you have the `aml` feature enabled then you can construct an
35+
//! [AML interpreter](`crate::aml::Interpreter`) by first constructing an
36+
//! [`AcpiPlatform`](platform::AcpiPlatform) and then the interpreter:
37+
//!
38+
//! ```ignore,rust
39+
//! let mut acpi_handler = YourHandler::new(/*args*/);
40+
//! let acpi_tables = unsafe { AcpiTables::from_rsdp(acpi_handler.clone(), rsdp_addr) }.unwrap();
41+
//! let platform = AcpiPlatform::new(acpi_tables, acpi_handler).unwrap();
42+
//! let interpreter = Interpreter::new_from_platform(&platform).unwrap();
43+
//! ```
3344
3445
#![no_std]
3546
#![feature(allocator_api)]
@@ -398,9 +409,9 @@ pub trait Handler: Clone {
398409
/// - `size` must be at least `size_of::<T>()`.
399410
unsafe fn map_physical_region<T>(&self, physical_address: usize, size: usize) -> PhysicalMapping<Self, T>;
400411

401-
/// Unmap the given physical mapping. This is called when a `PhysicalMapping` is dropped, you should **not** manually call this.
412+
/// Unmap the given physical mapping. This is called when a [`PhysicalMapping`] is dropped, you should **not** manually call this.
402413
///
403-
/// Note: A reference to the `Handler` used to construct `region` can be acquired by calling [`PhysicalMapping::mapper`].
414+
/// Note: A reference to the [`Handler`] used to construct `region` can be acquired from [`PhysicalMapping::handler`].
404415
fn unmap_physical_region<T>(region: &PhysicalMapping<Self, T>);
405416

406417
// TODO: maybe we should map stuff ourselves in the AML interpreter and do this internally?

tests/normal_fields.rs

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,109 @@
1+
// Test operations on "normal" fields - those that are not Index or Bank fields.
2+
3+
use aml_test_tools::handlers::std_test_handler::{
4+
Command,
5+
construct_std_handler,
6+
create_mutex,
7+
read_io_u8,
8+
read_io_u16,
9+
read_u16,
10+
write_io_u8,
11+
write_io_u16,
12+
write_u16,
13+
};
14+
15+
mod test_infra;
16+
17+
#[test]
18+
fn test_basic_store_and_load() {
19+
const AML: &str = r#"DefinitionBlock("%FN%", "DSDT", 1, "RSACPI", "BUFFLD", 1) {
20+
OperationRegion(MEM, SystemMemory, 0x40000, 0x1000)
21+
Field(MEM, WordAcc, NoLock, Preserve) {
22+
A, 16,
23+
B, 16
24+
}
25+
26+
Method(MAIN, 0, NotSerialized) {
27+
A = 0xA5A5
28+
B = A
29+
Return (0)
30+
}
31+
}
32+
"#;
33+
34+
const EXPECTED_COMMANDS: &[Command] = &[
35+
create_mutex(),
36+
// A = 0xA5A5
37+
write_u16(0x40000, 0xA5A5),
38+
// B = A
39+
read_u16(0x40000, 0xA5A5),
40+
write_u16(0x40002, 0xA5A5),
41+
];
42+
43+
let handler = construct_std_handler(EXPECTED_COMMANDS.to_vec());
44+
test_infra::run_aml_test(AML, handler);
45+
}
46+
47+
#[test]
48+
fn test_narrow_access_store_and_load() {
49+
const AML: &str = r#"DefinitionBlock("%FN%", "DSDT", 1, "RSACPI", "BUFFLD", 1) {
50+
OperationRegion(MEM, SystemIO, 0x40, 0x10)
51+
Field(MEM, ByteAcc, NoLock, Preserve) {
52+
A, 16,
53+
B, 16
54+
}
55+
56+
Method(MAIN, 0, NotSerialized) {
57+
A = 0xA55A
58+
B = A
59+
Return (0)
60+
}
61+
}
62+
"#;
63+
64+
const EXPECTED_COMMANDS: &[Command] = &[
65+
create_mutex(),
66+
// A = 0xA55A
67+
write_io_u8(0x40, 0x5A),
68+
write_io_u8(0x41, 0xA5),
69+
// B = A
70+
read_io_u8(0x40, 0x5A),
71+
read_io_u8(0x41, 0xA5),
72+
write_io_u8(0x42, 0x5A),
73+
write_io_u8(0x43, 0xA5),
74+
];
75+
76+
let handler = construct_std_handler(EXPECTED_COMMANDS.to_vec());
77+
test_infra::run_aml_test(AML, handler);
78+
}
79+
80+
#[test]
81+
fn test_unaligned_field_store() {
82+
const AML: &str = r#"DefinitionBlock("%FN%", "DSDT", 1, "RSACPI", "BUFFLD", 1) {
83+
OperationRegion(MEM, SystemIO, 0x40, 0x10)
84+
Field(MEM, WordAcc, NoLock, Preserve) {
85+
A, 7,
86+
B, 8
87+
}
88+
89+
Method(MAIN, 0, NotSerialized) {
90+
A = 4
91+
B = A
92+
93+
Return (0)
94+
}
95+
}
96+
"#;
97+
98+
const EXPECTED_COMMANDS: &[Command] = &[
99+
create_mutex(),
100+
read_io_u16(0x40, 0),
101+
write_io_u16(0x40, 0x04),
102+
read_io_u16(0x40, 4),
103+
read_io_u16(0x40, 4),
104+
write_io_u16(0x40, 0x204),
105+
];
106+
107+
let handler = construct_std_handler(EXPECTED_COMMANDS.to_vec());
108+
test_infra::run_aml_test(AML, handler);
109+
}

tests/test_infra/mod.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use acpi::Handler;
2+
use aml_test_tools::{new_interpreter, run_test_for_string, TestResult};
3+
use aml_test_tools::handlers::logging_handler::LoggingHandler;
4+
5+
pub fn run_aml_test(asl: &'static str, handler: impl Handler) {
6+
// Tests calling `run_aml_test` don't do much else, and we usually want logging, so initialize it here.
7+
let _ = pretty_env_logger::try_init();
8+
9+
let logged_handler = LoggingHandler::new(handler);
10+
let mut interpreter = new_interpreter(logged_handler);
11+
12+
assert_eq!(run_test_for_string(asl, &mut interpreter), TestResult::Pass);
13+
}

tools/aml_test_tools/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "aml_test_tools"
3+
version = "0.1.0"
4+
authors = ["Isaac Woods", "Martin Hughes"]
5+
edition = "2024"
6+
publish = false
7+
8+
[dependencies]
9+
acpi = { path = "../.." }
10+
log = "0.4"
11+
pci_types = "0.10.0"
12+
tempfile = "3.26.0"

0 commit comments

Comments
 (0)