]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
b0ed7a91 LM |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: utosi - Support for the _OSI predefined control method | |
5 | * | |
840c02ca | 6 | * Copyright (C) 2000 - 2019, Intel Corp. |
b0ed7a91 | 7 | * |
95857638 | 8 | *****************************************************************************/ |
b0ed7a91 LM |
9 | |
10 | #include <acpi/acpi.h> | |
11 | #include "accommon.h" | |
12 | ||
13 | #define _COMPONENT ACPI_UTILITIES | |
14 | ACPI_MODULE_NAME("utosi") | |
15 | ||
73581c02 BM |
16 | /****************************************************************************** |
17 | * | |
18 | * ACPICA policy for new _OSI strings: | |
19 | * | |
20 | * It is the stated policy of ACPICA that new _OSI strings will be integrated | |
21 | * into this module as soon as possible after they are defined. It is strongly | |
22 | * recommended that all ACPICA hosts mirror this policy and integrate any | |
23 | * changes to this module as soon as possible. There are several historical | |
24 | * reasons behind this policy: | |
25 | * | |
26 | * 1) New BIOSs tend to test only the case where the host responds TRUE to | |
27 | * the latest version of Windows, which would respond to the latest/newest | |
28 | * _OSI string. Not responding TRUE to the latest version of Windows will | |
29 | * risk executing untested code paths throughout the DSDT and SSDTs. | |
30 | * | |
31 | * 2) If a new _OSI string is recognized only after a significant delay, this | |
32 | * has the potential to cause problems on existing working machines because | |
33 | * of the possibility that a new and different path through the ASL code | |
34 | * will be executed. | |
35 | * | |
36 | * 3) New _OSI strings are tending to come out about once per year. A delay | |
37 | * in recognizing a new string for a significant amount of time risks the | |
38 | * release of another string which only compounds the initial problem. | |
39 | * | |
40 | *****************************************************************************/ | |
b0ed7a91 LM |
41 | /* |
42 | * Strings supported by the _OSI predefined control method (which is | |
43 | * implemented internally within this module.) | |
44 | * | |
45 | * March 2009: Removed "Linux" as this host no longer wants to respond true | |
46 | * for this string. Basically, the only safe OS strings are windows-related | |
47 | * and in many or most cases represent the only test path within the | |
48 | * BIOS-provided ASL code. | |
49 | * | |
50 | * The last element of each entry is used to track the newest version of | |
51 | * Windows that the BIOS has requested. | |
52 | */ | |
53 | static struct acpi_interface_info acpi_default_supported_interfaces[] = { | |
54 | /* Operating System Vendor Strings */ | |
55 | ||
56 | {"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000}, /* Windows 2000 */ | |
57 | {"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */ | |
58 | {"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */ | |
59 | {"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003}, /* Windows Server 2003 */ | |
60 | {"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */ | |
61 | {"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1}, /* Windows Server 2003 SP1 - Added 03/2006 */ | |
ba494bee | 62 | {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA}, /* Windows vista - Added 03/2006 */ |
b0ed7a91 LM |
63 | {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008}, /* Windows Server 2008 - Added 09/2009 */ |
64 | {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1}, /* Windows Vista SP1 - Added 09/2009 */ | |
23ebbf07 | 65 | {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2}, /* Windows Vista SP2 - Added 09/2010 */ |
b0ed7a91 | 66 | {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7}, /* Windows 7 and Server 2008 R2 - Added 09/2009 */ |
a57f7f91 | 67 | {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8}, /* Windows 8 and Server 2012 - Added 08/2012 */ |
be0381cf | 68 | {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8_1}, /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */ |
796888e9 | 69 | {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */ |
bc4d413a ML |
70 | {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */ |
71 | {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */ | |
ad584b46 | 72 | {"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3}, /* Windows 10 version 1709 - Added 02/2018 */ |
2db90876 | 73 | {"Windows 2018", NULL, 0, ACPI_OSI_WIN_10_RS4}, /* Windows 10 version 1803 - Added 11/2018 */ |
0fcb9a31 | 74 | {"Windows 2018.2", NULL, 0, ACPI_OSI_WIN_10_RS5}, /* Windows 10 version 1809 - Added 11/2018 */ |
8696beed | 75 | {"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1}, /* Windows 10 version 1903 - Added 08/2019 */ |
b0ed7a91 LM |
76 | |
77 | /* Feature Group Strings */ | |
78 | ||
2cf9f5bc | 79 | {"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0}, |
b0ed7a91 LM |
80 | |
81 | /* | |
82 | * All "optional" feature group strings (features that are implemented | |
2cf9f5bc LZ |
83 | * by the host) should be dynamically modified to VALID by the host via |
84 | * acpi_install_interface or acpi_update_interfaces. Such optional feature | |
85 | * group strings are set as INVALID by default here. | |
b0ed7a91 | 86 | */ |
2cf9f5bc LZ |
87 | |
88 | {"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, | |
89 | {"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, | |
90 | {"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, | |
91 | {"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}, | |
92 | {"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0} | |
b0ed7a91 LM |
93 | }; |
94 | ||
95 | /******************************************************************************* | |
96 | * | |
97 | * FUNCTION: acpi_ut_initialize_interfaces | |
98 | * | |
99 | * PARAMETERS: None | |
100 | * | |
101 | * RETURN: Status | |
102 | * | |
103 | * DESCRIPTION: Initialize the global _OSI supported interfaces list | |
104 | * | |
105 | ******************************************************************************/ | |
106 | ||
107 | acpi_status acpi_ut_initialize_interfaces(void) | |
108 | { | |
388a9902 | 109 | acpi_status status; |
b0ed7a91 LM |
110 | u32 i; |
111 | ||
388a9902 JK |
112 | status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
113 | if (ACPI_FAILURE(status)) { | |
114 | return (status); | |
115 | } | |
116 | ||
b0ed7a91 LM |
117 | acpi_gbl_supported_interfaces = acpi_default_supported_interfaces; |
118 | ||
119 | /* Link the static list of supported interfaces */ | |
120 | ||
121 | for (i = 0; | |
122 | i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1); | |
123 | i++) { | |
124 | acpi_default_supported_interfaces[i].next = | |
f5c1e1c5 | 125 | &acpi_default_supported_interfaces[(acpi_size)i + 1]; |
b0ed7a91 LM |
126 | } |
127 | ||
128 | acpi_os_release_mutex(acpi_gbl_osi_mutex); | |
129 | return (AE_OK); | |
130 | } | |
131 | ||
132 | /******************************************************************************* | |
133 | * | |
134 | * FUNCTION: acpi_ut_interface_terminate | |
135 | * | |
136 | * PARAMETERS: None | |
137 | * | |
388a9902 | 138 | * RETURN: Status |
b0ed7a91 LM |
139 | * |
140 | * DESCRIPTION: Delete all interfaces in the global list. Sets | |
141 | * acpi_gbl_supported_interfaces to NULL. | |
142 | * | |
143 | ******************************************************************************/ | |
144 | ||
388a9902 | 145 | acpi_status acpi_ut_interface_terminate(void) |
b0ed7a91 | 146 | { |
388a9902 | 147 | acpi_status status; |
b0ed7a91 LM |
148 | struct acpi_interface_info *next_interface; |
149 | ||
388a9902 JK |
150 | status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
151 | if (ACPI_FAILURE(status)) { | |
152 | return (status); | |
153 | } | |
b0ed7a91 | 154 | |
388a9902 | 155 | next_interface = acpi_gbl_supported_interfaces; |
b0ed7a91 LM |
156 | while (next_interface) { |
157 | acpi_gbl_supported_interfaces = next_interface->next; | |
158 | ||
b0ed7a91 | 159 | if (next_interface->flags & ACPI_OSI_DYNAMIC) { |
2cf9f5bc LZ |
160 | |
161 | /* Only interfaces added at runtime can be freed */ | |
162 | ||
b0ed7a91 LM |
163 | ACPI_FREE(next_interface->name); |
164 | ACPI_FREE(next_interface); | |
2cf9f5bc LZ |
165 | } else { |
166 | /* Interface is in static list. Reset it to invalid or valid. */ | |
167 | ||
168 | if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) { | |
169 | next_interface->flags |= ACPI_OSI_INVALID; | |
170 | } else { | |
171 | next_interface->flags &= ~ACPI_OSI_INVALID; | |
172 | } | |
b0ed7a91 LM |
173 | } |
174 | ||
175 | next_interface = acpi_gbl_supported_interfaces; | |
176 | } | |
177 | ||
178 | acpi_os_release_mutex(acpi_gbl_osi_mutex); | |
388a9902 | 179 | return (AE_OK); |
b0ed7a91 LM |
180 | } |
181 | ||
182 | /******************************************************************************* | |
183 | * | |
184 | * FUNCTION: acpi_ut_install_interface | |
185 | * | |
186 | * PARAMETERS: interface_name - The interface to install | |
187 | * | |
188 | * RETURN: Status | |
189 | * | |
190 | * DESCRIPTION: Install the interface into the global interface list. | |
191 | * Caller MUST hold acpi_gbl_osi_mutex | |
192 | * | |
193 | ******************************************************************************/ | |
194 | ||
195 | acpi_status acpi_ut_install_interface(acpi_string interface_name) | |
196 | { | |
197 | struct acpi_interface_info *interface_info; | |
198 | ||
199 | /* Allocate info block and space for the name string */ | |
200 | ||
201 | interface_info = | |
202 | ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info)); | |
203 | if (!interface_info) { | |
204 | return (AE_NO_MEMORY); | |
205 | } | |
206 | ||
4fa4616e | 207 | interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1); |
b0ed7a91 LM |
208 | if (!interface_info->name) { |
209 | ACPI_FREE(interface_info); | |
210 | return (AE_NO_MEMORY); | |
211 | } | |
212 | ||
213 | /* Initialize new info and insert at the head of the global list */ | |
214 | ||
4fa4616e | 215 | strcpy(interface_info->name, interface_name); |
b0ed7a91 LM |
216 | interface_info->flags = ACPI_OSI_DYNAMIC; |
217 | interface_info->next = acpi_gbl_supported_interfaces; | |
218 | ||
219 | acpi_gbl_supported_interfaces = interface_info; | |
220 | return (AE_OK); | |
221 | } | |
222 | ||
223 | /******************************************************************************* | |
224 | * | |
225 | * FUNCTION: acpi_ut_remove_interface | |
226 | * | |
227 | * PARAMETERS: interface_name - The interface to remove | |
228 | * | |
229 | * RETURN: Status | |
230 | * | |
231 | * DESCRIPTION: Remove the interface from the global interface list. | |
232 | * Caller MUST hold acpi_gbl_osi_mutex | |
233 | * | |
234 | ******************************************************************************/ | |
235 | ||
236 | acpi_status acpi_ut_remove_interface(acpi_string interface_name) | |
237 | { | |
238 | struct acpi_interface_info *previous_interface; | |
239 | struct acpi_interface_info *next_interface; | |
240 | ||
241 | previous_interface = next_interface = acpi_gbl_supported_interfaces; | |
242 | while (next_interface) { | |
4fa4616e | 243 | if (!strcmp(interface_name, next_interface->name)) { |
1fad8738 BM |
244 | /* |
245 | * Found: name is in either the static list | |
246 | * or was added at runtime | |
247 | */ | |
b0ed7a91 LM |
248 | if (next_interface->flags & ACPI_OSI_DYNAMIC) { |
249 | ||
250 | /* Interface was added dynamically, remove and free it */ | |
251 | ||
252 | if (previous_interface == next_interface) { | |
253 | acpi_gbl_supported_interfaces = | |
254 | next_interface->next; | |
255 | } else { | |
256 | previous_interface->next = | |
257 | next_interface->next; | |
258 | } | |
259 | ||
260 | ACPI_FREE(next_interface->name); | |
261 | ACPI_FREE(next_interface); | |
262 | } else { | |
263 | /* | |
1fad8738 BM |
264 | * Interface is in static list. If marked invalid, then |
265 | * it does not actually exist. Else, mark it invalid. | |
b0ed7a91 LM |
266 | */ |
267 | if (next_interface->flags & ACPI_OSI_INVALID) { | |
268 | return (AE_NOT_EXIST); | |
269 | } | |
270 | ||
271 | next_interface->flags |= ACPI_OSI_INVALID; | |
272 | } | |
273 | ||
274 | return (AE_OK); | |
275 | } | |
276 | ||
277 | previous_interface = next_interface; | |
278 | next_interface = next_interface->next; | |
279 | } | |
280 | ||
281 | /* Interface was not found */ | |
282 | ||
283 | return (AE_NOT_EXIST); | |
284 | } | |
285 | ||
2cf9f5bc LZ |
286 | /******************************************************************************* |
287 | * | |
288 | * FUNCTION: acpi_ut_update_interfaces | |
289 | * | |
290 | * PARAMETERS: action - Actions to be performed during the | |
291 | * update | |
292 | * | |
293 | * RETURN: Status | |
294 | * | |
295 | * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor | |
296 | * strings or/and feature group strings. | |
297 | * Caller MUST hold acpi_gbl_osi_mutex | |
298 | * | |
299 | ******************************************************************************/ | |
300 | ||
301 | acpi_status acpi_ut_update_interfaces(u8 action) | |
302 | { | |
303 | struct acpi_interface_info *next_interface; | |
304 | ||
305 | next_interface = acpi_gbl_supported_interfaces; | |
306 | while (next_interface) { | |
307 | if (((next_interface->flags & ACPI_OSI_FEATURE) && | |
308 | (action & ACPI_FEATURE_STRINGS)) || | |
309 | (!(next_interface->flags & ACPI_OSI_FEATURE) && | |
310 | (action & ACPI_VENDOR_STRINGS))) { | |
311 | if (action & ACPI_DISABLE_INTERFACES) { | |
312 | ||
313 | /* Mark the interfaces as invalid */ | |
314 | ||
315 | next_interface->flags |= ACPI_OSI_INVALID; | |
316 | } else { | |
317 | /* Mark the interfaces as valid */ | |
318 | ||
319 | next_interface->flags &= ~ACPI_OSI_INVALID; | |
320 | } | |
321 | } | |
322 | ||
323 | next_interface = next_interface->next; | |
324 | } | |
325 | ||
326 | return (AE_OK); | |
327 | } | |
328 | ||
b0ed7a91 LM |
329 | /******************************************************************************* |
330 | * | |
331 | * FUNCTION: acpi_ut_get_interface | |
332 | * | |
333 | * PARAMETERS: interface_name - The interface to find | |
334 | * | |
335 | * RETURN: struct acpi_interface_info if found. NULL if not found. | |
336 | * | |
337 | * DESCRIPTION: Search for the specified interface name in the global list. | |
338 | * Caller MUST hold acpi_gbl_osi_mutex | |
339 | * | |
340 | ******************************************************************************/ | |
341 | ||
342 | struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name) | |
343 | { | |
344 | struct acpi_interface_info *next_interface; | |
345 | ||
346 | next_interface = acpi_gbl_supported_interfaces; | |
347 | while (next_interface) { | |
4fa4616e | 348 | if (!strcmp(interface_name, next_interface->name)) { |
b0ed7a91 LM |
349 | return (next_interface); |
350 | } | |
351 | ||
352 | next_interface = next_interface->next; | |
353 | } | |
354 | ||
355 | return (NULL); | |
356 | } | |
357 | ||
358 | /******************************************************************************* | |
359 | * | |
360 | * FUNCTION: acpi_ut_osi_implementation | |
361 | * | |
362 | * PARAMETERS: walk_state - Current walk state | |
363 | * | |
364 | * RETURN: Status | |
955f485d BM |
365 | * Integer: TRUE (0) if input string is matched |
366 | * FALSE (-1) if string is not matched | |
b0ed7a91 LM |
367 | * |
368 | * DESCRIPTION: Implementation of the _OSI predefined control method. When | |
369 | * an invocation of _OSI is encountered in the system AML, | |
370 | * control is transferred to this function. | |
371 | * | |
955f485d BM |
372 | * (August 2016) |
373 | * Note: _OSI is now defined to return "Ones" to indicate a match, for | |
374 | * compatibility with other ACPI implementations. On a 32-bit DSDT, Ones | |
375 | * is 0xFFFFFFFF. On a 64-bit DSDT, Ones is 0xFFFFFFFFFFFFFFFF | |
376 | * (ACPI_UINT64_MAX). | |
377 | * | |
378 | * This function always returns ACPI_UINT64_MAX for TRUE, and later code | |
379 | * will truncate this to 32 bits if necessary. | |
380 | * | |
b0ed7a91 LM |
381 | ******************************************************************************/ |
382 | ||
f5c1e1c5 | 383 | acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state) |
b0ed7a91 LM |
384 | { |
385 | union acpi_operand_object *string_desc; | |
386 | union acpi_operand_object *return_desc; | |
387 | struct acpi_interface_info *interface_info; | |
388 | acpi_interface_handler interface_handler; | |
388a9902 | 389 | acpi_status status; |
955f485d | 390 | u64 return_value; |
b0ed7a91 LM |
391 | |
392 | ACPI_FUNCTION_TRACE(ut_osi_implementation); | |
393 | ||
394 | /* Validate the string input argument (from the AML caller) */ | |
395 | ||
396 | string_desc = walk_state->arguments[0].object; | |
397 | if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) { | |
398 | return_ACPI_STATUS(AE_TYPE); | |
399 | } | |
400 | ||
401 | /* Create a return object */ | |
402 | ||
403 | return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER); | |
404 | if (!return_desc) { | |
405 | return_ACPI_STATUS(AE_NO_MEMORY); | |
406 | } | |
407 | ||
408 | /* Default return value is 0, NOT SUPPORTED */ | |
409 | ||
410 | return_value = 0; | |
388a9902 JK |
411 | status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER); |
412 | if (ACPI_FAILURE(status)) { | |
3aa2eeac JK |
413 | acpi_ut_remove_reference(return_desc); |
414 | return_ACPI_STATUS(status); | |
388a9902 | 415 | } |
b0ed7a91 LM |
416 | |
417 | /* Lookup the interface in the global _OSI list */ | |
418 | ||
419 | interface_info = acpi_ut_get_interface(string_desc->string.pointer); | |
420 | if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) { | |
421 | /* | |
422 | * The interface is supported. | |
423 | * Update the osi_data if necessary. We keep track of the latest | |
424 | * version of Windows that has been requested by the BIOS. | |
425 | */ | |
426 | if (interface_info->value > acpi_gbl_osi_data) { | |
427 | acpi_gbl_osi_data = interface_info->value; | |
428 | } | |
429 | ||
955f485d | 430 | return_value = ACPI_UINT64_MAX; |
b0ed7a91 LM |
431 | } |
432 | ||
433 | acpi_os_release_mutex(acpi_gbl_osi_mutex); | |
434 | ||
435 | /* | |
436 | * Invoke an optional _OSI interface handler. The host OS may wish | |
437 | * to do some interface-specific handling. For example, warn about | |
438 | * certain interfaces or override the true/false support value. | |
439 | */ | |
440 | interface_handler = acpi_gbl_interface_handler; | |
441 | if (interface_handler) { | |
955f485d BM |
442 | if (interface_handler |
443 | (string_desc->string.pointer, (u32)return_value)) { | |
444 | return_value = ACPI_UINT64_MAX; | |
445 | } | |
b0ed7a91 LM |
446 | } |
447 | ||
448 | ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO, | |
449 | "ACPI: BIOS _OSI(\"%s\") is %ssupported\n", | |
450 | string_desc->string.pointer, | |
451 | return_value == 0 ? "not " : "")); | |
452 | ||
453 | /* Complete the return object */ | |
454 | ||
455 | return_desc->integer.value = return_value; | |
456 | walk_state->return_desc = return_desc; | |
457 | return_ACPI_STATUS(AE_OK); | |
458 | } |