Home | History | Annotate | Line # | Download | only in executer
exfldio.c revision 1.1
      1 /******************************************************************************
      2  *
      3  * Module Name: exfldio - Aml Field I/O
      4  *
      5  *****************************************************************************/
      6 
      7 /******************************************************************************
      8  *
      9  * 1. Copyright Notice
     10  *
     11  * Some or all of this work - Copyright (c) 1999 - 2010, Intel Corp.
     12  * All rights reserved.
     13  *
     14  * 2. License
     15  *
     16  * 2.1. This is your license from Intel Corp. under its intellectual property
     17  * rights.  You may have additional license terms from the party that provided
     18  * you this software, covering your right to use that party's intellectual
     19  * property rights.
     20  *
     21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
     22  * copy of the source code appearing in this file ("Covered Code") an
     23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
     24  * base code distributed originally by Intel ("Original Intel Code") to copy,
     25  * make derivatives, distribute, use and display any portion of the Covered
     26  * Code in any form, with the right to sublicense such rights; and
     27  *
     28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
     29  * license (with the right to sublicense), under only those claims of Intel
     30  * patents that are infringed by the Original Intel Code, to make, use, sell,
     31  * offer to sell, and import the Covered Code and derivative works thereof
     32  * solely to the minimum extent necessary to exercise the above copyright
     33  * license, and in no event shall the patent license extend to any additions
     34  * to or modifications of the Original Intel Code.  No other license or right
     35  * is granted directly or by implication, estoppel or otherwise;
     36  *
     37  * The above copyright and patent license is granted only if the following
     38  * conditions are met:
     39  *
     40  * 3. Conditions
     41  *
     42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
     43  * Redistribution of source code of any substantial portion of the Covered
     44  * Code or modification with rights to further distribute source must include
     45  * the above Copyright Notice, the above License, this list of Conditions,
     46  * and the following Disclaimer and Export Compliance provision.  In addition,
     47  * Licensee must cause all Covered Code to which Licensee contributes to
     48  * contain a file documenting the changes Licensee made to create that Covered
     49  * Code and the date of any change.  Licensee must include in that file the
     50  * documentation of any changes made by any predecessor Licensee.  Licensee
     51  * must include a prominent statement that the modification is derived,
     52  * directly or indirectly, from Original Intel Code.
     53  *
     54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
     55  * Redistribution of source code of any substantial portion of the Covered
     56  * Code or modification without rights to further distribute source must
     57  * include the following Disclaimer and Export Compliance provision in the
     58  * documentation and/or other materials provided with distribution.  In
     59  * addition, Licensee may not authorize further sublicense of source of any
     60  * portion of the Covered Code, and must include terms to the effect that the
     61  * license from Licensee to its licensee is limited to the intellectual
     62  * property embodied in the software Licensee provides to its licensee, and
     63  * not to intellectual property embodied in modifications its licensee may
     64  * make.
     65  *
     66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
     67  * substantial portion of the Covered Code or modification must reproduce the
     68  * above Copyright Notice, and the following Disclaimer and Export Compliance
     69  * provision in the documentation and/or other materials provided with the
     70  * distribution.
     71  *
     72  * 3.4. Intel retains all right, title, and interest in and to the Original
     73  * Intel Code.
     74  *
     75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
     76  * Intel shall be used in advertising or otherwise to promote the sale, use or
     77  * other dealings in products derived from or relating to the Covered Code
     78  * without prior written authorization from Intel.
     79  *
     80  * 4. Disclaimer and Export Compliance
     81  *
     82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
     83  * HERE.  ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
     84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT,  ASSISTANCE,
     85  * INSTALLATION, TRAINING OR OTHER SERVICES.  INTEL WILL NOT PROVIDE ANY
     86  * UPDATES, ENHANCEMENTS OR EXTENSIONS.  INTEL SPECIFICALLY DISCLAIMS ANY
     87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
     88  * PARTICULAR PURPOSE.
     89  *
     90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
     91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
     92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
     93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
     94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
     95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES.  THESE LIMITATIONS
     96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
     97  * LIMITED REMEDY.
     98  *
     99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
    100  * software or system incorporating such software without first obtaining any
    101  * required license or other approval from the U. S. Department of Commerce or
    102  * any other agency or department of the United States Government.  In the
    103  * event Licensee exports any such software from the United States or
    104  * re-exports any such software from a foreign destination, Licensee shall
    105  * ensure that the distribution and export/re-export of the software is in
    106  * compliance with all laws, regulations, orders, or other restrictions of the
    107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
    108  * any of its subsidiaries will export/re-export any technical data, process,
    109  * software, or service, directly or indirectly, to any country for which the
    110  * United States government or any agency thereof requires an export license,
    111  * other governmental approval, or letter of assurance, without first obtaining
    112  * such license, approval or letter.
    113  *
    114  *****************************************************************************/
    115 
    116 
    117 #define __EXFLDIO_C__
    118 
    119 #include "acpi.h"
    120 #include "accommon.h"
    121 #include "acinterp.h"
    122 #include "amlcode.h"
    123 #include "acevents.h"
    124 #include "acdispat.h"
    125 
    126 
    127 #define _COMPONENT          ACPI_EXECUTER
    128         ACPI_MODULE_NAME    ("exfldio")
    129 
    130 /* Local prototypes */
    131 
    132 static ACPI_STATUS
    133 AcpiExFieldDatumIo (
    134     ACPI_OPERAND_OBJECT     *ObjDesc,
    135     UINT32                  FieldDatumByteOffset,
    136     UINT64                  *Value,
    137     UINT32                  ReadWrite);
    138 
    139 static BOOLEAN
    140 AcpiExRegisterOverflow (
    141     ACPI_OPERAND_OBJECT     *ObjDesc,
    142     UINT64                  Value);
    143 
    144 static ACPI_STATUS
    145 AcpiExSetupRegion (
    146     ACPI_OPERAND_OBJECT     *ObjDesc,
    147     UINT32                  FieldDatumByteOffset);
    148 
    149 
    150 /*******************************************************************************
    151  *
    152  * FUNCTION:    AcpiExSetupRegion
    153  *
    154  * PARAMETERS:  ObjDesc                 - Field to be read or written
    155  *              FieldDatumByteOffset    - Byte offset of this datum within the
    156  *                                        parent field
    157  *
    158  * RETURN:      Status
    159  *
    160  * DESCRIPTION: Common processing for AcpiExExtractFromField and
    161  *              AcpiExInsertIntoField.  Initialize the Region if necessary and
    162  *              validate the request.
    163  *
    164  ******************************************************************************/
    165 
    166 static ACPI_STATUS
    167 AcpiExSetupRegion (
    168     ACPI_OPERAND_OBJECT     *ObjDesc,
    169     UINT32                  FieldDatumByteOffset)
    170 {
    171     ACPI_STATUS             Status = AE_OK;
    172     ACPI_OPERAND_OBJECT     *RgnDesc;
    173 
    174 
    175     ACPI_FUNCTION_TRACE_U32 (ExSetupRegion, FieldDatumByteOffset);
    176 
    177 
    178     RgnDesc = ObjDesc->CommonField.RegionObj;
    179 
    180     /* We must have a valid region */
    181 
    182     if (RgnDesc->Common.Type != ACPI_TYPE_REGION)
    183     {
    184         ACPI_ERROR ((AE_INFO, "Needed Region, found type 0x%X (%s)",
    185             RgnDesc->Common.Type,
    186             AcpiUtGetObjectTypeName (RgnDesc)));
    187 
    188         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
    189     }
    190 
    191     /*
    192      * If the Region Address and Length have not been previously evaluated,
    193      * evaluate them now and save the results.
    194      */
    195     if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID))
    196     {
    197         Status = AcpiDsGetRegionArguments (RgnDesc);
    198         if (ACPI_FAILURE (Status))
    199         {
    200             return_ACPI_STATUS (Status);
    201         }
    202     }
    203 
    204     /*
    205      * Exit now for SMBus or IPMI address space, it has a non-linear
    206      * address space and the request cannot be directly validated
    207      */
    208     if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
    209         RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_IPMI)
    210     {
    211         /* SMBus or IPMI has a non-linear address space */
    212 
    213         return_ACPI_STATUS (AE_OK);
    214     }
    215 
    216 #ifdef ACPI_UNDER_DEVELOPMENT
    217     /*
    218      * If the Field access is AnyAcc, we can now compute the optimal
    219      * access (because we know know the length of the parent region)
    220      */
    221     if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
    222     {
    223         if (ACPI_FAILURE (Status))
    224         {
    225             return_ACPI_STATUS (Status);
    226         }
    227     }
    228 #endif
    229 
    230     /*
    231      * Validate the request.  The entire request from the byte offset for a
    232      * length of one field datum (access width) must fit within the region.
    233      * (Region length is specified in bytes)
    234      */
    235     if (RgnDesc->Region.Length <
    236             (ObjDesc->CommonField.BaseByteOffset + FieldDatumByteOffset +
    237             ObjDesc->CommonField.AccessByteWidth))
    238     {
    239         if (AcpiGbl_EnableInterpreterSlack)
    240         {
    241             /*
    242              * Slack mode only:  We will go ahead and allow access to this
    243              * field if it is within the region length rounded up to the next
    244              * access width boundary. ACPI_SIZE cast for 64-bit compile.
    245              */
    246             if (ACPI_ROUND_UP (RgnDesc->Region.Length,
    247                     ObjDesc->CommonField.AccessByteWidth) >=
    248                 ((ACPI_SIZE) ObjDesc->CommonField.BaseByteOffset +
    249                     ObjDesc->CommonField.AccessByteWidth +
    250                     FieldDatumByteOffset))
    251             {
    252                 return_ACPI_STATUS (AE_OK);
    253             }
    254         }
    255 
    256         if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth)
    257         {
    258             /*
    259              * This is the case where the AccessType (AccWord, etc.) is wider
    260              * than the region itself.  For example, a region of length one
    261              * byte, and a field with Dword access specified.
    262              */
    263             ACPI_ERROR ((AE_INFO,
    264                 "Field [%4.4s] access width (%u bytes) too large for region [%4.4s] (length %u)",
    265                 AcpiUtGetNodeName (ObjDesc->CommonField.Node),
    266                 ObjDesc->CommonField.AccessByteWidth,
    267                 AcpiUtGetNodeName (RgnDesc->Region.Node),
    268                 RgnDesc->Region.Length));
    269         }
    270 
    271         /*
    272          * Offset rounded up to next multiple of field width
    273          * exceeds region length, indicate an error
    274          */
    275         ACPI_ERROR ((AE_INFO,
    276             "Field [%4.4s] Base+Offset+Width %u+%u+%u is beyond end of region [%4.4s] (length %u)",
    277             AcpiUtGetNodeName (ObjDesc->CommonField.Node),
    278             ObjDesc->CommonField.BaseByteOffset,
    279             FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth,
    280             AcpiUtGetNodeName (RgnDesc->Region.Node),
    281             RgnDesc->Region.Length));
    282 
    283         return_ACPI_STATUS (AE_AML_REGION_LIMIT);
    284     }
    285 
    286     return_ACPI_STATUS (AE_OK);
    287 }
    288 
    289 
    290 /*******************************************************************************
    291  *
    292  * FUNCTION:    AcpiExAccessRegion
    293  *
    294  * PARAMETERS:  ObjDesc                 - Field to be read
    295  *              FieldDatumByteOffset    - Byte offset of this datum within the
    296  *                                        parent field
    297  *              Value                   - Where to store value (must at least
    298  *                                        64 bits)
    299  *              Function                - Read or Write flag plus other region-
    300  *                                        dependent flags
    301  *
    302  * RETURN:      Status
    303  *
    304  * DESCRIPTION: Read or Write a single field datum to an Operation Region.
    305  *
    306  ******************************************************************************/
    307 
    308 ACPI_STATUS
    309 AcpiExAccessRegion (
    310     ACPI_OPERAND_OBJECT     *ObjDesc,
    311     UINT32                  FieldDatumByteOffset,
    312     UINT64                  *Value,
    313     UINT32                  Function)
    314 {
    315     ACPI_STATUS             Status;
    316     ACPI_OPERAND_OBJECT     *RgnDesc;
    317     UINT32                  RegionOffset;
    318 
    319 
    320     ACPI_FUNCTION_TRACE (ExAccessRegion);
    321 
    322 
    323     /*
    324      * Ensure that the region operands are fully evaluated and verify
    325      * the validity of the request
    326      */
    327     Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset);
    328     if (ACPI_FAILURE (Status))
    329     {
    330         return_ACPI_STATUS (Status);
    331     }
    332 
    333     /*
    334      * The physical address of this field datum is:
    335      *
    336      * 1) The base of the region, plus
    337      * 2) The base offset of the field, plus
    338      * 3) The current offset into the field
    339      */
    340     RgnDesc = ObjDesc->CommonField.RegionObj;
    341     RegionOffset =
    342         ObjDesc->CommonField.BaseByteOffset +
    343         FieldDatumByteOffset;
    344 
    345     if ((Function & ACPI_IO_MASK) == ACPI_READ)
    346     {
    347         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]"));
    348     }
    349     else
    350     {
    351         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]"));
    352     }
    353 
    354     ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD,
    355         " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %p\n",
    356         AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    357         RgnDesc->Region.SpaceId,
    358         ObjDesc->CommonField.AccessByteWidth,
    359         ObjDesc->CommonField.BaseByteOffset,
    360         FieldDatumByteOffset,
    361         ACPI_CAST_PTR (void, (RgnDesc->Region.Address + RegionOffset))));
    362 
    363     /* Invoke the appropriate AddressSpace/OpRegion handler */
    364 
    365     Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, RegionOffset,
    366                 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value);
    367 
    368     if (ACPI_FAILURE (Status))
    369     {
    370         if (Status == AE_NOT_IMPLEMENTED)
    371         {
    372             ACPI_ERROR ((AE_INFO,
    373                 "Region %s(0x%X) not implemented",
    374                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    375                 RgnDesc->Region.SpaceId));
    376         }
    377         else if (Status == AE_NOT_EXIST)
    378         {
    379             ACPI_ERROR ((AE_INFO,
    380                 "Region %s(0x%X) has no handler",
    381                 AcpiUtGetRegionName (RgnDesc->Region.SpaceId),
    382                 RgnDesc->Region.SpaceId));
    383         }
    384     }
    385 
    386     return_ACPI_STATUS (Status);
    387 }
    388 
    389 
    390 /*******************************************************************************
    391  *
    392  * FUNCTION:    AcpiExRegisterOverflow
    393  *
    394  * PARAMETERS:  ObjDesc                 - Register(Field) to be written
    395  *              Value                   - Value to be stored
    396  *
    397  * RETURN:      TRUE if value overflows the field, FALSE otherwise
    398  *
    399  * DESCRIPTION: Check if a value is out of range of the field being written.
    400  *              Used to check if the values written to Index and Bank registers
    401  *              are out of range.  Normally, the value is simply truncated
    402  *              to fit the field, but this case is most likely a serious
    403  *              coding error in the ASL.
    404  *
    405  ******************************************************************************/
    406 
    407 static BOOLEAN
    408 AcpiExRegisterOverflow (
    409     ACPI_OPERAND_OBJECT     *ObjDesc,
    410     UINT64                  Value)
    411 {
    412 
    413     if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE)
    414     {
    415         /*
    416          * The field is large enough to hold the maximum integer, so we can
    417          * never overflow it.
    418          */
    419         return (FALSE);
    420     }
    421 
    422     if (Value >= ((UINT64) 1 << ObjDesc->CommonField.BitLength))
    423     {
    424         /*
    425          * The Value is larger than the maximum value that can fit into
    426          * the register.
    427          */
    428         return (TRUE);
    429     }
    430 
    431     /* The Value will fit into the field with no truncation */
    432 
    433     return (FALSE);
    434 }
    435 
    436 
    437 /*******************************************************************************
    438  *
    439  * FUNCTION:    AcpiExFieldDatumIo
    440  *
    441  * PARAMETERS:  ObjDesc                 - Field to be read
    442  *              FieldDatumByteOffset    - Byte offset of this datum within the
    443  *                                        parent field
    444  *              Value                   - Where to store value (must be 64 bits)
    445  *              ReadWrite               - Read or Write flag
    446  *
    447  * RETURN:      Status
    448  *
    449  * DESCRIPTION: Read or Write a single datum of a field.  The FieldType is
    450  *              demultiplexed here to handle the different types of fields
    451  *              (BufferField, RegionField, IndexField, BankField)
    452  *
    453  ******************************************************************************/
    454 
    455 static ACPI_STATUS
    456 AcpiExFieldDatumIo (
    457     ACPI_OPERAND_OBJECT     *ObjDesc,
    458     UINT32                  FieldDatumByteOffset,
    459     UINT64                  *Value,
    460     UINT32                  ReadWrite)
    461 {
    462     ACPI_STATUS             Status;
    463     UINT64                  LocalValue;
    464 
    465 
    466     ACPI_FUNCTION_TRACE_U32 (ExFieldDatumIo, FieldDatumByteOffset);
    467 
    468 
    469     if (ReadWrite == ACPI_READ)
    470     {
    471         if (!Value)
    472         {
    473             LocalValue = 0;
    474 
    475             /* To support reads without saving return value */
    476             Value = &LocalValue;
    477         }
    478 
    479         /* Clear the entire return buffer first, [Very Important!] */
    480 
    481         *Value = 0;
    482     }
    483 
    484     /*
    485      * The four types of fields are:
    486      *
    487      * BufferField - Read/write from/to a Buffer
    488      * RegionField - Read/write from/to a Operation Region.
    489      * BankField   - Write to a Bank Register, then read/write from/to an
    490      *               OperationRegion
    491      * IndexField  - Write to an Index Register, then read/write from/to a
    492      *               Data Register
    493      */
    494     switch (ObjDesc->Common.Type)
    495     {
    496     case ACPI_TYPE_BUFFER_FIELD:
    497         /*
    498          * If the BufferField arguments have not been previously evaluated,
    499          * evaluate them now and save the results.
    500          */
    501         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
    502         {
    503             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
    504             if (ACPI_FAILURE (Status))
    505             {
    506                 return_ACPI_STATUS (Status);
    507             }
    508         }
    509 
    510         if (ReadWrite == ACPI_READ)
    511         {
    512             /*
    513              * Copy the data from the source buffer.
    514              * Length is the field width in bytes.
    515              */
    516             ACPI_MEMCPY (Value,
    517                 (ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
    518                     ObjDesc->BufferField.BaseByteOffset +
    519                     FieldDatumByteOffset,
    520                 ObjDesc->CommonField.AccessByteWidth);
    521         }
    522         else
    523         {
    524             /*
    525              * Copy the data to the target buffer.
    526              * Length is the field width in bytes.
    527              */
    528             ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer +
    529                 ObjDesc->BufferField.BaseByteOffset +
    530                 FieldDatumByteOffset,
    531                 Value, ObjDesc->CommonField.AccessByteWidth);
    532         }
    533 
    534         Status = AE_OK;
    535         break;
    536 
    537 
    538     case ACPI_TYPE_LOCAL_BANK_FIELD:
    539 
    540         /*
    541          * Ensure that the BankValue is not beyond the capacity of
    542          * the register
    543          */
    544         if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj,
    545                 (UINT64) ObjDesc->BankField.Value))
    546         {
    547             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
    548         }
    549 
    550         /*
    551          * For BankFields, we must write the BankValue to the BankRegister
    552          * (itself a RegionField) before we can access the data.
    553          */
    554         Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj,
    555                     &ObjDesc->BankField.Value,
    556                     sizeof (ObjDesc->BankField.Value));
    557         if (ACPI_FAILURE (Status))
    558         {
    559             return_ACPI_STATUS (Status);
    560         }
    561 
    562         /*
    563          * Now that the Bank has been selected, fall through to the
    564          * RegionField case and write the datum to the Operation Region
    565          */
    566 
    567         /*lint -fallthrough */
    568 
    569 
    570     case ACPI_TYPE_LOCAL_REGION_FIELD:
    571         /*
    572          * For simple RegionFields, we just directly access the owning
    573          * Operation Region.
    574          */
    575         Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value,
    576                     ReadWrite);
    577         break;
    578 
    579 
    580     case ACPI_TYPE_LOCAL_INDEX_FIELD:
    581 
    582 
    583         /*
    584          * Ensure that the IndexValue is not beyond the capacity of
    585          * the register
    586          */
    587         if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj,
    588                 (UINT64) ObjDesc->IndexField.Value))
    589         {
    590             return_ACPI_STATUS (AE_AML_REGISTER_LIMIT);
    591         }
    592 
    593         /* Write the index value to the IndexRegister (itself a RegionField) */
    594 
    595         FieldDatumByteOffset += ObjDesc->IndexField.Value;
    596 
    597         ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    598             "Write to Index Register: Value %8.8X\n",
    599             FieldDatumByteOffset));
    600 
    601         Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj,
    602                     &FieldDatumByteOffset,
    603                     sizeof (FieldDatumByteOffset));
    604         if (ACPI_FAILURE (Status))
    605         {
    606             return_ACPI_STATUS (Status);
    607         }
    608 
    609         if (ReadWrite == ACPI_READ)
    610         {
    611             /* Read the datum from the DataRegister */
    612 
    613             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    614                 "Read from Data Register\n"));
    615 
    616             Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj,
    617                         Value, sizeof (UINT64));
    618         }
    619         else
    620         {
    621             /* Write the datum to the DataRegister */
    622 
    623             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    624                 "Write to Data Register: Value %8.8X%8.8X\n",
    625                 ACPI_FORMAT_UINT64 (*Value)));
    626 
    627             Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj,
    628                         Value, sizeof (UINT64));
    629         }
    630         break;
    631 
    632 
    633     default:
    634 
    635         ACPI_ERROR ((AE_INFO, "Wrong object type in field I/O %u",
    636             ObjDesc->Common.Type));
    637         Status = AE_AML_INTERNAL;
    638         break;
    639     }
    640 
    641     if (ACPI_SUCCESS (Status))
    642     {
    643         if (ReadWrite == ACPI_READ)
    644         {
    645             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    646                 "Value Read %8.8X%8.8X, Width %u\n",
    647                 ACPI_FORMAT_UINT64 (*Value),
    648                 ObjDesc->CommonField.AccessByteWidth));
    649         }
    650         else
    651         {
    652             ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    653                 "Value Written %8.8X%8.8X, Width %u\n",
    654                 ACPI_FORMAT_UINT64 (*Value),
    655                 ObjDesc->CommonField.AccessByteWidth));
    656         }
    657     }
    658 
    659     return_ACPI_STATUS (Status);
    660 }
    661 
    662 
    663 /*******************************************************************************
    664  *
    665  * FUNCTION:    AcpiExWriteWithUpdateRule
    666  *
    667  * PARAMETERS:  ObjDesc                 - Field to be written
    668  *              Mask                    - bitmask within field datum
    669  *              FieldValue              - Value to write
    670  *              FieldDatumByteOffset    - Offset of datum within field
    671  *
    672  * RETURN:      Status
    673  *
    674  * DESCRIPTION: Apply the field update rule to a field write
    675  *
    676  ******************************************************************************/
    677 
    678 ACPI_STATUS
    679 AcpiExWriteWithUpdateRule (
    680     ACPI_OPERAND_OBJECT     *ObjDesc,
    681     UINT64                  Mask,
    682     UINT64                  FieldValue,
    683     UINT32                  FieldDatumByteOffset)
    684 {
    685     ACPI_STATUS             Status = AE_OK;
    686     UINT64                  MergedValue;
    687     UINT64                  CurrentValue;
    688 
    689 
    690     ACPI_FUNCTION_TRACE_U32 (ExWriteWithUpdateRule, Mask);
    691 
    692 
    693     /* Start with the new bits  */
    694 
    695     MergedValue = FieldValue;
    696 
    697     /* If the mask is all ones, we don't need to worry about the update rule */
    698 
    699     if (Mask != ACPI_UINT64_MAX)
    700     {
    701         /* Decode the update rule */
    702 
    703         switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)
    704         {
    705         case AML_FIELD_UPDATE_PRESERVE:
    706             /*
    707              * Check if update rule needs to be applied (not if mask is all
    708              * ones)  The left shift drops the bits we want to ignore.
    709              */
    710             if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) -
    711                            ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0)
    712             {
    713                 /*
    714                  * Read the current contents of the byte/word/dword containing
    715                  * the field, and merge with the new field value.
    716                  */
    717                 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
    718                             &CurrentValue, ACPI_READ);
    719                 if (ACPI_FAILURE (Status))
    720                 {
    721                     return_ACPI_STATUS (Status);
    722                 }
    723 
    724                 MergedValue |= (CurrentValue & ~Mask);
    725             }
    726             break;
    727 
    728         case AML_FIELD_UPDATE_WRITE_AS_ONES:
    729 
    730             /* Set positions outside the field to all ones */
    731 
    732             MergedValue |= ~Mask;
    733             break;
    734 
    735         case AML_FIELD_UPDATE_WRITE_AS_ZEROS:
    736 
    737             /* Set positions outside the field to all zeros */
    738 
    739             MergedValue &= Mask;
    740             break;
    741 
    742         default:
    743 
    744             ACPI_ERROR ((AE_INFO,
    745                 "Unknown UpdateRule value: 0x%X",
    746                 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK)));
    747             return_ACPI_STATUS (AE_AML_OPERAND_VALUE);
    748         }
    749     }
    750 
    751     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
    752         "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n",
    753         ACPI_FORMAT_UINT64 (Mask),
    754         FieldDatumByteOffset,
    755         ObjDesc->CommonField.AccessByteWidth,
    756         ACPI_FORMAT_UINT64 (FieldValue),
    757         ACPI_FORMAT_UINT64 (MergedValue)));
    758 
    759     /* Write the merged value */
    760 
    761     Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset,
    762                 &MergedValue, ACPI_WRITE);
    763 
    764     return_ACPI_STATUS (Status);
    765 }
    766 
    767 
    768 /*******************************************************************************
    769  *
    770  * FUNCTION:    AcpiExExtractFromField
    771  *
    772  * PARAMETERS:  ObjDesc             - Field to be read
    773  *              Buffer              - Where to store the field data
    774  *              BufferLength        - Length of Buffer
    775  *
    776  * RETURN:      Status
    777  *
    778  * DESCRIPTION: Retrieve the current value of the given field
    779  *
    780  ******************************************************************************/
    781 
    782 ACPI_STATUS
    783 AcpiExExtractFromField (
    784     ACPI_OPERAND_OBJECT     *ObjDesc,
    785     void                    *Buffer,
    786     UINT32                  BufferLength)
    787 {
    788     ACPI_STATUS             Status;
    789     UINT64                  RawDatum;
    790     UINT64                  MergedDatum;
    791     UINT32                  FieldOffset = 0;
    792     UINT32                  BufferOffset = 0;
    793     UINT32                  BufferTailBits;
    794     UINT32                  DatumCount;
    795     UINT32                  FieldDatumCount;
    796     UINT32                  AccessBitWidth;
    797     UINT32                  i;
    798 
    799 
    800     ACPI_FUNCTION_TRACE (ExExtractFromField);
    801 
    802 
    803     /* Validate target buffer and clear it */
    804 
    805     if (BufferLength <
    806         ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->CommonField.BitLength))
    807     {
    808         ACPI_ERROR ((AE_INFO,
    809             "Field size %u (bits) is too large for buffer (%u)",
    810             ObjDesc->CommonField.BitLength, BufferLength));
    811 
    812         return_ACPI_STATUS (AE_BUFFER_OVERFLOW);
    813     }
    814 
    815     ACPI_MEMSET (Buffer, 0, BufferLength);
    816     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
    817 
    818     /* Handle the simple case here */
    819 
    820     if ((ObjDesc->CommonField.StartFieldBitOffset == 0) &&
    821         (ObjDesc->CommonField.BitLength == AccessBitWidth))
    822     {
    823         Status = AcpiExFieldDatumIo (ObjDesc, 0, Buffer, ACPI_READ);
    824         return_ACPI_STATUS (Status);
    825     }
    826 
    827 /* TBD: Move to common setup code */
    828 
    829     /* Field algorithm is limited to sizeof(UINT64), truncate if needed */
    830 
    831     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    832     {
    833         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    834         AccessBitWidth = sizeof (UINT64) * 8;
    835     }
    836 
    837     /* Compute the number of datums (access width data items) */
    838 
    839     DatumCount = ACPI_ROUND_UP_TO (
    840         ObjDesc->CommonField.BitLength, AccessBitWidth);
    841 
    842     FieldDatumCount = ACPI_ROUND_UP_TO (
    843         ObjDesc->CommonField.BitLength +
    844         ObjDesc->CommonField.StartFieldBitOffset, AccessBitWidth);
    845 
    846     /* Priming read from the field */
    847 
    848     Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset, &RawDatum, ACPI_READ);
    849     if (ACPI_FAILURE (Status))
    850     {
    851         return_ACPI_STATUS (Status);
    852     }
    853     MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    854 
    855     /* Read the rest of the field */
    856 
    857     for (i = 1; i < FieldDatumCount; i++)
    858     {
    859         /* Get next input datum from the field */
    860 
    861         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
    862         Status = AcpiExFieldDatumIo (ObjDesc, FieldOffset,
    863                     &RawDatum, ACPI_READ);
    864         if (ACPI_FAILURE (Status))
    865         {
    866             return_ACPI_STATUS (Status);
    867         }
    868 
    869         /*
    870          * Merge with previous datum if necessary.
    871          *
    872          * Note: Before the shift, check if the shift value will be larger than
    873          * the integer size. If so, there is no need to perform the operation.
    874          * This avoids the differences in behavior between different compilers
    875          * concerning shift values larger than the target data width.
    876          */
    877         if (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset <
    878             ACPI_INTEGER_BIT_SIZE)
    879         {
    880             MergedDatum |= RawDatum <<
    881                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
    882         }
    883 
    884         if (i == DatumCount)
    885         {
    886             break;
    887         }
    888 
    889         /* Write merged datum to target buffer */
    890 
    891         ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
    892             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    893                 BufferLength - BufferOffset));
    894 
    895         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
    896         MergedDatum = RawDatum >> ObjDesc->CommonField.StartFieldBitOffset;
    897     }
    898 
    899     /* Mask off any extra bits in the last datum */
    900 
    901     BufferTailBits = ObjDesc->CommonField.BitLength % AccessBitWidth;
    902     if (BufferTailBits)
    903     {
    904         MergedDatum &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
    905     }
    906 
    907     /* Write the last datum to the buffer */
    908 
    909     ACPI_MEMCPY (((char *) Buffer) + BufferOffset, &MergedDatum,
    910         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
    911             BufferLength - BufferOffset));
    912 
    913     return_ACPI_STATUS (AE_OK);
    914 }
    915 
    916 
    917 /*******************************************************************************
    918  *
    919  * FUNCTION:    AcpiExInsertIntoField
    920  *
    921  * PARAMETERS:  ObjDesc             - Field to be written
    922  *              Buffer              - Data to be written
    923  *              BufferLength        - Length of Buffer
    924  *
    925  * RETURN:      Status
    926  *
    927  * DESCRIPTION: Store the Buffer contents into the given field
    928  *
    929  ******************************************************************************/
    930 
    931 ACPI_STATUS
    932 AcpiExInsertIntoField (
    933     ACPI_OPERAND_OBJECT     *ObjDesc,
    934     void                    *Buffer,
    935     UINT32                  BufferLength)
    936 {
    937     void                    *NewBuffer;
    938     ACPI_STATUS             Status;
    939     UINT64                  Mask;
    940     UINT64                  WidthMask;
    941     UINT64                  MergedDatum;
    942     UINT64                  RawDatum = 0;
    943     UINT32                  FieldOffset = 0;
    944     UINT32                  BufferOffset = 0;
    945     UINT32                  BufferTailBits;
    946     UINT32                  DatumCount;
    947     UINT32                  FieldDatumCount;
    948     UINT32                  AccessBitWidth;
    949     UINT32                  RequiredLength;
    950     UINT32                  i;
    951 
    952 
    953     ACPI_FUNCTION_TRACE (ExInsertIntoField);
    954 
    955 
    956     /* Validate input buffer */
    957 
    958     NewBuffer = NULL;
    959     RequiredLength = ACPI_ROUND_BITS_UP_TO_BYTES (
    960                         ObjDesc->CommonField.BitLength);
    961     /*
    962      * We must have a buffer that is at least as long as the field
    963      * we are writing to.  This is because individual fields are
    964      * indivisible and partial writes are not supported -- as per
    965      * the ACPI specification.
    966      */
    967     if (BufferLength < RequiredLength)
    968     {
    969         /* We need to create a new buffer */
    970 
    971         NewBuffer = ACPI_ALLOCATE_ZEROED (RequiredLength);
    972         if (!NewBuffer)
    973         {
    974             return_ACPI_STATUS (AE_NO_MEMORY);
    975         }
    976 
    977         /*
    978          * Copy the original data to the new buffer, starting
    979          * at Byte zero.  All unused (upper) bytes of the
    980          * buffer will be 0.
    981          */
    982         ACPI_MEMCPY ((char *) NewBuffer, (char *) Buffer, BufferLength);
    983         Buffer = NewBuffer;
    984         BufferLength = RequiredLength;
    985     }
    986 
    987 /* TBD: Move to common setup code */
    988 
    989     /* Algo is limited to sizeof(UINT64), so cut the AccessByteWidth */
    990     if (ObjDesc->CommonField.AccessByteWidth > sizeof (UINT64))
    991     {
    992         ObjDesc->CommonField.AccessByteWidth = sizeof (UINT64);
    993     }
    994 
    995     AccessBitWidth = ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth);
    996 
    997     /*
    998      * Create the bitmasks used for bit insertion.
    999      * Note: This if/else is used to bypass compiler differences with the
   1000      * shift operator
   1001      */
   1002     if (AccessBitWidth == ACPI_INTEGER_BIT_SIZE)
   1003     {
   1004         WidthMask = ACPI_UINT64_MAX;
   1005     }
   1006     else
   1007     {
   1008         WidthMask = ACPI_MASK_BITS_ABOVE (AccessBitWidth);
   1009     }
   1010 
   1011     Mask = WidthMask &
   1012         ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset);
   1013 
   1014     /* Compute the number of datums (access width data items) */
   1015 
   1016     DatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength,
   1017         AccessBitWidth);
   1018 
   1019     FieldDatumCount = ACPI_ROUND_UP_TO (ObjDesc->CommonField.BitLength +
   1020         ObjDesc->CommonField.StartFieldBitOffset,
   1021         AccessBitWidth);
   1022 
   1023     /* Get initial Datum from the input buffer */
   1024 
   1025     ACPI_MEMCPY (&RawDatum, Buffer,
   1026         ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
   1027             BufferLength - BufferOffset));
   1028 
   1029     MergedDatum = RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
   1030 
   1031     /* Write the entire field */
   1032 
   1033     for (i = 1; i < FieldDatumCount; i++)
   1034     {
   1035         /* Write merged datum to the target field */
   1036 
   1037         MergedDatum &= Mask;
   1038         Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask,
   1039                     MergedDatum, FieldOffset);
   1040         if (ACPI_FAILURE (Status))
   1041         {
   1042             goto Exit;
   1043         }
   1044 
   1045         FieldOffset += ObjDesc->CommonField.AccessByteWidth;
   1046 
   1047         /*
   1048          * Start new output datum by merging with previous input datum
   1049          * if necessary.
   1050          *
   1051          * Note: Before the shift, check if the shift value will be larger than
   1052          * the integer size. If so, there is no need to perform the operation.
   1053          * This avoids the differences in behavior between different compilers
   1054          * concerning shift values larger than the target data width.
   1055          */
   1056         if ((AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset) <
   1057             ACPI_INTEGER_BIT_SIZE)
   1058         {
   1059             MergedDatum = RawDatum >>
   1060                 (AccessBitWidth - ObjDesc->CommonField.StartFieldBitOffset);
   1061         }
   1062         else
   1063         {
   1064             MergedDatum = 0;
   1065         }
   1066 
   1067         Mask = WidthMask;
   1068 
   1069         if (i == DatumCount)
   1070         {
   1071             break;
   1072         }
   1073 
   1074         /* Get the next input datum from the buffer */
   1075 
   1076         BufferOffset += ObjDesc->CommonField.AccessByteWidth;
   1077         ACPI_MEMCPY (&RawDatum, ((char *) Buffer) + BufferOffset,
   1078             ACPI_MIN(ObjDesc->CommonField.AccessByteWidth,
   1079                  BufferLength - BufferOffset));
   1080 
   1081         MergedDatum |= RawDatum << ObjDesc->CommonField.StartFieldBitOffset;
   1082     }
   1083 
   1084     /* Mask off any extra bits in the last datum */
   1085 
   1086     BufferTailBits = (ObjDesc->CommonField.BitLength +
   1087         ObjDesc->CommonField.StartFieldBitOffset) % AccessBitWidth;
   1088     if (BufferTailBits)
   1089     {
   1090         Mask &= ACPI_MASK_BITS_ABOVE (BufferTailBits);
   1091     }
   1092 
   1093     /* Write the last datum to the field */
   1094 
   1095     MergedDatum &= Mask;
   1096     Status = AcpiExWriteWithUpdateRule (ObjDesc,
   1097                 Mask, MergedDatum, FieldOffset);
   1098 
   1099 Exit:
   1100     /* Free temporary buffer if we used one */
   1101 
   1102     if (NewBuffer)
   1103     {
   1104         ACPI_FREE (NewBuffer);
   1105     }
   1106     return_ACPI_STATUS (Status);
   1107 }
   1108 
   1109 
   1110