Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
0002 /******************************************************************************
0003  *
0004  * Module Name: utaddress - op_region address range check
0005  *
0006  * Copyright (C) 2000 - 2022, Intel Corp.
0007  *
0008  *****************************************************************************/
0009 
0010 #include <acpi/acpi.h>
0011 #include "accommon.h"
0012 #include "acnamesp.h"
0013 
0014 #define _COMPONENT          ACPI_UTILITIES
0015 ACPI_MODULE_NAME("utaddress")
0016 
0017 /*******************************************************************************
0018  *
0019  * FUNCTION:    acpi_ut_add_address_range
0020  *
0021  * PARAMETERS:  space_id            - Address space ID
0022  *              address             - op_region start address
0023  *              length              - op_region length
0024  *              region_node         - op_region namespace node
0025  *
0026  * RETURN:      Status
0027  *
0028  * DESCRIPTION: Add the Operation Region address range to the global list.
0029  *              The only supported Space IDs are Memory and I/O. Called when
0030  *              the op_region address/length operands are fully evaluated.
0031  *
0032  * MUTEX:       Locks the namespace
0033  *
0034  * NOTE: Because this interface is only called when an op_region argument
0035  * list is evaluated, there cannot be any duplicate region_nodes.
0036  * Duplicate Address/Length values are allowed, however, so that multiple
0037  * address conflicts can be detected.
0038  *
0039  ******************************************************************************/
0040 acpi_status
0041 acpi_ut_add_address_range(acpi_adr_space_type space_id,
0042               acpi_physical_address address,
0043               u32 length, struct acpi_namespace_node *region_node)
0044 {
0045     struct acpi_address_range *range_info;
0046 
0047     ACPI_FUNCTION_TRACE(ut_add_address_range);
0048 
0049     if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
0050         (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
0051         return_ACPI_STATUS(AE_OK);
0052     }
0053 
0054     /* Allocate/init a new info block, add it to the appropriate list */
0055 
0056     range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range));
0057     if (!range_info) {
0058         return_ACPI_STATUS(AE_NO_MEMORY);
0059     }
0060 
0061     range_info->start_address = address;
0062     range_info->end_address = (address + length - 1);
0063     range_info->region_node = region_node;
0064 
0065     range_info->next = acpi_gbl_address_range_list[space_id];
0066     acpi_gbl_address_range_list[space_id] = range_info;
0067 
0068     ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
0069               "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
0070               acpi_ut_get_node_name(range_info->region_node),
0071               ACPI_FORMAT_UINT64(address),
0072               ACPI_FORMAT_UINT64(range_info->end_address)));
0073 
0074     return_ACPI_STATUS(AE_OK);
0075 }
0076 
0077 /*******************************************************************************
0078  *
0079  * FUNCTION:    acpi_ut_remove_address_range
0080  *
0081  * PARAMETERS:  space_id            - Address space ID
0082  *              region_node         - op_region namespace node
0083  *
0084  * RETURN:      None
0085  *
0086  * DESCRIPTION: Remove the Operation Region from the global list. The only
0087  *              supported Space IDs are Memory and I/O. Called when an
0088  *              op_region is deleted.
0089  *
0090  * MUTEX:       Assumes the namespace is locked
0091  *
0092  ******************************************************************************/
0093 
0094 void
0095 acpi_ut_remove_address_range(acpi_adr_space_type space_id,
0096                  struct acpi_namespace_node *region_node)
0097 {
0098     struct acpi_address_range *range_info;
0099     struct acpi_address_range *prev;
0100 
0101     ACPI_FUNCTION_TRACE(ut_remove_address_range);
0102 
0103     if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
0104         (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
0105         return_VOID;
0106     }
0107 
0108     /* Get the appropriate list head and check the list */
0109 
0110     range_info = prev = acpi_gbl_address_range_list[space_id];
0111     while (range_info) {
0112         if (range_info->region_node == region_node) {
0113             if (range_info == prev) {   /* Found at list head */
0114                 acpi_gbl_address_range_list[space_id] =
0115                     range_info->next;
0116             } else {
0117                 prev->next = range_info->next;
0118             }
0119 
0120             ACPI_DEBUG_PRINT((ACPI_DB_NAMES,
0121                       "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n",
0122                       acpi_ut_get_node_name(range_info->
0123                                 region_node),
0124                       ACPI_FORMAT_UINT64(range_info->
0125                                  start_address),
0126                       ACPI_FORMAT_UINT64(range_info->
0127                                  end_address)));
0128 
0129             ACPI_FREE(range_info);
0130             return_VOID;
0131         }
0132 
0133         prev = range_info;
0134         range_info = range_info->next;
0135     }
0136 
0137     return_VOID;
0138 }
0139 
0140 /*******************************************************************************
0141  *
0142  * FUNCTION:    acpi_ut_check_address_range
0143  *
0144  * PARAMETERS:  space_id            - Address space ID
0145  *              address             - Start address
0146  *              length              - Length of address range
0147  *              warn                - TRUE if warning on overlap desired
0148  *
0149  * RETURN:      Count of the number of conflicts detected. Zero is always
0150  *              returned for Space IDs other than Memory or I/O.
0151  *
0152  * DESCRIPTION: Check if the input address range overlaps any of the
0153  *              ASL operation region address ranges. The only supported
0154  *              Space IDs are Memory and I/O.
0155  *
0156  * MUTEX:       Assumes the namespace is locked.
0157  *
0158  ******************************************************************************/
0159 
0160 u32
0161 acpi_ut_check_address_range(acpi_adr_space_type space_id,
0162                 acpi_physical_address address, u32 length, u8 warn)
0163 {
0164     struct acpi_address_range *range_info;
0165     acpi_physical_address end_address;
0166     char *pathname;
0167     u32 overlap_count = 0;
0168 
0169     ACPI_FUNCTION_TRACE(ut_check_address_range);
0170 
0171     if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) &&
0172         (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) {
0173         return_UINT32(0);
0174     }
0175 
0176     range_info = acpi_gbl_address_range_list[space_id];
0177     end_address = address + length - 1;
0178 
0179     /* Check entire list for all possible conflicts */
0180 
0181     while (range_info) {
0182         /*
0183          * Check if the requested address/length overlaps this
0184          * address range. There are four cases to consider:
0185          *
0186          * 1) Input address/length is contained completely in the
0187          *    address range
0188          * 2) Input address/length overlaps range at the range start
0189          * 3) Input address/length overlaps range at the range end
0190          * 4) Input address/length completely encompasses the range
0191          */
0192         if ((address <= range_info->end_address) &&
0193             (end_address >= range_info->start_address)) {
0194 
0195             /* Found an address range overlap */
0196 
0197             overlap_count++;
0198             if (warn) { /* Optional warning message */
0199                 pathname =
0200                     acpi_ns_get_normalized_pathname(range_info->
0201                                     region_node,
0202                                     TRUE);
0203 
0204                 ACPI_WARNING((AE_INFO,
0205                           "%s range 0x%8.8X%8.8X-0x%8.8X%8.8X conflicts with OpRegion 0x%8.8X%8.8X-0x%8.8X%8.8X (%s)",
0206                           acpi_ut_get_region_name(space_id),
0207                           ACPI_FORMAT_UINT64(address),
0208                           ACPI_FORMAT_UINT64(end_address),
0209                           ACPI_FORMAT_UINT64(range_info->
0210                                  start_address),
0211                           ACPI_FORMAT_UINT64(range_info->
0212                                  end_address),
0213                           pathname));
0214                 ACPI_FREE(pathname);
0215             }
0216         }
0217 
0218         range_info = range_info->next;
0219     }
0220 
0221     return_UINT32(overlap_count);
0222 }
0223 
0224 /*******************************************************************************
0225  *
0226  * FUNCTION:    acpi_ut_delete_address_lists
0227  *
0228  * PARAMETERS:  None
0229  *
0230  * RETURN:      None
0231  *
0232  * DESCRIPTION: Delete all global address range lists (called during
0233  *              subsystem shutdown).
0234  *
0235  ******************************************************************************/
0236 
0237 void acpi_ut_delete_address_lists(void)
0238 {
0239     struct acpi_address_range *next;
0240     struct acpi_address_range *range_info;
0241     int i;
0242 
0243     /* Delete all elements in all address range lists */
0244 
0245     for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) {
0246         next = acpi_gbl_address_range_list[i];
0247 
0248         while (next) {
0249             range_info = next;
0250             next = range_info->next;
0251             ACPI_FREE(range_info);
0252         }
0253 
0254         acpi_gbl_address_range_list[i] = NULL;
0255     }
0256 }