Skip to content

Commit b77079b

Browse files
committed
aml: general parsing cleanup + little bits
1 parent 7c9931b commit b77079b

File tree

8 files changed

+261
-166
lines changed

8 files changed

+261
-166
lines changed

aml/src/lib.rs

Lines changed: 117 additions & 76 deletions
Large diffs are not rendered by default.

aml/src/namespace.rs

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,51 @@ impl Namespace {
6666
}
6767
}
6868

69+
/// Search for an object at the given path of the namespace, applying the search rules described in §5.3 of the
70+
/// ACPI specification, if they are applicable. Returns the resolved name, and the handle of the first valid
71+
/// object, if found.
72+
pub fn search(&self, path: &AmlName, starting_scope: &AmlName) -> Result<(AmlName, Arc<Object>), AmlError> {
73+
if path.search_rules_apply() {
74+
/*
75+
* If search rules apply, we need to recursively look through the namespace. If the
76+
* given name does not occur in the current scope, we look at the parent scope, until
77+
* we either find the name, or reach the root of the namespace.
78+
*/
79+
let mut scope = starting_scope.clone();
80+
assert!(scope.is_absolute());
81+
loop {
82+
// Search for the name at this namespace level. If we find it, we're done.
83+
let name = path.resolve(&scope)?;
84+
match self.get_level_for_path(&name) {
85+
Ok((level, last_seg)) => {
86+
if let Some(object) = level.values.get(&last_seg) {
87+
return Ok((name, object.clone()));
88+
}
89+
}
90+
91+
Err(err) => return Err(err),
92+
}
93+
94+
// If we don't find it, go up a level in the namespace and search for it there recursively
95+
match scope.parent() {
96+
Ok(parent) => scope = parent,
97+
Err(AmlError::RootHasNoParent) => return Err(AmlError::ObjectDoesNotExist(path.clone())),
98+
Err(err) => return Err(err),
99+
}
100+
}
101+
} else {
102+
// If search rules don't apply, simply resolve it against the starting scope
103+
let name = path.resolve(starting_scope)?;
104+
let (level, last_seg) = self.get_level_for_path(&path.resolve(starting_scope)?)?;
105+
106+
if let Some(object) = level.values.get(&last_seg) {
107+
Ok((name, object.clone()))
108+
} else {
109+
Err(AmlError::ObjectDoesNotExist(path.clone()))
110+
}
111+
}
112+
}
113+
69114
/// Split an absolute path into a bunch of level segments (used to traverse the level data structure), and a
70115
/// last segment to index into that level. This must not be called on `\\`.
71116
fn get_level_for_path(&self, path: &AmlName) -> Result<(&NamespaceLevel, NameSeg), AmlError> {
@@ -342,7 +387,7 @@ impl NameSeg {
342387
pub fn from_str(string: &str) -> Result<NameSeg, AmlError> {
343388
// Each NameSeg can only have four chars, and must have at least one
344389
if string.is_empty() || string.len() > 4 {
345-
return Err(AmlError::InvalidNameSeg);
390+
return Err(AmlError::InvalidNameSeg([0xff, 0xff, 0xff, 0xff]));
346391
}
347392

348393
// We pre-fill the array with '_', so it will already be correct if the length is < 4
@@ -351,14 +396,14 @@ impl NameSeg {
351396

352397
// Manually do the first one, because we have to check it's a LeadNameChar
353398
if !is_lead_name_char(bytes[0]) {
354-
return Err(AmlError::InvalidNameSeg);
399+
return Err(AmlError::InvalidNameSeg([bytes[0], bytes[1], bytes[2], bytes[3]]));
355400
}
356401
seg[0] = bytes[0];
357402

358403
// Copy the rest of the chars, checking that they're NameChars
359404
for i in 1..bytes.len() {
360405
if !is_name_char(bytes[i]) {
361-
return Err(AmlError::InvalidNameSeg);
406+
return Err(AmlError::InvalidNameSeg([bytes[0], bytes[1], bytes[2], bytes[3]]));
362407
}
363408
seg[i] = bytes[i];
364409
}
@@ -368,16 +413,16 @@ impl NameSeg {
368413

369414
pub fn from_bytes(bytes: [u8; 4]) -> Result<NameSeg, AmlError> {
370415
if !is_lead_name_char(bytes[0]) {
371-
return Err(AmlError::InvalidNameSeg);
416+
return Err(AmlError::InvalidNameSeg(bytes));
372417
}
373418
if !is_name_char(bytes[1]) {
374-
return Err(AmlError::InvalidNameSeg);
419+
return Err(AmlError::InvalidNameSeg(bytes));
375420
}
376421
if !is_name_char(bytes[2]) {
377-
return Err(AmlError::InvalidNameSeg);
422+
return Err(AmlError::InvalidNameSeg(bytes));
378423
}
379424
if !is_name_char(bytes[3]) {
380-
return Err(AmlError::InvalidNameSeg);
425+
return Err(AmlError::InvalidNameSeg(bytes));
381426
}
382427
Ok(NameSeg(bytes))
383428
}

aml/src/object.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ pub enum Object {
99
BufferField { buffer: Arc<Object>, offset: usize, length: usize },
1010
Device,
1111
Event,
12-
FieldUnit,
12+
FieldUnit(FieldUnit),
1313
Integer(u64),
1414
Method { code: Vec<u8>, flags: MethodFlags },
1515
Mutex,
@@ -44,6 +44,13 @@ impl Object {
4444
}
4545
}
4646

47+
#[derive(Debug)]
48+
pub enum FieldUnit {
49+
Normal { region: Arc<Object>, bit_index: usize, bit_length: usize },
50+
Bank,
51+
Index,
52+
}
53+
4754
#[derive(Clone, Copy, Debug)]
4855
pub struct MethodFlags(pub u8);
4956

aml/src/op_region.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
#[derive(Debug)]
22
pub struct OpRegion {
3-
space: RegionSpace,
4-
base: u64,
5-
limit: u64,
3+
pub space: RegionSpace,
4+
pub base: u64,
5+
pub length: u64,
66
// parent_device
77
}
88

tests/buffer_fields.asl

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,23 @@
11
DefinitionBlock("buffer_fields.aml", "DSDT", 1, "RSACPI", "BUFFLD", 1) {
2-
Name(X, Buffer (16) { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff })
3-
CreateBitField(X, 3, BIT3)
4-
CreateField(X, 0, 3, BITS)
5-
CreateByteField(X, 1, BYTE)
6-
CreateWordField(X, 2, WORD)
7-
CreateDWordField(X, 4, DWRD)
8-
CreateQWordField(X, 8, QWRD)
2+
Name(X, Buffer (16) { 0xf0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff })
3+
CreateBitField(X, 3, BIT3)
4+
CreateField(X, 0, 3, BITS)
5+
CreateByteField(X, 1, BYTE)
6+
CreateWordField(X, 2, WORD)
7+
CreateDWordField(X, 4, DWRD)
8+
CreateQWordField(X, 8, QWRD)
99

10-
// `X` should end up as [0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00]
11-
BIT3 = 1
12-
BITS = 7
13-
BYTE = 0x01
14-
WORD = 0x0302
15-
DWRD = 0x07060504
16-
// Last two bytes should be cleared because of zero-extension of this store
17-
// We do this as a buffer store a) to test them b) because `iasl` doesn't support 64-bit integer constants...
18-
QWRD = Buffer() { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d }
10+
// `X` should end up as [0xff, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x00, 0x00]
11+
BIT3 = 1
12+
BITS = 7
13+
BYTE = 0x01
14+
WORD = 0x0302
15+
DWRD = 0x07060504
16+
// Last two bytes should be cleared because of zero-extension of this store
17+
// We do this as a buffer store a) to test them b) because `iasl` doesn't support 64-bit integer constants...
18+
QWRD = Buffer() { 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d }
1919

20-
// `Y` should end up as `Integer(0x07060504)` (`Integer(117835012)` in decimal)
21-
Name(Y, 4)
22-
Y = DWRD
20+
// `Y` should end up as `Integer(0x07060504)` (`Integer(117835012)` in decimal)
21+
Name(Y, 4)
22+
Y = DWRD
2323
}

tests/power_res.asl

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,16 @@
11
DefinitionBlock("power_res.aml", "DSDT", 1, "RSACPI", "PWRRES", 1) {
2-
Scope(_SB) {
3-
PowerResource(PIDE, 0, 1) {
4-
Name(X, Zero)
5-
Method(_STA) {
6-
Return (X)
7-
}
8-
Method(_ON) {
9-
Store(One, X)
10-
}
11-
Method(_OFF) {
12-
Store(Zero, X)
13-
}
14-
}
15-
}
2+
Scope(_SB) {
3+
PowerResource(PIDE, 0, 1) {
4+
Name(X, Zero)
5+
Method(_STA) {
6+
Return (X)
7+
}
8+
Method(_ON) {
9+
Store(One, X)
10+
}
11+
Method(_OFF) {
12+
Store(Zero, X)
13+
}
14+
}
15+
}
1616
}

tests/scopes.asl

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
DefinitionBlock("scopes.aml", "DSDT", 1, "RSACPI", "SCOPES", 1) {
2-
Scope(_SB) {
3-
Name(X, 320)
4-
Device(PCI0) {
5-
Name(Y, 15)
6-
Name (_HID, EisaId ("PNP0A03"))
7-
Scope(\) {
8-
Name(Z, 413)
9-
}
10-
}
11-
}
2+
Scope(_SB) {
3+
Name(X, 320)
4+
Name(Y, Zero)
5+
6+
Device(PCI0) {
7+
Name(Y, 15)
8+
Name (_HID, EisaId ("PNP0A03"))
9+
Scope(\) {
10+
Name(Z, 413)
11+
}
12+
}
13+
}
1214
}

tests/thermal_zone.asl

Lines changed: 36 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,40 +1,40 @@
11
DefinitionBlock("thermal_zone.aml", "DSDT", 1, "RSACPI", "THERMZ", 1) {
2-
Scope(_SB) {
3-
Device(EC0) {
4-
Name(_HID, EISAID("PNP0C09"))
5-
OperationRegion(EC0, EmbeddedControl, 0, 0xFF)
6-
Field(EC0, ByteAcc, Lock, Preserve) {
7-
MODE, 1, // thermal policy (quiet/perform)
8-
FAN, 1, // fan power (on/off)
9-
, 6, // reserved
10-
TMP, 16, // current temp
11-
AC0, 16, // active cooling temp (fan high)
12-
, 16, // reserved
13-
PSV, 16, // passive cooling temp
14-
HOT, 16, // critical S4 temp
15-
CRT, 16 // critical temp
16-
}
17-
}
2+
Scope(_SB) {
3+
Device(EC0) {
4+
Name(_HID, EISAID("PNP0C09"))
5+
OperationRegion(EC0, EmbeddedControl, 0, 0xFF)
6+
Field(EC0, ByteAcc, Lock, Preserve) {
7+
MODE, 1, // thermal policy (quiet/perform)
8+
FAN, 1, // fan power (on/off)
9+
, 6, // reserved
10+
TMP, 16, // current temp
11+
AC0, 16, // active cooling temp (fan high)
12+
, 16, // reserved
13+
PSV, 16, // passive cooling temp
14+
HOT, 16, // critical S4 temp
15+
CRT, 16 // critical temp
16+
}
17+
}
1818

19-
Device(CPU0) {
20-
Name(_HID, "ACPI0007")
21-
Name(_UID, 1) // unique number for this processor
22-
}
19+
Device(CPU0) {
20+
Name(_HID, "ACPI0007")
21+
Name(_UID, 1) // unique number for this processor
22+
}
2323

24-
ThermalZone(TZ0) {
25-
Method(_TMP) { Return (\_SB.EC0.TMP )} // get current temp
26-
Method(_AC0) { Return (\_SB.EC0.AC0) } // fan high temp
27-
Name(_AL0, Package(){\_SB.EC0.FAN}) // fan is act cool dev
28-
Method(_PSV) { Return (\_SB.EC0.PSV) } // passive cooling temp
29-
Name(_PSL, Package (){\_SB.CPU0}) // passive cooling devices
30-
Method(_HOT) { Return (\_SB.EC0.HOT) } // get critical S4 temp
31-
Method(_CRT) { Return (\_SB.EC0.CRT) } // get critical temp
32-
Method(_SCP, 1) { Store (Arg0, \_SB.EC0.MODE) } // set cooling mode
33-
Name(_TC1, 4) // bogus example constant
34-
Name(_TC2, 3) // bogus example constant
35-
Name(_TSP, 150) // passive sampling = 15 sec
36-
Name(_TZP, 0) // polling not required
37-
Name (_STR, Unicode ("System thermal zone"))
38-
}
39-
}
24+
ThermalZone(TZ0) {
25+
Method(_TMP) { Return (\_SB.EC0.TMP )} // get current temp
26+
Method(_AC0) { Return (\_SB.EC0.AC0) } // fan high temp
27+
Name(_AL0, Package(){\_SB.EC0.FAN}) // fan is act cool dev
28+
Method(_PSV) { Return (\_SB.EC0.PSV) } // passive cooling temp
29+
Name(_PSL, Package (){\_SB.CPU0}) // passive cooling devices
30+
Method(_HOT) { Return (\_SB.EC0.HOT) } // get critical S4 temp
31+
Method(_CRT) { Return (\_SB.EC0.CRT) } // get critical temp
32+
Method(_SCP, 1) { Store (Arg0, \_SB.EC0.MODE) } // set cooling mode
33+
Name(_TC1, 4) // bogus example constant
34+
Name(_TC2, 3) // bogus example constant
35+
Name(_TSP, 150) // passive sampling = 15 sec
36+
Name(_TZP, 0) // polling not required
37+
Name (_STR, Unicode ("System thermal zone"))
38+
}
39+
}
4040
}

0 commit comments

Comments
 (0)