diff options
author | Len Brown <len.brown@intel.com> | 2016-11-30 23:00:30 -0500 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2016-12-02 20:36:26 -0500 |
commit | bc18461816bd3a6a141e472f68c886bb932a6c2e (patch) | |
tree | 0f88f89d5ad546d73ac5ac72205ee6666bcddf1c | |
parent | e5517c2a5a49ed5e99047008629f1cd60246ea0e (diff) |
ACPI: Document _OSI and _REV for Linux BIOS writers
Based on a recent session at the Linux Plumber's Conference,
we need to be more clear about how a BIOS should use _OSI
to properly support Linux.
Signed-off-by: Len Brown <len.brown@intel.com>
Reviewed-by: Lukas Wunner <lukas@wunner.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | Documentation/acpi/osi.txt | 187 |
1 files changed, 187 insertions, 0 deletions
diff --git a/Documentation/acpi/osi.txt b/Documentation/acpi/osi.txt new file mode 100644 index 000000000000..50cde0ceb9b0 --- /dev/null +++ b/Documentation/acpi/osi.txt | |||
@@ -0,0 +1,187 @@ | |||
1 | ACPI _OSI and _REV methods | ||
2 | -------------------------- | ||
3 | |||
4 | An ACPI BIOS can use the "Operating System Interfaces" method (_OSI) | ||
5 | to find out what the operating system supports. Eg. If BIOS | ||
6 | AML code includes _OSI("XYZ"), the kernel's AML interpreter | ||
7 | can evaluate that method, look to see if it supports 'XYZ' | ||
8 | and answer YES or NO to the BIOS. | ||
9 | |||
10 | The ACPI _REV method returns the "Revision of the ACPI specification | ||
11 | that OSPM supports" | ||
12 | |||
13 | This document explains how and why the BIOS and Linux should use these methods. | ||
14 | It also explains how and why they are widely misused. | ||
15 | |||
16 | How to use _OSI | ||
17 | --------------- | ||
18 | |||
19 | Linux runs on two groups of machines -- those that are tested by the OEM | ||
20 | to be compatible with Linux, and those that were never tested with Linux, | ||
21 | but where Linux was installed to replace the original OS (Windows or OSX). | ||
22 | |||
23 | The larger group is the systems tested to run only Windows. Not only that, | ||
24 | but many were tested to run with just one specific version of Windows. | ||
25 | So even though the BIOS may use _OSI to query what version of Windows is running, | ||
26 | only a single path through the BIOS has actually been tested. | ||
27 | Experience shows that taking untested paths through the BIOS | ||
28 | exposes Linux to an entire category of BIOS bugs. | ||
29 | For this reason, Linux _OSI defaults must continue to claim compatibility | ||
30 | with all versions of Windows. | ||
31 | |||
32 | But Linux isn't actually compatible with Windows, and the Linux community | ||
33 | has also been hurt with regressions when Linux adds the latest version of | ||
34 | Windows to its list of _OSI strings. So it is possible that additional strings | ||
35 | will be more thoroughly vetted before shipping upstream in the future. | ||
36 | But it is likely that they will all eventually be added. | ||
37 | |||
38 | What should an OEM do if they want to support Linux and Windows | ||
39 | using the same BIOS image? Often they need to do something different | ||
40 | for Linux to deal with how Linux is different from Windows. | ||
41 | Here the BIOS should ask exactly what it wants to know: | ||
42 | |||
43 | _OSI("Linux-OEM-my_interface_name") | ||
44 | where 'OEM' is needed if this is an OEM-specific hook, | ||
45 | and 'my_interface_name' describes the hook, which could be a | ||
46 | quirk, a bug, or a bug-fix. | ||
47 | |||
48 | In addition, the OEM should send a patch to upstream Linux | ||
49 | via the linux-acpi@vger.kernel.org mailing list. When that patch | ||
50 | is checked into Linux, the OS will answer "YES" when the BIOS | ||
51 | on the OEM's system uses _OSI to ask if the interface is supported | ||
52 | by the OS. Linux distributors can back-port that patch for Linux | ||
53 | pre-installs, and it will be included by all distributions that | ||
54 | re-base to upstream. If the distribution can not update the kernel binary, | ||
55 | they can also add an acpi_osi=Linux-OEM-my_interface_name | ||
56 | cmdline parameter to the boot loader, as needed. | ||
57 | |||
58 | If the string refers to a feature where the upstream kernel | ||
59 | eventually grows support, a patch should be sent to remove | ||
60 | the string when that support is added to the kernel. | ||
61 | |||
62 | That was easy. Read on, to find out how to do it wrong. | ||
63 | |||
64 | Before _OSI, there was _OS | ||
65 | -------------------------- | ||
66 | |||
67 | ACPI 1.0 specified "_OS" as an | ||
68 | "object that evaluates to a string that identifies the operating system." | ||
69 | |||
70 | The ACPI BIOS flow would include an evaluation of _OS, and the AML | ||
71 | interpreter in the kernel would return to it a string identifying the OS: | ||
72 | |||
73 | Windows 98, SE: "Microsoft Windows" | ||
74 | Windows ME: "Microsoft WindowsME:Millenium Edition" | ||
75 | Windows NT: "Microsoft Windows NT" | ||
76 | |||
77 | The idea was on a platform tasked with running multiple OS's, | ||
78 | the BIOS could use _OS to enable devices that an OS | ||
79 | might support, or enable quirks or bug workarounds | ||
80 | necessary to make the platform compatible with that pre-existing OS. | ||
81 | |||
82 | But _OS had fundamental problems. First, the BIOS needed to know the name | ||
83 | of every possible version of the OS that would run on it, and needed to know | ||
84 | all the quirks of those OS's. Certainly it would make more sense | ||
85 | for the BIOS to ask *specific* things of the OS, such | ||
86 | "do you support a specific interface", and thus in ACPI 3.0, | ||
87 | _OSI was born to replace _OS. | ||
88 | |||
89 | _OS was abandoned, though even today, many BIOS look for | ||
90 | _OS "Microsoft Windows NT", though it seems somewhat far-fetched | ||
91 | that anybody would install those old operating systems | ||
92 | over what came with the machine. | ||
93 | |||
94 | Linux answers "Microsoft Windows NT" to please that BIOS idiom. | ||
95 | That is the *only* viable strategy, as that is what modern Windows does, | ||
96 | and so doing otherwise could steer the BIOS down an untested path. | ||
97 | |||
98 | _OSI is born, and immediately misused | ||
99 | -------------------------------------- | ||
100 | |||
101 | With _OSI, the *BIOS* provides the string describing an interface, | ||
102 | and asks the OS: "YES/NO, are you compatible with this interface?" | ||
103 | |||
104 | eg. _OSI("3.0 Thermal Model") would return TRUE if the OS knows how | ||
105 | to deal with the thermal extensions made to the ACPI 3.0 specification. | ||
106 | An old OS that doesn't know about those extensions would answer FALSE, | ||
107 | and a new OS may be able to return TRUE. | ||
108 | |||
109 | For an OS-specific interface, the ACPI spec said that the BIOS and the OS | ||
110 | were to agree on a string of the form such as "Windows-interface_name". | ||
111 | |||
112 | But two bad things happened. First, the Windows ecosystem used _OSI | ||
113 | not as designed, but as a direct replacement for _OS -- identifying | ||
114 | the OS version, rather than an OS supported interface. Indeed, right | ||
115 | from the start, the ACPI 3.0 spec itself codified this misuse | ||
116 | in example code using _OSI("Windows 2001"). | ||
117 | |||
118 | This misuse was adopted and continues today. | ||
119 | |||
120 | Linux had no choice but to also return TRUE to _OSI("Windows 2001") | ||
121 | and its successors. To do otherwise would virtually guarantee breaking | ||
122 | a BIOS that has been tested only with that _OSI returning TRUE. | ||
123 | |||
124 | This strategy is problematic, as Linux is never completely compatible with | ||
125 | the latest version of Windows, and sometimes it takes more than a year | ||
126 | to iron out incompatibilities. | ||
127 | |||
128 | Not to be out-done, the Linux community made things worse by returning TRUE | ||
129 | to _OSI("Linux"). Doing so is even worse than the Windows misuse | ||
130 | of _OSI, as "Linux" does not even contain any version information. | ||
131 | _OSI("Linux") led to some BIOS' malfunctioning due to BIOS writer's | ||
132 | using it in untested BIOS flows. But some OEM's used _OSI("Linux") | ||
133 | in tested flows to support real Linux features. In 2009, Linux | ||
134 | removed _OSI("Linux"), and added a cmdline parameter to restore it | ||
135 | for legacy systems still needed it. Further a BIOS_BUG warning prints | ||
136 | for all BIOS's that invoke it. | ||
137 | |||
138 | No BIOS should use _OSI("Linux"). | ||
139 | |||
140 | The result is a strategy for Linux to maximize compatibility with | ||
141 | ACPI BIOS that are tested on Windows machines. There is a real risk | ||
142 | of over-stating that compatibility; but the alternative has often been | ||
143 | catastrophic failure resulting from the BIOS taking paths that | ||
144 | were never validated under *any* OS. | ||
145 | |||
146 | Do not use _REV | ||
147 | --------------- | ||
148 | |||
149 | Since _OSI("Linux") went away, some BIOS writers used _REV | ||
150 | to support Linux and Windows differences in the same BIOS. | ||
151 | |||
152 | _REV was defined in ACPI 1.0 to return the version of ACPI | ||
153 | supported by the OS and the OS AML interpreter. | ||
154 | |||
155 | Modern Windows returns _REV = 2. Linux used ACPI_CA_SUPPORT_LEVEL, | ||
156 | which would increment, based on the version of the spec supported. | ||
157 | |||
158 | Unfortunately, _REV was also misused. eg. some BIOS would check | ||
159 | for _REV = 3, and do something for Linux, but when Linux returned | ||
160 | _REV = 4, that support broke. | ||
161 | |||
162 | In response to this problem, Linux returns _REV = 2 always, | ||
163 | from mid-2015 onward. The ACPI specification will also be updated | ||
164 | to reflect that _REV is deprecated, and always returns 2. | ||
165 | |||
166 | Apple Mac and _OSI("Darwin") | ||
167 | ---------------------------- | ||
168 | |||
169 | On Apple's Mac platforms, the ACPI BIOS invokes _OSI("Darwin") | ||
170 | to determine if the machine is running Apple OSX. | ||
171 | |||
172 | Like Linux's _OSI("*Windows*") strategy, Linux defaults to | ||
173 | answering YES to _OSI("Darwin") to enable full access | ||
174 | to the hardware and validated BIOS paths seen by OSX. | ||
175 | Just like on Windows-tested platforms, this strategy has risks. | ||
176 | |||
177 | Starting in Linux-3.18, the kernel answered YES to _OSI("Darwin") | ||
178 | for the purpose of enabling Mac Thunderbolt support. Further, | ||
179 | if the kernel noticed _OSI("Darwin") being invoked, it additionally | ||
180 | disabled all _OSI("*Windows*") to keep poorly written Mac BIOS | ||
181 | from going down untested combinations of paths. | ||
182 | |||
183 | The Linux-3.18 change in default caused power regressions on Mac | ||
184 | laptops, and the 3.18 implementation did not allow changing | ||
185 | the default via cmdline "acpi_osi=!Darwin". Linux-4.7 fixed | ||
186 | the ability to use acpi_osi=!Darwin as a workaround, and | ||
187 | we hope to see Mac Thunderbolt power management support in Linux-4.11. | ||