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