]>
Commit | Line | Data |
---|---|---|
95857638 | 1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
f654c0fe LM |
2 | /****************************************************************************** |
3 | * | |
4 | * Module Name: utaddress - op_region address range check | |
5 | * | |
800ba7c5 | 6 | * Copyright (C) 2000 - 2020, Intel Corp. |
f654c0fe | 7 | * |
95857638 | 8 | *****************************************************************************/ |
f654c0fe LM |
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 | |
ba494bee BM |
22 | * address - op_region start address |
23 | * length - op_region length | |
f654c0fe LM |
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; | |
f654c0fe LM |
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 | ||
f654c0fe LM |
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, | |
cc2080b0 | 69 | "\nAdded [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", |
f654c0fe | 70 | acpi_ut_get_node_name(range_info->region_node), |
cc2080b0 LZ |
71 | ACPI_FORMAT_UINT64(address), |
72 | ACPI_FORMAT_UINT64(range_info->end_address))); | |
f654c0fe | 73 | |
f654c0fe LM |
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, | |
cc2080b0 | 121 | "\nRemoved [%4.4s] address range: 0x%8.8X%8.8X-0x%8.8X%8.8X\n", |
f654c0fe LM |
122 | acpi_ut_get_node_name(range_info-> |
123 | region_node), | |
cc2080b0 LZ |
124 | ACPI_FORMAT_UINT64(range_info-> |
125 | start_address), | |
126 | ACPI_FORMAT_UINT64(range_info-> | |
127 | end_address))); | |
f654c0fe LM |
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 | |
ba494bee BM |
145 | * address - Start address |
146 | * length - Length of address range | |
147 | * warn - TRUE if warning on overlap desired | |
f654c0fe LM |
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)) { | |
fd1af712 | 173 | return_UINT32(0); |
f654c0fe LM |
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 | /* | |
0f607cb5 BM |
183 | * Check if the requested address/length overlaps this |
184 | * address range. There are four cases to consider: | |
f654c0fe | 185 | * |
0f607cb5 BM |
186 | * 1) Input address/length is contained completely in the |
187 | * address range | |
f654c0fe LM |
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 = | |
0e166e4f LZ |
200 | acpi_ns_get_normalized_pathname(range_info-> |
201 | region_node, | |
202 | TRUE); | |
f654c0fe LM |
203 | |
204 | ACPI_WARNING((AE_INFO, | |
cc2080b0 | 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)", |
0f607cb5 | 206 | acpi_ut_get_region_name(space_id), |
cc2080b0 LZ |
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), | |
0f607cb5 | 213 | pathname)); |
f654c0fe LM |
214 | ACPI_FREE(pathname); |
215 | } | |
216 | } | |
217 | ||
218 | range_info = range_info->next; | |
219 | } | |
220 | ||
fd1af712 | 221 | return_UINT32(overlap_count); |
f654c0fe LM |
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 | } |