Skip to content

Commit 9cf6293

Browse files
committed
aml: start process for initializing namespace - _STA and _INI objects
1 parent de76c39 commit 9cf6293

File tree

4 files changed

+123
-4
lines changed

4 files changed

+123
-4
lines changed

aml/src/lib.rs

+91-1
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,17 @@ use bit_field::BitField;
2323
use core::{mem, str::FromStr};
2424
use log::{info, trace, warn};
2525
use namespace::{AmlName, Namespace, NamespaceLevelKind};
26-
use object::{FieldFlags, FieldUnit, FieldUnitKind, MethodFlags, Object, ObjectType, ReferenceKind};
26+
use object::{
27+
DeviceStatus,
28+
FieldFlags,
29+
FieldUnit,
30+
FieldUnitKind,
31+
FieldUpdateRule,
32+
MethodFlags,
33+
Object,
34+
ObjectType,
35+
ReferenceKind,
36+
};
2737
use op_region::{OpRegion, RegionHandler, RegionSpace};
2838
use spinning_top::Spinlock;
2939

@@ -109,6 +119,85 @@ where
109119
handlers.insert(space, Box::new(handler));
110120
}
111121

122+
/// Initialize the namespace - this should be called after all tables have been loaded and
123+
/// operation region handlers registered. Specifically, it will call relevant `_STA`, `_INI`,
124+
/// and `_REG` methods.
125+
pub fn initialize_namespace(&self) {
126+
/*
127+
* This should match the initialization order of ACPICA and uACPI.
128+
*/
129+
if let Err(err) = self.invoke_method_if_present(AmlName::from_str("\\_INI").unwrap(), vec![]) {
130+
warn!("Invoking \\_INI failed: {:?}", err);
131+
}
132+
if let Err(err) = self.invoke_method_if_present(AmlName::from_str("\\_SB._INI").unwrap(), vec![]) {
133+
warn!("Invoking \\_SB._INI failed: {:?}", err);
134+
}
135+
136+
// TODO: run all _REGs for globally-installed handlers (this might need more bookkeeping)
137+
138+
/*
139+
* We can now initialize each device in the namespace. For each device, we evaluate `_STA`,
140+
* which indicates if the device is present and functional. If this method does not exist,
141+
* we assume the device should be initialized.
142+
*
143+
* We then evaluate `_INI` for the device. This can dynamically populate objects such as
144+
* `_ADR`, `_CID`, `_HID`, `_SUN`, and `_UID`, and so is necessary before further
145+
* operation.
146+
*/
147+
let mut num_devices_initialized = 0;
148+
/*
149+
* TODO
150+
* We clone a copy of the namespace here to traverse while executing all the `_STA` and
151+
* `_INI` objects. Avoiding this would be good, but is not easy, as we need
152+
* potentially-mutable access while executing all of the methods.
153+
*/
154+
let mut namespace = self.namespace.lock().clone();
155+
let init_status = namespace.traverse(|path, level| {
156+
match level.kind {
157+
NamespaceLevelKind::Device
158+
| NamespaceLevelKind::Processor
159+
| NamespaceLevelKind::ThermalZone
160+
| NamespaceLevelKind::PowerResource => {
161+
let should_initialize = match self
162+
.invoke_method_if_present(AmlName::from_str("_STA").unwrap().resolve(path)?, vec![])
163+
{
164+
Ok(Some(result)) => {
165+
let Object::Integer(result) = *result else { panic!() };
166+
let status = DeviceStatus(result);
167+
status.present() && status.functioning()
168+
}
169+
Ok(None) => true,
170+
Err(err) => {
171+
warn!("Failed to evaluate _STA for device {}: {:?}", path, err);
172+
false
173+
}
174+
};
175+
176+
if should_initialize {
177+
num_devices_initialized += 1;
178+
if let Err(err) = self
179+
.invoke_method_if_present(AmlName::from_str("_INI").unwrap().resolve(path)?, vec![])
180+
{
181+
warn!("Failed to evaluate _INI for device {}: {:?}", path, err);
182+
}
183+
Ok(true)
184+
} else {
185+
/*
186+
* If this device should not be initialized, don't initialize it's children.
187+
*/
188+
Ok(false)
189+
}
190+
}
191+
_ => Ok(true),
192+
}
193+
});
194+
if let Err(err) = init_status {
195+
warn!("Error while traversing namespace for devices: {:?}", err);
196+
}
197+
198+
info!("Initialized {} devices", num_devices_initialized);
199+
}
200+
112201
fn do_execute_method(&self, mut context: MethodContext) -> Result<Arc<Object>, AmlError> {
113202
/*
114203
* This is the main loop that executes operations. Every op is handled at the top-level of
@@ -2529,6 +2618,7 @@ pub trait Handler: Send + Sync {
25292618
/// without causing a deadlock.
25302619
fn acquire(&self, mutex: Handle, timeout: u16) -> Result<(), AmlError>;
25312620
fn release(&self, mutex: Handle);
2621+
25322622
fn breakpoint(&self) {}
25332623

25342624
fn handle_debug(&self, _object: &Object) {}

aml/src/namespace.rs

+2
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ use alloc::{
99
use bit_field::BitField;
1010
use core::{fmt, str, str::FromStr};
1111

12+
#[derive(Clone)]
1213
pub struct Namespace {
1314
root: NamespaceLevel,
1415
}
@@ -312,6 +313,7 @@ pub enum NamespaceLevelKind {
312313
MethodLocals,
313314
}
314315

316+
#[derive(Clone)]
315317
pub struct NamespaceLevel {
316318
pub kind: NamespaceLevelKind,
317319
pub values: BTreeMap<NameSeg, (ObjectFlags, Arc<Object>)>,

aml/src/object.rs

+29-2
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::{AmlError, Handle, Operation, op_region::OpRegion};
22
use alloc::{borrow::Cow, string::String, sync::Arc, vec::Vec};
33
use bit_field::BitField;
44

5-
#[derive(Debug)]
5+
#[derive(Clone, Debug)]
66
pub enum Object {
77
Uninitialized,
88
Buffer(Vec<u8>),
@@ -183,7 +183,7 @@ impl Object {
183183
}
184184
}
185185

186-
#[derive(Debug)]
186+
#[derive(Clone, Debug)]
187187
pub struct FieldUnit {
188188
pub kind: FieldUnitKind,
189189
pub flags: FieldFlags,
@@ -305,6 +305,33 @@ pub enum ObjectType {
305305
Debug,
306306
}
307307

308+
/// Helper type for decoding the result of `_STA` objects.
309+
pub struct DeviceStatus(pub u64);
310+
311+
impl DeviceStatus {
312+
pub fn present(&self) -> bool {
313+
self.0.get_bit(0)
314+
}
315+
316+
pub fn enabled(&self) -> bool {
317+
self.0.get_bit(1)
318+
}
319+
320+
pub fn show_in_ui(&self) -> bool {
321+
self.0.get_bit(2)
322+
}
323+
324+
pub fn functioning(&self) -> bool {
325+
self.0.get_bit(3)
326+
}
327+
328+
/// This flag is only used for Battery devices (PNP0C0A), and indicates if the battery is
329+
/// present.
330+
pub fn battery_present(&self) -> bool {
331+
self.0.get_bit(4)
332+
}
333+
}
334+
308335
/// Copy an arbitrary bit range of `src` to an arbitrary bit range of `dst`. This is used for
309336
/// buffer fields. Data is zero-extended if `src` does not cover `length` bits, matching the
310337
/// expected behaviour for buffer fields.

aml/src/op_region.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
use crate::{AmlError, namespace::AmlName};
22

3-
#[derive(Debug)]
3+
#[derive(Clone, Debug)]
44
pub struct OpRegion {
55
pub space: RegionSpace,
66
pub base: u64,

0 commit comments

Comments
 (0)