Skip to content

Commit 425cd54

Browse files
committed
AML: define _OS, _OSI, and _REV predefined objects
1 parent 3fe6282 commit 425cd54

File tree

1 file changed

+96
-9
lines changed

1 file changed

+96
-9
lines changed

src/aml/namespace.rs

Lines changed: 96 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,16 @@
11
use super::{
22
AmlError,
3-
object::{MethodFlags, Object, WrappedObject},
3+
object::{Object, ObjectType, WrappedObject},
44
};
55
use alloc::{
66
collections::btree_map::BTreeMap,
77
string::{String, ToString},
8-
sync::Arc,
98
vec,
109
vec::Vec,
1110
};
1211
use bit_field::BitField;
1312
use core::{fmt, str, str::FromStr};
14-
use log::trace;
13+
use log::{trace, warn};
1514

1615
#[derive(Clone)]
1716
pub struct Namespace {
@@ -29,13 +28,101 @@ impl Namespace {
2928
namespace.add_level(AmlName::from_str("\\_PR").unwrap(), NamespaceLevelKind::Scope).unwrap();
3029
namespace.add_level(AmlName::from_str("\\_TZ").unwrap(), NamespaceLevelKind::Scope).unwrap();
3130

32-
// TODO: this is just testing the native methods atm - actually implement it
33-
namespace.insert(
34-
AmlName::from_str("\\_OSI").unwrap(),
35-
Object::NativeMethod { f: Arc::new(|args| todo!()), flags: MethodFlags(0) }.wrap(),
36-
);
31+
/*
32+
* In the dark ages of ACPI 1.0, before `\_OSI`, `\_OS` was used to communicate to the firmware which OS
33+
* was running. This was predictably not very good, and so was replaced in ACPI 3.0 with `_OSI`, which
34+
* allows support for individual capabilities to be queried. `_OS` should not be used by modern firmwares;
35+
* we follow the NT interpreter and ACPICA by calling ourselves `Microsoft Windows NT`.
36+
*
37+
* See https://www.kernel.org/doc/html/latest/firmware-guide/acpi/osi.html for more information.
38+
*/
39+
namespace
40+
.insert(AmlName::from_str("\\_OS").unwrap(), Object::String("Microsoft Windows NT".to_string()).wrap())
41+
.unwrap();
42+
43+
/*
44+
* `\_OSI` was introduced by ACPI 3.0 to improve the situation created by `\_OS`. Unfortunately, exactly
45+
* the same problem was immediately repeated by introducing capabilities reflecting that an ACPI
46+
* implementation is exactly the same as a particular version of Windows' (e.g. firmwares will call
47+
* `\_OSI("Windows 2001")`).
48+
*
49+
* We basically follow suit with whatever Linux does, as this will hopefully minimise breakage:
50+
* - We always claim `Windows *` compatability
51+
* - We answer 'yes' to `_OSI("Darwin")
52+
* - We answer 'no' to `_OSI("Linux")`, and report that the tables are doing the wrong thing
53+
*/
54+
namespace
55+
.insert(
56+
AmlName::from_str("\\_OSI").unwrap(),
57+
Object::native_method(1, |args| {
58+
if args.len() != 1 {
59+
return Err(AmlError::MethodArgCountIncorrect);
60+
}
61+
let Object::String(ref feature) = *args[0] else {
62+
return Err(AmlError::ObjectNotOfExpectedType {
63+
expected: ObjectType::String,
64+
got: args[0].typ(),
65+
});
66+
};
67+
68+
let is_supported = match feature.as_str() {
69+
"Windows 2000" => true, // 2000
70+
"Windows 2001" => true, // XP
71+
"Windows 2001 SP1" => true, // XP SP1
72+
"Windows 2001 SP2" => true, // XP SP2
73+
"Windows 2001.1" => true, // Server 2003
74+
"Windows 2001.1 SP1" => true, // Server 2003 SP1
75+
"Windows 2006" => true, // Vista
76+
"Windows 2006 SP1" => true, // Vista SP1
77+
"Windows 2006 SP2" => true, // Vista SP2
78+
"Windows 2006.1" => true, // Server 2008
79+
"Windows 2009" => true, // 7 and Server 2008 R2
80+
"Windows 2012" => true, // 8 and Server 2012
81+
"Windows 2013" => true, // 8.1 and Server 2012 R2
82+
"Windows 2015" => true, // 10
83+
"Windows 2016" => true, // 10 version 1607
84+
"Windows 2017" => true, // 10 version 1703
85+
"Windows 2017.2" => true, // 10 version 1709
86+
"Windows 2018" => true, // 10 version 1803
87+
"Windows 2018.2" => true, // 10 version 1809
88+
"Windows 2019" => true, // 10 version 1903
89+
"Windows 2020" => true, // 10 version 20H1
90+
"Windows 2021" => true, // 11
91+
"Windows 2022" => true, // 11 version 22H2
92+
93+
// TODO: Linux answers yes to this, NT answers no. Maybe make configurable
94+
"Darwin" => false,
95+
96+
"Linux" => {
97+
// TODO: should we allow users to specify that this should be true? Linux has a
98+
// command line option for this.
99+
warn!("ACPI evaluated `_OSI(\"Linux\")`. This is a bug. Reporting no support.");
100+
false
101+
}
102+
103+
"Extended Address Space Descriptor" => true,
104+
"Module Device" => true,
105+
"3.0 Thermal Model" => true,
106+
"3.0 _SCP Extensions" => true,
107+
"Processor Aggregator Device" => true,
108+
_ => false,
109+
};
110+
111+
Ok(Object::Integer(if is_supported { u64::MAX } else { 0 }).wrap())
112+
})
113+
.wrap(),
114+
)
115+
.unwrap();
116+
117+
/*
118+
* `\_REV` evaluates to the version of the ACPI specification supported by this interpreter. Linux did this
119+
* correctly until 2015, but firmwares misused this to detect Linux (as even modern versions of Windows
120+
* return `2`), and so they switched to just returning `2` (as we'll also do). `_REV` should be considered
121+
* useless and deprecated (this is mirrored in newer specs, which claim `2` means "ACPI 2 or greater").
122+
*/
123+
namespace.insert(AmlName::from_str("\\_REV").unwrap(), Object::Integer(2).wrap()).unwrap();
37124

38-
// TODO: add pre-defined objects as well - \GL, \OSI, etc.
125+
// TODO: _GL
39126

40127
namespace
41128
}

0 commit comments

Comments
 (0)