1 /******************************************************************************
   2  *
   3  * Module Name: exfield - ACPI AML (p-code) execution - field manipulation
   4  *
   5  *****************************************************************************/
   6 
   7 /*
   8  * Copyright (C) 2000 - 2011, 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_IPMI))
 117     {
 118         /*
 119          * This is an SMBus or IPMI read. We must create a buffer to hold
 120          * the data and then directly access the region handler.
 121          *
 122          * Note: Smbus protocol value is passed in upper 16-bits of Function
 123          */
 124         if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
 125         {
 126             Length = ACPI_SMBUS_BUFFER_SIZE;
 127             Function = ACPI_READ | (ObjDesc->Field.Attribute << 16);
 128         }
 129         else /* IPMI */
 130         {
 131             Length = ACPI_IPMI_BUFFER_SIZE;
 132             Function = ACPI_READ;
 133         }
 134 
 135         BufferDesc = AcpiUtCreateBufferObject (Length);
 136         if (!BufferDesc)
 137         {
 138             return_ACPI_STATUS (AE_NO_MEMORY);
 139         }
 140 
 141         /* Lock entire transaction if requested */
 142 
 143         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 144 
 145         /* Call the region handler for the read */
 146 
 147         Status = AcpiExAccessRegion (ObjDesc, 0,
 148                     ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer),
 149                     Function);
 150         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 151         goto Exit;
 152     }
 153 
 154     /*
 155      * Allocate a buffer for the contents of the field.
 156      *
 157      * If the field is larger than the current integer width, create
 158      * a BUFFER to hold it.  Otherwise, use an INTEGER.  This allows
 159      * the use of arithmetic operators on the returned value if the
 160      * field size is equal or smaller than an Integer.
 161      *
 162      * Note: Field.length is in bits.
 163      */
 164     Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength);
 165     if (Length > AcpiGbl_IntegerByteWidth)
 166     {
 167         /* Field is too large for an Integer, create a Buffer instead */
 168 
 169         BufferDesc = AcpiUtCreateBufferObject (Length);
 170         if (!BufferDesc)
 171         {
 172             return_ACPI_STATUS (AE_NO_MEMORY);
 173         }
 174         Buffer = BufferDesc->Buffer.Pointer;
 175     }
 176     else
 177     {
 178         /* Field will fit within an Integer (normal case) */
 179 
 180         BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0);
 181         if (!BufferDesc)
 182         {
 183             return_ACPI_STATUS (AE_NO_MEMORY);
 184         }
 185 
 186         Length = AcpiGbl_IntegerByteWidth;
 187         Buffer = &BufferDesc->Integer.Value;
 188     }
 189 
 190     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 191         "FieldRead [TO]:   Obj %p, Type %X, Buf %p, ByteLen %X\n",
 192         ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length));
 193     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 194         "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n",
 195         ObjDesc->CommonField.BitLength,
 196         ObjDesc->CommonField.StartFieldBitOffset,
 197         ObjDesc->CommonField.BaseByteOffset));
 198 
 199     /* Lock entire transaction if requested */
 200 
 201     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 202 
 203     /* Read from the field */
 204 
 205     Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length);
 206     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 207 
 208 
 209 Exit:
 210     if (ACPI_FAILURE (Status))
 211     {
 212         AcpiUtRemoveReference (BufferDesc);
 213     }
 214     else
 215     {
 216         *RetBufferDesc = BufferDesc;
 217     }
 218 
 219     return_ACPI_STATUS (Status);
 220 }
 221 
 222 
 223 /*******************************************************************************
 224  *
 225  * FUNCTION:    AcpiExWriteDataToField
 226  *
 227  * PARAMETERS:  SourceDesc          - Contains data to write
 228  *              ObjDesc             - The named field
 229  *              ResultDesc          - Where the return value is returned, if any
 230  *
 231  * RETURN:      Status
 232  *
 233  * DESCRIPTION: Write to a named field
 234  *
 235  ******************************************************************************/
 236 
 237 ACPI_STATUS
 238 AcpiExWriteDataToField (
 239     ACPI_OPERAND_OBJECT     *SourceDesc,
 240     ACPI_OPERAND_OBJECT     *ObjDesc,
 241     ACPI_OPERAND_OBJECT     **ResultDesc)
 242 {
 243     ACPI_STATUS             Status;
 244     UINT32                  Length;
 245     void                    *Buffer;
 246     ACPI_OPERAND_OBJECT     *BufferDesc;
 247     UINT32                  Function;
 248 
 249 
 250     ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc);
 251 
 252 
 253     /* Parameter validation */
 254 
 255     if (!SourceDesc || !ObjDesc)
 256     {
 257         return_ACPI_STATUS (AE_AML_NO_OPERAND);
 258     }
 259 
 260     if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD)
 261     {
 262         /*
 263          * If the BufferField arguments have not been previously evaluated,
 264          * evaluate them now and save the results.
 265          */
 266         if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID))
 267         {
 268             Status = AcpiDsGetBufferFieldArguments (ObjDesc);
 269             if (ACPI_FAILURE (Status))
 270             {
 271                 return_ACPI_STATUS (Status);
 272             }
 273         }
 274     }
 275     else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) &&
 276              (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS ||
 277               ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI))
 278     {
 279         /*
 280          * This is an SMBus or IPMI write. We will bypass the entire field
 281          * mechanism and handoff the buffer directly to the handler. For
 282          * these address spaces, the buffer is bi-directional; on a write,
 283          * return data is returned in the same buffer.
 284          *
 285          * Source must be a buffer of sufficient size:
 286          * ACPI_SMBUS_BUFFER_SIZE or ACPI_IPMI_BUFFER_SIZE.
 287          *
 288          * Note: SMBus protocol type is passed in upper 16-bits of Function
 289          */
 290         if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER)
 291         {
 292             ACPI_ERROR ((AE_INFO,
 293                 "SMBus or IPMI write requires Buffer, found type %s",
 294                 AcpiUtGetObjectTypeName (SourceDesc)));
 295 
 296             return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 297         }
 298 
 299         if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS)
 300         {
 301             Length = ACPI_SMBUS_BUFFER_SIZE;
 302             Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16);
 303         }
 304         else /* IPMI */
 305         {
 306             Length = ACPI_IPMI_BUFFER_SIZE;
 307             Function = ACPI_WRITE;
 308         }
 309 
 310         if (SourceDesc->Buffer.Length < Length)
 311         {
 312             ACPI_ERROR ((AE_INFO,
 313                 "SMBus or IPMI write requires Buffer of length %u, found length %u",
 314                 Length, SourceDesc->Buffer.Length));
 315 
 316             return_ACPI_STATUS (AE_AML_BUFFER_LIMIT);
 317         }
 318 
 319         /* Create the bi-directional buffer */
 320 
 321         BufferDesc = AcpiUtCreateBufferObject (Length);
 322         if (!BufferDesc)
 323         {
 324             return_ACPI_STATUS (AE_NO_MEMORY);
 325         }
 326 
 327         Buffer = BufferDesc->Buffer.Pointer;
 328         ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length);
 329 
 330         /* Lock entire transaction if requested */
 331 
 332         AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 333 
 334         /*
 335          * Perform the write (returns status and perhaps data in the
 336          * same buffer)
 337          */
 338         Status = AcpiExAccessRegion (ObjDesc, 0,
 339                     (UINT64 *) Buffer, Function);
 340         AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 341 
 342         *ResultDesc = BufferDesc;
 343         return_ACPI_STATUS (Status);
 344     }
 345 
 346     /* Get a pointer to the data to be written */
 347 
 348     switch (SourceDesc->Common.Type)
 349     {
 350     case ACPI_TYPE_INTEGER:
 351         Buffer = &SourceDesc->Integer.Value;
 352         Length = sizeof (SourceDesc->Integer.Value);
 353         break;
 354 
 355     case ACPI_TYPE_BUFFER:
 356         Buffer = SourceDesc->Buffer.Pointer;
 357         Length = SourceDesc->Buffer.Length;
 358         break;
 359 
 360     case ACPI_TYPE_STRING:
 361         Buffer = SourceDesc->String.Pointer;
 362         Length = SourceDesc->String.Length;
 363         break;
 364 
 365     default:
 366         return_ACPI_STATUS (AE_AML_OPERAND_TYPE);
 367     }
 368 
 369     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 370         "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n",
 371         SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type),
 372         SourceDesc->Common.Type, Buffer, Length));
 373 
 374     ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD,
 375         "FieldWrite [TO]:   Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n",
 376         ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type),
 377         ObjDesc->Common.Type,
 378         ObjDesc->CommonField.BitLength,
 379         ObjDesc->CommonField.StartFieldBitOffset,
 380         ObjDesc->CommonField.BaseByteOffset));
 381 
 382     /* Lock entire transaction if requested */
 383 
 384     AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags);
 385 
 386     /* Write to the field */
 387 
 388     Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length);
 389     AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags);
 390 
 391     return_ACPI_STATUS (Status);
 392 }
 393 
 394