1 /******************************************************************************
   2  *
   3  * Module Name: utaddress - OpRegion address range check
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2013, 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 }