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