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