11use super :: {
22 AmlError ,
3- object:: { MethodFlags , Object , WrappedObject } ,
3+ object:: { Object , ObjectType , WrappedObject } ,
44} ;
55use alloc:: {
66 collections:: btree_map:: BTreeMap ,
77 string:: { String , ToString } ,
8- sync:: Arc ,
98 vec,
109 vec:: Vec ,
1110} ;
1211use bit_field:: BitField ;
1312use core:: { fmt, str, str:: FromStr } ;
14- use log:: trace;
13+ use log:: { trace, warn } ;
1514
1615#[ derive( Clone ) ]
1716pub 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