Home | History | Annotate | Line # | Download | only in acpiexec
aeregion.c revision 1.1
      1  1.1  christos /******************************************************************************
      2  1.1  christos  *
      3  1.1  christos  * Module Name: aeregion - Operation region support for acpiexec
      4  1.1  christos  *
      5  1.1  christos  *****************************************************************************/
      6  1.1  christos 
      7  1.1  christos /*
      8  1.1  christos  * Copyright (C) 2000 - 2014, Intel Corp.
      9  1.1  christos  * All rights reserved.
     10  1.1  christos  *
     11  1.1  christos  * Redistribution and use in source and binary forms, with or without
     12  1.1  christos  * modification, are permitted provided that the following conditions
     13  1.1  christos  * are met:
     14  1.1  christos  * 1. Redistributions of source code must retain the above copyright
     15  1.1  christos  *    notice, this list of conditions, and the following disclaimer,
     16  1.1  christos  *    without modification.
     17  1.1  christos  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
     18  1.1  christos  *    substantially similar to the "NO WARRANTY" disclaimer below
     19  1.1  christos  *    ("Disclaimer") and any redistribution must be conditioned upon
     20  1.1  christos  *    including a substantially similar Disclaimer requirement for further
     21  1.1  christos  *    binary redistribution.
     22  1.1  christos  * 3. Neither the names of the above-listed copyright holders nor the names
     23  1.1  christos  *    of any contributors may be used to endorse or promote products derived
     24  1.1  christos  *    from this software without specific prior written permission.
     25  1.1  christos  *
     26  1.1  christos  * Alternatively, this software may be distributed under the terms of the
     27  1.1  christos  * GNU General Public License ("GPL") version 2 as published by the Free
     28  1.1  christos  * Software Foundation.
     29  1.1  christos  *
     30  1.1  christos  * NO WARRANTY
     31  1.1  christos  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     32  1.1  christos  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     33  1.1  christos  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
     34  1.1  christos  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     35  1.1  christos  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     36  1.1  christos  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     37  1.1  christos  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     38  1.1  christos  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
     39  1.1  christos  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
     40  1.1  christos  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     41  1.1  christos  * POSSIBILITY OF SUCH DAMAGES.
     42  1.1  christos  */
     43  1.1  christos 
     44  1.1  christos #include "aecommon.h"
     45  1.1  christos 
     46  1.1  christos #define _COMPONENT          ACPI_TOOLS
     47  1.1  christos         ACPI_MODULE_NAME    ("aeregion")
     48  1.1  christos 
     49  1.1  christos 
     50  1.1  christos /* Local prototypes */
     51  1.1  christos 
     52  1.1  christos static ACPI_STATUS
     53  1.1  christos AeRegionInit (
     54  1.1  christos     ACPI_HANDLE             RegionHandle,
     55  1.1  christos     UINT32                  Function,
     56  1.1  christos     void                    *HandlerContext,
     57  1.1  christos     void                    **RegionContext);
     58  1.1  christos 
     59  1.1  christos static ACPI_STATUS
     60  1.1  christos AeInstallEcHandler (
     61  1.1  christos     ACPI_HANDLE             ObjHandle,
     62  1.1  christos     UINT32                  Level,
     63  1.1  christos     void                    *Context,
     64  1.1  christos     void                    **ReturnValue);
     65  1.1  christos 
     66  1.1  christos static ACPI_STATUS
     67  1.1  christos AeInstallPciHandler (
     68  1.1  christos     ACPI_HANDLE             ObjHandle,
     69  1.1  christos     UINT32                  Level,
     70  1.1  christos     void                    *Context,
     71  1.1  christos     void                    **ReturnValue);
     72  1.1  christos 
     73  1.1  christos 
     74  1.1  christos static AE_DEBUG_REGIONS     AeRegions;
     75  1.1  christos BOOLEAN                     AcpiGbl_DisplayRegionAccess = FALSE;
     76  1.1  christos ACPI_CONNECTION_INFO        AeMyContext;
     77  1.1  christos 
     78  1.1  christos 
     79  1.1  christos /*
     80  1.1  christos  * We will override some of the default region handlers, especially
     81  1.1  christos  * the SystemMemory handler, which must be implemented locally.
     82  1.1  christos  * These handlers are installed "early" - before any _REG methods
     83  1.1  christos  * are executed - since they are special in the sense that the ACPI spec
     84  1.1  christos  * declares that they must "always be available". Cannot override the
     85  1.1  christos  * DataTable region handler either -- needed for test execution.
     86  1.1  christos  *
     87  1.1  christos  * NOTE: The local region handler will simulate access to these address
     88  1.1  christos  * spaces by creating a memory buffer behind each operation region.
     89  1.1  christos  */
     90  1.1  christos static ACPI_ADR_SPACE_TYPE  DefaultSpaceIdList[] =
     91  1.1  christos {
     92  1.1  christos     ACPI_ADR_SPACE_SYSTEM_MEMORY,
     93  1.1  christos     ACPI_ADR_SPACE_SYSTEM_IO,
     94  1.1  christos     ACPI_ADR_SPACE_PCI_CONFIG,
     95  1.1  christos     ACPI_ADR_SPACE_EC
     96  1.1  christos };
     97  1.1  christos 
     98  1.1  christos /*
     99  1.1  christos  * We will install handlers for some of the various address space IDs.
    100  1.1  christos  * Test one user-defined address space (used by aslts).
    101  1.1  christos  */
    102  1.1  christos #define ACPI_ADR_SPACE_USER_DEFINED1        0x80
    103  1.1  christos #define ACPI_ADR_SPACE_USER_DEFINED2        0xE4
    104  1.1  christos 
    105  1.1  christos static ACPI_ADR_SPACE_TYPE  SpaceIdList[] =
    106  1.1  christos {
    107  1.1  christos     ACPI_ADR_SPACE_SMBUS,
    108  1.1  christos     ACPI_ADR_SPACE_CMOS,
    109  1.1  christos     ACPI_ADR_SPACE_PCI_BAR_TARGET,
    110  1.1  christos     ACPI_ADR_SPACE_IPMI,
    111  1.1  christos     ACPI_ADR_SPACE_GPIO,
    112  1.1  christos     ACPI_ADR_SPACE_GSBUS,
    113  1.1  christos     ACPI_ADR_SPACE_FIXED_HARDWARE,
    114  1.1  christos     ACPI_ADR_SPACE_USER_DEFINED1,
    115  1.1  christos     ACPI_ADR_SPACE_USER_DEFINED2
    116  1.1  christos };
    117  1.1  christos 
    118  1.1  christos 
    119  1.1  christos /******************************************************************************
    120  1.1  christos  *
    121  1.1  christos  * FUNCTION:    AeRegionInit
    122  1.1  christos  *
    123  1.1  christos  * PARAMETERS:  Region init handler
    124  1.1  christos  *
    125  1.1  christos  * RETURN:      Status
    126  1.1  christos  *
    127  1.1  christos  * DESCRIPTION: Opregion init function.
    128  1.1  christos  *
    129  1.1  christos  *****************************************************************************/
    130  1.1  christos 
    131  1.1  christos static ACPI_STATUS
    132  1.1  christos AeRegionInit (
    133  1.1  christos     ACPI_HANDLE                 RegionHandle,
    134  1.1  christos     UINT32                      Function,
    135  1.1  christos     void                        *HandlerContext,
    136  1.1  christos     void                        **RegionContext)
    137  1.1  christos {
    138  1.1  christos 
    139  1.1  christos     if (Function == ACPI_REGION_DEACTIVATE)
    140  1.1  christos     {
    141  1.1  christos         *RegionContext = NULL;
    142  1.1  christos     }
    143  1.1  christos     else
    144  1.1  christos     {
    145  1.1  christos         *RegionContext = RegionHandle;
    146  1.1  christos     }
    147  1.1  christos 
    148  1.1  christos     return (AE_OK);
    149  1.1  christos }
    150  1.1  christos 
    151  1.1  christos 
    152  1.1  christos void
    153  1.1  christos AeInstallRegionHandlers (
    154  1.1  christos     void)
    155  1.1  christos {
    156  1.1  christos     UINT32                  i;
    157  1.1  christos     ACPI_STATUS             Status;
    158  1.1  christos 
    159  1.1  christos     /*
    160  1.1  christos      * Install handlers for some of the "device driver" address spaces
    161  1.1  christos      * such as SMBus, etc.
    162  1.1  christos      */
    163  1.1  christos     for (i = 0; i < ACPI_ARRAY_LENGTH (SpaceIdList); i++)
    164  1.1  christos     {
    165  1.1  christos         /* Install handler at the root object */
    166  1.1  christos 
    167  1.1  christos         Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT,
    168  1.1  christos                     SpaceIdList[i], AeRegionHandler,
    169  1.1  christos                     AeRegionInit, &AeMyContext);
    170  1.1  christos         if (ACPI_FAILURE (Status))
    171  1.1  christos         {
    172  1.1  christos             ACPI_EXCEPTION ((AE_INFO, Status,
    173  1.1  christos                 "Could not install an OpRegion handler for %s space(%u)",
    174  1.1  christos                 AcpiUtGetRegionName((UINT8) SpaceIdList[i]), SpaceIdList[i]));
    175  1.1  christos             return;
    176  1.1  christos         }
    177  1.1  christos     }
    178  1.1  christos }
    179  1.1  christos 
    180  1.1  christos 
    181  1.1  christos void
    182  1.1  christos AeOverrideRegionHandlers (
    183  1.1  christos     void)
    184  1.1  christos {
    185  1.1  christos     UINT32                  i;
    186  1.1  christos     ACPI_STATUS             Status;
    187  1.1  christos 
    188  1.1  christos     /*
    189  1.1  christos      * Install handlers that will override the default handlers for some of
    190  1.1  christos      * the space IDs.
    191  1.1  christos      */
    192  1.1  christos     for (i = 0; i < ACPI_ARRAY_LENGTH (DefaultSpaceIdList); i++)
    193  1.1  christos     {
    194  1.1  christos         /* Install handler at the root object */
    195  1.1  christos 
    196  1.1  christos         Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT,
    197  1.1  christos                     DefaultSpaceIdList[i], AeRegionHandler,
    198  1.1  christos                     AeRegionInit, &AeMyContext);
    199  1.1  christos         if (ACPI_FAILURE (Status))
    200  1.1  christos         {
    201  1.1  christos             ACPI_EXCEPTION ((AE_INFO, Status,
    202  1.1  christos                 "Could not install a default OpRegion handler for %s space(%u)",
    203  1.1  christos                 AcpiUtGetRegionName ((UINT8) DefaultSpaceIdList[i]),
    204  1.1  christos                 DefaultSpaceIdList[i]));
    205  1.1  christos             return;
    206  1.1  christos         }
    207  1.1  christos     }
    208  1.1  christos }
    209  1.1  christos 
    210  1.1  christos 
    211  1.1  christos /*******************************************************************************
    212  1.1  christos  *
    213  1.1  christos  * FUNCTION:    AeInstallDeviceHandlers,
    214  1.1  christos  *              AeInstallEcHandler,
    215  1.1  christos  *              AeInstallPciHandler
    216  1.1  christos  *
    217  1.1  christos  * PARAMETERS:  ACPI_WALK_NAMESPACE callback
    218  1.1  christos  *
    219  1.1  christos  * RETURN:      Status
    220  1.1  christos  *
    221  1.1  christos  * DESCRIPTION: Walk entire namespace, install a handler for every EC
    222  1.1  christos  *              and PCI device found.
    223  1.1  christos  *
    224  1.1  christos  ******************************************************************************/
    225  1.1  christos 
    226  1.1  christos static ACPI_STATUS
    227  1.1  christos AeInstallEcHandler (
    228  1.1  christos     ACPI_HANDLE             ObjHandle,
    229  1.1  christos     UINT32                  Level,
    230  1.1  christos     void                    *Context,
    231  1.1  christos     void                    **ReturnValue)
    232  1.1  christos {
    233  1.1  christos     ACPI_STATUS             Status;
    234  1.1  christos 
    235  1.1  christos 
    236  1.1  christos     /* Install the handler for this EC device */
    237  1.1  christos 
    238  1.1  christos     Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_EC,
    239  1.1  christos         AeRegionHandler, AeRegionInit, &AeMyContext);
    240  1.1  christos     if (ACPI_FAILURE (Status))
    241  1.1  christos     {
    242  1.1  christos         ACPI_EXCEPTION ((AE_INFO, Status,
    243  1.1  christos             "Could not install an OpRegion handler for EC device (%p)",
    244  1.1  christos             ObjHandle));
    245  1.1  christos     }
    246  1.1  christos 
    247  1.1  christos     return (Status);
    248  1.1  christos }
    249  1.1  christos 
    250  1.1  christos 
    251  1.1  christos static ACPI_STATUS
    252  1.1  christos AeInstallPciHandler (
    253  1.1  christos     ACPI_HANDLE             ObjHandle,
    254  1.1  christos     UINT32                  Level,
    255  1.1  christos     void                    *Context,
    256  1.1  christos     void                    **ReturnValue)
    257  1.1  christos {
    258  1.1  christos     ACPI_STATUS             Status;
    259  1.1  christos 
    260  1.1  christos 
    261  1.1  christos     /* Install memory and I/O handlers for the PCI device */
    262  1.1  christos 
    263  1.1  christos     Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_IO,
    264  1.1  christos         AeRegionHandler, AeRegionInit, &AeMyContext);
    265  1.1  christos     if (ACPI_FAILURE (Status))
    266  1.1  christos     {
    267  1.1  christos         ACPI_EXCEPTION ((AE_INFO, Status,
    268  1.1  christos             "Could not install an OpRegion handler for PCI device (%p)",
    269  1.1  christos             ObjHandle));
    270  1.1  christos     }
    271  1.1  christos 
    272  1.1  christos     Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_MEMORY,
    273  1.1  christos         AeRegionHandler, AeRegionInit, &AeMyContext);
    274  1.1  christos     if (ACPI_FAILURE (Status))
    275  1.1  christos     {
    276  1.1  christos         ACPI_EXCEPTION ((AE_INFO, Status,
    277  1.1  christos             "Could not install an OpRegion handler for PCI device (%p)",
    278  1.1  christos             ObjHandle));
    279  1.1  christos     }
    280  1.1  christos 
    281  1.1  christos     return (AE_CTRL_TERMINATE);
    282  1.1  christos }
    283  1.1  christos 
    284  1.1  christos 
    285  1.1  christos ACPI_STATUS
    286  1.1  christos AeInstallDeviceHandlers (
    287  1.1  christos     void)
    288  1.1  christos {
    289  1.1  christos 
    290  1.1  christos     /* Find all Embedded Controller devices */
    291  1.1  christos 
    292  1.1  christos     AcpiGetDevices ("PNP0C09", AeInstallEcHandler, NULL, NULL);
    293  1.1  christos 
    294  1.1  christos     /* Install a PCI handler */
    295  1.1  christos 
    296  1.1  christos     AcpiGetDevices ("PNP0A08", AeInstallPciHandler, NULL, NULL);
    297  1.1  christos     return (AE_OK);
    298  1.1  christos }
    299  1.1  christos 
    300  1.1  christos 
    301  1.1  christos /******************************************************************************
    302  1.1  christos  *
    303  1.1  christos  * FUNCTION:    AeRegionHandler
    304  1.1  christos  *
    305  1.1  christos  * PARAMETERS:  Standard region handler parameters
    306  1.1  christos  *
    307  1.1  christos  * RETURN:      Status
    308  1.1  christos  *
    309  1.1  christos  * DESCRIPTION: Test handler - Handles some dummy regions via memory that can
    310  1.1  christos  *              be manipulated in Ring 3. Simulates actual reads and writes.
    311  1.1  christos  *
    312  1.1  christos  *****************************************************************************/
    313  1.1  christos 
    314  1.1  christos ACPI_STATUS
    315  1.1  christos AeRegionHandler (
    316  1.1  christos     UINT32                  Function,
    317  1.1  christos     ACPI_PHYSICAL_ADDRESS   Address,
    318  1.1  christos     UINT32                  BitWidth,
    319  1.1  christos     UINT64                  *Value,
    320  1.1  christos     void                    *HandlerContext,
    321  1.1  christos     void                    *RegionContext)
    322  1.1  christos {
    323  1.1  christos 
    324  1.1  christos     ACPI_OPERAND_OBJECT     *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext);
    325  1.1  christos     UINT8                   *Buffer = ACPI_CAST_PTR (UINT8, Value);
    326  1.1  christos     UINT8                   *OldBuffer;
    327  1.1  christos     UINT8                   *NewBuffer;
    328  1.1  christos     ACPI_PHYSICAL_ADDRESS   BaseAddress;
    329  1.1  christos     ACPI_PHYSICAL_ADDRESS   BaseAddressEnd;
    330  1.1  christos     ACPI_PHYSICAL_ADDRESS   RegionAddress;
    331  1.1  christos     ACPI_PHYSICAL_ADDRESS   RegionAddressEnd;
    332  1.1  christos     ACPI_SIZE               Length;
    333  1.1  christos     BOOLEAN                 BufferExists;
    334  1.1  christos     BOOLEAN                 BufferResize;
    335  1.1  christos     AE_REGION               *RegionElement;
    336  1.1  christos     void                    *BufferValue;
    337  1.1  christos     ACPI_STATUS             Status;
    338  1.1  christos     UINT32                  ByteWidth;
    339  1.1  christos     UINT32                  RegionLength;
    340  1.1  christos     UINT32                  i;
    341  1.1  christos     UINT8                   SpaceId;
    342  1.1  christos     ACPI_CONNECTION_INFO    *MyContext;
    343  1.1  christos     UINT32                  Value1;
    344  1.1  christos     UINT32                  Value2;
    345  1.1  christos     ACPI_RESOURCE           *Resource;
    346  1.1  christos 
    347  1.1  christos 
    348  1.1  christos     ACPI_FUNCTION_NAME (AeRegionHandler);
    349  1.1  christos 
    350  1.1  christos     /*
    351  1.1  christos      * If the object is not a region, simply return
    352  1.1  christos      */
    353  1.1  christos     if (RegionObject->Region.Type != ACPI_TYPE_REGION)
    354  1.1  christos     {
    355  1.1  christos         return (AE_OK);
    356  1.1  christos     }
    357  1.1  christos 
    358  1.1  christos     /* Check that we actually got back our context parameter */
    359  1.1  christos 
    360  1.1  christos     if (HandlerContext != &AeMyContext)
    361  1.1  christos     {
    362  1.1  christos         printf ("Region handler received incorrect context %p, should be %p\n",
    363  1.1  christos             HandlerContext, &AeMyContext);
    364  1.1  christos     }
    365  1.1  christos 
    366  1.1  christos     MyContext = ACPI_CAST_PTR (ACPI_CONNECTION_INFO, HandlerContext);
    367  1.1  christos 
    368  1.1  christos     /*
    369  1.1  christos      * Find the region's address space and length before searching
    370  1.1  christos      * the linked list.
    371  1.1  christos      */
    372  1.1  christos     BaseAddress = RegionObject->Region.Address;
    373  1.1  christos     Length = (ACPI_SIZE) RegionObject->Region.Length;
    374  1.1  christos     SpaceId = RegionObject->Region.SpaceId;
    375  1.1  christos 
    376  1.1  christos     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Operation Region request on %s at 0x%X\n",
    377  1.1  christos             AcpiUtGetRegionName (RegionObject->Region.SpaceId),
    378  1.1  christos             (UINT32) Address));
    379  1.1  christos 
    380  1.1  christos     /*
    381  1.1  christos      * Region support can be disabled with the -do option.
    382  1.1  christos      * We use this to support dynamically loaded tables where we pass a valid
    383  1.1  christos      * address to the AML.
    384  1.1  christos      */
    385  1.1  christos     if (AcpiGbl_DbOpt_NoRegionSupport)
    386  1.1  christos     {
    387  1.1  christos         BufferValue = ACPI_TO_POINTER (Address);
    388  1.1  christos         ByteWidth = (BitWidth / 8);
    389  1.1  christos 
    390  1.1  christos         if (BitWidth % 8)
    391  1.1  christos         {
    392  1.1  christos             ByteWidth += 1;
    393  1.1  christos         }
    394  1.1  christos         goto DoFunction;
    395  1.1  christos     }
    396  1.1  christos 
    397  1.1  christos     switch (SpaceId)
    398  1.1  christos     {
    399  1.1  christos     case ACPI_ADR_SPACE_SYSTEM_IO:
    400  1.1  christos         /*
    401  1.1  christos          * For I/O space, exercise the port validation
    402  1.1  christos          * Note: ReadPort currently always returns all ones, length=BitLength
    403  1.1  christos          */
    404  1.1  christos         switch (Function & ACPI_IO_MASK)
    405  1.1  christos         {
    406  1.1  christos         case ACPI_READ:
    407  1.1  christos 
    408  1.1  christos             if (BitWidth == 64)
    409  1.1  christos             {
    410  1.1  christos                 /* Split the 64-bit request into two 32-bit requests */
    411  1.1  christos 
    412  1.1  christos                 Status = AcpiHwReadPort (Address, &Value1, 32);
    413  1.1  christos                 AE_CHECK_OK (AcpiHwReadPort, Status);
    414  1.1  christos                 Status = AcpiHwReadPort (Address+4, &Value2, 32);
    415  1.1  christos                 AE_CHECK_OK (AcpiHwReadPort, Status);
    416  1.1  christos 
    417  1.1  christos                 *Value = Value1 | ((UINT64) Value2 << 32);
    418  1.1  christos             }
    419  1.1  christos             else
    420  1.1  christos             {
    421  1.1  christos                 Status = AcpiHwReadPort (Address, &Value1, BitWidth);
    422  1.1  christos                 AE_CHECK_OK (AcpiHwReadPort, Status);
    423  1.1  christos                 *Value = (UINT64) Value1;
    424  1.1  christos             }
    425  1.1  christos             break;
    426  1.1  christos 
    427  1.1  christos         case ACPI_WRITE:
    428  1.1  christos 
    429  1.1  christos             if (BitWidth == 64)
    430  1.1  christos             {
    431  1.1  christos                 /* Split the 64-bit request into two 32-bit requests */
    432  1.1  christos 
    433  1.1  christos                 Status = AcpiHwWritePort (Address, ACPI_LODWORD (*Value), 32);
    434  1.1  christos                 AE_CHECK_OK (AcpiHwWritePort, Status);
    435  1.1  christos                 Status = AcpiHwWritePort (Address+4, ACPI_HIDWORD (*Value), 32);
    436  1.1  christos                 AE_CHECK_OK (AcpiHwWritePort, Status);
    437  1.1  christos             }
    438  1.1  christos             else
    439  1.1  christos             {
    440  1.1  christos                 Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth);
    441  1.1  christos                 AE_CHECK_OK (AcpiHwWritePort, Status);
    442  1.1  christos             }
    443  1.1  christos             break;
    444  1.1  christos 
    445  1.1  christos         default:
    446  1.1  christos 
    447  1.1  christos             Status = AE_BAD_PARAMETER;
    448  1.1  christos             break;
    449  1.1  christos         }
    450  1.1  christos 
    451  1.1  christos         if (ACPI_FAILURE (Status))
    452  1.1  christos         {
    453  1.1  christos             return (Status);
    454  1.1  christos         }
    455  1.1  christos 
    456  1.1  christos         /* Now go ahead and simulate the hardware */
    457  1.1  christos         break;
    458  1.1  christos 
    459  1.1  christos     /*
    460  1.1  christos      * SMBus and GenericSerialBus support the various bidirectional
    461  1.1  christos      * protocols.
    462  1.1  christos      */
    463  1.1  christos     case ACPI_ADR_SPACE_SMBUS:
    464  1.1  christos     case ACPI_ADR_SPACE_GSBUS:  /* ACPI 5.0 */
    465  1.1  christos 
    466  1.1  christos         Length = 0;
    467  1.1  christos 
    468  1.1  christos         switch (Function & ACPI_IO_MASK)
    469  1.1  christos         {
    470  1.1  christos         case ACPI_READ:
    471  1.1  christos 
    472  1.1  christos             switch (Function >> 16)
    473  1.1  christos             {
    474  1.1  christos             case AML_FIELD_ATTRIB_QUICK:
    475  1.1  christos 
    476  1.1  christos                 Length = 0;
    477  1.1  christos                 break;
    478  1.1  christos 
    479  1.1  christos             case AML_FIELD_ATTRIB_SEND_RCV:
    480  1.1  christos             case AML_FIELD_ATTRIB_BYTE:
    481  1.1  christos 
    482  1.1  christos                 Length = 1;
    483  1.1  christos                 break;
    484  1.1  christos 
    485  1.1  christos             case AML_FIELD_ATTRIB_WORD:
    486  1.1  christos             case AML_FIELD_ATTRIB_WORD_CALL:
    487  1.1  christos 
    488  1.1  christos                 Length = 2;
    489  1.1  christos                 break;
    490  1.1  christos 
    491  1.1  christos             case AML_FIELD_ATTRIB_BLOCK:
    492  1.1  christos             case AML_FIELD_ATTRIB_BLOCK_CALL:
    493  1.1  christos 
    494  1.1  christos                 Length = 32;
    495  1.1  christos                 break;
    496  1.1  christos 
    497  1.1  christos             case AML_FIELD_ATTRIB_MULTIBYTE:
    498  1.1  christos             case AML_FIELD_ATTRIB_RAW_BYTES:
    499  1.1  christos             case AML_FIELD_ATTRIB_RAW_PROCESS:
    500  1.1  christos 
    501  1.1  christos                 Length = MyContext->AccessLength;
    502  1.1  christos                 break;
    503  1.1  christos 
    504  1.1  christos             default:
    505  1.1  christos 
    506  1.1  christos                 break;
    507  1.1  christos             }
    508  1.1  christos             break;
    509  1.1  christos 
    510  1.1  christos         case ACPI_WRITE:
    511  1.1  christos 
    512  1.1  christos             switch (Function >> 16)
    513  1.1  christos             {
    514  1.1  christos             case AML_FIELD_ATTRIB_QUICK:
    515  1.1  christos             case AML_FIELD_ATTRIB_SEND_RCV:
    516  1.1  christos             case AML_FIELD_ATTRIB_BYTE:
    517  1.1  christos             case AML_FIELD_ATTRIB_WORD:
    518  1.1  christos             case AML_FIELD_ATTRIB_BLOCK:
    519  1.1  christos 
    520  1.1  christos                 Length = 0;
    521  1.1  christos                 break;
    522  1.1  christos 
    523  1.1  christos             case AML_FIELD_ATTRIB_WORD_CALL:
    524  1.1  christos                 Length = 2;
    525  1.1  christos                 break;
    526  1.1  christos 
    527  1.1  christos             case AML_FIELD_ATTRIB_BLOCK_CALL:
    528  1.1  christos                 Length = 32;
    529  1.1  christos                 break;
    530  1.1  christos 
    531  1.1  christos             case AML_FIELD_ATTRIB_MULTIBYTE:
    532  1.1  christos             case AML_FIELD_ATTRIB_RAW_BYTES:
    533  1.1  christos             case AML_FIELD_ATTRIB_RAW_PROCESS:
    534  1.1  christos 
    535  1.1  christos                 Length = MyContext->AccessLength;
    536  1.1  christos                 break;
    537  1.1  christos 
    538  1.1  christos             default:
    539  1.1  christos 
    540  1.1  christos                 break;
    541  1.1  christos             }
    542  1.1  christos             break;
    543  1.1  christos 
    544  1.1  christos         default:
    545  1.1  christos 
    546  1.1  christos             break;
    547  1.1  christos         }
    548  1.1  christos 
    549  1.1  christos         if (AcpiGbl_DisplayRegionAccess)
    550  1.1  christos         {
    551  1.1  christos             AcpiOsPrintf ("AcpiExec: %s "
    552  1.1  christos                 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X",
    553  1.1  christos                 AcpiUtGetRegionName (SpaceId),
    554  1.1  christos                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
    555  1.1  christos                 (UINT32) (Function >> 16),
    556  1.1  christos                 (UINT32) Address, (UINT32) BaseAddress,
    557  1.1  christos                 Length, BitWidth, Buffer[1]);
    558  1.1  christos 
    559  1.1  christos             /* GenericSerialBus has a Connection() parameter */
    560  1.1  christos 
    561  1.1  christos             if (SpaceId == ACPI_ADR_SPACE_GSBUS)
    562  1.1  christos             {
    563  1.1  christos                 Status = AcpiBufferToResource (MyContext->Connection,
    564  1.1  christos                     MyContext->Length, &Resource);
    565  1.1  christos 
    566  1.1  christos                 AcpiOsPrintf (" [AccLen %.2X Conn %p]",
    567  1.1  christos                     MyContext->AccessLength, MyContext->Connection);
    568  1.1  christos             }
    569  1.1  christos             AcpiOsPrintf ("\n");
    570  1.1  christos         }
    571  1.1  christos 
    572  1.1  christos         /* Setup the return buffer. Note: ASLTS depends on these fill values */
    573  1.1  christos 
    574  1.1  christos         for (i = 0; i < Length; i++)
    575  1.1  christos         {
    576  1.1  christos             Buffer[i+2] = (UINT8) (0xA0 + i);
    577  1.1  christos         }
    578  1.1  christos 
    579  1.1  christos         Buffer[0] = 0x7A;
    580  1.1  christos         Buffer[1] = (UINT8) Length;
    581  1.1  christos         return (AE_OK);
    582  1.1  christos 
    583  1.1  christos 
    584  1.1  christos     case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */
    585  1.1  christos 
    586  1.1  christos         if (AcpiGbl_DisplayRegionAccess)
    587  1.1  christos         {
    588  1.1  christos             AcpiOsPrintf ("AcpiExec: IPMI "
    589  1.1  christos                 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X\n",
    590  1.1  christos                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
    591  1.1  christos                 (UINT32) (Function >> 16), (UINT32) Address, (UINT32) BaseAddress,
    592  1.1  christos                 Length, BitWidth, Buffer[1]);
    593  1.1  christos         }
    594  1.1  christos 
    595  1.1  christos         /*
    596  1.1  christos          * Regardless of a READ or WRITE, this handler is passed a 66-byte
    597  1.1  christos          * buffer in which to return the IPMI status/length/data.
    598  1.1  christos          *
    599  1.1  christos          * Return some example data to show use of the bidirectional buffer
    600  1.1  christos          */
    601  1.1  christos         Buffer[0] = 0;       /* Status byte */
    602  1.1  christos         Buffer[1] = 64;      /* Return buffer data length */
    603  1.1  christos         Buffer[2] = 0;       /* Completion code */
    604  1.1  christos         Buffer[3] = 0;       /* Reserved */
    605  1.1  christos 
    606  1.1  christos         /*
    607  1.1  christos          * Fill the 66-byte buffer with the return data.
    608  1.1  christos          * Note: ASLTS depends on these fill values.
    609  1.1  christos          */
    610  1.1  christos         for (i = 4; i < 66; i++)
    611  1.1  christos         {
    612  1.1  christos             Buffer[i] = (UINT8) (i);
    613  1.1  christos         }
    614  1.1  christos         return (AE_OK);
    615  1.1  christos 
    616  1.1  christos     /*
    617  1.1  christos      * GPIO has some special semantics:
    618  1.1  christos      * 1) Address is the pin number index into the Connection() pin list
    619  1.1  christos      * 2) BitWidth is the actual number of bits (pins) defined by the field
    620  1.1  christos      */
    621  1.1  christos     case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
    622  1.1  christos 
    623  1.1  christos         if (AcpiGbl_DisplayRegionAccess)
    624  1.1  christos         {
    625  1.1  christos             AcpiOsPrintf ("AcpiExec: GPIO "
    626  1.1  christos                 "%s: Addr %.4X Width %X Conn %p\n",
    627  1.1  christos                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
    628  1.1  christos                 (UINT32) Address, BitWidth, MyContext->Connection);
    629  1.1  christos         }
    630  1.1  christos         return (AE_OK);
    631  1.1  christos 
    632  1.1  christos     default:
    633  1.1  christos         break;
    634  1.1  christos     }
    635  1.1  christos 
    636  1.1  christos     /*
    637  1.1  christos      * Search through the linked list for this region's buffer
    638  1.1  christos      */
    639  1.1  christos     BufferExists = FALSE;
    640  1.1  christos     BufferResize = FALSE;
    641  1.1  christos     RegionElement = AeRegions.RegionList;
    642  1.1  christos 
    643  1.1  christos     if (AeRegions.NumberOfRegions)
    644  1.1  christos     {
    645  1.1  christos         BaseAddressEnd = BaseAddress + Length - 1;
    646  1.1  christos         while (!BufferExists && RegionElement)
    647  1.1  christos         {
    648  1.1  christos             RegionAddress = RegionElement->Address;
    649  1.1  christos             RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1;
    650  1.1  christos             RegionLength = RegionElement->Length;
    651  1.1  christos 
    652  1.1  christos             /*
    653  1.1  christos              * Overlapping Region Support
    654  1.1  christos              *
    655  1.1  christos              * While searching through the region buffer list, determine if an
    656  1.1  christos              * overlap exists between the requested buffer space and the current
    657  1.1  christos              * RegionElement space. If there is an overlap then replace the old
    658  1.1  christos              * buffer with a new buffer of increased size before continuing to
    659  1.1  christos              * do the read or write
    660  1.1  christos              */
    661  1.1  christos             if (RegionElement->SpaceId != SpaceId ||
    662  1.1  christos                 BaseAddressEnd < RegionAddress ||
    663  1.1  christos                 BaseAddress > RegionAddressEnd)
    664  1.1  christos             {
    665  1.1  christos                 /*
    666  1.1  christos                  * Requested buffer is outside of the current RegionElement
    667  1.1  christos                  * bounds
    668  1.1  christos                  */
    669  1.1  christos                 RegionElement = RegionElement->NextRegion;
    670  1.1  christos             }
    671  1.1  christos             else
    672  1.1  christos             {
    673  1.1  christos                 /*
    674  1.1  christos                  * Some amount of buffer space sharing exists. There are 4 cases
    675  1.1  christos                  * to consider:
    676  1.1  christos                  *
    677  1.1  christos                  * 1. Right overlap
    678  1.1  christos                  * 2. Left overlap
    679  1.1  christos                  * 3. Left and right overlap
    680  1.1  christos                  * 4. Fully contained - no resizing required
    681  1.1  christos                  */
    682  1.1  christos                 BufferExists = TRUE;
    683  1.1  christos 
    684  1.1  christos                 if ((BaseAddress >= RegionAddress) &&
    685  1.1  christos                     (BaseAddress <= RegionAddressEnd) &&
    686  1.1  christos                     (BaseAddressEnd > RegionAddressEnd))
    687  1.1  christos                 {
    688  1.1  christos                     /* Right overlap */
    689  1.1  christos 
    690  1.1  christos                     RegionElement->Length = BaseAddress -
    691  1.1  christos                         RegionAddress + Length;
    692  1.1  christos                     BufferResize = TRUE;
    693  1.1  christos                 }
    694  1.1  christos 
    695  1.1  christos                 else if ((BaseAddressEnd >= RegionAddress) &&
    696  1.1  christos                          (BaseAddressEnd <= RegionAddressEnd) &&
    697  1.1  christos                          (BaseAddress < RegionAddress))
    698  1.1  christos                 {
    699  1.1  christos                     /* Left overlap */
    700  1.1  christos 
    701  1.1  christos                     RegionElement->Address = BaseAddress;
    702  1.1  christos                     RegionElement->Length = RegionAddress -
    703  1.1  christos                         BaseAddress + RegionElement->Length;
    704  1.1  christos                     BufferResize = TRUE;
    705  1.1  christos                 }
    706  1.1  christos 
    707  1.1  christos                 else if ((BaseAddress < RegionAddress) &&
    708  1.1  christos                          (BaseAddressEnd > RegionAddressEnd))
    709  1.1  christos                 {
    710  1.1  christos                     /* Left and right overlap */
    711  1.1  christos 
    712  1.1  christos                     RegionElement->Address = BaseAddress;
    713  1.1  christos                     RegionElement->Length = Length;
    714  1.1  christos                     BufferResize = TRUE;
    715  1.1  christos                 }
    716  1.1  christos 
    717  1.1  christos                 /*
    718  1.1  christos                  * only remaining case is fully contained for which we don't
    719  1.1  christos                  * need to do anything
    720  1.1  christos                  */
    721  1.1  christos                 if (BufferResize)
    722  1.1  christos                 {
    723  1.1  christos                     NewBuffer = AcpiOsAllocate (RegionElement->Length);
    724  1.1  christos                     if (!NewBuffer)
    725  1.1  christos                     {
    726  1.1  christos                         return (AE_NO_MEMORY);
    727  1.1  christos                     }
    728  1.1  christos 
    729  1.1  christos                     OldBuffer = RegionElement->Buffer;
    730  1.1  christos                     RegionElement->Buffer = NewBuffer;
    731  1.1  christos                     NewBuffer = NULL;
    732  1.1  christos 
    733  1.1  christos                     /* Initialize the region with the default fill value */
    734  1.1  christos 
    735  1.1  christos                     ACPI_MEMSET (RegionElement->Buffer,
    736  1.1  christos                         AcpiGbl_RegionFillValue, RegionElement->Length);
    737  1.1  christos 
    738  1.1  christos                     /*
    739  1.1  christos                      * Get BufferValue to point (within the new buffer) to the
    740  1.1  christos                      * base address of the old buffer
    741  1.1  christos                      */
    742  1.1  christos                     BufferValue = (UINT8 *) RegionElement->Buffer +
    743  1.1  christos                         (UINT64) RegionAddress -
    744  1.1  christos                         (UINT64) RegionElement->Address;
    745  1.1  christos 
    746  1.1  christos                     /*
    747  1.1  christos                      * Copy the old buffer to its same location within the new
    748  1.1  christos                      * buffer
    749  1.1  christos                      */
    750  1.1  christos                     ACPI_MEMCPY (BufferValue, OldBuffer, RegionLength);
    751  1.1  christos                     AcpiOsFree (OldBuffer);
    752  1.1  christos                 }
    753  1.1  christos             }
    754  1.1  christos         }
    755  1.1  christos     }
    756  1.1  christos 
    757  1.1  christos     /*
    758  1.1  christos      * If the Region buffer does not exist, create it now
    759  1.1  christos      */
    760  1.1  christos     if (!BufferExists)
    761  1.1  christos     {
    762  1.1  christos         /* Do the memory allocations first */
    763  1.1  christos 
    764  1.1  christos         RegionElement = AcpiOsAllocate (sizeof (AE_REGION));
    765  1.1  christos         if (!RegionElement)
    766  1.1  christos         {
    767  1.1  christos             return (AE_NO_MEMORY);
    768  1.1  christos         }
    769  1.1  christos 
    770  1.1  christos         RegionElement->Buffer = AcpiOsAllocate (Length);
    771  1.1  christos         if (!RegionElement->Buffer)
    772  1.1  christos         {
    773  1.1  christos             AcpiOsFree (RegionElement);
    774  1.1  christos             return (AE_NO_MEMORY);
    775  1.1  christos         }
    776  1.1  christos 
    777  1.1  christos         /* Initialize the region with the default fill value */
    778  1.1  christos 
    779  1.1  christos         ACPI_MEMSET (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length);
    780  1.1  christos 
    781  1.1  christos         RegionElement->Address      = BaseAddress;
    782  1.1  christos         RegionElement->Length       = Length;
    783  1.1  christos         RegionElement->SpaceId      = SpaceId;
    784  1.1  christos         RegionElement->NextRegion   = NULL;
    785  1.1  christos 
    786  1.1  christos         /*
    787  1.1  christos          * Increment the number of regions and put this one
    788  1.1  christos          * at the head of the list as it will probably get accessed
    789  1.1  christos          * more often anyway.
    790  1.1  christos          */
    791  1.1  christos         AeRegions.NumberOfRegions += 1;
    792  1.1  christos 
    793  1.1  christos         if (AeRegions.RegionList)
    794  1.1  christos         {
    795  1.1  christos             RegionElement->NextRegion = AeRegions.RegionList;
    796  1.1  christos         }
    797  1.1  christos 
    798  1.1  christos         AeRegions.RegionList = RegionElement;
    799  1.1  christos     }
    800  1.1  christos 
    801  1.1  christos     /* Calculate the size of the memory copy */
    802  1.1  christos 
    803  1.1  christos     ByteWidth = (BitWidth / 8);
    804  1.1  christos 
    805  1.1  christos     if (BitWidth % 8)
    806  1.1  christos     {
    807  1.1  christos         ByteWidth += 1;
    808  1.1  christos     }
    809  1.1  christos 
    810  1.1  christos     /*
    811  1.1  christos      * The buffer exists and is pointed to by RegionElement.
    812  1.1  christos      * We now need to verify the request is valid and perform the operation.
    813  1.1  christos      *
    814  1.1  christos      * NOTE: RegionElement->Length is in bytes, therefore it we compare against
    815  1.1  christos      * ByteWidth (see above)
    816  1.1  christos      */
    817  1.1  christos     if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) &&
    818  1.1  christos         ((UINT64) Address + ByteWidth) >
    819  1.1  christos         ((UINT64)(RegionElement->Address) + RegionElement->Length))
    820  1.1  christos     {
    821  1.1  christos         ACPI_WARNING ((AE_INFO,
    822  1.1  christos             "Request on [%4.4s] is beyond region limit Req-0x%X+0x%X, Base=0x%X, Len-0x%X",
    823  1.1  christos             (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address,
    824  1.1  christos             ByteWidth, (UINT32)(RegionElement->Address),
    825  1.1  christos             RegionElement->Length));
    826  1.1  christos 
    827  1.1  christos         return (AE_AML_REGION_LIMIT);
    828  1.1  christos     }
    829  1.1  christos 
    830  1.1  christos     /*
    831  1.1  christos      * Get BufferValue to point to the "address" in the buffer
    832  1.1  christos      */
    833  1.1  christos     BufferValue = ((UINT8 *) RegionElement->Buffer +
    834  1.1  christos                     ((UINT64) Address - (UINT64) RegionElement->Address));
    835  1.1  christos 
    836  1.1  christos DoFunction:
    837  1.1  christos     /*
    838  1.1  christos      * Perform a read or write to the buffer space
    839  1.1  christos      */
    840  1.1  christos     switch (Function)
    841  1.1  christos     {
    842  1.1  christos     case ACPI_READ:
    843  1.1  christos         /*
    844  1.1  christos          * Set the pointer Value to whatever is in the buffer
    845  1.1  christos          */
    846  1.1  christos         ACPI_MEMCPY (Value, BufferValue, ByteWidth);
    847  1.1  christos         break;
    848  1.1  christos 
    849  1.1  christos     case ACPI_WRITE:
    850  1.1  christos         /*
    851  1.1  christos          * Write the contents of Value to the buffer
    852  1.1  christos          */
    853  1.1  christos         ACPI_MEMCPY (BufferValue, Value, ByteWidth);
    854  1.1  christos         break;
    855  1.1  christos 
    856  1.1  christos     default:
    857  1.1  christos 
    858  1.1  christos         return (AE_BAD_PARAMETER);
    859  1.1  christos     }
    860  1.1  christos 
    861  1.1  christos     if (AcpiGbl_DisplayRegionAccess)
    862  1.1  christos     {
    863  1.1  christos         switch (SpaceId)
    864  1.1  christos         {
    865  1.1  christos         case ACPI_ADR_SPACE_SYSTEM_MEMORY:
    866  1.1  christos 
    867  1.1  christos             AcpiOsPrintf ("AcpiExec: SystemMemory "
    868  1.1  christos                 "%s: Val %.8X Addr %.4X Width %X [REGION: BaseAddr %.4X Len %.2X]\n",
    869  1.1  christos                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
    870  1.1  christos                 (UINT32) *Value, (UINT32) Address, BitWidth, (UINT32) BaseAddress, Length);
    871  1.1  christos             break;
    872  1.1  christos 
    873  1.1  christos         case ACPI_ADR_SPACE_GPIO:   /* ACPI 5.0 */
    874  1.1  christos 
    875  1.1  christos             /* This space is required to always be ByteAcc */
    876  1.1  christos 
    877  1.1  christos             Status = AcpiBufferToResource (MyContext->Connection,
    878  1.1  christos                 MyContext->Length, &Resource);
    879  1.1  christos 
    880  1.1  christos             AcpiOsPrintf ("AcpiExec: GeneralPurposeIo "
    881  1.1  christos                 "%s: Val %.8X Addr %.4X BaseAddr %.4X Len %.2X Width %X AccLen %.2X Conn %p\n",
    882  1.1  christos                 (Function & ACPI_IO_MASK) ? "Write" : "Read ", (UINT32) *Value,
    883  1.1  christos                 (UINT32) Address, (UINT32) BaseAddress, Length, BitWidth,
    884  1.1  christos                 MyContext->AccessLength, MyContext->Connection);
    885  1.1  christos             break;
    886  1.1  christos 
    887  1.1  christos         default:
    888  1.1  christos 
    889  1.1  christos             break;
    890  1.1  christos         }
    891  1.1  christos     }
    892  1.1  christos 
    893  1.1  christos     return (AE_OK);
    894  1.1  christos }
    895