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