1 /*******************************************************************************
   2  *
   3  * Module Name: rscalc - Calculate stream and list lengths
   4  *
   5  ******************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2011, 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 __RSCALC_C__
  45 
  46 #include "acpi.h"
  47 #include "accommon.h"
  48 #include "acresrc.h"
  49 #include "acnamesp.h"
  50 
  51 
  52 #define _COMPONENT          ACPI_RESOURCES
  53         ACPI_MODULE_NAME    ("rscalc")
  54 
  55 
  56 /* Local prototypes */
  57 
  58 static UINT8
  59 AcpiRsCountSetBits (
  60     UINT16                  BitField);
  61 
  62 static ACPI_RS_LENGTH
  63 AcpiRsStructOptionLength (
  64     ACPI_RESOURCE_SOURCE    *ResourceSource);
  65 
  66 static UINT32
  67 AcpiRsStreamOptionLength (
  68     UINT32                  ResourceLength,
  69     UINT32                  MinimumTotalLength);
  70 
  71 
  72 /*******************************************************************************
  73  *
  74  * FUNCTION:    AcpiRsCountSetBits
  75  *
  76  * PARAMETERS:  BitField        - Field in which to count bits
  77  *
  78  * RETURN:      Number of bits set within the field
  79  *
  80  * DESCRIPTION: Count the number of bits set in a resource field. Used for
  81  *              (Short descriptor) interrupt and DMA lists.
  82  *
  83  ******************************************************************************/
  84 
  85 static UINT8
  86 AcpiRsCountSetBits (
  87     UINT16                  BitField)
  88 {
  89     UINT8                   BitsSet;
  90 
  91 
  92     ACPI_FUNCTION_ENTRY ();
  93 
  94 
  95     for (BitsSet = 0; BitField; BitsSet++)
  96     {
  97         /* Zero the least significant bit that is set */
  98 
  99         BitField &= (UINT16) (BitField - 1);
 100     }
 101 
 102     return (BitsSet);
 103 }
 104 
 105 
 106 /*******************************************************************************
 107  *
 108  * FUNCTION:    AcpiRsStructOptionLength
 109  *
 110  * PARAMETERS:  ResourceSource      - Pointer to optional descriptor field
 111  *
 112  * RETURN:      Status
 113  *
 114  * DESCRIPTION: Common code to handle optional ResourceSourceIndex and
 115  *              ResourceSource fields in some Large descriptors. Used during
 116  *              list-to-stream conversion
 117  *
 118  ******************************************************************************/
 119 
 120 static ACPI_RS_LENGTH
 121 AcpiRsStructOptionLength (
 122     ACPI_RESOURCE_SOURCE    *ResourceSource)
 123 {
 124     ACPI_FUNCTION_ENTRY ();
 125 
 126 
 127     /*
 128      * If the ResourceSource string is valid, return the size of the string
 129      * (StringLength includes the NULL terminator) plus the size of the
 130      * ResourceSourceIndex (1).
 131      */
 132     if (ResourceSource->StringPtr)
 133     {
 134         return ((ACPI_RS_LENGTH) (ResourceSource->StringLength + 1));
 135     }
 136 
 137     return (0);
 138 }
 139 
 140 
 141 /*******************************************************************************
 142  *
 143  * FUNCTION:    AcpiRsStreamOptionLength
 144  *
 145  * PARAMETERS:  ResourceLength      - Length from the resource header
 146  *              MinimumTotalLength  - Minimum length of this resource, before
 147  *                                    any optional fields. Includes header size
 148  *
 149  * RETURN:      Length of optional string (0 if no string present)
 150  *
 151  * DESCRIPTION: Common code to handle optional ResourceSourceIndex and
 152  *              ResourceSource fields in some Large descriptors. Used during
 153  *              stream-to-list conversion
 154  *
 155  ******************************************************************************/
 156 
 157 static UINT32
 158 AcpiRsStreamOptionLength (
 159     UINT32                  ResourceLength,
 160     UINT32                  MinimumAmlResourceLength)
 161 {
 162     UINT32                  StringLength = 0;
 163 
 164 
 165     ACPI_FUNCTION_ENTRY ();
 166 
 167 
 168     /*
 169      * The ResourceSourceIndex and ResourceSource are optional elements of some
 170      * Large-type resource descriptors.
 171      */
 172 
 173     /*
 174      * If the length of the actual resource descriptor is greater than the ACPI
 175      * spec-defined minimum length, it means that a ResourceSourceIndex exists
 176      * and is followed by a (required) null terminated string. The string length
 177      * (including the null terminator) is the resource length minus the minimum
 178      * length, minus one byte for the ResourceSourceIndex itself.
 179      */
 180     if (ResourceLength > MinimumAmlResourceLength)
 181     {
 182         /* Compute the length of the optional string */
 183 
 184         StringLength = ResourceLength - MinimumAmlResourceLength - 1;
 185     }
 186 
 187     /*
 188      * Round the length up to a multiple of the native word in order to
 189      * guarantee that the entire resource descriptor is native word aligned
 190      */
 191     return ((UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (StringLength));
 192 }
 193 
 194 
 195 /*******************************************************************************
 196  *
 197  * FUNCTION:    AcpiRsGetAmlLength
 198  *
 199  * PARAMETERS:  Resource            - Pointer to the resource linked list
 200  *              SizeNeeded          - Where the required size is returned
 201  *
 202  * RETURN:      Status
 203  *
 204  * DESCRIPTION: Takes a linked list of internal resource descriptors and
 205  *              calculates the size buffer needed to hold the corresponding
 206  *              external resource byte stream.
 207  *
 208  ******************************************************************************/
 209 
 210 ACPI_STATUS
 211 AcpiRsGetAmlLength (
 212     ACPI_RESOURCE           *Resource,
 213     ACPI_SIZE               *SizeNeeded)
 214 {
 215     ACPI_SIZE               AmlSizeNeeded = 0;
 216     ACPI_RS_LENGTH          TotalSize;
 217 
 218 
 219     ACPI_FUNCTION_TRACE (RsGetAmlLength);
 220 
 221 
 222     /* Traverse entire list of internal resource descriptors */
 223 
 224     while (Resource)
 225     {
 226         /* Validate the descriptor type */
 227 
 228         if (Resource->Type > ACPI_RESOURCE_TYPE_MAX)
 229         {
 230             return_ACPI_STATUS (AE_AML_INVALID_RESOURCE_TYPE);
 231         }
 232 
 233         /* Get the base size of the (external stream) resource descriptor */
 234 
 235         TotalSize = AcpiGbl_AmlResourceSizes [Resource->Type];
 236 
 237         /*
 238          * Augment the base size for descriptors with optional and/or
 239          * variable-length fields
 240          */
 241         switch (Resource->Type)
 242         {
 243         case ACPI_RESOURCE_TYPE_IRQ:
 244 
 245             /* Length can be 3 or 2 */
 246 
 247             if (Resource->Data.Irq.DescriptorLength == 2)
 248             {
 249                 TotalSize--;
 250             }
 251             break;
 252 
 253 
 254         case ACPI_RESOURCE_TYPE_START_DEPENDENT:
 255 
 256             /* Length can be 1 or 0 */
 257 
 258             if (Resource->Data.Irq.DescriptorLength == 0)
 259             {
 260                 TotalSize--;
 261             }
 262             break;
 263 
 264 
 265         case ACPI_RESOURCE_TYPE_VENDOR:
 266             /*
 267              * Vendor Defined Resource:
 268              * For a Vendor Specific resource, if the Length is between 1 and 7
 269              * it will be created as a Small Resource data type, otherwise it
 270              * is a Large Resource data type.
 271              */
 272             if (Resource->Data.Vendor.ByteLength > 7)
 273             {
 274                 /* Base size of a Large resource descriptor */
 275 
 276                 TotalSize = sizeof (AML_RESOURCE_LARGE_HEADER);
 277             }
 278 
 279             /* Add the size of the vendor-specific data */
 280 
 281             TotalSize = (ACPI_RS_LENGTH)
 282                 (TotalSize + Resource->Data.Vendor.ByteLength);
 283             break;
 284 
 285 
 286         case ACPI_RESOURCE_TYPE_END_TAG:
 287             /*
 288              * End Tag:
 289              * We are done -- return the accumulated total size.
 290              */
 291             *SizeNeeded = AmlSizeNeeded + TotalSize;
 292 
 293             /* Normal exit */
 294 
 295             return_ACPI_STATUS (AE_OK);
 296 
 297 
 298         case ACPI_RESOURCE_TYPE_ADDRESS16:
 299             /*
 300              * 16-Bit Address Resource:
 301              * Add the size of the optional ResourceSource info
 302              */
 303             TotalSize = (ACPI_RS_LENGTH)
 304                 (TotalSize + AcpiRsStructOptionLength (
 305                                 &Resource->Data.Address16.ResourceSource));
 306             break;
 307 
 308 
 309         case ACPI_RESOURCE_TYPE_ADDRESS32:
 310             /*
 311              * 32-Bit Address Resource:
 312              * Add the size of the optional ResourceSource info
 313              */
 314             TotalSize = (ACPI_RS_LENGTH)
 315                 (TotalSize + AcpiRsStructOptionLength (
 316                                 &Resource->Data.Address32.ResourceSource));
 317             break;
 318 
 319 
 320         case ACPI_RESOURCE_TYPE_ADDRESS64:
 321             /*
 322              * 64-Bit Address Resource:
 323              * Add the size of the optional ResourceSource info
 324              */
 325             TotalSize = (ACPI_RS_LENGTH)
 326                 (TotalSize + AcpiRsStructOptionLength (
 327                                 &Resource->Data.Address64.ResourceSource));
 328             break;
 329 
 330 
 331         case ACPI_RESOURCE_TYPE_EXTENDED_IRQ:
 332             /*
 333              * Extended IRQ Resource:
 334              * Add the size of each additional optional interrupt beyond the
 335              * required 1 (4 bytes for each UINT32 interrupt number)
 336              */
 337             TotalSize = (ACPI_RS_LENGTH)
 338                 (TotalSize +
 339                 ((Resource->Data.ExtendedIrq.InterruptCount - 1) * 4) +
 340 
 341                 /* Add the size of the optional ResourceSource info */
 342 
 343                 AcpiRsStructOptionLength (
 344                     &Resource->Data.ExtendedIrq.ResourceSource));
 345             break;
 346 
 347 
 348         default:
 349             break;
 350         }
 351 
 352         /* Update the total */
 353 
 354         AmlSizeNeeded += TotalSize;
 355 
 356         /* Point to the next object */
 357 
 358         Resource = ACPI_ADD_PTR (ACPI_RESOURCE, Resource, Resource->Length);
 359     }
 360 
 361     /* Did not find an EndTag resource descriptor */
 362 
 363     return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
 364 }
 365 
 366 
 367 /*******************************************************************************
 368  *
 369  * FUNCTION:    AcpiRsGetListLength
 370  *
 371  * PARAMETERS:  AmlBuffer           - Pointer to the resource byte stream
 372  *              AmlBufferLength     - Size of AmlBuffer
 373  *              SizeNeeded          - Where the size needed is returned
 374  *
 375  * RETURN:      Status
 376  *
 377  * DESCRIPTION: Takes an external resource byte stream and calculates the size
 378  *              buffer needed to hold the corresponding internal resource
 379  *              descriptor linked list.
 380  *
 381  ******************************************************************************/
 382 
 383 ACPI_STATUS
 384 AcpiRsGetListLength (
 385     UINT8                   *AmlBuffer,
 386     UINT32                  AmlBufferLength,
 387     ACPI_SIZE               *SizeNeeded)
 388 {
 389     ACPI_STATUS             Status;
 390     UINT8                   *EndAml;
 391     UINT8                   *Buffer;
 392     UINT32                  BufferSize;
 393     UINT16                  Temp16;
 394     UINT16                  ResourceLength;
 395     UINT32                  ExtraStructBytes;
 396     UINT8                   ResourceIndex;
 397     UINT8                   MinimumAmlResourceLength;
 398 
 399 
 400     ACPI_FUNCTION_TRACE (RsGetListLength);
 401 
 402 
 403     *SizeNeeded = 0;
 404     EndAml = AmlBuffer + AmlBufferLength;
 405 
 406     /* Walk the list of AML resource descriptors */
 407 
 408     while (AmlBuffer < EndAml)
 409     {
 410         /* Validate the Resource Type and Resource Length */
 411 
 412         Status = AcpiUtValidateResource (AmlBuffer, &ResourceIndex);
 413         if (ACPI_FAILURE (Status))
 414         {
 415             return_ACPI_STATUS (Status);
 416         }
 417 
 418         /* Get the resource length and base (minimum) AML size */
 419 
 420         ResourceLength = AcpiUtGetResourceLength (AmlBuffer);
 421         MinimumAmlResourceLength = AcpiGbl_ResourceAmlSizes[ResourceIndex];
 422 
 423         /*
 424          * Augment the size for descriptors with optional
 425          * and/or variable length fields
 426          */
 427         ExtraStructBytes = 0;
 428         Buffer = AmlBuffer + AcpiUtGetResourceHeaderLength (AmlBuffer);
 429 
 430         switch (AcpiUtGetResourceType (AmlBuffer))
 431         {
 432         case ACPI_RESOURCE_NAME_IRQ:
 433             /*
 434              * IRQ Resource:
 435              * Get the number of bits set in the 16-bit IRQ mask
 436              */
 437             ACPI_MOVE_16_TO_16 (&Temp16, Buffer);
 438             ExtraStructBytes = AcpiRsCountSetBits (Temp16);
 439             break;
 440 
 441 
 442         case ACPI_RESOURCE_NAME_DMA:
 443             /*
 444              * DMA Resource:
 445              * Get the number of bits set in the 8-bit DMA mask
 446              */
 447             ExtraStructBytes = AcpiRsCountSetBits (*Buffer);
 448             break;
 449 
 450 
 451         case ACPI_RESOURCE_NAME_VENDOR_SMALL:
 452         case ACPI_RESOURCE_NAME_VENDOR_LARGE:
 453             /*
 454              * Vendor Resource:
 455              * Get the number of vendor data bytes
 456              */
 457             ExtraStructBytes = ResourceLength;
 458             break;
 459 
 460 
 461         case ACPI_RESOURCE_NAME_END_TAG:
 462             /*
 463              * End Tag:
 464              * This is the normal exit, add size of EndTag
 465              */
 466             *SizeNeeded += ACPI_RS_SIZE_MIN;
 467             return_ACPI_STATUS (AE_OK);
 468 
 469 
 470         case ACPI_RESOURCE_NAME_ADDRESS32:
 471         case ACPI_RESOURCE_NAME_ADDRESS16:
 472         case ACPI_RESOURCE_NAME_ADDRESS64:
 473             /*
 474              * Address Resource:
 475              * Add the size of the optional ResourceSource
 476              */
 477             ExtraStructBytes = AcpiRsStreamOptionLength (
 478                 ResourceLength, MinimumAmlResourceLength);
 479             break;
 480 
 481 
 482         case ACPI_RESOURCE_NAME_EXTENDED_IRQ:
 483             /*
 484              * Extended IRQ Resource:
 485              * Using the InterruptTableLength, add 4 bytes for each additional
 486              * interrupt. Note: at least one interrupt is required and is
 487              * included in the minimum descriptor size (reason for the -1)
 488              */
 489             ExtraStructBytes = (Buffer[1] - 1) * sizeof (UINT32);
 490 
 491             /* Add the size of the optional ResourceSource */
 492 
 493             ExtraStructBytes += AcpiRsStreamOptionLength (
 494                 ResourceLength - ExtraStructBytes, MinimumAmlResourceLength);
 495             break;
 496 
 497 
 498         default:
 499             break;
 500         }
 501 
 502         /*
 503          * Update the required buffer size for the internal descriptor structs
 504          *
 505          * Important: Round the size up for the appropriate alignment. This
 506          * is a requirement on IA64.
 507          */
 508         BufferSize = AcpiGbl_ResourceStructSizes[ResourceIndex] +
 509                         ExtraStructBytes;
 510         BufferSize = (UINT32) ACPI_ROUND_UP_TO_NATIVE_WORD (BufferSize);
 511 
 512         *SizeNeeded += BufferSize;
 513 
 514         ACPI_DEBUG_PRINT ((ACPI_DB_RESOURCES,
 515             "Type %.2X, AmlLength %.2X InternalLength %.2X\n",
 516             AcpiUtGetResourceType (AmlBuffer),
 517             AcpiUtGetDescriptorLength (AmlBuffer), BufferSize));
 518 
 519         /*
 520          * Point to the next resource within the AML stream using the length
 521          * contained in the resource descriptor header
 522          */
 523         AmlBuffer += AcpiUtGetDescriptorLength (AmlBuffer);
 524     }
 525 
 526     /* Did not find an EndTag resource descriptor */
 527 
 528     return_ACPI_STATUS (AE_AML_NO_RESOURCE_END_TAG);
 529 }
 530 
 531 
 532 /*******************************************************************************
 533  *
 534  * FUNCTION:    AcpiRsGetPciRoutingTableLength
 535  *
 536  * PARAMETERS:  PackageObject           - Pointer to the package object
 537  *              BufferSizeNeeded        - UINT32 pointer of the size buffer
 538  *                                        needed to properly return the
 539  *                                        parsed data
 540  *
 541  * RETURN:      Status
 542  *
 543  * DESCRIPTION: Given a package representing a PCI routing table, this
 544  *              calculates the size of the corresponding linked list of
 545  *              descriptions.
 546  *
 547  ******************************************************************************/
 548 
 549 ACPI_STATUS
 550 AcpiRsGetPciRoutingTableLength (
 551     ACPI_OPERAND_OBJECT     *PackageObject,
 552     ACPI_SIZE               *BufferSizeNeeded)
 553 {
 554     UINT32                  NumberOfElements;
 555     ACPI_SIZE               TempSizeNeeded = 0;
 556     ACPI_OPERAND_OBJECT     **TopObjectList;
 557     UINT32                  Index;
 558     ACPI_OPERAND_OBJECT     *PackageElement;
 559     ACPI_OPERAND_OBJECT     **SubObjectList;
 560     BOOLEAN                 NameFound;
 561     UINT32                  TableIndex;
 562 
 563 
 564     ACPI_FUNCTION_TRACE (RsGetPciRoutingTableLength);
 565 
 566 
 567     NumberOfElements = PackageObject->Package.Count;
 568 
 569     /*
 570      * Calculate the size of the return buffer.
 571      * The base size is the number of elements * the sizes of the
 572      * structures.  Additional space for the strings is added below.
 573      * The minus one is to subtract the size of the UINT8 Source[1]
 574      * member because it is added below.
 575      *
 576      * But each PRT_ENTRY structure has a pointer to a string and
 577      * the size of that string must be found.
 578      */
 579     TopObjectList = PackageObject->Package.Elements;
 580 
 581     for (Index = 0; Index < NumberOfElements; Index++)
 582     {
 583         /* Dereference the sub-package */
 584 
 585         PackageElement = *TopObjectList;
 586 
 587         /* We must have a valid Package object */
 588 
 589         if (!PackageElement ||
 590             (PackageElement->Common.Type != ACPI_TYPE_PACKAGE))
 591         {
 592             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 593         }
 594 
 595         /*
 596          * The SubObjectList will now point to an array of the
 597          * four IRQ elements: Address, Pin, Source and SourceIndex
 598          */
 599         SubObjectList = PackageElement->Package.Elements;
 600 
 601         /* Scan the IrqTableElements for the Source Name String */
 602 
 603         NameFound = FALSE;
 604 
 605         for (TableIndex = 0; TableIndex < 4 && !NameFound; TableIndex++)
 606         {
 607             if (*SubObjectList && /* Null object allowed */
 608 
 609                 ((ACPI_TYPE_STRING ==
 610                     (*SubObjectList)->Common.Type) ||
 611 
 612                 ((ACPI_TYPE_LOCAL_REFERENCE ==
 613                     (*SubObjectList)->Common.Type) &&
 614 
 615                     ((*SubObjectList)->Reference.Class ==
 616                         ACPI_REFCLASS_NAME))))
 617             {
 618                 NameFound = TRUE;
 619             }
 620             else
 621             {
 622                 /* Look at the next element */
 623 
 624                 SubObjectList++;
 625             }
 626         }
 627 
 628         TempSizeNeeded += (sizeof (ACPI_PCI_ROUTING_TABLE) - 4);
 629 
 630         /* Was a String type found? */
 631 
 632         if (NameFound)
 633         {
 634             if ((*SubObjectList)->Common.Type == ACPI_TYPE_STRING)
 635             {
 636                 /*
 637                  * The length String.Length field does not include the
 638                  * terminating NULL, add 1
 639                  */
 640                 TempSizeNeeded += ((ACPI_SIZE)
 641                     (*SubObjectList)->String.Length + 1);
 642             }
 643             else
 644             {
 645                 TempSizeNeeded += AcpiNsGetPathnameLength (
 646                                     (*SubObjectList)->Reference.Node);
 647             }
 648         }
 649         else
 650         {
 651             /*
 652              * If no name was found, then this is a NULL, which is
 653              * translated as a UINT32 zero.
 654              */
 655             TempSizeNeeded += sizeof (UINT32);
 656         }
 657 
 658         /* Round up the size since each element must be aligned */
 659 
 660         TempSizeNeeded = ACPI_ROUND_UP_TO_64BIT (TempSizeNeeded);
 661 
 662         /* Point to the next ACPI_OPERAND_OBJECT */
 663 
 664         TopObjectList++;
 665     }
 666 
 667     /*
 668      * Add an extra element to the end of the list, essentially a
 669      * NULL terminator
 670      */
 671     *BufferSizeNeeded = TempSizeNeeded + sizeof (ACPI_PCI_ROUTING_TABLE);
 672     return_ACPI_STATUS (AE_OK);
 673 }