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