1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 2 /****************************************************************************** 3 * 4 * Module Name: utaddress - op_region address range check 5 * 6 * Copyright (C) 2000 - 2023, Intel Corp. 7 * 8 *****************************************************************************/ 9 10 #include <acpi/acpi.h> 11 #include "accommon.h" 12 #include "acnamesp.h" 13 14 #define _COMPONENT ACPI_UTILITIES 15 ACPI_MODULE_NAME("utaddress") 16 17 /******************************************************************************* 18 * 19 * FUNCTION: acpi_ut_add_address_range 20 * 21 * PARAMETERS: space_id - Address space ID 22 * address - op_region start address 23 * length - op_region length 24 * region_node - op_region namespace node 25 * 26 * RETURN: Status 27 * 28 * DESCRIPTION: Add the Operation Region address range to the global list. 29 * The only supported Space IDs are Memory and I/O. Called when 30 * the op_region address/length operands are fully evaluated. 31 * 32 * MUTEX: Locks the namespace 33 * 34 * NOTE: Because this interface is only called when an op_region argument 35 * list is evaluated, there cannot be any duplicate region_nodes. 36 * Duplicate Address/Length values are allowed, however, so that multiple 37 * address conflicts can be detected. 38 * 39 ******************************************************************************/ 40 acpi_status 41 acpi_ut_add_address_range(acpi_adr_space_type space_id, 42 acpi_physical_address address, 43 u32 length, struct acpi_namespace_node *region_node) 44 { 45 struct acpi_address_range *range_info; 46 47 ACPI_FUNCTION_TRACE(ut_add_address_range); 48 49 if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 50 (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 51 return_ACPI_STATUS(AE_OK); 52 } 53 54 /* Allocate/init a new info block, add it to the appropriate list */ 55 56 range_info = ACPI_ALLOCATE(sizeof(struct acpi_address_range)); 57 if (!range_info) { 58 return_ACPI_STATUS(AE_NO_MEMORY); 59 } 60 61 range_info->start_address = address; 62 range_info->end_address = (address + length - 1); 63 range_info->region_node = region_node; 64 65 range_info->next = acpi_gbl_address_range_list[space_id]; 66 acpi_gbl_address_range_list[space_id] = range_info; 67 68 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 69 "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", 70 acpi_ut_get_node_name(range_info->region_node), 71 ACPI_FORMAT_UINT64(address), 72 ACPI_FORMAT_UINT64(range_info->end_address))); 73 74 return_ACPI_STATUS(AE_OK); 75 } 76 77 /******************************************************************************* 78 * 79 * FUNCTION: acpi_ut_remove_address_range 80 * 81 * PARAMETERS: space_id - Address space ID 82 * region_node - op_region namespace node 83 * 84 * RETURN: None 85 * 86 * DESCRIPTION: Remove the Operation Region from the global list. The only 87 * supported Space IDs are Memory and I/O. Called when an 88 * op_region is deleted. 89 * 90 * MUTEX: Assumes the namespace is locked 91 * 92 ******************************************************************************/ 93 94 void 95 acpi_ut_remove_address_range(acpi_adr_space_type space_id, 96 struct acpi_namespace_node *region_node) 97 { 98 struct acpi_address_range *range_info; 99 struct acpi_address_range *prev; 100 101 ACPI_FUNCTION_TRACE(ut_remove_address_range); 102 103 if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 104 (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 105 return_VOID; 106 } 107 108 /* Get the appropriate list head and check the list */ 109 110 range_info = prev = acpi_gbl_address_range_list[space_id]; 111 while (range_info) { 112 if (range_info->region_node == region_node) { 113 if (range_info == prev) { /* Found at list head */ 114 acpi_gbl_address_range_list[space_id] = 115 range_info->next; 116 } else { 117 prev->next = range_info->next; 118 } 119 120 ACPI_DEBUG_PRINT((ACPI_DB_NAMES, 121 "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", 122 acpi_ut_get_node_name(range_info-> 123 region_node), 124 ACPI_FORMAT_UINT64(range_info-> 125 start_address), 126 ACPI_FORMAT_UINT64(range_info-> 127 end_address))); 128 129 ACPI_FREE(range_info); 130 return_VOID; 131 } 132 133 prev = range_info; 134 range_info = range_info->next; 135 } 136 137 return_VOID; 138 } 139 140 /******************************************************************************* 141 * 142 * FUNCTION: acpi_ut_check_address_range 143 * 144 * PARAMETERS: space_id - Address space ID 145 * address - Start address 146 * length - Length of address range 147 * warn - TRUE if warning on overlap desired 148 * 149 * RETURN: Count of the number of conflicts detected. Zero is always 150 * returned for Space IDs other than Memory or I/O. 151 * 152 * DESCRIPTION: Check if the input address range overlaps any of the 153 * ASL operation region address ranges. The only supported 154 * Space IDs are Memory and I/O. 155 * 156 * MUTEX: Assumes the namespace is locked. 157 * 158 ******************************************************************************/ 159 160 u32 161 acpi_ut_check_address_range(acpi_adr_space_type space_id, 162 acpi_physical_address address, u32 length, u8 warn) 163 { 164 struct acpi_address_range *range_info; 165 acpi_physical_address end_address; 166 char *pathname; 167 u32 overlap_count = 0; 168 169 ACPI_FUNCTION_TRACE(ut_check_address_range); 170 171 if ((space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY) && 172 (space_id != ACPI_ADR_SPACE_SYSTEM_IO)) { 173 return_UINT32(0); 174 } 175 176 range_info = acpi_gbl_address_range_list[space_id]; 177 end_address = address + length - 1; 178 179 /* Check entire list for all possible conflicts */ 180 181 while (range_info) { 182 /* 183 * Check if the requested address/length overlaps this 184 * address range. There are four cases to consider: 185 * 186 * 1) Input address/length is contained completely in the 187 * address range 188 * 2) Input address/length overlaps range at the range start 189 * 3) Input address/length overlaps range at the range end 190 * 4) Input address/length completely encompasses the range 191 */ 192 if ((address <= range_info->end_address) && 193 (end_address >= range_info->start_address)) { 194 195 /* Found an address range overlap */ 196 197 overlap_count++; 198 if (warn) { /* Optional warning message */ 199 pathname = 200 acpi_ns_get_normalized_pathname(range_info-> 201 region_node, 202 TRUE); 203 204 ACPI_WARNING((AE_INFO, 205 "%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)", 206 acpi_ut_get_region_name(space_id), 207 ACPI_FORMAT_UINT64(address), 208 ACPI_FORMAT_UINT64(end_address), 209 ACPI_FORMAT_UINT64(range_info-> 210 start_address), 211 ACPI_FORMAT_UINT64(range_info-> 212 end_address), 213 pathname)); 214 ACPI_FREE(pathname); 215 } 216 } 217 218 range_info = range_info->next; 219 } 220 221 return_UINT32(overlap_count); 222 } 223 224 /******************************************************************************* 225 * 226 * FUNCTION: acpi_ut_delete_address_lists 227 * 228 * PARAMETERS: None 229 * 230 * RETURN: None 231 * 232 * DESCRIPTION: Delete all global address range lists (called during 233 * subsystem shutdown). 234 * 235 ******************************************************************************/ 236 237 void acpi_ut_delete_address_lists(void) 238 { 239 struct acpi_address_range *next; 240 struct acpi_address_range *range_info; 241 int i; 242 243 /* Delete all elements in all address range lists */ 244 245 for (i = 0; i < ACPI_ADDRESS_RANGE_MAX; i++) { 246 next = acpi_gbl_address_range_list[i]; 247 248 while (next) { 249 range_info = next; 250 next = range_info->next; 251 ACPI_FREE(range_info); 252 } 253 254 acpi_gbl_address_range_list[i] = NULL; 255 } 256 } 257