1 /******************************************************************************
   2  *
   3  * Module Name: exfldio - Aml Field I/O
   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 
  45 #define __EXFLDIO_C__
  46 
  47 #include "acpi.h"
  48 #include "accommon.h"
  49 #include "acinterp.h"
  50 #include "amlcode.h"
  51 #include "acevents.h"
  52 #include "acdispat.h"
  53 
  54 
  55 #define _COMPONENT          ACPI_EXECUTER
  56         ACPI_MODULE_NAME    ("exfldio")
  57 
  58 /* Local prototypes */
  59 
  60 static ACPI_STATUS
  61 AcpiExFieldDatumIo (
  62     ACPI_OPERAND_OBJECT     *ObjDesc,
  63     UINT32                  FieldDatumByteOffset,
  64     UINT64                  *Value,
  65     UINT32                  ReadWrite);
  66 
  67 static BOOLEAN
  68 AcpiExRegisterOverflow (
  69     ACPI_OPERAND_OBJECT     *ObjDesc,
  70     UINT64                  Value);
  71 
  72 static ACPI_STATUS
  73 AcpiExSetupRegion (
  74     ACPI_OPERAND_OBJECT     *ObjDesc,
  75     UINT32                  FieldDatumByteOffset);
  76 
  77 
  78 /*******************************************************************************
  79  *
  80  * FUNCTION:    AcpiExSetupRegion
  81  *
  82  * PARAMETERS:  ObjDesc                 - Field to be read or written
  83  *              FieldDatumByteOffset    - Byte offset of this datum within the
  84  *                                        parent field
  85  *
  86  * RETURN:      Status
  87  *
  88  * DESCRIPTION: Common processing for AcpiExExtractFromField and
  89  *              AcpiExInsertIntoField.  Initialize the Region if necessary and
  90  *              validate the request.
  91  *
  92  ******************************************************************************/
  93 
  94 static ACPI_STATUS
  95 AcpiExSetupRegion (
  96     ACPI_OPERAND_OBJECT     *ObjDesc,
  97     UINT32                  FieldDatumByteOffset)
  98 {
  99     ACPI_STATUS             Status = AE_OK;
 100     ACPI_OPERAND_OBJECT     *RgnDesc;
 101 
 102 
 103     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
 104 
 105 
 106     RgnDesc = ObjDesc->CommonField.RegionObj;
 107 
 108     /* We must have a valid region */
 109 
 110     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
 111     {
 112         ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
 113             RgnDesc->Common.Type,
 114             AcpiUtGetObjectTypeName (RgnDesc)));
 115 
 116         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 117     }
 118 
 119     /*
 120      * If the Region Address and Length have not been previously evaluated,
 121      * evaluate them now and save the results.
 122      */
 123     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
 124     {
 125         Status = AcpiDsGetRegionArguments (RgnDesc);
 126         if (ACPI_FAILURE (Status))
 127         {
 128             return_ACPI_STATUS (Status);
 129         }
 130     }
 131 
 132     /*
 133      * Exit now for SMBus or IPMI address space, it has a non-linear
 134      * address space and the request cannot be directly validated
 135      */
 136     if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
 137         RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI)
 138     {
 139         /* SMBus or IPMI has a non-linear address space */
 140 
 141         return_ACPI_STATUS (AE_OK);
 142     }
 143 
 144 #ifdef ACPI_UNDER_DEVELOPMENT
 145     /*
 146      * If the Field access is AnyAcc, we can now compute the optimal
 147      * access (because we know know the length of the parent region)
 148      */
 149     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
 150     {
 151         if (ACPI_FAILURE (Status))
 152         {
 153             return_ACPI_STATUS (Status);
 154         }
 155     }
 156 #endif
 157 
 158     /*
 159      * Validate the request.  The entire request from the byte offset for a
 160      * length of one field datum (access width) must fit within the region.
 161      * (Region length is specified in bytes)
 162      */
 163     if (RgnDesc->Region.Length <
 164             (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
 165             ObjDesc->CommonField.AccessByteWidth))
 166     {
 167         if (AcpiGbl_EnableInterpreterSlack)
 168         {
 169             /*
 170              * Slack mode only:  We will go ahead and allow access to this
 171              * field if it is within the region length rounded up to the next
 172              * access width boundary. ACPI_SIZE cast for 64-bit compile.
 173              */
 174             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
 175                     ObjDesc->CommonField.AccessByteWidth) >=
 176                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
 177                     ObjDesc->CommonField.AccessByteWidth +
 178                     FieldDatumByteOffset))
 179             {
 180                 return_ACPI_STATUS (AE_OK);
 181             }
 182         }
 183 
 184         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
 185         {
 186             /*
 187              * This is the case where the AccessType (AccWord, etc.) is wider
 188              * than the region itself.  For example, a region of length one
 189              * byte, and a field with Dword access specified.
 190              */
 191             ACPI_ERROR ((AE_INFO,
 192                 "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
 193                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
 194                 ObjDesc->CommonField.AccessByteWidth,
 195                 AcpiUtGetNodeName (RgnDesc->Region.Node),
 196                 RgnDesc->Region.Length));
 197         }
 198 
 199         /*
 200          * Offset rounded up to next multiple of field width
 201          * exceeds region length, indicate an error
 202          */
 203         ACPI_ERROR ((AE_INFO,
 204             "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
 205             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
 206             ObjDesc->CommonField.BaseByteOffset,
 207             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
 208             AcpiUtGetNodeName (RgnDesc->Region.Node),
 209             RgnDesc->Region.Length));
 210 
 211         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
 212     }
 213 
 214     return_ACPI_STATUS (AE_OK);
 215 }
 216 
 217 
 218 /*******************************************************************************
 219  *
 220  * FUNCTION:    AcpiExAccessRegion
 221  *
 222  * PARAMETERS:  ObjDesc                 - Field to be read
 223  *              FieldDatumByteOffset    - Byte offset of this datum within the
 224  *                                        parent field
 225  *              Value                   - Where to store value (must at least
 226  *                                        64 bits)
 227  *              Function                - Read or Write flag plus other region-
 228  *                                        dependent flags
 229  *
 230  * RETURN:      Status
 231  *
 232  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
 233  *
 234  ******************************************************************************/
 235 
 236 ACPI_STATUS
 237 AcpiExAccessRegion (
 238     ACPI_OPERAND_OBJECT     *ObjDesc,
 239     UINT32                  FieldDatumByteOffset,
 240     UINT64                  *Value,
 241     UINT32                  Function)
 242 {
 243     ACPI_STATUS             Status;
 244     ACPI_OPERAND_OBJECT     *RgnDesc;
 245     UINT32                  RegionOffset;
 246 
 247 
 248     ACPI_FUNCTION_TRACE (ExAccessRegion);
 249 
 250 
 251     /*
 252      * Ensure that the region operands are fully evaluated and verify
 253      * the validity of the request
 254      */
 255     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
 256     if (ACPI_FAILURE (Status))
 257     {
 258         return_ACPI_STATUS (Status);
 259     }
 260 
 261     /*
 262      * The physical address of this field datum is:
 263      *
 264      * 1) The base of the region, plus
 265      * 2) The base offset of the field, plus
 266      * 3) The current offset into the field
 267      */
 268     RgnDesc = ObjDesc->CommonField.RegionObj;
 269     RegionOffset =
 270         ObjDesc->CommonField.BaseByteOffset +
 271         FieldDatumByteOffset;
 272 
 273     if ((Function & ACPI_IO_MASK) == ACPI_READ)
 274     {
 275         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
 276     }
 277     else
 278     {
 279         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
 280     }
 281 
 282     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
 283         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
 284         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
 285         RgnDesc->Region.SpaceId,
 286         ObjDesc->CommonField.AccessByteWidth,
 287         ObjDesc->CommonField.BaseByteOffset,
 288         FieldDatumByteOffset,
 289         ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
 290 
 291     /* Invoke the appropriate AddressSpace/OpRegion handler */
 292 
 293     Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset,
 294                 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
 295 
 296     if (ACPI_FAILURE (Status))
 297     {
 298         if (Status == AE_NOT_IMPLEMENTED)
 299         {
 300             ACPI_ERROR ((AE_INFO,
 301                 "Region %s (ID=%u) not implemented",
 302                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
 303                 RgnDesc->Region.SpaceId));
 304         }
 305         else if (Status == AE_NOT_EXIST)
 306         {
 307             ACPI_ERROR ((AE_INFO,
 308                 "Region %s (ID=%u) has no handler",
 309                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
 310                 RgnDesc->Region.SpaceId));
 311         }
 312     }
 313 
 314     return_ACPI_STATUS (Status);
 315 }
 316 
 317 
 318 /*******************************************************************************
 319  *
 320  * FUNCTION:    AcpiExRegisterOverflow
 321  *
 322  * PARAMETERS:  ObjDesc                 - Register(Field) to be written
 323  *              Value                   - Value to be stored
 324  *
 325  * RETURN:      TRUE if value overflows the field, FALSE otherwise
 326  *
 327  * DESCRIPTION: Check if a value is out of range of the field being written.
 328  *              Used to check if the values written to Index and Bank registers
 329  *              are out of range.  Normally, the value is simply truncated
 330  *              to fit the field, but this case is most likely a serious
 331  *              coding error in the ASL.
 332  *
 333  ******************************************************************************/
 334 
 335 static BOOLEAN
 336 AcpiExRegisterOverflow (
 337     ACPI_OPERAND_OBJECT     *ObjDesc,
 338     UINT64                  Value)
 339 {
 340 
 341     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
 342     {
 343         /*
 344          * The field is large enough to hold the maximum integer, so we can
 345          * never overflow it.
 346          */
 347         return (FALSE);
 348     }
 349 
 350     if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
 351     {
 352         /*
 353          * The Value is larger than the maximum value that can fit into
 354          * the register.
 355          */
 356         return (TRUE);
 357     }
 358 
 359     /* The Value will fit into the field with no truncation */
 360 
 361     return (FALSE);
 362 }
 363 
 364 
 365 /*******************************************************************************
 366  *
 367  * FUNCTION:    AcpiExFieldDatumIo
 368  *
 369  * PARAMETERS:  ObjDesc                 - Field to be read
 370  *              FieldDatumByteOffset    - Byte offset of this datum within the
 371  *                                        parent field
 372  *              Value                   - Where to store value (must be 64 bits)
 373  *              ReadWrite               - Read or Write flag
 374  *
 375  * RETURN:      Status
 376  *
 377  * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
 378  *              demultiplexed here to handle the different types of fields
 379  *              (BufferField, RegionField, IndexField, BankField)
 380  *
 381  ******************************************************************************/
 382 
 383 static ACPI_STATUS
 384 AcpiExFieldDatumIo (
 385     ACPI_OPERAND_OBJECT     *ObjDesc,
 386     UINT32                  FieldDatumByteOffset,
 387     UINT64                  *Value,
 388     UINT32                  ReadWrite)
 389 {
 390     ACPI_STATUS             Status;
 391     UINT64                  LocalValue;
 392 
 393 
 394     ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
 395 
 396 
 397     if (ReadWrite == ACPI_READ)
 398     {
 399         if (!Value)
 400         {
 401             LocalValue = 0;
 402 
 403             /* To support reads without saving return value */
 404             Value = &LocalValue;
 405         }
 406 
 407         /* Clear the entire return buffer first, [Very Important!] */
 408 
 409         *Value = 0;
 410     }
 411 
 412     /*
 413      * The four types of fields are:
 414      *
 415      * BufferField - Read/write from/to a Buffer
 416      * RegionField - Read/write from/to a Operation Region.
 417      * BankField   - Write to a Bank Register, then read/write from/to an
 418      *               OperationRegion
 419      * IndexField  - Write to an Index Register, then read/write from/to a
 420      *               Data Register
 421      */
 422     switch (ObjDesc->Common.Type)
 423     {
 424     case ACPI_TYPE_BUFFER_FIELD:
 425         /*
 426          * If the BufferField arguments have not been previously evaluated,
 427          * evaluate them now and save the results.
 428          */
 429         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
 430         {
 431             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
 432             if (ACPI_FAILURE (Status))
 433             {
 434                 return_ACPI_STATUS (Status);
 435             }
 436         }
 437 
 438         if (ReadWrite == ACPI_READ)
 439         {
 440             /*
 441              * Copy the data from the source buffer.
 442              * Length is the field width in bytes.
 443              */
 444             ACPI_MEMCPY (Value,
 445                 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
 446                     ObjDesc->BufferField.BaseByteOffset +
 447                     FieldDatumByteOffset,
 448                 ObjDesc->CommonField.AccessByteWidth);
 449         }
 450         else
 451         {
 452             /*
 453              * Copy the data to the target buffer.
 454              * Length is the field width in bytes.
 455              */
 456             ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
 457                 ObjDesc->BufferField.BaseByteOffset +
 458                 FieldDatumByteOffset,
 459                 Value, ObjDesc->CommonField.AccessByteWidth);
 460         }
 461 
 462         Status = AE_OK;
 463         break;
 464 
 465 
 466     case ACPI_TYPE_LOCAL_BANK_FIELD:
 467 
 468         /*
 469          * Ensure that the BankValue is not beyond the capacity of
 470          * the register
 471          */
 472         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
 473                 (UINT64) ObjDesc->BankField.Value))
 474         {
 475             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
 476         }
 477 
 478         /*
 479          * For BankFields, we must write the BankValue to the BankRegister
 480          * (itself a RegionField) before we can access the data.
 481          */
 482         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
 483                     &ObjDesc->BankField.Value,
 484                     sizeof (ObjDesc->BankField.Value));
 485         if (ACPI_FAILURE (Status))
 486         {
 487             return_ACPI_STATUS (Status);
 488         }
 489 
 490         /*
 491          * Now that the Bank has been selected, fall through to the
 492          * RegionField case and write the datum to the Operation Region
 493          */
 494 
 495         /*lint -fallthrough */
 496 
 497 
 498     case ACPI_TYPE_LOCAL_REGION_FIELD:
 499         /*
 500          * For simple RegionFields, we just directly access the owning
 501          * Operation Region.
 502          */
 503         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
 504                     ReadWrite);
 505         break;
 506 
 507 
 508     case ACPI_TYPE_LOCAL_INDEX_FIELD:
 509 
 510 
 511         /*
 512          * Ensure that the IndexValue is not beyond the capacity of
 513          * the register
 514          */
 515         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
 516                 (UINT64) ObjDesc->IndexField.Value))
 517         {
 518             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
 519         }
 520 
 521         /* Write the index value to the IndexRegister (itself a RegionField) */
 522 
 523         FieldDatumByteOffset += ObjDesc->IndexField.Value;
 524 
 525         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 526             "Write to Index Register: Value %8.8X\n",
 527             FieldDatumByteOffset));
 528 
 529         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
 530                     &FieldDatumByteOffset,
 531                     sizeof (FieldDatumByteOffset));
 532         if (ACPI_FAILURE (Status))
 533         {
 534             return_ACPI_STATUS (Status);
 535         }
 536 
 537         if (ReadWrite == ACPI_READ)
 538         {
 539             /* Read the datum from the DataRegister */
 540 
 541             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 542                 "Read from Data Register\n"));
 543 
 544             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
 545                         Value, sizeof (UINT64));
 546         }
 547         else
 548         {
 549             /* Write the datum to the DataRegister */
 550 
 551             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 552                 "Write to Data Register: Value %8.8X%8.8X\n",
 553                 ACPI_FORMAT_UINT64 (*Value)));
 554 
 555             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
 556                         Value, sizeof (UINT64));
 557         }
 558         break;
 559 
 560 
 561     default:
 562 
 563         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
 564             ObjDesc->Common.Type));
 565         Status = AE_AML_INTERNAL;
 566         break;
 567     }
 568 
 569     if (ACPI_SUCCESS (Status))
 570     {
 571         if (ReadWrite == ACPI_READ)
 572         {
 573             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 574                 "Value Read %8.8X%8.8X, Width %u\n",
 575                 ACPI_FORMAT_UINT64 (*Value),
 576                 ObjDesc->CommonField.AccessByteWidth));
 577         }
 578         else
 579         {
 580             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 581                 "Value Written %8.8X%8.8X, Width %u\n",
 582                 ACPI_FORMAT_UINT64 (*Value),
 583                 ObjDesc->CommonField.AccessByteWidth));
 584         }
 585     }
 586 
 587     return_ACPI_STATUS (Status);
 588 }
 589 
 590 
 591 /*******************************************************************************
 592  *
 593  * FUNCTION:    AcpiExWriteWithUpdateRule
 594  *
 595  * PARAMETERS:  ObjDesc                 - Field to be written
 596  *              Mask                    - bitmask within field datum
 597  *              FieldValue              - Value to write
 598  *              FieldDatumByteOffset    - Offset of datum within field
 599  *
 600  * RETURN:      Status
 601  *
 602  * DESCRIPTION: Apply the field update rule to a field write
 603  *
 604  ******************************************************************************/
 605 
 606 ACPI_STATUS
 607 AcpiExWriteWithUpdateRule (
 608     ACPI_OPERAND_OBJECT     *ObjDesc,
 609     UINT64                  Mask,
 610     UINT64                  FieldValue,
 611     UINT32                  FieldDatumByteOffset)
 612 {
 613     ACPI_STATUS             Status = AE_OK;
 614     UINT64                  MergedValue;
 615     UINT64                  CurrentValue;
 616 
 617 
 618     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
 619 
 620 
 621     /* Start with the new bits  */
 622 
 623     MergedValue = FieldValue;
 624 
 625     /* If the mask is all ones, we don't need to worry about the update rule */
 626 
 627     if (Mask != ACPI_UINT64_MAX)
 628     {
 629         /* Decode the update rule */
 630 
 631         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
 632         {
 633         case AML_FIELD_UPDATE_PRESERVE:
 634             /*
 635              * Check if update rule needs to be applied (not if mask is all
 636              * ones)  The left shift drops the bits we want to ignore.
 637              */
 638             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
 639                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
 640             {
 641                 /*
 642                  * Read the current contents of the byte/word/dword containing
 643                  * the field, and merge with the new field value.
 644                  */
 645                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
 646                             &CurrentValue, ACPI_READ);
 647                 if (ACPI_FAILURE (Status))
 648                 {
 649                     return_ACPI_STATUS (Status);
 650                 }
 651 
 652                 MergedValue |= (CurrentValue & ~Mask);
 653             }
 654             break;
 655 
 656         case AML_FIELD_UPDATE_WRITE_AS_ONES:
 657 
 658             /* Set positions outside the field to all ones */
 659 
 660             MergedValue |= ~Mask;
 661             break;
 662 
 663         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
 664 
 665             /* Set positions outside the field to all zeros */
 666 
 667             MergedValue &= Mask;
 668             break;
 669 
 670         default:
 671 
 672             ACPI_ERROR ((AE_INFO,
 673                 "Unknown UpdateRule value: 0x%X",
 674                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
 675             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
 676         }
 677     }
 678 
 679     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 680         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
 681         ACPI_FORMAT_UINT64 (Mask),
 682         FieldDatumByteOffset,
 683         ObjDesc->CommonField.AccessByteWidth,
 684         ACPI_FORMAT_UINT64 (FieldValue),
 685         ACPI_FORMAT_UINT64 (MergedValue)));
 686 
 687     /* Write the merged value */
 688 
 689     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
 690                 &MergedValue, ACPI_WRITE);
 691 
 692     return_ACPI_STATUS (Status);
 693 }
 694 
 695 
 696 /*******************************************************************************
 697  *
 698  * FUNCTION:    AcpiExExtractFromField
 699  *
 700  * PARAMETERS:  ObjDesc             - Field to be read
 701  *              Buffer              - Where to store the field data
 702  *              BufferLength        - Length of Buffer
 703  *
 704  * RETURN:      Status
 705  *
 706  * DESCRIPTION: Retrieve the current value of the given field
 707  *
 708  ******************************************************************************/
 709 
 710 ACPI_STATUS
 711 AcpiExExtractFromField (
 712     ACPI_OPERAND_OBJECT     *ObjDesc,
 713     void                    *Buffer,
 714     UINT32                  BufferLength)
 715 {
 716     ACPI_STATUS             Status;
 717     UINT64                  RawDatum;
 718     UINT64                  MergedDatum;
 719     UINT32                  FieldOffset = 0;
 720     UINT32                  BufferOffset = 0;
 721     UINT32                  BufferTailBits;
 722     UINT32                  DatumCount;
 723     UINT32                  FieldDatumCount;
 724     UINT32                  AccessBitWidth;
 725     UINT32                  i;
 726 
 727 
 728     ACPI_FUNCTION_TRACE (ExExtractFromField);
 729 
 730 
 731     /* Validate target buffer and clear it */
 732 
 733     if (BufferLength <
 734         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
 735     {
 736         ACPI_ERROR ((AE_INFO,
 737             "Field size %u (bits) is too large for buffer (%u)",
 738             ObjDesc->CommonField.BitLength, BufferLength));
 739 
 740         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
 741     }
 742 
 743     ACPI_MEMSET (Buffer, 0, BufferLength);
 744     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
 745 
 746     /* Handle the simple case here */
 747 
 748     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
 749         (ObjDesc->CommonField.BitLength == AccessBitWidth))
 750     {
 751         Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
 752         return_ACPI_STATUS (Status);
 753     }
 754 
 755 /* TBD: Move to common setup code */
 756 
 757     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
 758 
 759     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
 760     {
 761         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
 762         AccessBitWidth = sizeof (UINT64) * 8;
 763     }
 764 
 765     /* Compute the number of datums (access width data items) */
 766 
 767     DatumCount = ACPI_ROUND_UP_TO (
 768         ObjDesc->CommonField.BitLength, AccessBitWidth);
 769 
 770     FieldDatumCount = ACPI_ROUND_UP_TO (
 771         ObjDesc->CommonField.BitLength +
 772         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
 773 
 774     /* Priming read from the field */
 775 
 776     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
 777     if (ACPI_FAILURE (Status))
 778     {
 779         return_ACPI_STATUS (Status);
 780     }
 781     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
 782 
 783     /* Read the rest of the field */
 784 
 785     for (i = 1; i < FieldDatumCount; i++)
 786     {
 787         /* Get next input datum from the field */
 788 
 789         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
 790         Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
 791                     &RawDatum, ACPI_READ);
 792         if (ACPI_FAILURE (Status))
 793         {
 794             return_ACPI_STATUS (Status);
 795         }
 796 
 797         /*
 798          * Merge with previous datum if necessary.
 799          *
 800          * Note: Before the shift, check if the shift value will be larger than
 801          * the integer size. If so, there is no need to perform the operation.
 802          * This avoids the differences in behavior between different compilers
 803          * concerning shift values larger than the target data width.
 804          */
 805         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
 806             ACPI_INTEGER_BIT_SIZE)
 807         {
 808             MergedDatum |= RawDatum <<
 809                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
 810         }
 811 
 812         if (i == DatumCount)
 813         {
 814             break;
 815         }
 816 
 817         /* Write merged datum to target buffer */
 818 
 819         ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
 820             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
 821                 BufferLength - BufferOffset));
 822 
 823         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
 824         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
 825     }
 826 
 827     /* Mask off any extra bits in the last datum */
 828 
 829     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
 830     if (BufferTailBits)
 831     {
 832         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
 833     }
 834 
 835     /* Write the last datum to the buffer */
 836 
 837     ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
 838         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
 839             BufferLength - BufferOffset));
 840 
 841     return_ACPI_STATUS (AE_OK);
 842 }
 843 
 844 
 845 /*******************************************************************************
 846  *
 847  * FUNCTION:    AcpiExInsertIntoField
 848  *
 849  * PARAMETERS:  ObjDesc             - Field to be written
 850  *              Buffer              - Data to be written
 851  *              BufferLength        - Length of Buffer
 852  *
 853  * RETURN:      Status
 854  *
 855  * DESCRIPTION: Store the Buffer contents into the given field
 856  *
 857  ******************************************************************************/
 858 
 859 ACPI_STATUS
 860 AcpiExInsertIntoField (
 861     ACPI_OPERAND_OBJECT     *ObjDesc,
 862     void                    *Buffer,
 863     UINT32                  BufferLength)
 864 {
 865     void                    *NewBuffer;
 866     ACPI_STATUS             Status;
 867     UINT64                  Mask;
 868     UINT64                  WidthMask;
 869     UINT64                  MergedDatum;
 870     UINT64                  RawDatum = 0;
 871     UINT32                  FieldOffset = 0;
 872     UINT32                  BufferOffset = 0;
 873     UINT32                  BufferTailBits;
 874     UINT32                  DatumCount;
 875     UINT32                  FieldDatumCount;
 876     UINT32                  AccessBitWidth;
 877     UINT32                  RequiredLength;
 878     UINT32                  i;
 879 
 880 
 881     ACPI_FUNCTION_TRACE (ExInsertIntoField);
 882 
 883 
 884     /* Validate input buffer */
 885 
 886     NewBuffer = NULL;
 887     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
 888                         ObjDesc->CommonField.BitLength);
 889     /*
 890      * We must have a buffer that is at least as long as the field
 891      * we are writing to.  This is because individual fields are
 892      * indivisible and partial writes are not supported -- as per
 893      * the ACPI specification.
 894      */
 895     if (BufferLength < RequiredLength)
 896     {
 897         /* We need to create a new buffer */
 898 
 899         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
 900         if (!NewBuffer)
 901         {
 902             return_ACPI_STATUS (AE_NO_MEMORY);
 903         }
 904 
 905         /*
 906          * Copy the original data to the new buffer, starting
 907          * at Byte zero.  All unused (upper) bytes of the
 908          * buffer will be 0.
 909          */
 910         ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
 911         Buffer = NewBuffer;
 912         BufferLength = RequiredLength;
 913     }
 914 
 915 /* TBD: Move to common setup code */
 916 
 917     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
 918     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
 919     {
 920         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
 921     }
 922 
 923     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
 924 
 925     /*
 926      * Create the bitmasks used for bit insertion.
 927      * Note: This if/else is used to bypass compiler differences with the
 928      * shift operator
 929      */
 930     if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
 931     {
 932         WidthMask = ACPI_UINT64_MAX;
 933     }
 934     else
 935     {
 936         WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
 937     }
 938 
 939     Mask = WidthMask &
 940         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
 941 
 942     /* Compute the number of datums (access width data items) */
 943 
 944     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
 945         AccessBitWidth);
 946 
 947     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
 948         ObjDesc->CommonField.StartFieldBitOffset,
 949         AccessBitWidth);
 950 
 951     /* Get initial Datum from the input buffer */
 952 
 953     ACPI_MEMCPY (&RawDatum, Buffer,
 954         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
 955             BufferLength - BufferOffset));
 956 
 957     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
 958 
 959     /* Write the entire field */
 960 
 961     for (i = 1; i < FieldDatumCount; i++)
 962     {
 963         /* Write merged datum to the target field */
 964 
 965         MergedDatum &= Mask;
 966         Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
 967                     MergedDatum, FieldOffset);
 968         if (ACPI_FAILURE (Status))
 969         {
 970             goto Exit;
 971         }
 972 
 973         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
 974 
 975         /*
 976          * Start new output datum by merging with previous input datum
 977          * if necessary.
 978          *
 979          * Note: Before the shift, check if the shift value will be larger than
 980          * the integer size. If so, there is no need to perform the operation.
 981          * This avoids the differences in behavior between different compilers
 982          * concerning shift values larger than the target data width.
 983          */
 984         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
 985             ACPI_INTEGER_BIT_SIZE)
 986         {
 987             MergedDatum = RawDatum >>
 988                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
 989         }
 990         else
 991         {
 992             MergedDatum = 0;
 993         }
 994 
 995         Mask = WidthMask;
 996 
 997         if (i == DatumCount)
 998         {
 999             break;
1000         }
1001 
1002         /* Get the next input datum from the buffer */
1003 
1004         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
1005         ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
1006             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
1007                  BufferLength - BufferOffset));
1008 
1009         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
1010     }
1011 
1012     /* Mask off any extra bits in the last datum */
1013 
1014     BufferTailBits = (ObjDesc->CommonField.BitLength +
1015         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
1016     if (BufferTailBits)
1017     {
1018         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
1019     }
1020 
1021     /* Write the last datum to the field */
1022 
1023     MergedDatum &= Mask;
1024     Status = AcpiExWriteWithUpdateRule (ObjDesc,
1025                 Mask, MergedDatum, FieldOffset);
1026 
1027 Exit:
1028     /* Free temporary buffer if we used one */
1029 
1030     if (NewBuffer)
1031     {
1032         ACPI_FREE (NewBuffer);
1033     }
1034     return_ACPI_STATUS (Status);
1035 }
1036 
1037