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