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