Back to home page

OSCL-LXR

 
 

    


0001 .. SPDX-License-Identifier: GPL-2.0
0002 
0003 ==========================
0004 ACPI _OSI and _REV methods
0005 ==========================
0006 
0007 An ACPI BIOS can use the "Operating System Interfaces" method (_OSI)
0008 to find out what the operating system supports. Eg. If BIOS
0009 AML code includes _OSI("XYZ"), the kernel's AML interpreter
0010 can evaluate that method, look to see if it supports 'XYZ'
0011 and answer YES or NO to the BIOS.
0012 
0013 The ACPI _REV method returns the "Revision of the ACPI specification
0014 that OSPM supports"
0015 
0016 This document explains how and why the BIOS and Linux should use these methods.
0017 It also explains how and why they are widely misused.
0018 
0019 How to use _OSI
0020 ===============
0021 
0022 Linux runs on two groups of machines -- those that are tested by the OEM
0023 to be compatible with Linux, and those that were never tested with Linux,
0024 but where Linux was installed to replace the original OS (Windows or OSX).
0025 
0026 The larger group is the systems tested to run only Windows.  Not only that,
0027 but many were tested to run with just one specific version of Windows.
0028 So even though the BIOS may use _OSI to query what version of Windows is running,
0029 only a single path through the BIOS has actually been tested.
0030 Experience shows that taking untested paths through the BIOS
0031 exposes Linux to an entire category of BIOS bugs.
0032 For this reason, Linux _OSI defaults must continue to claim compatibility
0033 with all versions of Windows.
0034 
0035 But Linux isn't actually compatible with Windows, and the Linux community
0036 has also been hurt with regressions when Linux adds the latest version of
0037 Windows to its list of _OSI strings.  So it is possible that additional strings
0038 will be more thoroughly vetted before shipping upstream in the future.
0039 But it is likely that they will all eventually be added.
0040 
0041 What should an OEM do if they want to support Linux and Windows
0042 using the same BIOS image?  Often they need to do something different
0043 for Linux to deal with how Linux is different from Windows.
0044 Here the BIOS should ask exactly what it wants to know:
0045 
0046 _OSI("Linux-OEM-my_interface_name")
0047 where 'OEM' is needed if this is an OEM-specific hook,
0048 and 'my_interface_name' describes the hook, which could be a
0049 quirk, a bug, or a bug-fix.
0050 
0051 In addition, the OEM should send a patch to upstream Linux
0052 via the linux-acpi@vger.kernel.org mailing list.  When that patch
0053 is checked into Linux, the OS will answer "YES" when the BIOS
0054 on the OEM's system uses _OSI to ask if the interface is supported
0055 by the OS.  Linux distributors can back-port that patch for Linux
0056 pre-installs, and it will be included by all distributions that
0057 re-base to upstream.  If the distribution can not update the kernel binary,
0058 they can also add an acpi_osi=Linux-OEM-my_interface_name
0059 cmdline parameter to the boot loader, as needed.
0060 
0061 If the string refers to a feature where the upstream kernel
0062 eventually grows support, a patch should be sent to remove
0063 the string when that support is added to the kernel.
0064 
0065 That was easy.  Read on, to find out how to do it wrong.
0066 
0067 Before _OSI, there was _OS
0068 ==========================
0069 
0070 ACPI 1.0 specified "_OS" as an
0071 "object that evaluates to a string that identifies the operating system."
0072 
0073 The ACPI BIOS flow would include an evaluation of _OS, and the AML
0074 interpreter in the kernel would return to it a string identifying the OS:
0075 
0076 Windows 98, SE: "Microsoft Windows"
0077 Windows ME: "Microsoft WindowsME:Millennium Edition"
0078 Windows NT: "Microsoft Windows NT"
0079 
0080 The idea was on a platform tasked with running multiple OS's,
0081 the BIOS could use _OS to enable devices that an OS
0082 might support, or enable quirks or bug workarounds
0083 necessary to make the platform compatible with that pre-existing OS.
0084 
0085 But _OS had fundamental problems.  First, the BIOS needed to know the name
0086 of every possible version of the OS that would run on it, and needed to know
0087 all the quirks of those OS's.  Certainly it would make more sense
0088 for the BIOS to ask *specific* things of the OS, such
0089 "do you support a specific interface", and thus in ACPI 3.0,
0090 _OSI was born to replace _OS.
0091 
0092 _OS was abandoned, though even today, many BIOS look for
0093 _OS "Microsoft Windows NT", though it seems somewhat far-fetched
0094 that anybody would install those old operating systems
0095 over what came with the machine.
0096 
0097 Linux answers "Microsoft Windows NT" to please that BIOS idiom.
0098 That is the *only* viable strategy, as that is what modern Windows does,
0099 and so doing otherwise could steer the BIOS down an untested path.
0100 
0101 _OSI is born, and immediately misused
0102 =====================================
0103 
0104 With _OSI, the *BIOS* provides the string describing an interface,
0105 and asks the OS: "YES/NO, are you compatible with this interface?"
0106 
0107 eg. _OSI("3.0 Thermal Model") would return TRUE if the OS knows how
0108 to deal with the thermal extensions made to the ACPI 3.0 specification.
0109 An old OS that doesn't know about those extensions would answer FALSE,
0110 and a new OS may be able to return TRUE.
0111 
0112 For an OS-specific interface, the ACPI spec said that the BIOS and the OS
0113 were to agree on a string of the form such as "Windows-interface_name".
0114 
0115 But two bad things happened.  First, the Windows ecosystem used _OSI
0116 not as designed, but as a direct replacement for _OS -- identifying
0117 the OS version, rather than an OS supported interface.  Indeed, right
0118 from the start, the ACPI 3.0 spec itself codified this misuse
0119 in example code using _OSI("Windows 2001").
0120 
0121 This misuse was adopted and continues today.
0122 
0123 Linux had no choice but to also return TRUE to _OSI("Windows 2001")
0124 and its successors.  To do otherwise would virtually guarantee breaking
0125 a BIOS that has been tested only with that _OSI returning TRUE.
0126 
0127 This strategy is problematic, as Linux is never completely compatible with
0128 the latest version of Windows, and sometimes it takes more than a year
0129 to iron out incompatibilities.
0130 
0131 Not to be out-done, the Linux community made things worse by returning TRUE
0132 to _OSI("Linux").  Doing so is even worse than the Windows misuse
0133 of _OSI, as "Linux" does not even contain any version information.
0134 _OSI("Linux") led to some BIOS' malfunctioning due to BIOS writer's
0135 using it in untested BIOS flows.  But some OEM's used _OSI("Linux")
0136 in tested flows to support real Linux features.  In 2009, Linux
0137 removed _OSI("Linux"), and added a cmdline parameter to restore it
0138 for legacy systems still needed it.  Further a BIOS_BUG warning prints
0139 for all BIOS's that invoke it.
0140 
0141 No BIOS should use _OSI("Linux").
0142 
0143 The result is a strategy for Linux to maximize compatibility with
0144 ACPI BIOS that are tested on Windows machines.  There is a real risk
0145 of over-stating that compatibility; but the alternative has often been
0146 catastrophic failure resulting from the BIOS taking paths that
0147 were never validated under *any* OS.
0148 
0149 Do not use _REV
0150 ===============
0151 
0152 Since _OSI("Linux") went away, some BIOS writers used _REV
0153 to support Linux and Windows differences in the same BIOS.
0154 
0155 _REV was defined in ACPI 1.0 to return the version of ACPI
0156 supported by the OS and the OS AML interpreter.
0157 
0158 Modern Windows returns _REV = 2.  Linux used ACPI_CA_SUPPORT_LEVEL,
0159 which would increment, based on the version of the spec supported.
0160 
0161 Unfortunately, _REV was also misused.  eg. some BIOS would check
0162 for _REV = 3, and do something for Linux, but when Linux returned
0163 _REV = 4, that support broke.
0164 
0165 In response to this problem, Linux returns _REV = 2 always,
0166 from mid-2015 onward.  The ACPI specification will also be updated
0167 to reflect that _REV is deprecated, and always returns 2.
0168 
0169 Apple Mac and _OSI("Darwin")
0170 ============================
0171 
0172 On Apple's Mac platforms, the ACPI BIOS invokes _OSI("Darwin")
0173 to determine if the machine is running Apple OSX.
0174 
0175 Like Linux's _OSI("*Windows*") strategy, Linux defaults to
0176 answering YES to _OSI("Darwin") to enable full access
0177 to the hardware and validated BIOS paths seen by OSX.
0178 Just like on Windows-tested platforms, this strategy has risks.
0179 
0180 Starting in Linux-3.18, the kernel answered YES to _OSI("Darwin")
0181 for the purpose of enabling Mac Thunderbolt support.  Further,
0182 if the kernel noticed _OSI("Darwin") being invoked, it additionally
0183 disabled all _OSI("*Windows*") to keep poorly written Mac BIOS
0184 from going down untested combinations of paths.
0185 
0186 The Linux-3.18 change in default caused power regressions on Mac
0187 laptops, and the 3.18 implementation did not allow changing
0188 the default via cmdline "acpi_osi=!Darwin".  Linux-4.7 fixed
0189 the ability to use acpi_osi=!Darwin as a workaround, and
0190 we hope to see Mac Thunderbolt power management support in Linux-4.11.