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