Skip to main content

stable_aml/
namespace.rs

1use crate::{name_object::NameSeg, value::AmlValue, AmlError};
2use alloc::{
3    collections::BTreeMap,
4    string::{String, ToString},
5    vec::Vec,
6};
7use core::fmt;
8
9/// A handle is used to refer to an AML value without actually borrowing it until you need to
10/// access it (this makes borrowing situation much easier as you only have to consider who's
11/// borrowing the namespace). They can also be cached to avoid expensive namespace lookups.
12///
13/// Handles are never reused (the handle to a removed object will never be reused to point to a new
14/// object). This ensures handles cached by the library consumer will never point to an object they
15/// did not originally point to, but also means that, in theory, we can run out of handles on a
16/// very-long-running system (we are yet to see if this is a problem, practically).
17#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
18pub struct AmlHandle(u32);
19
20impl AmlHandle {
21    pub(self) fn increment(&mut self) {
22        self.0 += 1;
23    }
24}
25
26#[derive(Clone, Copy, PartialEq, Eq, Debug)]
27pub enum LevelType {
28    Scope,
29    Device,
30    /// A legacy `Processor` object's sub-objects are stored in a level of this type. Modern tables define
31    /// processors as `Device`s.
32    Processor,
33    /// A `PowerResource` object's sub-objects are stored in a level of this type.
34    PowerResource,
35    /// A `ThermalZone` object's sub-objects are stored in a level of this type.
36    ThermalZone,
37    /// A level of this type is created at the same path as the name of a method when it is invoked. It can be
38    /// used by the method to store local variables.
39    MethodLocals,
40}
41
42#[derive(Clone, Debug)]
43pub struct NamespaceLevel {
44    pub typ: LevelType,
45    pub children: BTreeMap<NameSeg, NamespaceLevel>,
46    pub values: BTreeMap<NameSeg, AmlHandle>,
47}
48
49impl NamespaceLevel {
50    pub(crate) fn new(typ: LevelType) -> NamespaceLevel {
51        NamespaceLevel {
52            typ,
53            children: BTreeMap::new(),
54            values: BTreeMap::new(),
55        }
56    }
57}
58
59#[derive(Clone)]
60pub struct Namespace {
61    /// This is a running count of ids, which are never reused. This is incremented every time we
62    /// add a new object to the namespace. We can then remove objects, freeing their memory, without
63    /// risking using the same id for two objects.
64    next_handle: AmlHandle,
65
66    /// This maps handles to actual values, and is used to access the actual AML values. When removing a value
67    /// from the object map, care must be taken to also remove references to its handle in the level data
68    /// structure, as invalid handles will cause panics.
69    object_map: BTreeMap<AmlHandle, AmlValue>,
70
71    /// Holds the first level of the namespace - containing items such as `\_SB`. Subsequent levels are held
72    /// recursively inside this structure. It holds handles to references, which need to be indexed into
73    /// `object_map` to acctually access the object.
74    root: NamespaceLevel,
75}
76
77impl Namespace {
78    pub fn new() -> Namespace {
79        Namespace {
80            next_handle: AmlHandle(0),
81            object_map: BTreeMap::new(),
82            root: NamespaceLevel::new(LevelType::Scope),
83        }
84    }
85
86    /// Add a new level to the namespace. A "level" is named by a single `NameSeg`, and can contain values, and
87    /// also other further sub-levels. Once a level has been created, AML values can be added to it with
88    /// `add_value`.
89    ///
90    /// ### Note
91    /// At first glance, you might expect `DefDevice` to add a value of type `Device`. However, because all
92    /// `Devices` do is hold other values, we model them as namespace levels, and so they must be created
93    /// accordingly.
94    pub fn add_level(&mut self, path: AmlName, typ: LevelType) -> Result<(), AmlError> {
95        let path = path.normalize().unwrap_or(AmlName::root());
96
97        /*
98         * We need to handle a special case here: if a `Scope(\) { ... }` appears in the AML, the parser will
99         * try and recreate the root scope. Instead of handling this specially in the parser, we just
100         * return nicely here.
101         */
102        if path != AmlName::root() {
103            let (level, last_seg) = self.get_level_for_path_mut(&path)?;
104
105            /*
106             * If the level has already been added, we don't need to add it again. The parser can try to add it
107             * multiple times if the ASL contains multiple blocks that add to the same scope/device.
108             */
109            if !level.children.contains_key(&last_seg) {
110                level.children.insert(last_seg, NamespaceLevel::new(typ));
111            }
112        }
113
114        Ok(())
115    }
116
117    pub fn remove_level(&mut self, path: AmlName) -> Result<(), AmlError> {
118        let path = path.normalize().unwrap_or(AmlName::root());
119
120        if path != AmlName::root() {
121            let (level, last_seg) = self.get_level_for_path_mut(&path)?;
122
123            match level.children.remove(&last_seg) {
124                Some(_) => Ok(()),
125                None => Err(AmlError::LevelDoesNotExist(path)),
126            }
127        } else {
128            Err(AmlError::TriedToRemoveRootNamespace)
129        }
130    }
131
132    /// Add a value to the namespace at the given path, which must be a normalized, absolute AML
133    /// name. If you want to add at a path relative to a given scope, use `add_at_resolved_path`
134    /// instead.
135    pub fn add_value(&mut self, path: AmlName, value: AmlValue) -> Result<AmlHandle, AmlError> {
136        let path = path.normalize().unwrap_or(AmlName::root());
137
138        let handle = self.next_handle;
139        self.next_handle.increment();
140        self.object_map.insert(handle, value);
141
142        let (level, last_seg) = self.get_level_for_path_mut(&path)?;
143        match level.values.insert(last_seg, handle) {
144            None => Ok(handle),
145            Some(_) => Err(AmlError::NameCollision(path)),
146        }
147    }
148
149    /// Helper method for adding a value to the namespace at a path that is relative to the given
150    /// scope. This operation involves a lot of error handling in parts of the parser, so is
151    /// encapsulated here.
152    pub fn add_value_at_resolved_path(
153        &mut self,
154        path: AmlName,
155        scope: &AmlName,
156        value: AmlValue,
157    ) -> Result<AmlHandle, AmlError> {
158        self.add_value(path.resolve(scope)?, value)
159    }
160
161    /// Add an alias for an existing name. The alias will refer to the same value as the original,
162    /// and the fact that the alias exists is forgotten.
163    pub fn add_alias_at_resolved_path(
164        &mut self,
165        path: AmlName,
166        scope: &AmlName,
167        target: AmlName,
168    ) -> Result<AmlHandle, AmlError> {
169        let path = path.resolve(scope)?;
170        let target = target.resolve(scope)?;
171
172        let handle = self.get_handle(&target)?;
173
174        let (level, last_seg) = self.get_level_for_path_mut(&path)?;
175        match level.values.insert(last_seg, handle) {
176            None => Ok(handle),
177            Some(_) => Err(AmlError::NameCollision(path)),
178        }
179    }
180
181    pub fn get(&self, handle: AmlHandle) -> Result<&AmlValue, AmlError> {
182        Ok(self.object_map.get(&handle).unwrap())
183    }
184
185    pub fn get_mut(&mut self, handle: AmlHandle) -> Result<&mut AmlValue, AmlError> {
186        Ok(self.object_map.get_mut(&handle).unwrap())
187    }
188
189    pub fn get_handle(&self, path: &AmlName) -> Result<AmlHandle, AmlError> {
190        let (level, last_seg) = self.get_level_for_path(path)?;
191        Ok(*level
192            .values
193            .get(&last_seg)
194            .ok_or(AmlError::ValueDoesNotExist(path.clone()))?)
195    }
196
197    pub fn get_by_path(&self, path: &AmlName) -> Result<&AmlValue, AmlError> {
198        let handle = self.get_handle(path)?;
199        Ok(self.get(handle).unwrap())
200    }
201
202    pub fn get_by_path_mut(&mut self, path: &AmlName) -> Result<&mut AmlValue, AmlError> {
203        let handle = self.get_handle(path)?;
204        Ok(self.get_mut(handle).unwrap())
205    }
206
207    /// Search for an object at the given path of the namespace, applying the search rules described in ยง5.3 of the
208    /// ACPI specification, if they are applicable. Returns the resolved name, and the handle of the first valid
209    /// object, if found.
210    pub fn search(
211        &self,
212        path: &AmlName,
213        starting_scope: &AmlName,
214    ) -> Result<(AmlName, AmlHandle), AmlError> {
215        if path.search_rules_apply() {
216            /*
217             * If search rules apply, we need to recursively look through the namespace. If the
218             * given name does not occur in the current scope, we look at the parent scope, until
219             * we either find the name, or reach the root of the namespace.
220             */
221            let scope = starting_scope.clone();
222            let mut scope = scope.normalize().unwrap_or(AmlName::root());
223            loop {
224                // Search for the name at this namespace level. If we find it, we're done.
225                let name = path.resolve(&scope)?;
226                match self.get_level_for_path(&name) {
227                    Ok((level, last_seg)) => {
228                        if let Some(&handle) = level.values.get(&last_seg) {
229                            return Ok((name, handle));
230                        }
231                    }
232
233                    /*
234                     * This error is caught specially to avoid a case that seems bizzare but is quite useful - when
235                     * the passed starting scope doesn't exist. Certain methods return values that reference names
236                     * from the point of view of the method, so it makes sense for the starting scope to be inside
237                     * the method.  However, because we have destroyed all the objects created by the method
238                     * dynamically, the level no longer exists.
239                     *
240                     * To avoid erroring here, we simply continue to the parent scope. If the whole scope doesn't
241                     * exist, this will error when we get to the root, so this seems unlikely to introduce bugs.
242                     */
243                    Err(AmlError::LevelDoesNotExist(_)) => (),
244                    Err(err) => return Err(err),
245                }
246
247                // If we don't find it, go up a level in the namespace and search for it there recursively
248                match scope.parent() {
249                    Ok(parent) => scope = parent,
250                    // If we still haven't found the value and have run out of parents, return `None`.
251                    Err(AmlError::RootHasNoParent) => {
252                        return Err(AmlError::ValueDoesNotExist(path.clone()))
253                    }
254                    Err(err) => return Err(err),
255                }
256            }
257        } else {
258            // If search rules don't apply, simply resolve it against the starting scope
259            let name = path.resolve(starting_scope)?;
260            // TODO: the fuzzer crashes when path is `\` and the scope is also `\`. This means that name is `\`,
261            // which then trips up get_level_for_path. I don't know where to best solve this: we could check for
262            // specific things that crash `search`, or look for a more general solution.
263            let (level, last_seg) = self.get_level_for_path(&path.resolve(starting_scope)?)?;
264
265            if let Some(&handle) = level.values.get(&last_seg) {
266                Ok((name, handle))
267            } else {
268                Err(AmlError::ValueDoesNotExist(path.clone()))
269            }
270        }
271    }
272
273    pub fn search_for_level(
274        &self,
275        level_name: &AmlName,
276        starting_scope: &AmlName,
277    ) -> Result<AmlName, AmlError> {
278        if level_name.search_rules_apply() {
279            let scope = starting_scope.clone().normalize()?;
280            let mut scope = scope.normalize().unwrap_or(AmlName::root());
281
282            loop {
283                let name = level_name.resolve(&scope)?;
284                if let Ok((level, last_seg)) = self.get_level_for_path(&name) {
285                    if let Some(_) = level.children.get(&last_seg) {
286                        return Ok(name);
287                    }
288                }
289
290                // If we don't find it, move the scope up a level and search for it there recursively
291                match scope.parent() {
292                    Ok(parent) => scope = parent,
293                    Err(AmlError::RootHasNoParent) => {
294                        return Err(AmlError::LevelDoesNotExist(level_name.clone()))
295                    }
296                    Err(err) => return Err(err),
297                }
298            }
299        } else {
300            Ok(level_name.clone())
301        }
302    }
303
304    fn get_level_for_path(&self, path: &AmlName) -> Result<(&NamespaceLevel, NameSeg), AmlError> {
305        assert_ne!(*path, AmlName::root());
306
307        let (last_seg, levels) = path.0[1..].split_last().unwrap();
308        let last_seg = last_seg.as_segment().unwrap();
309
310        // TODO: this helps with diagnostics, but requires a heap allocation just in case we need to error.
311        let mut traversed_path = AmlName::root();
312
313        let mut current_level = &self.root;
314        for level in levels {
315            traversed_path.0.push(*level);
316            current_level = current_level
317                .children
318                .get(&level.as_segment().unwrap())
319                .ok_or(AmlError::LevelDoesNotExist(traversed_path.clone()))?;
320        }
321
322        Ok((current_level, last_seg))
323    }
324
325    /// Split an absolute path into a bunch of level segments (used to traverse the level data structure), and a
326    /// last segment to index into that level. This must not be called on `\\`.
327    fn get_level_for_path_mut(
328        &mut self,
329        path: &AmlName,
330    ) -> Result<(&mut NamespaceLevel, NameSeg), AmlError> {
331        assert_ne!(*path, AmlName::root());
332
333        let (last_seg, levels) = path.0[1..].split_last().unwrap();
334        let last_seg = last_seg.as_segment().unwrap();
335
336        // TODO: this helps with diagnostics, but requires a heap allocation just in case we need to error. We can
337        // improve this by changing the `levels` interation into an `enumerate()`, and then using the index to
338        // create the correct path on the error path
339        let mut traversed_path = AmlName::root();
340
341        let mut current_level = &mut self.root;
342        for level in levels {
343            traversed_path.0.push(*level);
344            current_level = current_level
345                .children
346                .get_mut(&level.as_segment().unwrap())
347                .ok_or(AmlError::LevelDoesNotExist(traversed_path.clone()))?;
348        }
349
350        Ok((current_level, last_seg))
351    }
352
353    /// Traverse the namespace, calling `f` on each namespace level. `f` returns a `Result<bool, AmlError>` -
354    /// errors terminate the traversal and are propagated, and the `bool` on the successful path marks whether the
355    /// children of the level should also be traversed.
356    pub fn traverse<F>(&mut self, mut f: F) -> Result<(), AmlError>
357    where
358        F: FnMut(&AmlName, &NamespaceLevel) -> Result<bool, AmlError>,
359    {
360        fn traverse_level<F>(
361            level: &NamespaceLevel,
362            scope: &AmlName,
363            f: &mut F,
364        ) -> Result<(), AmlError>
365        where
366            F: FnMut(&AmlName, &NamespaceLevel) -> Result<bool, AmlError>,
367        {
368            for (name, ref child) in level.children.iter() {
369                let name = AmlName::from_name_seg(*name).resolve(scope)?;
370
371                if f(&name, child)? {
372                    traverse_level(child, &name, f)?;
373                }
374            }
375
376            Ok(())
377        }
378
379        if f(&AmlName::root(), &self.root)? {
380            traverse_level(&self.root, &AmlName::root(), &mut f)?;
381        }
382
383        Ok(())
384    }
385}
386
387impl fmt::Debug for Namespace {
388    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
389        const INDENT_PER_LEVEL: usize = 4;
390
391        fn print_level(
392            namespace: &Namespace,
393            f: &mut fmt::Formatter<'_>,
394            level_name: &str,
395            level: &NamespaceLevel,
396            indent: usize,
397        ) -> fmt::Result {
398            writeln!(f, "{:indent$}{}:", "", level_name, indent = indent)?;
399
400            for (name, handle) in level.values.iter() {
401                writeln!(
402                    f,
403                    "{:indent$}{}: {:?}",
404                    "",
405                    name.as_str(),
406                    namespace.object_map.get(handle).unwrap(),
407                    indent = indent + INDENT_PER_LEVEL
408                )?;
409            }
410
411            for (name, sub_level) in level.children.iter() {
412                print_level(
413                    namespace,
414                    f,
415                    name.as_str(),
416                    sub_level,
417                    indent + INDENT_PER_LEVEL,
418                )?;
419            }
420
421            Ok(())
422        }
423
424        print_level(self, f, "\\", &self.root, 0)
425    }
426}
427
428#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
429pub struct AmlName(Vec<NameComponent>);
430
431impl AmlName {
432    pub fn root() -> AmlName {
433        AmlName(alloc::vec![NameComponent::Root])
434    }
435
436    pub fn from_name_seg(seg: NameSeg) -> AmlName {
437        AmlName(alloc::vec![NameComponent::Segment(seg)])
438    }
439
440    pub fn from_components(components: Vec<NameComponent>) -> AmlName {
441        assert!(components.len() > 0);
442        AmlName(components)
443    }
444
445    /// Convert a string representation of an AML name into an `AmlName`.
446    pub fn from_str(mut string: &str) -> Result<AmlName, AmlError> {
447        if string.len() == 0 {
448            return Err(AmlError::EmptyNamesAreInvalid);
449        }
450
451        let mut components = Vec::new();
452
453        // If it starts with a \, make it an absolute name
454        if string.starts_with('\\') {
455            components.push(NameComponent::Root);
456            string = &string[1..];
457        }
458
459        if string.len() > 0 {
460            // Divide the rest of it into segments, and parse those
461            for mut part in string.split('.') {
462                // Handle prefix chars
463                while part.starts_with('^') {
464                    components.push(NameComponent::Prefix);
465                    part = &part[1..];
466                }
467
468                components.push(NameComponent::Segment(NameSeg::from_str(part)?));
469            }
470        }
471
472        Ok(AmlName(components))
473    }
474
475    pub fn as_string(&self) -> String {
476        self.0
477            .iter()
478            .fold(String::new(), |name, component| match component {
479                NameComponent::Root => name + "\\",
480                NameComponent::Prefix => name + "^",
481                NameComponent::Segment(seg) => name + seg.as_str() + ".",
482            })
483            .trim_end_matches('.')
484            .to_string()
485    }
486
487    /// An AML path is normal if it does not contain any prefix elements ("^" characters, when
488    /// expressed as a string).
489    pub fn is_normal(&self) -> bool {
490        !self.0.contains(&NameComponent::Prefix)
491    }
492
493    pub fn is_absolute(&self) -> bool {
494        self.0.first() == Some(&NameComponent::Root)
495    }
496
497    /// Special rules apply when searching for certain paths (specifically, those that are made up
498    /// of a single name segment). Returns `true` if those rules apply.
499    pub fn search_rules_apply(&self) -> bool {
500        if self.0.len() != 1 {
501            return false;
502        }
503
504        match self.0[0] {
505            NameComponent::Segment(_) => true,
506            _ => false,
507        }
508    }
509
510    /// Normalize an AML path, resolving prefix chars. Returns `AmlError::InvalidNormalizedName` if the path
511    /// normalizes to an invalid path (e.g. `\^_FOO`)
512    pub fn normalize(self) -> Result<AmlName, AmlError> {
513        /*
514         * If the path is already normal, just return it as-is. This avoids an unneccessary heap allocation and
515         * free.
516         */
517        if self.is_normal() {
518            return Ok(self);
519        }
520
521        Ok(AmlName(self.0.iter().try_fold(
522            Vec::new(),
523            |mut name, &component| match component {
524                seg @ NameComponent::Segment(_) => {
525                    name.push(seg);
526                    Ok(name)
527                }
528
529                NameComponent::Root => {
530                    name.push(NameComponent::Root);
531                    Ok(name)
532                }
533
534                NameComponent::Prefix => {
535                    if let Some(NameComponent::Segment(_)) = name.iter().last() {
536                        name.pop().unwrap();
537                        Ok(name)
538                    } else {
539                        Err(AmlError::InvalidNormalizedName(self.clone()))
540                    }
541                }
542            },
543        )?))
544    }
545
546    /// Get the parent of this `AmlName`. For example, the parent of `\_SB.PCI0._PRT` is `\_SB.PCI0`. The root
547    /// path has no parent, and so returns `None`.
548    pub fn parent(&self) -> Result<AmlName, AmlError> {
549        // Firstly, normalize the path so we don't have to deal with prefix chars
550        let mut normalized_self = self.clone().normalize()?;
551
552        match normalized_self.0.last() {
553            None | Some(NameComponent::Root) => Err(AmlError::RootHasNoParent),
554            Some(NameComponent::Segment(_)) => {
555                normalized_self.0.pop();
556                Ok(normalized_self)
557            }
558            Some(NameComponent::Prefix) => unreachable!(), // Prefix chars are removed by normalization
559        }
560    }
561
562    /// Resolve this path against a given scope, making it absolute. If the path is absolute, it is
563    /// returned directly. The path is also normalized.
564    pub fn resolve(&self, scope: &AmlName) -> Result<AmlName, AmlError> {
565        let scope = scope.clone().normalize().unwrap_or(AmlName::root());
566
567        if self.is_absolute() {
568            return Ok(self.clone());
569        }
570
571        let mut resolved_path = scope.clone();
572        resolved_path.0.extend_from_slice(&(self.0));
573        resolved_path.normalize()
574    }
575}
576
577impl fmt::Display for AmlName {
578    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
579        write!(f, "{}", self.as_string())
580    }
581}
582
583#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)]
584pub enum NameComponent {
585    Root,
586    Prefix,
587    Segment(NameSeg),
588}
589
590impl NameComponent {
591    pub fn as_segment(self) -> Result<NameSeg, ()> {
592        match self {
593            NameComponent::Segment(seg) => Ok(seg),
594            NameComponent::Root | NameComponent::Prefix => Err(()),
595        }
596    }
597}