1 | /****************************************************************************** |
2 | * |
3 | * Module Name: utosi - Support for the _OSI predefined control method |
4 | * |
5 | *****************************************************************************/ |
6 | |
7 | /* |
8 | * Copyright (C) 2000 - 2016, Intel Corp. |
9 | * All rights reserved. |
10 | * |
11 | * Redistribution and use in source and binary forms, with or without |
12 | * modification, are permitted provided that the following conditions |
13 | * are met: |
14 | * 1. Redistributions of source code must retain the above copyright |
15 | * notice, this list of conditions, and the following disclaimer, |
16 | * without modification. |
17 | * 2. Redistributions in binary form must reproduce at minimum a disclaimer |
18 | * substantially similar to the "NO WARRANTY" disclaimer below |
19 | * ("Disclaimer") and any redistribution must be conditioned upon |
20 | * including a substantially similar Disclaimer requirement for further |
21 | * binary redistribution. |
22 | * 3. Neither the names of the above-listed copyright holders nor the names |
23 | * of any contributors may be used to endorse or promote products derived |
24 | * from this software without specific prior written permission. |
25 | * |
26 | * Alternatively, this software may be distributed under the terms of the |
27 | * GNU General Public License ("GPL") version 2 as published by the Free |
28 | * Software Foundation. |
29 | * |
30 | * NO WARRANTY |
31 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS |
32 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT |
33 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR |
34 | * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT |
35 | * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
36 | * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
37 | * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
38 | * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, |
39 | * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING |
40 | * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE |
41 | * POSSIBILITY OF SUCH DAMAGES. |
42 | */ |
43 | |
44 | #include "acpi.h" |
45 | #include "accommon.h" |
46 | |
47 | |
48 | #define _COMPONENT ACPI_UTILITIES |
49 | ACPI_MODULE_NAME ("utosi" ) |
50 | |
51 | |
52 | /****************************************************************************** |
53 | * |
54 | * ACPICA policy for new _OSI strings: |
55 | * |
56 | * It is the stated policy of ACPICA that new _OSI strings will be integrated |
57 | * into this module as soon as possible after they are defined. It is strongly |
58 | * recommended that all ACPICA hosts mirror this policy and integrate any |
59 | * changes to this module as soon as possible. There are several historical |
60 | * reasons behind this policy: |
61 | * |
62 | * 1) New BIOSs tend to test only the case where the host responds TRUE to |
63 | * the latest version of Windows, which would respond to the latest/newest |
64 | * _OSI string. Not responding TRUE to the latest version of Windows will |
65 | * risk executing untested code paths throughout the DSDT and SSDTs. |
66 | * |
67 | * 2) If a new _OSI string is recognized only after a significant delay, this |
68 | * has the potential to cause problems on existing working machines because |
69 | * of the possibility that a new and different path through the ASL code |
70 | * will be executed. |
71 | * |
72 | * 3) New _OSI strings are tending to come out about once per year. A delay |
73 | * in recognizing a new string for a significant amount of time risks the |
74 | * release of another string which only compounds the initial problem. |
75 | * |
76 | *****************************************************************************/ |
77 | |
78 | |
79 | /* |
80 | * Strings supported by the _OSI predefined control method (which is |
81 | * implemented internally within this module.) |
82 | * |
83 | * March 2009: Removed "Linux" as this host no longer wants to respond true |
84 | * for this string. Basically, the only safe OS strings are windows-related |
85 | * and in many or most cases represent the only test path within the |
86 | * BIOS-provided ASL code. |
87 | * |
88 | * The last element of each entry is used to track the newest version of |
89 | * Windows that the BIOS has requested. |
90 | */ |
91 | static ACPI_INTERFACE_INFO AcpiDefaultSupportedInterfaces[] = |
92 | { |
93 | /* Operating System Vendor Strings */ |
94 | |
95 | {__UNCONST("Windows 2000" ), NULL, 0, ACPI_OSI_WIN_2000}, /* Windows 2000 */ |
96 | {__UNCONST("Windows 2001" ), NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */ |
97 | {__UNCONST("Windows 2001 SP1" ), NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */ |
98 | {__UNCONST("Windows 2001.1" ), NULL, 0, ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */ |
99 | {__UNCONST("Windows 2001 SP2" ), NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */ |
100 | {__UNCONST("Windows 2001.1 SP1" ), NULL, 0, ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */ |
101 | {__UNCONST("Windows 2006" ), NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows Vista - Added 03/2006 */ |
102 | {__UNCONST("Windows 2006.1" ), NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */ |
103 | {__UNCONST("Windows 2006 SP1" ), NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */ |
104 | {__UNCONST("Windows 2006 SP2" ), NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */ |
105 | {__UNCONST("Windows 2009" ), NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ |
106 | {__UNCONST("Windows 2012" ), NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ |
107 | {__UNCONST("Windows 2013" ), NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ |
108 | {__UNCONST("Windows 2015" ), NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ |
109 | |
110 | /* Feature Group Strings */ |
111 | |
112 | {__UNCONST("Extended Address Space Descriptor" ), NULL, ACPI_OSI_FEATURE, 0}, |
113 | |
114 | /* |
115 | * All "optional" feature group strings (features that are implemented |
116 | * by the host) should be dynamically modified to VALID by the host via |
117 | * AcpiInstallInterface or AcpiUpdateInterfaces. Such optional feature |
118 | * group strings are set as INVALID by default here. |
119 | */ |
120 | |
121 | {__UNCONST("Module Device" ), NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
122 | {__UNCONST("Processor Device" ), NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
123 | {__UNCONST("3.0 Thermal Model" ), NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
124 | {__UNCONST("3.0 _SCP Extensions" ), NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, |
125 | {__UNCONST("Processor Aggregator Device" ), NULL, ACPI_OSI_OPTIONAL_FEATURE, 0} |
126 | }; |
127 | |
128 | |
129 | /******************************************************************************* |
130 | * |
131 | * FUNCTION: AcpiUtInitializeInterfaces |
132 | * |
133 | * PARAMETERS: None |
134 | * |
135 | * RETURN: Status |
136 | * |
137 | * DESCRIPTION: Initialize the global _OSI supported interfaces list |
138 | * |
139 | ******************************************************************************/ |
140 | |
141 | ACPI_STATUS |
142 | AcpiUtInitializeInterfaces ( |
143 | void) |
144 | { |
145 | ACPI_STATUS Status; |
146 | UINT32 i; |
147 | |
148 | |
149 | Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); |
150 | if (ACPI_FAILURE (Status)) |
151 | { |
152 | return (Status); |
153 | } |
154 | |
155 | AcpiGbl_SupportedInterfaces = AcpiDefaultSupportedInterfaces; |
156 | |
157 | /* Link the static list of supported interfaces */ |
158 | |
159 | for (i = 0; |
160 | i < (ACPI_ARRAY_LENGTH (AcpiDefaultSupportedInterfaces) - 1); |
161 | i++) |
162 | { |
163 | AcpiDefaultSupportedInterfaces[i].Next = |
164 | &AcpiDefaultSupportedInterfaces[(ACPI_SIZE) i + 1]; |
165 | } |
166 | |
167 | AcpiOsReleaseMutex (AcpiGbl_OsiMutex); |
168 | return (AE_OK); |
169 | } |
170 | |
171 | |
172 | /******************************************************************************* |
173 | * |
174 | * FUNCTION: AcpiUtInterfaceTerminate |
175 | * |
176 | * PARAMETERS: None |
177 | * |
178 | * RETURN: Status |
179 | * |
180 | * DESCRIPTION: Delete all interfaces in the global list. Sets |
181 | * AcpiGbl_SupportedInterfaces to NULL. |
182 | * |
183 | ******************************************************************************/ |
184 | |
185 | ACPI_STATUS |
186 | AcpiUtInterfaceTerminate ( |
187 | void) |
188 | { |
189 | ACPI_STATUS Status; |
190 | ACPI_INTERFACE_INFO *NextInterface; |
191 | |
192 | |
193 | Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); |
194 | if (ACPI_FAILURE (Status)) |
195 | { |
196 | return (Status); |
197 | } |
198 | |
199 | NextInterface = AcpiGbl_SupportedInterfaces; |
200 | while (NextInterface) |
201 | { |
202 | AcpiGbl_SupportedInterfaces = NextInterface->Next; |
203 | |
204 | if (NextInterface->Flags & ACPI_OSI_DYNAMIC) |
205 | { |
206 | /* Only interfaces added at runtime can be freed */ |
207 | |
208 | ACPI_FREE (NextInterface->Name); |
209 | ACPI_FREE (NextInterface); |
210 | } |
211 | else |
212 | { |
213 | /* Interface is in static list. Reset it to invalid or valid. */ |
214 | |
215 | if (NextInterface->Flags & ACPI_OSI_DEFAULT_INVALID) |
216 | { |
217 | NextInterface->Flags |= ACPI_OSI_INVALID; |
218 | } |
219 | else |
220 | { |
221 | NextInterface->Flags &= ~ACPI_OSI_INVALID; |
222 | } |
223 | } |
224 | |
225 | NextInterface = AcpiGbl_SupportedInterfaces; |
226 | } |
227 | |
228 | AcpiOsReleaseMutex (AcpiGbl_OsiMutex); |
229 | return (AE_OK); |
230 | } |
231 | |
232 | |
233 | /******************************************************************************* |
234 | * |
235 | * FUNCTION: AcpiUtInstallInterface |
236 | * |
237 | * PARAMETERS: InterfaceName - The interface to install |
238 | * |
239 | * RETURN: Status |
240 | * |
241 | * DESCRIPTION: Install the interface into the global interface list. |
242 | * Caller MUST hold AcpiGbl_OsiMutex |
243 | * |
244 | ******************************************************************************/ |
245 | |
246 | ACPI_STATUS |
247 | AcpiUtInstallInterface ( |
248 | ACPI_STRING InterfaceName) |
249 | { |
250 | ACPI_INTERFACE_INFO *InterfaceInfo; |
251 | |
252 | |
253 | /* Allocate info block and space for the name string */ |
254 | |
255 | InterfaceInfo = ACPI_ALLOCATE_ZEROED (sizeof (ACPI_INTERFACE_INFO)); |
256 | if (!InterfaceInfo) |
257 | { |
258 | return (AE_NO_MEMORY); |
259 | } |
260 | |
261 | InterfaceInfo->Name = ACPI_ALLOCATE_ZEROED (strlen (InterfaceName) + 1); |
262 | if (!InterfaceInfo->Name) |
263 | { |
264 | ACPI_FREE (InterfaceInfo); |
265 | return (AE_NO_MEMORY); |
266 | } |
267 | |
268 | /* Initialize new info and insert at the head of the global list */ |
269 | |
270 | strcpy (InterfaceInfo->Name, InterfaceName); |
271 | InterfaceInfo->Flags = ACPI_OSI_DYNAMIC; |
272 | InterfaceInfo->Next = AcpiGbl_SupportedInterfaces; |
273 | |
274 | AcpiGbl_SupportedInterfaces = InterfaceInfo; |
275 | return (AE_OK); |
276 | } |
277 | |
278 | |
279 | /******************************************************************************* |
280 | * |
281 | * FUNCTION: AcpiUtRemoveInterface |
282 | * |
283 | * PARAMETERS: InterfaceName - The interface to remove |
284 | * |
285 | * RETURN: Status |
286 | * |
287 | * DESCRIPTION: Remove the interface from the global interface list. |
288 | * Caller MUST hold AcpiGbl_OsiMutex |
289 | * |
290 | ******************************************************************************/ |
291 | |
292 | ACPI_STATUS |
293 | AcpiUtRemoveInterface ( |
294 | ACPI_STRING InterfaceName) |
295 | { |
296 | ACPI_INTERFACE_INFO *PreviousInterface; |
297 | ACPI_INTERFACE_INFO *NextInterface; |
298 | |
299 | |
300 | PreviousInterface = NextInterface = AcpiGbl_SupportedInterfaces; |
301 | while (NextInterface) |
302 | { |
303 | if (!strcmp (InterfaceName, NextInterface->Name)) |
304 | { |
305 | /* |
306 | * Found: name is in either the static list |
307 | * or was added at runtime |
308 | */ |
309 | if (NextInterface->Flags & ACPI_OSI_DYNAMIC) |
310 | { |
311 | /* Interface was added dynamically, remove and free it */ |
312 | |
313 | if (PreviousInterface == NextInterface) |
314 | { |
315 | AcpiGbl_SupportedInterfaces = NextInterface->Next; |
316 | } |
317 | else |
318 | { |
319 | PreviousInterface->Next = NextInterface->Next; |
320 | } |
321 | |
322 | ACPI_FREE (NextInterface->Name); |
323 | ACPI_FREE (NextInterface); |
324 | } |
325 | else |
326 | { |
327 | /* |
328 | * Interface is in static list. If marked invalid, then |
329 | * it does not actually exist. Else, mark it invalid. |
330 | */ |
331 | if (NextInterface->Flags & ACPI_OSI_INVALID) |
332 | { |
333 | return (AE_NOT_EXIST); |
334 | } |
335 | |
336 | NextInterface->Flags |= ACPI_OSI_INVALID; |
337 | } |
338 | |
339 | return (AE_OK); |
340 | } |
341 | |
342 | PreviousInterface = NextInterface; |
343 | NextInterface = NextInterface->Next; |
344 | } |
345 | |
346 | /* Interface was not found */ |
347 | |
348 | return (AE_NOT_EXIST); |
349 | } |
350 | |
351 | |
352 | /******************************************************************************* |
353 | * |
354 | * FUNCTION: AcpiUtUpdateInterfaces |
355 | * |
356 | * PARAMETERS: Action - Actions to be performed during the |
357 | * update |
358 | * |
359 | * RETURN: Status |
360 | * |
361 | * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor |
362 | * strings or/and feature group strings. |
363 | * Caller MUST hold AcpiGbl_OsiMutex |
364 | * |
365 | ******************************************************************************/ |
366 | |
367 | ACPI_STATUS |
368 | AcpiUtUpdateInterfaces ( |
369 | UINT8 Action) |
370 | { |
371 | ACPI_INTERFACE_INFO *NextInterface; |
372 | |
373 | |
374 | NextInterface = AcpiGbl_SupportedInterfaces; |
375 | while (NextInterface) |
376 | { |
377 | if (((NextInterface->Flags & ACPI_OSI_FEATURE) && |
378 | (Action & ACPI_FEATURE_STRINGS)) || |
379 | (!(NextInterface->Flags & ACPI_OSI_FEATURE) && |
380 | (Action & ACPI_VENDOR_STRINGS))) |
381 | { |
382 | if (Action & ACPI_DISABLE_INTERFACES) |
383 | { |
384 | /* Mark the interfaces as invalid */ |
385 | |
386 | NextInterface->Flags |= ACPI_OSI_INVALID; |
387 | } |
388 | else |
389 | { |
390 | /* Mark the interfaces as valid */ |
391 | |
392 | NextInterface->Flags &= ~ACPI_OSI_INVALID; |
393 | } |
394 | } |
395 | |
396 | NextInterface = NextInterface->Next; |
397 | } |
398 | |
399 | return (AE_OK); |
400 | } |
401 | |
402 | |
403 | /******************************************************************************* |
404 | * |
405 | * FUNCTION: AcpiUtGetInterface |
406 | * |
407 | * PARAMETERS: InterfaceName - The interface to find |
408 | * |
409 | * RETURN: ACPI_INTERFACE_INFO if found. NULL if not found. |
410 | * |
411 | * DESCRIPTION: Search for the specified interface name in the global list. |
412 | * Caller MUST hold AcpiGbl_OsiMutex |
413 | * |
414 | ******************************************************************************/ |
415 | |
416 | ACPI_INTERFACE_INFO * |
417 | AcpiUtGetInterface ( |
418 | ACPI_STRING InterfaceName) |
419 | { |
420 | ACPI_INTERFACE_INFO *NextInterface; |
421 | |
422 | |
423 | NextInterface = AcpiGbl_SupportedInterfaces; |
424 | while (NextInterface) |
425 | { |
426 | if (!strcmp (InterfaceName, NextInterface->Name)) |
427 | { |
428 | return (NextInterface); |
429 | } |
430 | |
431 | NextInterface = NextInterface->Next; |
432 | } |
433 | |
434 | return (NULL); |
435 | } |
436 | |
437 | |
438 | /******************************************************************************* |
439 | * |
440 | * FUNCTION: AcpiUtOsiImplementation |
441 | * |
442 | * PARAMETERS: WalkState - Current walk state |
443 | * |
444 | * RETURN: Status |
445 | * Integer: TRUE (0) if input string is matched |
446 | * FALSE (-1) if string is not matched |
447 | * |
448 | * DESCRIPTION: Implementation of the _OSI predefined control method. When |
449 | * an invocation of _OSI is encountered in the system AML, |
450 | * control is transferred to this function. |
451 | * |
452 | * (August 2016) |
453 | * Note: _OSI is now defined to return "Ones" to indicate a match, for |
454 | * compatibility with other ACPI implementations. On a 32-bit DSDT, Ones |
455 | * is 0xFFFFFFFF. On a 64-bit DSDT, Ones is 0xFFFFFFFFFFFFFFFF |
456 | * (ACPI_UINT64_MAX). |
457 | * |
458 | * This function always returns ACPI_UINT64_MAX for TRUE, and later code |
459 | * will truncate this to 32 bits if necessary. |
460 | * |
461 | ******************************************************************************/ |
462 | |
463 | ACPI_STATUS |
464 | AcpiUtOsiImplementation ( |
465 | ACPI_WALK_STATE *WalkState) |
466 | { |
467 | ACPI_OPERAND_OBJECT *StringDesc; |
468 | ACPI_OPERAND_OBJECT *ReturnDesc; |
469 | ACPI_INTERFACE_INFO *InterfaceInfo; |
470 | ACPI_INTERFACE_HANDLER InterfaceHandler; |
471 | ACPI_STATUS Status; |
472 | UINT64 ReturnValue; |
473 | |
474 | |
475 | ACPI_FUNCTION_TRACE (UtOsiImplementation); |
476 | |
477 | |
478 | /* Validate the string input argument (from the AML caller) */ |
479 | |
480 | StringDesc = WalkState->Arguments[0].Object; |
481 | if (!StringDesc || |
482 | (StringDesc->Common.Type != ACPI_TYPE_STRING)) |
483 | { |
484 | return_ACPI_STATUS (AE_TYPE); |
485 | } |
486 | |
487 | /* Create a return object */ |
488 | |
489 | ReturnDesc = AcpiUtCreateInternalObject (ACPI_TYPE_INTEGER); |
490 | if (!ReturnDesc) |
491 | { |
492 | return_ACPI_STATUS (AE_NO_MEMORY); |
493 | } |
494 | |
495 | /* Default return value is 0, NOT SUPPORTED */ |
496 | |
497 | ReturnValue = 0; |
498 | Status = AcpiOsAcquireMutex (AcpiGbl_OsiMutex, ACPI_WAIT_FOREVER); |
499 | if (ACPI_FAILURE (Status)) |
500 | { |
501 | AcpiUtRemoveReference (ReturnDesc); |
502 | return_ACPI_STATUS (Status); |
503 | } |
504 | |
505 | /* Lookup the interface in the global _OSI list */ |
506 | |
507 | InterfaceInfo = AcpiUtGetInterface (StringDesc->String.Pointer); |
508 | if (InterfaceInfo && |
509 | !(InterfaceInfo->Flags & ACPI_OSI_INVALID)) |
510 | { |
511 | /* |
512 | * The interface is supported. |
513 | * Update the OsiData if necessary. We keep track of the latest |
514 | * version of Windows that has been requested by the BIOS. |
515 | */ |
516 | if (InterfaceInfo->Value > AcpiGbl_OsiData) |
517 | { |
518 | AcpiGbl_OsiData = InterfaceInfo->Value; |
519 | } |
520 | |
521 | ReturnValue = ACPI_UINT64_MAX; |
522 | } |
523 | |
524 | AcpiOsReleaseMutex (AcpiGbl_OsiMutex); |
525 | |
526 | /* |
527 | * Invoke an optional _OSI interface handler. The host OS may wish |
528 | * to do some interface-specific handling. For example, warn about |
529 | * certain interfaces or override the true/false support value. |
530 | */ |
531 | InterfaceHandler = AcpiGbl_InterfaceHandler; |
532 | if (InterfaceHandler) |
533 | { |
534 | if (InterfaceHandler ( |
535 | StringDesc->String.Pointer, (UINT32) ReturnValue)) |
536 | { |
537 | ReturnValue = ACPI_UINT64_MAX; |
538 | } |
539 | } |
540 | |
541 | ACPI_DEBUG_PRINT_RAW ((ACPI_DB_INFO, |
542 | "ACPI: BIOS _OSI(\"%s\") is %ssupported\n" , |
543 | StringDesc->String.Pointer, ReturnValue == 0 ? "not " : "" )); |
544 | |
545 | /* Complete the return object */ |
546 | |
547 | ReturnDesc->Integer.Value = ReturnValue; |
548 | WalkState->ReturnDesc = ReturnDesc; |
549 | return_ACPI_STATUS (AE_OK); |
550 | } |
551 | |