Home | History | Annotate | Line # | Download | only in executer
exfldio.c revision 1.1.1.10
      1 /******************************************************************************
      2  *
      3  * Module Name: exfldio - Aml Field I/O
      4  *
      5  *****************************************************************************/
      6 
      7 /*
      8  * Copyright (C) 2000 - 2017, 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 #include "acpi.h"
     45 #include "accommon.h"
     46 #include "acinterp.h"
     47 #include "amlcode.h"
     48 #include "acevents.h"
     49 #include "acdispat.h"
     50 
     51 
     52 #define _COMPONENT          ACPI_EXECUTER
     53         ACPI_MODULE_NAME    ("exfldio")
     54 
     55 /* Local prototypes */
     56 
     57 static ACPI_STATUS
     58 AcpiExFieldDatumIo (
     59     ACPI_OPERAND_OBJECT     *ObjDesc,
     60     UINT32                  FieldDatumByteOffset,
     61     UINT64                  *Value,
     62     UINT32                  ReadWrite);
     63 
     64 static BOOLEAN
     65 AcpiExRegisterOverflow (
     66     ACPI_OPERAND_OBJECT     *ObjDesc,
     67     UINT64                  Value);
     68 
     69 static ACPI_STATUS
     70 AcpiExSetupRegion (
     71     ACPI_OPERAND_OBJECT     *ObjDesc,
     72     UINT32                  FieldDatumByteOffset);
     73 
     74 
     75 /*******************************************************************************
     76  *
     77  * FUNCTION:    AcpiExSetupRegion
     78  *
     79  * PARAMETERS:  ObjDesc                 - Field to be read or written
     80  *              FieldDatumByteOffset    - Byte offset of this datum within the
     81  *                                        parent field
     82  *
     83  * RETURN:      Status
     84  *
     85  * DESCRIPTION: Common processing for AcpiExExtractFromField and
     86  *              AcpiExInsertIntoField. Initialize the Region if necessary and
     87  *              validate the request.
     88  *
     89  ******************************************************************************/
     90 
     91 static ACPI_STATUS
     92 AcpiExSetupRegion (
     93     ACPI_OPERAND_OBJECT     *ObjDesc,
     94     UINT32                  FieldDatumByteOffset)
     95 {
     96     ACPI_STATUS             Status = AE_OK;
     97     ACPI_OPERAND_OBJECT     *RgnDesc;
     98     UINT8                   SpaceId;
     99 
    100 
    101     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
    102 
    103 
    104     RgnDesc = ObjDesc->CommonField.RegionObj;
    105 
    106     /* We must have a valid region */
    107 
    108     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
    109     {
    110         ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
    111             RgnDesc->Common.Type,
    112             AcpiUtGetObjectTypeName (RgnDesc)));
    113 
    114         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    115     }
    116 
    117     SpaceId = RgnDesc->Region.SpaceId;
    118 
    119     /* Validate the Space ID */
    120 
    121     if (!AcpiIsValidSpaceId (SpaceId))
    122     {
    123         ACPI_ERROR ((AE_INFO,
    124             "Invalid/unknown Address Space ID: 0x%2.2X", SpaceId));
    125         return_ACPI_STATUS (AE_AML_INVALID_SPACE_ID);
    126     }
    127 
    128     /*
    129      * If the Region Address and Length have not been previously evaluated,
    130      * evaluate them now and save the results.
    131      */
    132     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
    133     {
    134         Status = AcpiDsGetRegionArguments (RgnDesc);
    135         if (ACPI_FAILURE (Status))
    136         {
    137             return_ACPI_STATUS (Status);
    138         }
    139     }
    140 
    141     /*
    142      * Exit now for SMBus, GSBus or IPMI address space, it has a non-linear
    143      * address space and the request cannot be directly validated
    144      */
    145     if (SpaceId == ACPI_ADR_SPACE_SMBUS ||
    146         SpaceId == ACPI_ADR_SPACE_GSBUS ||
    147         SpaceId == ACPI_ADR_SPACE_IPMI)
    148     {
    149         /* SMBus or IPMI has a non-linear address space */
    150 
    151         return_ACPI_STATUS (AE_OK);
    152     }
    153 
    154 #ifdef ACPI_UNDER_DEVELOPMENT
    155     /*
    156      * If the Field access is AnyAcc, we can now compute the optimal
    157      * access (because we know know the length of the parent region)
    158      */
    159     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
    160     {
    161         if (ACPI_FAILURE (Status))
    162         {
    163             return_ACPI_STATUS (Status);
    164         }
    165     }
    166 #endif
    167 
    168     /*
    169      * Validate the request. The entire request from the byte offset for a
    170      * length of one field datum (access width) must fit within the region.
    171      * (Region length is specified in bytes)
    172      */
    173     if (RgnDesc->Region.Length <
    174         (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
    175         ObjDesc->CommonField.AccessByteWidth))
    176     {
    177         if (AcpiGbl_EnableInterpreterSlack)
    178         {
    179             /*
    180              * Slack mode only:  We will go ahead and allow access to this
    181              * field if it is within the region length rounded up to the next
    182              * access width boundary. ACPI_SIZE cast for 64-bit compile.
    183              */
    184             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
    185                     ObjDesc->CommonField.AccessByteWidth) >=
    186                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
    187                     ObjDesc->CommonField.AccessByteWidth +
    188                     FieldDatumByteOffset))
    189             {
    190                 return_ACPI_STATUS (AE_OK);
    191             }
    192         }
    193 
    194         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
    195         {
    196             /*
    197              * This is the case where the AccessType (AccWord, etc.) is wider
    198              * than the region itself. For example, a region of length one
    199              * byte, and a field with Dword access specified.
    200              */
    201             ACPI_ERROR ((AE_INFO,
    202                 "Field [%4.4s] access width (%u bytes) "
    203                 "too large for region [%4.4s] (length %u)",
    204                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
    205                 ObjDesc->CommonField.AccessByteWidth,
    206                 AcpiUtGetNodeName (RgnDesc->Region.Node),
    207                 RgnDesc->Region.Length));
    208         }
    209 
    210         /*
    211          * Offset rounded up to next multiple of field width
    212          * exceeds region length, indicate an error
    213          */
    214         ACPI_ERROR ((AE_INFO,
    215             "Field [%4.4s] Base+Offset+Width %u+%u+%u "
    216             "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 %8.8X%8.8X\n",
    296         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    297         RgnDesc->Region.SpaceId,
    298         ObjDesc->CommonField.AccessByteWidth,
    299         ObjDesc->CommonField.BaseByteOffset,
    300         FieldDatumByteOffset,
    301         ACPI_FORMAT_UINT64 (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             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             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 (
    519             ObjDesc, FieldDatumByteOffset, Value, 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, sizeof (FieldDatumByteOffset));
    543         if (ACPI_FAILURE (Status))
    544         {
    545             return_ACPI_STATUS (Status);
    546         }
    547 
    548         if (ReadWrite == ACPI_READ)
    549         {
    550             /* Read the datum from the DataRegister */
    551 
    552             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    553                 "Read from Data Register\n"));
    554 
    555             Status = AcpiExExtractFromField (
    556                 ObjDesc->IndexField.DataObj, Value, sizeof (UINT64));
    557         }
    558         else
    559         {
    560             /* Write the datum to the DataRegister */
    561 
    562             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    563                 "Write to Data Register: Value %8.8X%8.8X\n",
    564                 ACPI_FORMAT_UINT64 (*Value)));
    565 
    566             Status = AcpiExInsertIntoField (
    567                 ObjDesc->IndexField.DataObj, Value, sizeof (UINT64));
    568         }
    569         break;
    570 
    571     default:
    572 
    573         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
    574             ObjDesc->Common.Type));
    575         Status = AE_AML_INTERNAL;
    576         break;
    577     }
    578 
    579     if (ACPI_SUCCESS (Status))
    580     {
    581         if (ReadWrite == ACPI_READ)
    582         {
    583             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    584                 "Value Read %8.8X%8.8X, Width %u\n",
    585                 ACPI_FORMAT_UINT64 (*Value),
    586                 ObjDesc->CommonField.AccessByteWidth));
    587         }
    588         else
    589         {
    590             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    591                 "Value Written %8.8X%8.8X, Width %u\n",
    592                 ACPI_FORMAT_UINT64 (*Value),
    593                 ObjDesc->CommonField.AccessByteWidth));
    594         }
    595     }
    596 
    597     return_ACPI_STATUS (Status);
    598 }
    599 
    600 
    601 /*******************************************************************************
    602  *
    603  * FUNCTION:    AcpiExWriteWithUpdateRule
    604  *
    605  * PARAMETERS:  ObjDesc                 - Field to be written
    606  *              Mask                    - bitmask within field datum
    607  *              FieldValue              - Value to write
    608  *              FieldDatumByteOffset    - Offset of datum within field
    609  *
    610  * RETURN:      Status
    611  *
    612  * DESCRIPTION: Apply the field update rule to a field write
    613  *
    614  ******************************************************************************/
    615 
    616 ACPI_STATUS
    617 AcpiExWriteWithUpdateRule (
    618     ACPI_OPERAND_OBJECT     *ObjDesc,
    619     UINT64                  Mask,
    620     UINT64                  FieldValue,
    621     UINT32                  FieldDatumByteOffset)
    622 {
    623     ACPI_STATUS             Status = AE_OK;
    624     UINT64                  MergedValue;
    625     UINT64                  CurrentValue;
    626 
    627 
    628     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
    629 
    630 
    631     /* Start with the new bits  */
    632 
    633     MergedValue = FieldValue;
    634 
    635     /* If the mask is all ones, we don't need to worry about the update rule */
    636 
    637     if (Mask != ACPI_UINT64_MAX)
    638     {
    639         /* Decode the update rule */
    640 
    641         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
    642         {
    643         case AML_FIELD_UPDATE_PRESERVE:
    644             /*
    645              * Check if update rule needs to be applied (not if mask is all
    646              * ones)  The left shift drops the bits we want to ignore.
    647              */
    648             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
    649                    ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
    650             {
    651                 /*
    652                  * Read the current contents of the byte/word/dword containing
    653                  * the field, and merge with the new field value.
    654                  */
    655                 Status = AcpiExFieldDatumIo (
    656                     ObjDesc, FieldDatumByteOffset, &CurrentValue, ACPI_READ);
    657                 if (ACPI_FAILURE (Status))
    658                 {
    659                     return_ACPI_STATUS (Status);
    660                 }
    661 
    662                 MergedValue |= (CurrentValue & ~Mask);
    663             }
    664             break;
    665 
    666         case AML_FIELD_UPDATE_WRITE_AS_ONES:
    667 
    668             /* Set positions outside the field to all ones */
    669 
    670             MergedValue |= ~Mask;
    671             break;
    672 
    673         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
    674 
    675             /* Set positions outside the field to all zeros */
    676 
    677             MergedValue &= Mask;
    678             break;
    679 
    680         default:
    681 
    682             ACPI_ERROR ((AE_INFO,
    683                 "Unknown UpdateRule value: 0x%X",
    684                 (ObjDesc->CommonField.FieldFlags &
    685                     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, "
    692         "Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
    693         ACPI_FORMAT_UINT64 (Mask),
    694         FieldDatumByteOffset,
    695         ObjDesc->CommonField.AccessByteWidth,
    696         ACPI_FORMAT_UINT64 (FieldValue),
    697         ACPI_FORMAT_UINT64 (MergedValue)));
    698 
    699     /* Write the merged value */
    700 
    701     Status = AcpiExFieldDatumIo (
    702         ObjDesc, FieldDatumByteOffset, &MergedValue, ACPI_WRITE);
    703 
    704     return_ACPI_STATUS (Status);
    705 }
    706 
    707 
    708 /*******************************************************************************
    709  *
    710  * FUNCTION:    AcpiExExtractFromField
    711  *
    712  * PARAMETERS:  ObjDesc             - Field to be read
    713  *              Buffer              - Where to store the field data
    714  *              BufferLength        - Length of Buffer
    715  *
    716  * RETURN:      Status
    717  *
    718  * DESCRIPTION: Retrieve the current value of the given field
    719  *
    720  ******************************************************************************/
    721 
    722 ACPI_STATUS
    723 AcpiExExtractFromField (
    724     ACPI_OPERAND_OBJECT     *ObjDesc,
    725     void                    *Buffer,
    726     UINT32                  BufferLength)
    727 {
    728     ACPI_STATUS             Status;
    729     UINT64                  RawDatum;
    730     UINT64                  MergedDatum;
    731     UINT32                  FieldOffset = 0;
    732     UINT32                  BufferOffset = 0;
    733     UINT32                  BufferTailBits;
    734     UINT32                  DatumCount;
    735     UINT32                  FieldDatumCount;
    736     UINT32                  AccessBitWidth;
    737     UINT32                  i;
    738 
    739 
    740     ACPI_FUNCTION_TRACE (ExExtractFromField);
    741 
    742 
    743     /* Validate target buffer and clear it */
    744 
    745     if (BufferLength <
    746         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
    747     {
    748         ACPI_ERROR ((AE_INFO,
    749             "Field size %u (bits) is too large for buffer (%u)",
    750             ObjDesc->CommonField.BitLength, BufferLength));
    751 
    752         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
    753     }
    754 
    755     memset (Buffer, 0, BufferLength);
    756     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
    757 
    758     /* Handle the simple case here */
    759 
    760     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
    761         (ObjDesc->CommonField.BitLength == AccessBitWidth))
    762     {
    763         if (BufferLength >= sizeof (UINT64))
    764         {
    765             Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
    766         }
    767         else
    768         {
    769             /* Use RawDatum (UINT64) to handle buffers < 64 bits */
    770 
    771             Status = AcpiExFieldDatumIo (ObjDesc, 0, &RawDatum, ACPI_READ);
    772             memcpy (Buffer, &RawDatum, BufferLength);
    773         }
    774 
    775         return_ACPI_STATUS (Status);
    776     }
    777 
    778 /* TBD: Move to common setup code */
    779 
    780     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
    781 
    782     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    783     {
    784         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    785         AccessBitWidth = sizeof (UINT64) * 8;
    786     }
    787 
    788     /* Compute the number of datums (access width data items) */
    789 
    790     DatumCount = ACPI_ROUND_UP_TO (
    791         ObjDesc->CommonField.BitLength, AccessBitWidth);
    792 
    793     FieldDatumCount = ACPI_ROUND_UP_TO (
    794         ObjDesc->CommonField.BitLength +
    795         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
    796 
    797     /* Priming read from the field */
    798 
    799     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
    800     if (ACPI_FAILURE (Status))
    801     {
    802         return_ACPI_STATUS (Status);
    803     }
    804     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    805 
    806     /* Read the rest of the field */
    807 
    808     for (i = 1; i < FieldDatumCount; i++)
    809     {
    810         /* Get next input datum from the field */
    811 
    812         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
    813         Status = AcpiExFieldDatumIo (
    814             ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
    815         if (ACPI_FAILURE (Status))
    816         {
    817             return_ACPI_STATUS (Status);
    818         }
    819 
    820         /*
    821          * Merge with previous datum if necessary.
    822          *
    823          * Note: Before the shift, check if the shift value will be larger than
    824          * the integer size. If so, there is no need to perform the operation.
    825          * This avoids the differences in behavior between different compilers
    826          * concerning shift values larger than the target data width.
    827          */
    828         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
    829             ACPI_INTEGER_BIT_SIZE)
    830         {
    831             MergedDatum |= RawDatum <<
    832                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
    833         }
    834 
    835         if (i == DatumCount)
    836         {
    837             break;
    838         }
    839 
    840         /* Write merged datum to target buffer */
    841 
    842         memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
    843             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    844                 BufferLength - BufferOffset));
    845 
    846         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
    847         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    848     }
    849 
    850     /* Mask off any extra bits in the last datum */
    851 
    852     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
    853     if (BufferTailBits)
    854     {
    855         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
    856     }
    857 
    858     /* Write the last datum to the buffer */
    859 
    860     memcpy (((char *) Buffer) + BufferOffset, &MergedDatum,
    861         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    862             BufferLength - BufferOffset));
    863 
    864     return_ACPI_STATUS (AE_OK);
    865 }
    866 
    867 
    868 /*******************************************************************************
    869  *
    870  * FUNCTION:    AcpiExInsertIntoField
    871  *
    872  * PARAMETERS:  ObjDesc             - Field to be written
    873  *              Buffer              - Data to be written
    874  *              BufferLength        - Length of Buffer
    875  *
    876  * RETURN:      Status
    877  *
    878  * DESCRIPTION: Store the Buffer contents into the given field
    879  *
    880  ******************************************************************************/
    881 
    882 ACPI_STATUS
    883 AcpiExInsertIntoField (
    884     ACPI_OPERAND_OBJECT     *ObjDesc,
    885     void                    *Buffer,
    886     UINT32                  BufferLength)
    887 {
    888     void                    *NewBuffer;
    889     ACPI_STATUS             Status;
    890     UINT64                  Mask;
    891     UINT64                  WidthMask;
    892     UINT64                  MergedDatum;
    893     UINT64                  RawDatum = 0;
    894     UINT32                  FieldOffset = 0;
    895     UINT32                  BufferOffset = 0;
    896     UINT32                  BufferTailBits;
    897     UINT32                  DatumCount;
    898     UINT32                  FieldDatumCount;
    899     UINT32                  AccessBitWidth;
    900     UINT32                  RequiredLength;
    901     UINT32                  i;
    902 
    903 
    904     ACPI_FUNCTION_TRACE (ExInsertIntoField);
    905 
    906 
    907     /* Validate input buffer */
    908 
    909     NewBuffer = NULL;
    910     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
    911         ObjDesc->CommonField.BitLength);
    912 
    913     /*
    914      * We must have a buffer that is at least as long as the field
    915      * we are writing to. This is because individual fields are
    916      * indivisible and partial writes are not supported -- as per
    917      * the ACPI specification.
    918      */
    919     if (BufferLength < RequiredLength)
    920     {
    921         /* We need to create a new buffer */
    922 
    923         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
    924         if (!NewBuffer)
    925         {
    926             return_ACPI_STATUS (AE_NO_MEMORY);
    927         }
    928 
    929         /*
    930          * Copy the original data to the new buffer, starting
    931          * at Byte zero. All unused (upper) bytes of the
    932          * buffer will be 0.
    933          */
    934         memcpy ((char *) NewBuffer, (char *) Buffer, BufferLength);
    935         Buffer = NewBuffer;
    936         BufferLength = RequiredLength;
    937     }
    938 
    939 /* TBD: Move to common setup code */
    940 
    941     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
    942     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    943     {
    944         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    945     }
    946 
    947     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
    948 
    949     /* Create the bitmasks used for bit insertion */
    950 
    951     WidthMask = ACPI_MASK_BITS_ABOVE_64 (AccessBitWidth);
    952     Mask = WidthMask &
    953         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
    954 
    955     /* Compute the number of datums (access width data items) */
    956 
    957     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
    958         AccessBitWidth);
    959 
    960     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
    961         ObjDesc->CommonField.StartFieldBitOffset,
    962         AccessBitWidth);
    963 
    964     /* Get initial Datum from the input buffer */
    965 
    966     memcpy (&RawDatum, Buffer,
    967         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    968             BufferLength - BufferOffset));
    969 
    970     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
    971 
    972     /* Write the entire field */
    973 
    974     for (i = 1; i < FieldDatumCount; i++)
    975     {
    976         /* Write merged datum to the target field */
    977 
    978         MergedDatum &= Mask;
    979         Status = AcpiExWriteWithUpdateRule (
    980             ObjDesc, Mask, MergedDatum, FieldOffset);
    981         if (ACPI_FAILURE (Status))
    982         {
    983             goto Exit;
    984         }
    985 
    986         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
    987 
    988         /*
    989          * Start new output datum by merging with previous input datum
    990          * if necessary.
    991          *
    992          * Note: Before the shift, check if the shift value will be larger than
    993          * the integer size. If so, there is no need to perform the operation.
    994          * This avoids the differences in behavior between different compilers
    995          * concerning shift values larger than the target data width.
    996          */
    997         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
    998             ACPI_INTEGER_BIT_SIZE)
    999         {
   1000             MergedDatum = RawDatum >>
   1001                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
   1002         }
   1003         else
   1004         {
   1005             MergedDatum = 0;
   1006         }
   1007 
   1008         Mask = WidthMask;
   1009 
   1010         if (i == DatumCount)
   1011         {
   1012             break;
   1013         }
   1014 
   1015         /* Get the next input datum from the buffer */
   1016 
   1017         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
   1018         memcpy (&RawDatum, ((char *) Buffer) + BufferOffset,
   1019             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
   1020                  BufferLength - BufferOffset));
   1021 
   1022         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
   1023     }
   1024 
   1025     /* Mask off any extra bits in the last datum */
   1026 
   1027     BufferTailBits = (ObjDesc->CommonField.BitLength +
   1028         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
   1029     if (BufferTailBits)
   1030     {
   1031         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
   1032     }
   1033 
   1034     /* Write the last datum to the field */
   1035 
   1036     MergedDatum &= Mask;
   1037     Status = AcpiExWriteWithUpdateRule (
   1038         ObjDesc, Mask, MergedDatum, FieldOffset);
   1039 
   1040 Exit:
   1041     /* Free temporary buffer if we used one */
   1042 
   1043     if (NewBuffer)
   1044     {
   1045         ACPI_FREE (NewBuffer);
   1046     }
   1047     return_ACPI_STATUS (Status);
   1048 }
   1049