The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/contrib/dev/acpica/components/executer/exfldio.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: d9cf4521338fc75b95bbf1c03e65dfcc


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.