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 }