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