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 #define __EXFIELD_C__ 45 46 #include "acpi.h" 47 #include "accommon.h" 48 #include "acdispat.h" 49 #include "acinterp.h" 50 #include "amlcode.h" 51 52 53 #define _COMPONENT ACPI_EXECUTER 54 ACPI_MODULE_NAME ("exfield") 55 56 /* Local prototypes */ 57 58 static UINT32 59 AcpiExGetSerialAccessLength ( 60 UINT32 AccessorType, 61 UINT32 AccessLength); 62 63 64 /******************************************************************************* 65 * 66 * FUNCTION: AcpiExGetSerialAccessLength 67 * 68 * PARAMETERS: AccessorType - The type of the protocol indicated by region 69 * field access attributes 70 * AccessLength - The access length of the region field 71 * 72 * RETURN: Decoded access length 73 * 74 * DESCRIPTION: This routine returns the length of the GenericSerialBus 75 * protocol bytes 76 * 77 ******************************************************************************/ 78 79 static UINT32 80 AcpiExGetSerialAccessLength ( 81 UINT32 AccessorType, 82 UINT32 AccessLength) 83 { 84 UINT32 Length; 85 86 87 switch (AccessorType) 88 { 89 case AML_FIELD_ATTRIB_QUICK: 90 91 Length = 0; 92 break; 93 94 case AML_FIELD_ATTRIB_SEND_RCV: 95 case AML_FIELD_ATTRIB_BYTE: 96 97 Length = 1; 98 break; 99 100 case AML_FIELD_ATTRIB_WORD: 101 case AML_FIELD_ATTRIB_WORD_CALL: 102 103 Length = 2; 104 break; 105 106 case AML_FIELD_ATTRIB_MULTIBYTE: 107 case AML_FIELD_ATTRIB_RAW_BYTES: 108 case AML_FIELD_ATTRIB_RAW_PROCESS: 109 110 Length = AccessLength; 111 break; 112 113 case AML_FIELD_ATTRIB_BLOCK: 114 case AML_FIELD_ATTRIB_BLOCK_CALL: 115 default: 116 117 Length = ACPI_GSBUS_BUFFER_SIZE - 2; 118 break; 119 } 120 121 return (Length); 122 } 123 124 125 /******************************************************************************* 126 * 127 * FUNCTION: AcpiExReadDataFromField 128 * 129 * PARAMETERS: WalkState - Current execution state 130 * ObjDesc - The named field 131 * RetBufferDesc - Where the return data object is stored 132 * 133 * RETURN: Status 134 * 135 * DESCRIPTION: Read from a named field. Returns either an Integer or a 136 * Buffer, depending on the size of the field. 137 * 138 ******************************************************************************/ 139 140 ACPI_STATUS 141 AcpiExReadDataFromField ( 142 ACPI_WALK_STATE *WalkState, 143 ACPI_OPERAND_OBJECT *ObjDesc, 144 ACPI_OPERAND_OBJECT **RetBufferDesc) 145 { 146 ACPI_STATUS Status; 147 ACPI_OPERAND_OBJECT *BufferDesc; 148 ACPI_SIZE Length; 149 void *Buffer; 150 UINT32 Function; 151 UINT16 AccessorType; 152 153 154 ACPI_FUNCTION_TRACE_PTR (ExReadDataFromField, ObjDesc); 155 156 157 /* Parameter validation */ 158 159 if (!ObjDesc) 160 { 161 return_ACPI_STATUS (AE_AML_NO_OPERAND); 162 } 163 if (!RetBufferDesc) 164 { 165 return_ACPI_STATUS (AE_BAD_PARAMETER); 166 } 167 168 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 169 { 170 /* 171 * If the BufferField arguments have not been previously evaluated, 172 * evaluate them now and save the results. 173 */ 174 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 175 { 176 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 177 if (ACPI_FAILURE (Status)) 178 { 179 return_ACPI_STATUS (Status); 180 } 181 } 182 } 183 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 184 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 185 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || 186 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 187 { 188 /* 189 * This is an SMBus, GSBus or IPMI read. We must create a buffer to hold 190 * the data and then directly access the region handler. 191 * 192 * Note: SMBus and GSBus protocol value is passed in upper 16-bits of Function 193 */ 194 if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 195 { 196 Length = ACPI_SMBUS_BUFFER_SIZE; 197 Function = ACPI_READ | (ObjDesc->Field.Attribute << 16); 198 } 199 else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) 200 { 201 AccessorType = ObjDesc->Field.Attribute; 202 Length = AcpiExGetSerialAccessLength (AccessorType, 203 ObjDesc->Field.AccessLength); 204 205 /* 206 * Add additional 2 bytes for the GenericSerialBus data buffer: 207 * 208 * Status; (Byte 0 of the data buffer) 209 * Length; (Byte 1 of the data buffer) 210 * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) 211 */ 212 Length += 2; 213 Function = ACPI_READ | (AccessorType << 16); 214 } 215 else /* IPMI */ 216 { 217 Length = ACPI_IPMI_BUFFER_SIZE; 218 Function = ACPI_READ; 219 } 220 221 BufferDesc = AcpiUtCreateBufferObject (Length); 222 if (!BufferDesc) 223 { 224 return_ACPI_STATUS (AE_NO_MEMORY); 225 } 226 227 /* Lock entire transaction if requested */ 228 229 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 230 231 /* Call the region handler for the read */ 232 233 Status = AcpiExAccessRegion (ObjDesc, 0, 234 ACPI_CAST_PTR (UINT64, BufferDesc->Buffer.Pointer), 235 Function); 236 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 237 goto Exit; 238 } 239 240 /* 241 * Allocate a buffer for the contents of the field. 242 * 243 * If the field is larger than the current integer width, create 244 * a BUFFER to hold it. Otherwise, use an INTEGER. This allows 245 * the use of arithmetic operators on the returned value if the 246 * field size is equal or smaller than an Integer. 247 * 248 * Note: Field.length is in bits. 249 */ 250 Length = (ACPI_SIZE) ACPI_ROUND_BITS_UP_TO_BYTES (ObjDesc->Field.BitLength); 251 if (Length > AcpiGbl_IntegerByteWidth) 252 { 253 /* Field is too large for an Integer, create a Buffer instead */ 254 255 BufferDesc = AcpiUtCreateBufferObject (Length); 256 if (!BufferDesc) 257 { 258 return_ACPI_STATUS (AE_NO_MEMORY); 259 } 260 Buffer = BufferDesc->Buffer.Pointer; 261 } 262 else 263 { 264 /* Field will fit within an Integer (normal case) */ 265 266 BufferDesc = AcpiUtCreateIntegerObject ((UINT64) 0); 267 if (!BufferDesc) 268 { 269 return_ACPI_STATUS (AE_NO_MEMORY); 270 } 271 272 Length = AcpiGbl_IntegerByteWidth; 273 Buffer = &BufferDesc->Integer.Value; 274 } 275 276 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 277 "FieldRead [TO]: Obj %p, Type %X, Buf %p, ByteLen %X\n", 278 ObjDesc, ObjDesc->Common.Type, Buffer, (UINT32) Length)); 279 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 280 "FieldRead [FROM]: BitLen %X, BitOff %X, ByteOff %X\n", 281 ObjDesc->CommonField.BitLength, 282 ObjDesc->CommonField.StartFieldBitOffset, 283 ObjDesc->CommonField.BaseByteOffset)); 284 285 /* Lock entire transaction if requested */ 286 287 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 288 289 /* Read from the field */ 290 291 Status = AcpiExExtractFromField (ObjDesc, Buffer, (UINT32) Length); 292 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 293 294 295 Exit: 296 if (ACPI_FAILURE (Status)) 297 { 298 AcpiUtRemoveReference (BufferDesc); 299 } 300 else 301 { 302 *RetBufferDesc = BufferDesc; 303 } 304 305 return_ACPI_STATUS (Status); 306 } 307 308 309 /******************************************************************************* 310 * 311 * FUNCTION: AcpiExWriteDataToField 312 * 313 * PARAMETERS: SourceDesc - Contains data to write 314 * ObjDesc - The named field 315 * ResultDesc - Where the return value is returned, if any 316 * 317 * RETURN: Status 318 * 319 * DESCRIPTION: Write to a named field 320 * 321 ******************************************************************************/ 322 323 ACPI_STATUS 324 AcpiExWriteDataToField ( 325 ACPI_OPERAND_OBJECT *SourceDesc, 326 ACPI_OPERAND_OBJECT *ObjDesc, 327 ACPI_OPERAND_OBJECT **ResultDesc) 328 { 329 ACPI_STATUS Status; 330 UINT32 Length; 331 void *Buffer; 332 ACPI_OPERAND_OBJECT *BufferDesc; 333 UINT32 Function; 334 UINT16 AccessorType; 335 336 337 ACPI_FUNCTION_TRACE_PTR (ExWriteDataToField, ObjDesc); 338 339 340 /* Parameter validation */ 341 342 if (!SourceDesc || !ObjDesc) 343 { 344 return_ACPI_STATUS (AE_AML_NO_OPERAND); 345 } 346 347 if (ObjDesc->Common.Type == ACPI_TYPE_BUFFER_FIELD) 348 { 349 /* 350 * If the BufferField arguments have not been previously evaluated, 351 * evaluate them now and save the results. 352 */ 353 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 354 { 355 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 356 if (ACPI_FAILURE (Status)) 357 { 358 return_ACPI_STATUS (Status); 359 } 360 } 361 } 362 else if ((ObjDesc->Common.Type == ACPI_TYPE_LOCAL_REGION_FIELD) && 363 (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS || 364 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS || 365 ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_IPMI)) 366 { 367 /* 368 * This is an SMBus, GSBus or IPMI write. We will bypass the entire field 369 * mechanism and handoff the buffer directly to the handler. For 370 * these address spaces, the buffer is bi-directional; on a write, 371 * return data is returned in the same buffer. 372 * 373 * Source must be a buffer of sufficient size: 374 * ACPI_SMBUS_BUFFER_SIZE, ACPI_GSBUS_BUFFER_SIZE, or ACPI_IPMI_BUFFER_SIZE. 375 * 376 * Note: SMBus and GSBus protocol type is passed in upper 16-bits of Function 377 */ 378 if (SourceDesc->Common.Type != ACPI_TYPE_BUFFER) 379 { 380 ACPI_ERROR ((AE_INFO, 381 "SMBus/IPMI/GenericSerialBus write requires Buffer, found type %s", 382 AcpiUtGetObjectTypeName (SourceDesc))); 383 384 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 385 } 386 387 if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 388 { 389 Length = ACPI_SMBUS_BUFFER_SIZE; 390 Function = ACPI_WRITE | (ObjDesc->Field.Attribute << 16); 391 } 392 else if (ObjDesc->Field.RegionObj->Region.SpaceId == ACPI_ADR_SPACE_GSBUS) 393 { 394 AccessorType = ObjDesc->Field.Attribute; 395 Length = AcpiExGetSerialAccessLength (AccessorType, 396 ObjDesc->Field.AccessLength); 397 398 /* 399 * Add additional 2 bytes for the GenericSerialBus data buffer: 400 * 401 * Status; (Byte 0 of the data buffer) 402 * Length; (Byte 1 of the data buffer) 403 * Data[x-1]; (Bytes 2-x of the arbitrary length data buffer) 404 */ 405 Length += 2; 406 Function = ACPI_WRITE | (AccessorType << 16); 407 } 408 else /* IPMI */ 409 { 410 Length = ACPI_IPMI_BUFFER_SIZE; 411 Function = ACPI_WRITE; 412 } 413 414 if (SourceDesc->Buffer.Length < Length) 415 { 416 ACPI_ERROR ((AE_INFO, 417 "SMBus/IPMI/GenericSerialBus write requires Buffer of length %u, found length %u", 418 Length, SourceDesc->Buffer.Length)); 419 420 return_ACPI_STATUS (AE_AML_BUFFER_LIMIT); 421 } 422 423 /* Create the bi-directional buffer */ 424 425 BufferDesc = AcpiUtCreateBufferObject (Length); 426 if (!BufferDesc) 427 { 428 return_ACPI_STATUS (AE_NO_MEMORY); 429 } 430 431 Buffer = BufferDesc->Buffer.Pointer; 432 ACPI_MEMCPY (Buffer, SourceDesc->Buffer.Pointer, Length); 433 434 /* Lock entire transaction if requested */ 435 436 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 437 438 /* 439 * Perform the write (returns status and perhaps data in the 440 * same buffer) 441 */ 442 Status = AcpiExAccessRegion (ObjDesc, 0, 443 (UINT64 *) Buffer, Function); 444 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 445 446 *ResultDesc = BufferDesc; 447 return_ACPI_STATUS (Status); 448 } 449 450 /* Get a pointer to the data to be written */ 451 452 switch (SourceDesc->Common.Type) 453 { 454 case ACPI_TYPE_INTEGER: 455 456 Buffer = &SourceDesc->Integer.Value; 457 Length = sizeof (SourceDesc->Integer.Value); 458 break; 459 460 case ACPI_TYPE_BUFFER: 461 462 Buffer = SourceDesc->Buffer.Pointer; 463 Length = SourceDesc->Buffer.Length; 464 break; 465 466 case ACPI_TYPE_STRING: 467 468 Buffer = SourceDesc->String.Pointer; 469 Length = SourceDesc->String.Length; 470 break; 471 472 default: 473 474 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 475 } 476 477 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 478 "FieldWrite [FROM]: Obj %p (%s:%X), Buf %p, ByteLen %X\n", 479 SourceDesc, AcpiUtGetTypeName (SourceDesc->Common.Type), 480 SourceDesc->Common.Type, Buffer, Length)); 481 482 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 483 "FieldWrite [TO]: Obj %p (%s:%X), BitLen %X, BitOff %X, ByteOff %X\n", 484 ObjDesc, AcpiUtGetTypeName (ObjDesc->Common.Type), 485 ObjDesc->Common.Type, 486 ObjDesc->CommonField.BitLength, 487 ObjDesc->CommonField.StartFieldBitOffset, 488 ObjDesc->CommonField.BaseByteOffset)); 489 490 /* Lock entire transaction if requested */ 491 492 AcpiExAcquireGlobalLock (ObjDesc->CommonField.FieldFlags); 493 494 /* Write to the field */ 495 496 Status = AcpiExInsertIntoField (ObjDesc, Buffer, Length); 497 AcpiExReleaseGlobalLock (ObjDesc->CommonField.FieldFlags); 498 499 return_ACPI_STATUS (Status); 500 } 501