Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: utosi - Support for the _OSI predefined control method
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 
0013 #define _COMPONENT          ACPI_UTILITIES
0014 ACPI_MODULE_NAME("utosi")
0015 
0016 /******************************************************************************
0017  *
0018  * ACPICA policy for new _OSI strings:
0019  *
0020  * It is the stated policy of ACPICA that new _OSI strings will be integrated
0021  * into this module as soon as possible after they are defined. It is strongly
0022  * recommended that all ACPICA hosts mirror this policy and integrate any
0023  * changes to this module as soon as possible. There are several historical
0024  * reasons behind this policy:
0025  *
0026  * 1) New BIOSs tend to test only the case where the host responds TRUE to
0027  *    the latest version of Windows, which would respond to the latest/newest
0028  *    _OSI string. Not responding TRUE to the latest version of Windows will
0029  *    risk executing untested code paths throughout the DSDT and SSDTs.
0030  *
0031  * 2) If a new _OSI string is recognized only after a significant delay, this
0032  *    has the potential to cause problems on existing working machines because
0033  *    of the possibility that a new and different path through the ASL code
0034  *    will be executed.
0035  *
0036  * 3) New _OSI strings are tending to come out about once per year. A delay
0037  *    in recognizing a new string for a significant amount of time risks the
0038  *    release of another string which only compounds the initial problem.
0039  *
0040  *****************************************************************************/
0041 /*
0042  * Strings supported by the _OSI predefined control method (which is
0043  * implemented internally within this module.)
0044  *
0045  * March 2009: Removed "Linux" as this host no longer wants to respond true
0046  * for this string. Basically, the only safe OS strings are windows-related
0047  * and in many or most cases represent the only test path within the
0048  * BIOS-provided ASL code.
0049  *
0050  * The last element of each entry is used to track the newest version of
0051  * Windows that the BIOS has requested.
0052  */
0053 static struct acpi_interface_info acpi_default_supported_interfaces[] = {
0054     /* Operating System Vendor Strings */
0055 
0056     {"Windows 2000", NULL, 0, ACPI_OSI_WIN_2000},   /* Windows 2000 */
0057     {"Windows 2001", NULL, 0, ACPI_OSI_WIN_XP}, /* Windows XP */
0058     {"Windows 2001 SP1", NULL, 0, ACPI_OSI_WIN_XP_SP1}, /* Windows XP SP1 */
0059     {"Windows 2001.1", NULL, 0, ACPI_OSI_WINSRV_2003},  /* Windows Server 2003 */
0060     {"Windows 2001 SP2", NULL, 0, ACPI_OSI_WIN_XP_SP2}, /* Windows XP SP2 */
0061     {"Windows 2001.1 SP1", NULL, 0, ACPI_OSI_WINSRV_2003_SP1},  /* Windows Server 2003 SP1 - Added 03/2006 */
0062     {"Windows 2006", NULL, 0, ACPI_OSI_WIN_VISTA},  /* Windows vista - Added 03/2006 */
0063     {"Windows 2006.1", NULL, 0, ACPI_OSI_WINSRV_2008},  /* Windows Server 2008 - Added 09/2009 */
0064     {"Windows 2006 SP1", NULL, 0, ACPI_OSI_WIN_VISTA_SP1},  /* Windows Vista SP1 - Added 09/2009 */
0065     {"Windows 2006 SP2", NULL, 0, ACPI_OSI_WIN_VISTA_SP2},  /* Windows Vista SP2 - Added 09/2010 */
0066     {"Windows 2009", NULL, 0, ACPI_OSI_WIN_7},  /* Windows 7 and Server 2008 R2 - Added 09/2009 */
0067     {"Windows 2012", NULL, 0, ACPI_OSI_WIN_8},  /* Windows 8 and Server 2012 - Added 08/2012 */
0068     {"Windows 2013", NULL, 0, ACPI_OSI_WIN_8_1},    /* Windows 8.1 and Server 2012 R2 - Added 01/2014 */
0069     {"Windows 2015", NULL, 0, ACPI_OSI_WIN_10}, /* Windows 10 - Added 03/2015 */
0070     {"Windows 2016", NULL, 0, ACPI_OSI_WIN_10_RS1}, /* Windows 10 version 1607 - Added 12/2017 */
0071     {"Windows 2017", NULL, 0, ACPI_OSI_WIN_10_RS2}, /* Windows 10 version 1703 - Added 12/2017 */
0072     {"Windows 2017.2", NULL, 0, ACPI_OSI_WIN_10_RS3},   /* Windows 10 version 1709 - Added 02/2018 */
0073     {"Windows 2018", NULL, 0, ACPI_OSI_WIN_10_RS4}, /* Windows 10 version 1803 - Added 11/2018 */
0074     {"Windows 2018.2", NULL, 0, ACPI_OSI_WIN_10_RS5},   /* Windows 10 version 1809 - Added 11/2018 */
0075     {"Windows 2019", NULL, 0, ACPI_OSI_WIN_10_19H1},    /* Windows 10 version 1903 - Added 08/2019 */
0076     {"Windows 2020", NULL, 0, ACPI_OSI_WIN_10_20H1},    /* Windows 10 version 2004 - Added 08/2021 */
0077     {"Windows 2021", NULL, 0, ACPI_OSI_WIN_11}, /* Windows 11 - Added 01/2022 */
0078 
0079     /* Feature Group Strings */
0080 
0081     {"Extended Address Space Descriptor", NULL, ACPI_OSI_FEATURE, 0},
0082 
0083     /*
0084      * All "optional" feature group strings (features that are implemented
0085      * by the host) should be dynamically modified to VALID by the host via
0086      * acpi_install_interface or acpi_update_interfaces. Such optional feature
0087      * group strings are set as INVALID by default here.
0088      */
0089 
0090     {"Module Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
0091     {"Processor Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
0092     {"3.0 Thermal Model", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
0093     {"3.0 _SCP Extensions", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0},
0094     {"Processor Aggregator Device", NULL, ACPI_OSI_OPTIONAL_FEATURE, 0}
0095 };
0096 
0097 /*******************************************************************************
0098  *
0099  * FUNCTION:    acpi_ut_initialize_interfaces
0100  *
0101  * PARAMETERS:  None
0102  *
0103  * RETURN:      Status
0104  *
0105  * DESCRIPTION: Initialize the global _OSI supported interfaces list
0106  *
0107  ******************************************************************************/
0108 
0109 acpi_status acpi_ut_initialize_interfaces(void)
0110 {
0111     acpi_status status;
0112     u32 i;
0113 
0114     status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
0115     if (ACPI_FAILURE(status)) {
0116         return (status);
0117     }
0118 
0119     acpi_gbl_supported_interfaces = acpi_default_supported_interfaces;
0120 
0121     /* Link the static list of supported interfaces */
0122 
0123     for (i = 0;
0124          i < (ACPI_ARRAY_LENGTH(acpi_default_supported_interfaces) - 1);
0125          i++) {
0126         acpi_default_supported_interfaces[i].next =
0127             &acpi_default_supported_interfaces[(acpi_size)i + 1];
0128     }
0129 
0130     acpi_os_release_mutex(acpi_gbl_osi_mutex);
0131     return (AE_OK);
0132 }
0133 
0134 /*******************************************************************************
0135  *
0136  * FUNCTION:    acpi_ut_interface_terminate
0137  *
0138  * PARAMETERS:  None
0139  *
0140  * RETURN:      Status
0141  *
0142  * DESCRIPTION: Delete all interfaces in the global list. Sets
0143  *              acpi_gbl_supported_interfaces to NULL.
0144  *
0145  ******************************************************************************/
0146 
0147 acpi_status acpi_ut_interface_terminate(void)
0148 {
0149     acpi_status status;
0150     struct acpi_interface_info *next_interface;
0151 
0152     status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
0153     if (ACPI_FAILURE(status)) {
0154         return (status);
0155     }
0156 
0157     next_interface = acpi_gbl_supported_interfaces;
0158     while (next_interface) {
0159         acpi_gbl_supported_interfaces = next_interface->next;
0160 
0161         if (next_interface->flags & ACPI_OSI_DYNAMIC) {
0162 
0163             /* Only interfaces added at runtime can be freed */
0164 
0165             ACPI_FREE(next_interface->name);
0166             ACPI_FREE(next_interface);
0167         } else {
0168             /* Interface is in static list. Reset it to invalid or valid. */
0169 
0170             if (next_interface->flags & ACPI_OSI_DEFAULT_INVALID) {
0171                 next_interface->flags |= ACPI_OSI_INVALID;
0172             } else {
0173                 next_interface->flags &= ~ACPI_OSI_INVALID;
0174             }
0175         }
0176 
0177         next_interface = acpi_gbl_supported_interfaces;
0178     }
0179 
0180     acpi_os_release_mutex(acpi_gbl_osi_mutex);
0181     return (AE_OK);
0182 }
0183 
0184 /*******************************************************************************
0185  *
0186  * FUNCTION:    acpi_ut_install_interface
0187  *
0188  * PARAMETERS:  interface_name      - The interface to install
0189  *
0190  * RETURN:      Status
0191  *
0192  * DESCRIPTION: Install the interface into the global interface list.
0193  *              Caller MUST hold acpi_gbl_osi_mutex
0194  *
0195  ******************************************************************************/
0196 
0197 acpi_status acpi_ut_install_interface(acpi_string interface_name)
0198 {
0199     struct acpi_interface_info *interface_info;
0200 
0201     /* Allocate info block and space for the name string */
0202 
0203     interface_info =
0204         ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_interface_info));
0205     if (!interface_info) {
0206         return (AE_NO_MEMORY);
0207     }
0208 
0209     interface_info->name = ACPI_ALLOCATE_ZEROED(strlen(interface_name) + 1);
0210     if (!interface_info->name) {
0211         ACPI_FREE(interface_info);
0212         return (AE_NO_MEMORY);
0213     }
0214 
0215     /* Initialize new info and insert at the head of the global list */
0216 
0217     strcpy(interface_info->name, interface_name);
0218     interface_info->flags = ACPI_OSI_DYNAMIC;
0219     interface_info->next = acpi_gbl_supported_interfaces;
0220 
0221     acpi_gbl_supported_interfaces = interface_info;
0222     return (AE_OK);
0223 }
0224 
0225 /*******************************************************************************
0226  *
0227  * FUNCTION:    acpi_ut_remove_interface
0228  *
0229  * PARAMETERS:  interface_name      - The interface to remove
0230  *
0231  * RETURN:      Status
0232  *
0233  * DESCRIPTION: Remove the interface from the global interface list.
0234  *              Caller MUST hold acpi_gbl_osi_mutex
0235  *
0236  ******************************************************************************/
0237 
0238 acpi_status acpi_ut_remove_interface(acpi_string interface_name)
0239 {
0240     struct acpi_interface_info *previous_interface;
0241     struct acpi_interface_info *next_interface;
0242 
0243     previous_interface = next_interface = acpi_gbl_supported_interfaces;
0244     while (next_interface) {
0245         if (!strcmp(interface_name, next_interface->name)) {
0246             /*
0247              * Found: name is in either the static list
0248              * or was added at runtime
0249              */
0250             if (next_interface->flags & ACPI_OSI_DYNAMIC) {
0251 
0252                 /* Interface was added dynamically, remove and free it */
0253 
0254                 if (previous_interface == next_interface) {
0255                     acpi_gbl_supported_interfaces =
0256                         next_interface->next;
0257                 } else {
0258                     previous_interface->next =
0259                         next_interface->next;
0260                 }
0261 
0262                 ACPI_FREE(next_interface->name);
0263                 ACPI_FREE(next_interface);
0264             } else {
0265                 /*
0266                  * Interface is in static list. If marked invalid, then
0267                  * it does not actually exist. Else, mark it invalid.
0268                  */
0269                 if (next_interface->flags & ACPI_OSI_INVALID) {
0270                     return (AE_NOT_EXIST);
0271                 }
0272 
0273                 next_interface->flags |= ACPI_OSI_INVALID;
0274             }
0275 
0276             return (AE_OK);
0277         }
0278 
0279         previous_interface = next_interface;
0280         next_interface = next_interface->next;
0281     }
0282 
0283     /* Interface was not found */
0284 
0285     return (AE_NOT_EXIST);
0286 }
0287 
0288 /*******************************************************************************
0289  *
0290  * FUNCTION:    acpi_ut_update_interfaces
0291  *
0292  * PARAMETERS:  action              - Actions to be performed during the
0293  *                                    update
0294  *
0295  * RETURN:      Status
0296  *
0297  * DESCRIPTION: Update _OSI interface strings, disabling or enabling OS vendor
0298  *              strings or/and feature group strings.
0299  *              Caller MUST hold acpi_gbl_osi_mutex
0300  *
0301  ******************************************************************************/
0302 
0303 acpi_status acpi_ut_update_interfaces(u8 action)
0304 {
0305     struct acpi_interface_info *next_interface;
0306 
0307     next_interface = acpi_gbl_supported_interfaces;
0308     while (next_interface) {
0309         if (((next_interface->flags & ACPI_OSI_FEATURE) &&
0310              (action & ACPI_FEATURE_STRINGS)) ||
0311             (!(next_interface->flags & ACPI_OSI_FEATURE) &&
0312              (action & ACPI_VENDOR_STRINGS))) {
0313             if (action & ACPI_DISABLE_INTERFACES) {
0314 
0315                 /* Mark the interfaces as invalid */
0316 
0317                 next_interface->flags |= ACPI_OSI_INVALID;
0318             } else {
0319                 /* Mark the interfaces as valid */
0320 
0321                 next_interface->flags &= ~ACPI_OSI_INVALID;
0322             }
0323         }
0324 
0325         next_interface = next_interface->next;
0326     }
0327 
0328     return (AE_OK);
0329 }
0330 
0331 /*******************************************************************************
0332  *
0333  * FUNCTION:    acpi_ut_get_interface
0334  *
0335  * PARAMETERS:  interface_name      - The interface to find
0336  *
0337  * RETURN:      struct acpi_interface_info if found. NULL if not found.
0338  *
0339  * DESCRIPTION: Search for the specified interface name in the global list.
0340  *              Caller MUST hold acpi_gbl_osi_mutex
0341  *
0342  ******************************************************************************/
0343 
0344 struct acpi_interface_info *acpi_ut_get_interface(acpi_string interface_name)
0345 {
0346     struct acpi_interface_info *next_interface;
0347 
0348     next_interface = acpi_gbl_supported_interfaces;
0349     while (next_interface) {
0350         if (!strcmp(interface_name, next_interface->name)) {
0351             return (next_interface);
0352         }
0353 
0354         next_interface = next_interface->next;
0355     }
0356 
0357     return (NULL);
0358 }
0359 
0360 /*******************************************************************************
0361  *
0362  * FUNCTION:    acpi_ut_osi_implementation
0363  *
0364  * PARAMETERS:  walk_state          - Current walk state
0365  *
0366  * RETURN:      Status
0367  *              Integer: TRUE (0) if input string is matched
0368  *                       FALSE (-1) if string is not matched
0369  *
0370  * DESCRIPTION: Implementation of the _OSI predefined control method. When
0371  *              an invocation of _OSI is encountered in the system AML,
0372  *              control is transferred to this function.
0373  *
0374  * (August 2016)
0375  * Note:  _OSI is now defined to return "Ones" to indicate a match, for
0376  * compatibility with other ACPI implementations. On a 32-bit DSDT, Ones
0377  * is 0xFFFFFFFF. On a 64-bit DSDT, Ones is 0xFFFFFFFFFFFFFFFF
0378  * (ACPI_UINT64_MAX).
0379  *
0380  * This function always returns ACPI_UINT64_MAX for TRUE, and later code
0381  * will truncate this to 32 bits if necessary.
0382  *
0383  ******************************************************************************/
0384 
0385 acpi_status acpi_ut_osi_implementation(struct acpi_walk_state *walk_state)
0386 {
0387     union acpi_operand_object *string_desc;
0388     union acpi_operand_object *return_desc;
0389     struct acpi_interface_info *interface_info;
0390     acpi_interface_handler interface_handler;
0391     acpi_status status;
0392     u64 return_value;
0393 
0394     ACPI_FUNCTION_TRACE(ut_osi_implementation);
0395 
0396     /* Validate the string input argument (from the AML caller) */
0397 
0398     string_desc = walk_state->arguments[0].object;
0399     if (!string_desc || (string_desc->common.type != ACPI_TYPE_STRING)) {
0400         return_ACPI_STATUS(AE_TYPE);
0401     }
0402 
0403     /* Create a return object */
0404 
0405     return_desc = acpi_ut_create_internal_object(ACPI_TYPE_INTEGER);
0406     if (!return_desc) {
0407         return_ACPI_STATUS(AE_NO_MEMORY);
0408     }
0409 
0410     /* Default return value is 0, NOT SUPPORTED */
0411 
0412     return_value = 0;
0413     status = acpi_os_acquire_mutex(acpi_gbl_osi_mutex, ACPI_WAIT_FOREVER);
0414     if (ACPI_FAILURE(status)) {
0415         acpi_ut_remove_reference(return_desc);
0416         return_ACPI_STATUS(status);
0417     }
0418 
0419     /* Lookup the interface in the global _OSI list */
0420 
0421     interface_info = acpi_ut_get_interface(string_desc->string.pointer);
0422     if (interface_info && !(interface_info->flags & ACPI_OSI_INVALID)) {
0423         /*
0424          * The interface is supported.
0425          * Update the osi_data if necessary. We keep track of the latest
0426          * version of Windows that has been requested by the BIOS.
0427          */
0428         if (interface_info->value > acpi_gbl_osi_data) {
0429             acpi_gbl_osi_data = interface_info->value;
0430         }
0431 
0432         return_value = ACPI_UINT64_MAX;
0433     }
0434 
0435     acpi_os_release_mutex(acpi_gbl_osi_mutex);
0436 
0437     /*
0438      * Invoke an optional _OSI interface handler. The host OS may wish
0439      * to do some interface-specific handling. For example, warn about
0440      * certain interfaces or override the true/false support value.
0441      */
0442     interface_handler = acpi_gbl_interface_handler;
0443     if (interface_handler) {
0444         if (interface_handler
0445             (string_desc->string.pointer, (u32)return_value)) {
0446             return_value = ACPI_UINT64_MAX;
0447         }
0448     }
0449 
0450     ACPI_DEBUG_PRINT_RAW((ACPI_DB_INFO,
0451                   "ACPI: BIOS _OSI(\"%s\") is %ssupported\n",
0452                   string_desc->string.pointer,
0453                   return_value == 0 ? "not " : ""));
0454 
0455     /* Complete the return object */
0456 
0457     return_desc->integer.value = return_value;
0458     walk_state->return_desc = return_desc;
0459     return_ACPI_STATUS(AE_OK);
0460 }