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