1 /******************************************************************************
   2  *
   3  * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2014, Intel Corp.
   9  * All rights reserved.
  10  *
  11  * Redistribution and use in source and binary forms, with or without
  12  * modification, are permitted provided that the following conditions
  13  * are met:
  14  * 1. Redistributions of source code must retain the above copyright
  15  *    notice, this list of conditions, and the following disclaimer,
  16  *    without modification.
  17  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
  18  *    substantially similar to the "NO WARRANTY" disclaimer below
  19  *    ("Disclaimer") and any redistribution must be conditioned upon
  20  *    including a substantially similar Disclaimer requirement for further
  21  *    binary redistribution.
  22  * 3. Neither the names of the above-listed copyright holders nor the names
  23  *    of any contributors may be used to endorse or promote products derived
  24  *    from this software without specific prior written permission.
  25  *
  26  * Alternatively, this software may be distributed under the terms of the
  27  * GNU General Public License ("GPL") version 2 as published by the Free
  28  * Software Foundation.
  29  *
  30  * NO WARRANTY
  31  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  32  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  33  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR
  34  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  35  * HOLDERS OR CONTRIBUTORS BE LIABLE FOR SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  36  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  37  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  38  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  39  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
  40  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
  41  * POSSIBILITY OF SUCH DAMAGES.
  42  */
  43 
  44 
  45 #define __EXFIELD_C__
  46 
  47 #include "acpi.h"
  48 #include "accommon.h"
  49 #include "acdispat.h"
  50 #include "acinterp.h"
  51 
  52 
  53 #define _COMPONENT          ACPI_EXECUTER
  54         ACPI_MODULE_NAME    ("exfield")
  55 
  56 
  57 /*******************************************************************************
  58  *
  59  * FUNCTION:    AcpiExReadDataFromField
  60  *
  61  * PARAMETERS:  WalkState           - Current execution state
  62  *              ObjDesc             - The named field
  63  *              RetBufferDesc       - Where the return data object is stored
  64  *
  65  * RETURN:      Status
  66  *
  67  * DESCRIPTION: Read from a named field. Returns either an Integer or a
  68  *              Buffer, depending on the size of the field.
  69  *
  70  ******************************************************************************/
  71 
  72 ACPI_STATUS
  73 AcpiExReadDataFromField (
  74     ACPI_WALK_STATE         *WalkState,
  75     ACPI_OPERAND_OBJECT     *ObjDesc,
  76     ACPI_OPERAND_OBJECT     **RetBufferDesc)
  77 {
  78     ACPI_STATUS             Status;
  79     ACPI_OPERAND_OBJECT     *BufferDesc;
  80     ACPI_SIZE               Length;
  81     void                    *Buffer;
  82     UINT32                  Function;
  83 
  84 
  85     ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc);
  86 
  87 
  88     /* Parameter validation */
  89 
  90     if (!ObjDesc)
  91     {
  92         return_ACPI_STATUS (AE_AML_NO_OPERAND);
  93     }
  94     if (!RetBufferDesc)
  95     {
  96         return_ACPI_STATUS (AE_BAD_PARAMETER);
  97     }
  98 
  99     if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
 100     {
 101         /*
 102          * If the BufferField arguments have not been previously evaluated,
 103          * evaluate them now and save the results.
 104          */
 105         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
 106         {
 107             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
 108             if (ACPI_FAILURE (Status))
 109             {
 110                 return_ACPI_STATUS (Status);
 111             }
 112         }
 113     }
 114     else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 115              (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
 116               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
 117               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
 118     {
 119         /*
 120          * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold
 121          * the data and then directly access the region handler.
 122          *
 123          * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function
 124          */
 125         if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
 126         {
 127             Length = ACPI_SMBUS_BUFFER_SIZE;
 128             Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
 129         }
 130         else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
 131         {
 132             Length = ACPI_GSBUS_BUFFER_SIZE;
 133             Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
 134         }
 135         else /* IPMI */
 136         {
 137             Length = ACPI_IPMI_BUFFER_SIZE;
 138             Function = ACPI_READ;
 139         }
 140 
 141         BufferDesc = AcpiUtCreateBufferObject (Length);
 142         if (!BufferDesc)
 143         {
 144             return_ACPI_STATUS (AE_NO_MEMORY);
 145         }
 146 
 147         /* Lock entire transaction if requested */
 148 
 149         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 150 
 151         /* Call the region handler for the read */
 152 
 153         Status = AcpiExAccessRegion (ObjDesc, 0,
 154                     ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
 155                     Function);
 156         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 157         goto Exit;
 158     }
 159 
 160     /*
 161      * Allocate a buffer for the contents of the field.
 162      *
 163      * If the field is larger than the current integer width, create
 164      * a BUFFER to hold it. Otherwise, use an INTEGER. This allows
 165      * the use of arithmetic operators on the returned value if the
 166      * field size is equal or smaller than an Integer.
 167      *
 168      * Note: Field.length is in bits.
 169      */
 170     Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
 171     if (Length > AcpiGbl_IntegerByteWidth)
 172     {
 173         /* Field is too large for an Integer, create a Buffer instead */
 174 
 175         BufferDesc = AcpiUtCreateBufferObject (Length);
 176         if (!BufferDesc)
 177         {
 178             return_ACPI_STATUS (AE_NO_MEMORY);
 179         }
 180         Buffer = BufferDesc->Buffer.Pointer;
 181     }
 182     else
 183     {
 184         /* Field will fit within an Integer (normal case) */
 185 
 186         BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
 187         if (!BufferDesc)
 188         {
 189             return_ACPI_STATUS (AE_NO_MEMORY);
 190         }
 191 
 192         Length = AcpiGbl_IntegerByteWidth;
 193         Buffer = &BufferDesc->Integer.Value;
 194     }
 195 
 196     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 197         "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
 198         ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
 199     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 200         "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
 201         ObjDesc->CommonField.BitLength,
 202         ObjDesc->CommonField.StartFieldBitOffset,
 203         ObjDesc->CommonField.BaseByteOffset));
 204 
 205     /* Lock entire transaction if requested */
 206 
 207     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 208 
 209     /* Read from the field */
 210 
 211     Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
 212     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 213 
 214 
 215 Exit:
 216     if (ACPI_FAILURE (Status))
 217     {
 218         AcpiUtRemoveReference (BufferDesc);
 219     }
 220     else
 221     {
 222         *RetBufferDesc = BufferDesc;
 223     }
 224 
 225     return_ACPI_STATUS (Status);
 226 }
 227 
 228 
 229 /*******************************************************************************
 230  *
 231  * FUNCTION:    AcpiExWriteDataToField
 232  *
 233  * PARAMETERS:  SourceDesc          - Contains data to write
 234  *              ObjDesc             - The named field
 235  *              ResultDesc          - Where the return value is returned, if any
 236  *
 237  * RETURN:      Status
 238  *
 239  * DESCRIPTION: Write to a named field
 240  *
 241  ******************************************************************************/
 242 
 243 ACPI_STATUS
 244 AcpiExWriteDataToField (
 245     ACPI_OPERAND_OBJECT     *SourceDesc,
 246     ACPI_OPERAND_OBJECT     *ObjDesc,
 247     ACPI_OPERAND_OBJECT     **ResultDesc)
 248 {
 249     ACPI_STATUS             Status;
 250     UINT32                  Length;
 251     void                    *Buffer;
 252     ACPI_OPERAND_OBJECT     *BufferDesc;
 253     UINT32                  Function;
 254 
 255 
 256     ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
 257 
 258 
 259     /* Parameter validation */
 260 
 261     if (!SourceDesc || !ObjDesc)
 262     {
 263         return_ACPI_STATUS (AE_AML_NO_OPERAND);
 264     }
 265 
 266     if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
 267     {
 268         /*
 269          * If the BufferField arguments have not been previously evaluated,
 270          * evaluate them now and save the results.
 271          */
 272         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
 273         {
 274             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
 275             if (ACPI_FAILURE (Status))
 276             {
 277                 return_ACPI_STATUS (Status);
 278             }
 279         }
 280     }
 281     else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 282              (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
 283               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS ||
 284               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
 285     {
 286         /*
 287          * This is an SMBus, GSBus or IPMI write. We will bypass the entire field
 288          * mechanism and handoff the buffer directly to the handler. For
 289          * these address spaces, the buffer is bi-directional; on a write,
 290          * return data is returned in the same buffer.
 291          *
 292          * Source must be a buffer of sufficient size:
 293          * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE.
 294          *
 295          * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function
 296          */
 297         if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
 298         {
 299             ACPI_ERROR ((AE_INFO,
 300                 "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s",
 301                 AcpiUtGetObjectTypeName (SourceDesc)));
 302 
 303             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 304         }
 305 
 306         if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
 307         {
 308             Length = ACPI_SMBUS_BUFFER_SIZE;
 309             Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
 310         }
 311         else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS)
 312         {
 313             Length = ACPI_GSBUS_BUFFER_SIZE;
 314             Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
 315         }
 316         else /* IPMI */
 317         {
 318             Length = ACPI_IPMI_BUFFER_SIZE;
 319             Function = ACPI_WRITE;
 320         }
 321 
 322         if (SourceDesc->Buffer.Length < Length)
 323         {
 324             ACPI_ERROR ((AE_INFO,
 325                 "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u",
 326                 Length, SourceDesc->Buffer.Length));
 327 
 328             return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
 329         }
 330 
 331         /* Create the bi-directional buffer */
 332 
 333         BufferDesc = AcpiUtCreateBufferObject (Length);
 334         if (!BufferDesc)
 335         {
 336             return_ACPI_STATUS (AE_NO_MEMORY);
 337         }
 338 
 339         Buffer = BufferDesc->Buffer.Pointer;
 340         ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
 341 
 342         /* Lock entire transaction if requested */
 343 
 344         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 345 
 346         /*
 347          * Perform the write (returns status and perhaps data in the
 348          * same buffer)
 349          */
 350         Status = AcpiExAccessRegion (ObjDesc, 0,
 351                     (UINT64 *) Buffer, Function);
 352         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 353 
 354         *ResultDesc = BufferDesc;
 355         return_ACPI_STATUS (Status);
 356     }
 357 
 358     /* Get a pointer to the data to be written */
 359 
 360     switch (SourceDesc->Common.Type)
 361     {
 362     case ACPI_TYPE_INTEGER:
 363 
 364         Buffer = &SourceDesc->Integer.Value;
 365         Length = sizeof (SourceDesc->Integer.Value);
 366         break;
 367 
 368     case ACPI_TYPE_BUFFER:
 369 
 370         Buffer = SourceDesc->Buffer.Pointer;
 371         Length = SourceDesc->Buffer.Length;
 372         break;
 373 
 374     case ACPI_TYPE_STRING:
 375 
 376         Buffer = SourceDesc->String.Pointer;
 377         Length = SourceDesc->String.Length;
 378         break;
 379 
 380     default:
 381 
 382         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 383     }
 384 
 385     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 386         "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
 387         SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
 388         SourceDesc->Common.Type, Buffer, Length));
 389 
 390     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 391         "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
 392         ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
 393         ObjDesc->Common.Type,
 394         ObjDesc->CommonField.BitLength,
 395         ObjDesc->CommonField.StartFieldBitOffset,
 396         ObjDesc->CommonField.BaseByteOffset));
 397 
 398     /* Lock entire transaction if requested */
 399 
 400     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 401 
 402     /* Write to the field */
 403 
 404     Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
 405     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 406 
 407     return_ACPI_STATUS (Status);
 408 }