exfldio.c revision 138287
1/****************************************************************************** 2 * 3 * Module Name: exfldio - Aml Field I/O 4 * $Revision: 111 $ 5 * 6 *****************************************************************************/ 7 8/****************************************************************************** 9 * 10 * 1. Copyright Notice 11 * 12 * Some or all of this work - Copyright (c) 1999 - 2004, Intel Corp. 13 * All rights reserved. 14 * 15 * 2. License 16 * 17 * 2.1. This is your license from Intel Corp. under its intellectual property 18 * rights. You may have additional license terms from the party that provided 19 * you this software, covering your right to use that party's intellectual 20 * property rights. 21 * 22 * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a 23 * copy of the source code appearing in this file ("Covered Code") an 24 * irrevocable, perpetual, worldwide license under Intel's copyrights in the 25 * base code distributed originally by Intel ("Original Intel Code") to copy, 26 * make derivatives, distribute, use and display any portion of the Covered 27 * Code in any form, with the right to sublicense such rights; and 28 * 29 * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent 30 * license (with the right to sublicense), under only those claims of Intel 31 * patents that are infringed by the Original Intel Code, to make, use, sell, 32 * offer to sell, and import the Covered Code and derivative works thereof 33 * solely to the minimum extent necessary to exercise the above copyright 34 * license, and in no event shall the patent license extend to any additions 35 * to or modifications of the Original Intel Code. No other license or right 36 * is granted directly or by implication, estoppel or otherwise; 37 * 38 * The above copyright and patent license is granted only if the following 39 * conditions are met: 40 * 41 * 3. Conditions 42 * 43 * 3.1. Redistribution of Source with Rights to Further Distribute Source. 44 * Redistribution of source code of any substantial portion of the Covered 45 * Code or modification with rights to further distribute source must include 46 * the above Copyright Notice, the above License, this list of Conditions, 47 * and the following Disclaimer and Export Compliance provision. In addition, 48 * Licensee must cause all Covered Code to which Licensee contributes to 49 * contain a file documenting the changes Licensee made to create that Covered 50 * Code and the date of any change. Licensee must include in that file the 51 * documentation of any changes made by any predecessor Licensee. Licensee 52 * must include a prominent statement that the modification is derived, 53 * directly or indirectly, from Original Intel Code. 54 * 55 * 3.2. Redistribution of Source with no Rights to Further Distribute Source. 56 * Redistribution of source code of any substantial portion of the Covered 57 * Code or modification without rights to further distribute source must 58 * include the following Disclaimer and Export Compliance provision in the 59 * documentation and/or other materials provided with distribution. In 60 * addition, Licensee may not authorize further sublicense of source of any 61 * portion of the Covered Code, and must include terms to the effect that the 62 * license from Licensee to its licensee is limited to the intellectual 63 * property embodied in the software Licensee provides to its licensee, and 64 * not to intellectual property embodied in modifications its licensee may 65 * make. 66 * 67 * 3.3. Redistribution of Executable. Redistribution in executable form of any 68 * substantial portion of the Covered Code or modification must reproduce the 69 * above Copyright Notice, and the following Disclaimer and Export Compliance 70 * provision in the documentation and/or other materials provided with the 71 * distribution. 72 * 73 * 3.4. Intel retains all right, title, and interest in and to the Original 74 * Intel Code. 75 * 76 * 3.5. Neither the name Intel nor any other trademark owned or controlled by 77 * Intel shall be used in advertising or otherwise to promote the sale, use or 78 * other dealings in products derived from or relating to the Covered Code 79 * without prior written authorization from Intel. 80 * 81 * 4. Disclaimer and Export Compliance 82 * 83 * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED 84 * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE 85 * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE, 86 * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY 87 * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY 88 * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A 89 * PARTICULAR PURPOSE. 90 * 91 * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES 92 * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR 93 * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT, 94 * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY 95 * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL 96 * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS 97 * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY 98 * LIMITED REMEDY. 99 * 100 * 4.3. Licensee shall not export, either directly or indirectly, any of this 101 * software or system incorporating such software without first obtaining any 102 * required license or other approval from the U. S. Department of Commerce or 103 * any other agency or department of the United States Government. In the 104 * event Licensee exports any such software from the United States or 105 * re-exports any such software from a foreign destination, Licensee shall 106 * ensure that the distribution and export/re-export of the software is in 107 * compliance with all laws, regulations, orders, or other restrictions of the 108 * U.S. Export Administration Regulations. Licensee agrees that neither it nor 109 * any of its subsidiaries will export/re-export any technical data, process, 110 * software, or service, directly or indirectly, to any country for which the 111 * United States government or any agency thereof requires an export license, 112 * other governmental approval, or letter of assurance, without first obtaining 113 * such license, approval or letter. 114 * 115 *****************************************************************************/ 116 117 118#define __EXFLDIO_C__ 119 120#include "acpi.h" 121#include "acinterp.h" 122#include "amlcode.h" 123#include "acevents.h" 124#include "acdispat.h" 125 126 127#define _COMPONENT ACPI_EXECUTER 128 ACPI_MODULE_NAME ("exfldio") 129 130 131/******************************************************************************* 132 * 133 * FUNCTION: AcpiExSetupRegion 134 * 135 * PARAMETERS: *ObjDesc - Field to be read or written 136 * FieldDatumByteOffset - Byte offset of this datum within the 137 * parent field 138 * 139 * RETURN: Status 140 * 141 * DESCRIPTION: Common processing for AcpiExExtractFromField and 142 * AcpiExInsertIntoField. Initialize the Region if necessary and 143 * validate the request. 144 * 145 ******************************************************************************/ 146 147ACPI_STATUS 148AcpiExSetupRegion ( 149 ACPI_OPERAND_OBJECT *ObjDesc, 150 UINT32 FieldDatumByteOffset) 151{ 152 ACPI_STATUS Status = AE_OK; 153 ACPI_OPERAND_OBJECT *RgnDesc; 154 155 156 ACPI_FUNCTION_TRACE_U32 ("ExSetupRegion", FieldDatumByteOffset); 157 158 159 RgnDesc = ObjDesc->CommonField.RegionObj; 160 161 /* We must have a valid region */ 162 163 if (ACPI_GET_OBJECT_TYPE (RgnDesc) != ACPI_TYPE_REGION) 164 { 165 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, "Needed Region, found type %X (%s)\n", 166 ACPI_GET_OBJECT_TYPE (RgnDesc), 167 AcpiUtGetObjectTypeName (RgnDesc))); 168 169 return_ACPI_STATUS (AE_AML_OPERAND_TYPE); 170 } 171 172 /* 173 * If the Region Address and Length have not been previously evaluated, 174 * evaluate them now and save the results. 175 */ 176 if (!(RgnDesc->Common.Flags & AOPOBJ_DATA_VALID)) 177 { 178 Status = AcpiDsGetRegionArguments (RgnDesc); 179 if (ACPI_FAILURE (Status)) 180 { 181 return_ACPI_STATUS (Status); 182 } 183 } 184 185 if (RgnDesc->Region.SpaceId == ACPI_ADR_SPACE_SMBUS) 186 { 187 /* SMBus has a non-linear address space */ 188 189 return_ACPI_STATUS (AE_OK); 190 } 191 192#ifdef ACPI_UNDER_DEVELOPMENT 193 /* 194 * If the Field access is AnyAcc, we can now compute the optimal 195 * access (because we know know the length of the parent region) 196 */ 197 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 198 { 199 if (ACPI_FAILURE (Status)) 200 { 201 return_ACPI_STATUS (Status); 202 } 203 } 204#endif 205 206 /* 207 * Validate the request. The entire request from the byte offset for a 208 * length of one field datum (access width) must fit within the region. 209 * (Region length is specified in bytes) 210 */ 211 if (RgnDesc->Region.Length < (ObjDesc->CommonField.BaseByteOffset 212 + FieldDatumByteOffset 213 + ObjDesc->CommonField.AccessByteWidth)) 214 { 215 if (AcpiGbl_EnableInterpreterSlack) 216 { 217 /* 218 * Slack mode only: We will go ahead and allow access to this 219 * field if it is within the region length rounded up to the next 220 * access width boundary. 221 */ 222 if (ACPI_ROUND_UP (RgnDesc->Region.Length, 223 ObjDesc->CommonField.AccessByteWidth) >= 224 (ObjDesc->CommonField.BaseByteOffset + 225 (ACPI_NATIVE_UINT) ObjDesc->CommonField.AccessByteWidth + 226 FieldDatumByteOffset)) 227 { 228 return_ACPI_STATUS (AE_OK); 229 } 230 } 231 232 if (RgnDesc->Region.Length < ObjDesc->CommonField.AccessByteWidth) 233 { 234 /* 235 * This is the case where the AccessType (AccWord, etc.) is wider 236 * than the region itself. For example, a region of length one 237 * byte, and a field with Dword access specified. 238 */ 239 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 240 "Field [%4.4s] access width (%d bytes) too large for region [%4.4s] (length %X)\n", 241 AcpiUtGetNodeName (ObjDesc->CommonField.Node), 242 ObjDesc->CommonField.AccessByteWidth, 243 AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length)); 244 } 245 246 /* 247 * Offset rounded up to next multiple of field width 248 * exceeds region length, indicate an error 249 */ 250 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 251 "Field [%4.4s] Base+Offset+Width %X+%X+%X is beyond end of region [%4.4s] (length %X)\n", 252 AcpiUtGetNodeName (ObjDesc->CommonField.Node), 253 ObjDesc->CommonField.BaseByteOffset, 254 FieldDatumByteOffset, ObjDesc->CommonField.AccessByteWidth, 255 AcpiUtGetNodeName (RgnDesc->Region.Node), RgnDesc->Region.Length)); 256 257 return_ACPI_STATUS (AE_AML_REGION_LIMIT); 258 } 259 260 return_ACPI_STATUS (AE_OK); 261} 262 263 264/******************************************************************************* 265 * 266 * FUNCTION: AcpiExAccessRegion 267 * 268 * PARAMETERS: *ObjDesc - Field to be read 269 * FieldDatumByteOffset - Byte offset of this datum within the 270 * parent field 271 * *Value - Where to store value (must at least 272 * the size of ACPI_INTEGER) 273 * Function - Read or Write flag plus other region- 274 * dependent flags 275 * 276 * RETURN: Status 277 * 278 * DESCRIPTION: Read or Write a single field datum to an Operation Region. 279 * 280 ******************************************************************************/ 281 282ACPI_STATUS 283AcpiExAccessRegion ( 284 ACPI_OPERAND_OBJECT *ObjDesc, 285 UINT32 FieldDatumByteOffset, 286 ACPI_INTEGER *Value, 287 UINT32 Function) 288{ 289 ACPI_STATUS Status; 290 ACPI_OPERAND_OBJECT *RgnDesc; 291 ACPI_PHYSICAL_ADDRESS Address; 292 293 294 ACPI_FUNCTION_TRACE ("ExAccessRegion"); 295 296 297 /* 298 * Ensure that the region operands are fully evaluated and verify 299 * the validity of the request 300 */ 301 Status = AcpiExSetupRegion (ObjDesc, FieldDatumByteOffset); 302 if (ACPI_FAILURE (Status)) 303 { 304 return_ACPI_STATUS (Status); 305 } 306 307 /* 308 * The physical address of this field datum is: 309 * 310 * 1) The base of the region, plus 311 * 2) The base offset of the field, plus 312 * 3) The current offset into the field 313 */ 314 RgnDesc = ObjDesc->CommonField.RegionObj; 315 Address = RgnDesc->Region.Address 316 + ObjDesc->CommonField.BaseByteOffset 317 + FieldDatumByteOffset; 318 319 if ((Function & ACPI_IO_MASK) == ACPI_READ) 320 { 321 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[READ]")); 322 } 323 else 324 { 325 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "[WRITE]")); 326 } 327 328 ACPI_DEBUG_PRINT_RAW ((ACPI_DB_BFIELD, 329 " Region [%s:%X], Width %X, ByteBase %X, Offset %X at %8.8X%8.8X\n", 330 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 331 RgnDesc->Region.SpaceId, 332 ObjDesc->CommonField.AccessByteWidth, 333 ObjDesc->CommonField.BaseByteOffset, 334 FieldDatumByteOffset, 335 ACPI_FORMAT_UINT64 (Address))); 336 337 /* Invoke the appropriate AddressSpace/OpRegion handler */ 338 339 Status = AcpiEvAddressSpaceDispatch (RgnDesc, Function, 340 Address, ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth), Value); 341 342 if (ACPI_FAILURE (Status)) 343 { 344 if (Status == AE_NOT_IMPLEMENTED) 345 { 346 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 347 "Region %s(%X) not implemented\n", 348 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 349 RgnDesc->Region.SpaceId)); 350 } 351 else if (Status == AE_NOT_EXIST) 352 { 353 ACPI_REPORT_ERROR (( 354 "Region %s(%X) has no handler\n", 355 AcpiUtGetRegionName (RgnDesc->Region.SpaceId), 356 RgnDesc->Region.SpaceId)); 357 } 358 } 359 360 return_ACPI_STATUS (Status); 361} 362 363 364/******************************************************************************* 365 * 366 * FUNCTION: AcpiExRegisterOverflow 367 * 368 * PARAMETERS: *ObjDesc - Register(Field) to be written 369 * Value - Value to be stored 370 * 371 * RETURN: TRUE if value overflows the field, FALSE otherwise 372 * 373 * DESCRIPTION: Check if a value is out of range of the field being written. 374 * Used to check if the values written to Index and Bank registers 375 * are out of range. Normally, the value is simply truncated 376 * to fit the field, but this case is most likely a serious 377 * coding error in the ASL. 378 * 379 ******************************************************************************/ 380 381BOOLEAN 382AcpiExRegisterOverflow ( 383 ACPI_OPERAND_OBJECT *ObjDesc, 384 ACPI_INTEGER Value) 385{ 386 387 if (ObjDesc->CommonField.BitLength >= ACPI_INTEGER_BIT_SIZE) 388 { 389 /* 390 * The field is large enough to hold the maximum integer, so we can 391 * never overflow it. 392 */ 393 return (FALSE); 394 } 395 396 if (Value >= ((ACPI_INTEGER) 1 << ObjDesc->CommonField.BitLength)) 397 { 398 /* 399 * The Value is larger than the maximum value that can fit into 400 * the register. 401 */ 402 return (TRUE); 403 } 404 405 /* The Value will fit into the field with no truncation */ 406 407 return (FALSE); 408} 409 410 411/******************************************************************************* 412 * 413 * FUNCTION: AcpiExFieldDatumIo 414 * 415 * PARAMETERS: *ObjDesc - Field to be read 416 * FieldDatumByteOffset - Byte offset of this datum within the 417 * parent field 418 * *Value - Where to store value (must be 64 bits) 419 * ReadWrite - Read or Write flag 420 * 421 * RETURN: Status 422 * 423 * DESCRIPTION: Read or Write a single datum of a field. The FieldType is 424 * demultiplexed here to handle the different types of fields 425 * (BufferField, RegionField, IndexField, BankField) 426 * 427 ******************************************************************************/ 428 429ACPI_STATUS 430AcpiExFieldDatumIo ( 431 ACPI_OPERAND_OBJECT *ObjDesc, 432 UINT32 FieldDatumByteOffset, 433 ACPI_INTEGER *Value, 434 UINT32 ReadWrite) 435{ 436 ACPI_STATUS Status; 437 ACPI_INTEGER LocalValue; 438 439 440 ACPI_FUNCTION_TRACE_U32 ("ExFieldDatumIo", FieldDatumByteOffset); 441 442 443 if (ReadWrite == ACPI_READ) 444 { 445 if (!Value) 446 { 447 LocalValue = 0; 448 Value = &LocalValue; /* To support reads without saving return value */ 449 } 450 451 /* Clear the entire return buffer first, [Very Important!] */ 452 453 *Value = 0; 454 } 455 456 /* 457 * The four types of fields are: 458 * 459 * BufferField - Read/write from/to a Buffer 460 * RegionField - Read/write from/to a Operation Region. 461 * BankField - Write to a Bank Register, then read/write from/to an OpRegion 462 * IndexField - Write to an Index Register, then read/write from/to a Data Register 463 */ 464 switch (ACPI_GET_OBJECT_TYPE (ObjDesc)) 465 { 466 case ACPI_TYPE_BUFFER_FIELD: 467 /* 468 * If the BufferField arguments have not been previously evaluated, 469 * evaluate them now and save the results. 470 */ 471 if (!(ObjDesc->Common.Flags & AOPOBJ_DATA_VALID)) 472 { 473 Status = AcpiDsGetBufferFieldArguments (ObjDesc); 474 if (ACPI_FAILURE (Status)) 475 { 476 return_ACPI_STATUS (Status); 477 } 478 } 479 480 if (ReadWrite == ACPI_READ) 481 { 482 /* 483 * Copy the data from the source buffer. 484 * Length is the field width in bytes. 485 */ 486 ACPI_MEMCPY (Value, (ObjDesc->BufferField.BufferObj)->Buffer.Pointer 487 + ObjDesc->BufferField.BaseByteOffset 488 + FieldDatumByteOffset, 489 ObjDesc->CommonField.AccessByteWidth); 490 } 491 else 492 { 493 /* 494 * Copy the data to the target buffer. 495 * Length is the field width in bytes. 496 */ 497 ACPI_MEMCPY ((ObjDesc->BufferField.BufferObj)->Buffer.Pointer 498 + ObjDesc->BufferField.BaseByteOffset 499 + FieldDatumByteOffset, 500 Value, ObjDesc->CommonField.AccessByteWidth); 501 } 502 503 Status = AE_OK; 504 break; 505 506 507 case ACPI_TYPE_LOCAL_BANK_FIELD: 508 509 /* Ensure that the BankValue is not beyond the capacity of the register */ 510 511 if (AcpiExRegisterOverflow (ObjDesc->BankField.BankObj, 512 (ACPI_INTEGER) ObjDesc->BankField.Value)) 513 { 514 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 515 } 516 517 /* 518 * For BankFields, we must write the BankValue to the BankRegister 519 * (itself a RegionField) before we can access the data. 520 */ 521 Status = AcpiExInsertIntoField (ObjDesc->BankField.BankObj, 522 &ObjDesc->BankField.Value, 523 sizeof (ObjDesc->BankField.Value)); 524 if (ACPI_FAILURE (Status)) 525 { 526 return_ACPI_STATUS (Status); 527 } 528 529 /* 530 * Now that the Bank has been selected, fall through to the 531 * RegionField case and write the datum to the Operation Region 532 */ 533 534 /*lint -fallthrough */ 535 536 537 case ACPI_TYPE_LOCAL_REGION_FIELD: 538 /* 539 * For simple RegionFields, we just directly access the owning 540 * Operation Region. 541 */ 542 Status = AcpiExAccessRegion (ObjDesc, FieldDatumByteOffset, Value, 543 ReadWrite); 544 break; 545 546 547 case ACPI_TYPE_LOCAL_INDEX_FIELD: 548 549 550 /* Ensure that the IndexValue is not beyond the capacity of the register */ 551 552 if (AcpiExRegisterOverflow (ObjDesc->IndexField.IndexObj, 553 (ACPI_INTEGER) ObjDesc->IndexField.Value)) 554 { 555 return_ACPI_STATUS (AE_AML_REGISTER_LIMIT); 556 } 557 558 /* Write the index value to the IndexRegister (itself a RegionField) */ 559 560 FieldDatumByteOffset += ObjDesc->IndexField.Value; 561 562 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 563 "Write to Index Register: Value %8.8X\n", 564 FieldDatumByteOffset)); 565 566 Status = AcpiExInsertIntoField (ObjDesc->IndexField.IndexObj, 567 &FieldDatumByteOffset, 568 sizeof (FieldDatumByteOffset)); 569 if (ACPI_FAILURE (Status)) 570 { 571 return_ACPI_STATUS (Status); 572 } 573 574 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 575 "I/O to Data Register: ValuePtr %p\n", 576 Value)); 577 578 if (ReadWrite == ACPI_READ) 579 { 580 /* Read the datum from the DataRegister */ 581 582 Status = AcpiExExtractFromField (ObjDesc->IndexField.DataObj, 583 Value, sizeof (ACPI_INTEGER)); 584 } 585 else 586 { 587 /* Write the datum to the DataRegister */ 588 589 Status = AcpiExInsertIntoField (ObjDesc->IndexField.DataObj, 590 Value, sizeof (ACPI_INTEGER)); 591 } 592 break; 593 594 595 default: 596 597 ACPI_REPORT_ERROR (("Wrong object type in field I/O %X\n", 598 ACPI_GET_OBJECT_TYPE (ObjDesc))); 599 Status = AE_AML_INTERNAL; 600 break; 601 } 602 603 if (ACPI_SUCCESS (Status)) 604 { 605 if (ReadWrite == ACPI_READ) 606 { 607 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Read %8.8X%8.8X, Width %d\n", 608 ACPI_FORMAT_UINT64 (*Value), 609 ObjDesc->CommonField.AccessByteWidth)); 610 } 611 else 612 { 613 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, "Value Written %8.8X%8.8X, Width %d\n", 614 ACPI_FORMAT_UINT64 (*Value), 615 ObjDesc->CommonField.AccessByteWidth)); 616 } 617 } 618 619 return_ACPI_STATUS (Status); 620} 621 622 623/******************************************************************************* 624 * 625 * FUNCTION: AcpiExWriteWithUpdateRule 626 * 627 * PARAMETERS: *ObjDesc - Field to be set 628 * Value - Value to store 629 * 630 * RETURN: Status 631 * 632 * DESCRIPTION: Apply the field update rule to a field write 633 * 634 ******************************************************************************/ 635 636ACPI_STATUS 637AcpiExWriteWithUpdateRule ( 638 ACPI_OPERAND_OBJECT *ObjDesc, 639 ACPI_INTEGER Mask, 640 ACPI_INTEGER FieldValue, 641 UINT32 FieldDatumByteOffset) 642{ 643 ACPI_STATUS Status = AE_OK; 644 ACPI_INTEGER MergedValue; 645 ACPI_INTEGER CurrentValue; 646 647 648 ACPI_FUNCTION_TRACE_U32 ("ExWriteWithUpdateRule", Mask); 649 650 651 /* Start with the new bits */ 652 653 MergedValue = FieldValue; 654 655 /* If the mask is all ones, we don't need to worry about the update rule */ 656 657 if (Mask != ACPI_INTEGER_MAX) 658 { 659 /* Decode the update rule */ 660 661 switch (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK) 662 { 663 case AML_FIELD_UPDATE_PRESERVE: 664 /* 665 * Check if update rule needs to be applied (not if mask is all 666 * ones) The left shift drops the bits we want to ignore. 667 */ 668 if ((~Mask << (ACPI_MUL_8 (sizeof (Mask)) - 669 ACPI_MUL_8 (ObjDesc->CommonField.AccessByteWidth))) != 0) 670 { 671 /* 672 * Read the current contents of the byte/word/dword containing 673 * the field, and merge with the new field value. 674 */ 675 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 676 &CurrentValue, ACPI_READ); 677 if (ACPI_FAILURE (Status)) 678 { 679 return_ACPI_STATUS (Status); 680 } 681 682 MergedValue |= (CurrentValue & ~Mask); 683 } 684 break; 685 686 case AML_FIELD_UPDATE_WRITE_AS_ONES: 687 688 /* Set positions outside the field to all ones */ 689 690 MergedValue |= ~Mask; 691 break; 692 693 case AML_FIELD_UPDATE_WRITE_AS_ZEROS: 694 695 /* Set positions outside the field to all zeros */ 696 697 MergedValue &= Mask; 698 break; 699 700 default: 701 702 ACPI_DEBUG_PRINT ((ACPI_DB_ERROR, 703 "WriteWithUpdateRule: Unknown UpdateRule setting: %X\n", 704 (ObjDesc->CommonField.FieldFlags & AML_FIELD_UPDATE_RULE_MASK))); 705 return_ACPI_STATUS (AE_AML_OPERAND_VALUE); 706 } 707 } 708 709 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 710 "Mask %8.8X%8.8X, DatumOffset %X, Width %X, Value %8.8X%8.8X, MergedValue %8.8X%8.8X\n", 711 ACPI_FORMAT_UINT64 (Mask), 712 FieldDatumByteOffset, 713 ObjDesc->CommonField.AccessByteWidth, 714 ACPI_FORMAT_UINT64 (FieldValue), 715 ACPI_FORMAT_UINT64 (MergedValue))); 716 717 /* Write the merged value */ 718 719 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 720 &MergedValue, ACPI_WRITE); 721 722 return_ACPI_STATUS (Status); 723} 724 725 726/******************************************************************************* 727 * 728 * FUNCTION: AcpiExGetBufferDatum 729 * 730 * PARAMETERS: Datum - Where the Datum is returned 731 * Buffer - Raw field buffer 732 * BufferLength - Entire length (used for big-endian only) 733 * ByteGranularity - 1/2/4/8 Granularity of the field 734 * (aka Datum Size) 735 * BufferOffset - Datum offset into the buffer 736 * 737 * RETURN: none 738 * 739 * DESCRIPTION: Get a datum from the buffer according to the buffer field 740 * byte granularity 741 * 742 ******************************************************************************/ 743 744void 745AcpiExGetBufferDatum ( 746 ACPI_INTEGER *Datum, 747 void *Buffer, 748 UINT32 BufferLength, 749 UINT32 ByteGranularity, 750 UINT32 BufferOffset) 751{ 752 UINT32 Index; 753 754 755 ACPI_FUNCTION_TRACE_U32 ("ExGetBufferDatum", ByteGranularity); 756 757 758 /* Get proper index into buffer (handles big/little endian) */ 759 760 Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity); 761 762 /* Move the requested number of bytes */ 763 764 switch (ByteGranularity) 765 { 766 case ACPI_FIELD_BYTE_GRANULARITY: 767 768 *Datum = ((UINT8 *) Buffer) [Index]; 769 break; 770 771 case ACPI_FIELD_WORD_GRANULARITY: 772 773 ACPI_MOVE_16_TO_64 (Datum, &(((UINT16 *) Buffer) [Index])); 774 break; 775 776 case ACPI_FIELD_DWORD_GRANULARITY: 777 778 ACPI_MOVE_32_TO_64 (Datum, &(((UINT32 *) Buffer) [Index])); 779 break; 780 781 case ACPI_FIELD_QWORD_GRANULARITY: 782 783 ACPI_MOVE_64_TO_64 (Datum, &(((UINT64 *) Buffer) [Index])); 784 break; 785 786 default: 787 /* Should not get here */ 788 break; 789 } 790 791 return_VOID; 792} 793 794 795/******************************************************************************* 796 * 797 * FUNCTION: AcpiExSetBufferDatum 798 * 799 * PARAMETERS: MergedDatum - Value to store 800 * Buffer - Receiving buffer 801 * BufferLength - Entire length (used for big-endian only) 802 * ByteGranularity - 1/2/4/8 Granularity of the field 803 * (aka Datum Size) 804 * BufferOffset - Datum offset into the buffer 805 * 806 * RETURN: none 807 * 808 * DESCRIPTION: Store the merged datum to the buffer according to the 809 * byte granularity 810 * 811 ******************************************************************************/ 812 813void 814AcpiExSetBufferDatum ( 815 ACPI_INTEGER MergedDatum, 816 void *Buffer, 817 UINT32 BufferLength, 818 UINT32 ByteGranularity, 819 UINT32 BufferOffset) 820{ 821 UINT32 Index; 822 823 824 ACPI_FUNCTION_TRACE_U32 ("ExSetBufferDatum", ByteGranularity); 825 826 827 /* Get proper index into buffer (handles big/little endian) */ 828 829 Index = ACPI_BUFFER_INDEX (BufferLength, BufferOffset, ByteGranularity); 830 831 /* Move the requested number of bytes */ 832 833 switch (ByteGranularity) 834 { 835 case ACPI_FIELD_BYTE_GRANULARITY: 836 837 ((UINT8 *) Buffer) [Index] = (UINT8) MergedDatum; 838 break; 839 840 case ACPI_FIELD_WORD_GRANULARITY: 841 842 ACPI_MOVE_64_TO_16 (&(((UINT16 *) Buffer)[Index]), &MergedDatum); 843 break; 844 845 case ACPI_FIELD_DWORD_GRANULARITY: 846 847 ACPI_MOVE_64_TO_32 (&(((UINT32 *) Buffer)[Index]), &MergedDatum); 848 break; 849 850 case ACPI_FIELD_QWORD_GRANULARITY: 851 852 ACPI_MOVE_64_TO_64 (&(((UINT64 *) Buffer)[Index]), &MergedDatum); 853 break; 854 855 default: 856 /* Should not get here */ 857 break; 858 } 859 860 return_VOID; 861} 862 863 864/******************************************************************************* 865 * 866 * FUNCTION: AcpiExCommonBufferSetup 867 * 868 * PARAMETERS: ObjDesc - Field object 869 * BufferLength - Length of caller's buffer 870 * DatumCount - Where the DatumCount is returned 871 * 872 * RETURN: Status, DatumCount 873 * 874 * DESCRIPTION: Common code to validate the incoming buffer size and compute 875 * the number of field "datums" that must be read or written. 876 * A "datum" is the smallest unit that can be read or written 877 * to the field, it is either 1,2,4, or 8 bytes. 878 * 879 ******************************************************************************/ 880 881ACPI_STATUS 882AcpiExCommonBufferSetup ( 883 ACPI_OPERAND_OBJECT *ObjDesc, 884 UINT32 BufferLength, 885 UINT32 *DatumCount) 886{ 887 UINT32 ByteFieldLength; 888 UINT32 ActualByteFieldLength; 889 890 891 ACPI_FUNCTION_TRACE ("ExCommonBufferSetup"); 892 893 894 /* 895 * Incoming buffer must be at least as long as the field, we do not 896 * allow "partial" field reads/writes. We do not care if the buffer is 897 * larger than the field, this typically happens when an integer is 898 * read/written to a field that is actually smaller than an integer. 899 */ 900 ByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 901 ObjDesc->CommonField.BitLength); 902 if (ByteFieldLength > BufferLength) 903 { 904 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 905 "Field size %X (bytes) is too large for buffer (%X)\n", 906 ByteFieldLength, BufferLength)); 907 908 return_ACPI_STATUS (AE_BUFFER_OVERFLOW); 909 } 910 911 /* 912 * Create "actual" field byte count (minimum number of bytes that 913 * must be read), then convert to datum count (minimum number 914 * of datum-sized units that must be read) 915 */ 916 ActualByteFieldLength = ACPI_ROUND_BITS_UP_TO_BYTES ( 917 ObjDesc->CommonField.StartFieldBitOffset + 918 ObjDesc->CommonField.BitLength); 919 920 921 *DatumCount = ACPI_ROUND_UP_TO (ActualByteFieldLength, 922 ObjDesc->CommonField.AccessByteWidth); 923 924 ACPI_DEBUG_PRINT ((ACPI_DB_BFIELD, 925 "BufferBytes %X, ActualBytes %X, Datums %X, ByteGran %X\n", 926 ByteFieldLength, ActualByteFieldLength, 927 *DatumCount, ObjDesc->CommonField.AccessByteWidth)); 928 929 return_ACPI_STATUS (AE_OK); 930} 931 932 933/******************************************************************************* 934 * 935 * FUNCTION: AcpiExExtractFromField 936 * 937 * PARAMETERS: ObjDesc - Field to be read 938 * Buffer - Where to store the field data 939 * BufferLength - Length of Buffer 940 * 941 * RETURN: Status 942 * 943 * DESCRIPTION: Retrieve the current value of the given field 944 * 945 ******************************************************************************/ 946 947ACPI_STATUS 948AcpiExExtractFromField ( 949 ACPI_OPERAND_OBJECT *ObjDesc, 950 void *Buffer, 951 UINT32 BufferLength) 952{ 953 ACPI_STATUS Status; 954 UINT32 FieldDatumByteOffset; 955 UINT32 BufferDatumOffset; 956 ACPI_INTEGER PreviousRawDatum = 0; 957 ACPI_INTEGER ThisRawDatum = 0; 958 ACPI_INTEGER MergedDatum = 0; 959 UINT32 DatumCount; 960 UINT32 i; 961 962 963 ACPI_FUNCTION_TRACE ("ExExtractFromField"); 964 965 966 /* Validate buffer, compute number of datums */ 967 968 Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount); 969 if (ACPI_FAILURE (Status)) 970 { 971 return_ACPI_STATUS (Status); 972 } 973 974 /* 975 * Clear the caller's buffer (the whole buffer length as given) 976 * This is very important, especially in the cases where the buffer 977 * is longer than the size of the field. 978 */ 979 ACPI_MEMSET (Buffer, 0, BufferLength); 980 981 FieldDatumByteOffset = 0; 982 BufferDatumOffset= 0; 983 984 /* Read the entire field */ 985 986 for (i = 0; i < DatumCount; i++) 987 { 988 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 989 &ThisRawDatum, ACPI_READ); 990 if (ACPI_FAILURE (Status)) 991 { 992 return_ACPI_STATUS (Status); 993 } 994 995 /* We might actually be done if the request fits in one datum */ 996 997 if ((DatumCount == 1) && 998 (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)) 999 { 1000 /* 1) Shift the valid data bits down to start at bit 0 */ 1001 1002 MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); 1003 1004 /* 2) Mask off any upper unused bits (bits not part of the field) */ 1005 1006 if (ObjDesc->CommonField.EndBufferValidBits) 1007 { 1008 MergedDatum &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndBufferValidBits); 1009 } 1010 1011 /* Store the datum to the caller buffer */ 1012 1013 AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, 1014 ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); 1015 1016 return_ACPI_STATUS (AE_OK); 1017 } 1018 1019 /* Special handling for the last datum to ignore extra bits */ 1020 1021 if ((i >= (DatumCount -1)) && 1022 (ObjDesc->CommonField.EndFieldValidBits)) 1023 { 1024 /* 1025 * This is the last iteration of the loop. We need to clear 1026 * any unused bits (bits that are not part of this field) before 1027 * we store the final merged datum into the caller buffer. 1028 */ 1029 ThisRawDatum &= 1030 ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); 1031 } 1032 1033 /* 1034 * Create the (possibly) merged datum to be stored to the caller buffer 1035 */ 1036 if (ObjDesc->CommonField.StartFieldBitOffset == 0) 1037 { 1038 /* Field is not skewed and we can just copy the datum */ 1039 1040 AcpiExSetBufferDatum (ThisRawDatum, Buffer, BufferLength, 1041 ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); 1042 BufferDatumOffset++; 1043 } 1044 else 1045 { 1046 /* Not aligned -- on the first iteration, just save the datum */ 1047 1048 if (i != 0) 1049 { 1050 /* 1051 * Put together the appropriate bits of the two raw data to make a 1052 * single complete field datum 1053 * 1054 * 1) Normalize the first datum down to bit 0 1055 */ 1056 MergedDatum = (PreviousRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); 1057 1058 /* 2) Insert the second datum "above" the first datum */ 1059 1060 MergedDatum |= (ThisRawDatum << ObjDesc->CommonField.DatumValidBits); 1061 1062 AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, 1063 ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); 1064 BufferDatumOffset++; 1065 } 1066 1067 /* 1068 * Save the raw datum that was just acquired since it may contain bits 1069 * of the *next* field datum 1070 */ 1071 PreviousRawDatum = ThisRawDatum; 1072 } 1073 1074 FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; 1075 } 1076 1077 /* For non-aligned case, there is one last datum to insert */ 1078 1079 if (ObjDesc->CommonField.StartFieldBitOffset != 0) 1080 { 1081 MergedDatum = (ThisRawDatum >> ObjDesc->CommonField.StartFieldBitOffset); 1082 1083 AcpiExSetBufferDatum (MergedDatum, Buffer, BufferLength, 1084 ObjDesc->CommonField.AccessByteWidth, BufferDatumOffset); 1085 } 1086 1087 return_ACPI_STATUS (AE_OK); 1088} 1089 1090 1091/******************************************************************************* 1092 * 1093 * FUNCTION: AcpiExInsertIntoField 1094 * 1095 * PARAMETERS: ObjDesc - Field to be written 1096 * Buffer - Data to be written 1097 * BufferLength - Length of Buffer 1098 * 1099 * RETURN: Status 1100 * 1101 * DESCRIPTION: Store the Buffer contents into the given field 1102 * 1103 ******************************************************************************/ 1104 1105ACPI_STATUS 1106AcpiExInsertIntoField ( 1107 ACPI_OPERAND_OBJECT *ObjDesc, 1108 void *Buffer, 1109 UINT32 BufferLength) 1110{ 1111 ACPI_STATUS Status; 1112 UINT32 FieldDatumByteOffset; 1113 UINT32 DatumOffset; 1114 ACPI_INTEGER Mask; 1115 ACPI_INTEGER MergedDatum; 1116 ACPI_INTEGER PreviousRawDatum; 1117 ACPI_INTEGER ThisRawDatum; 1118 UINT32 DatumCount; 1119 1120 1121 ACPI_FUNCTION_TRACE ("ExInsertIntoField"); 1122 1123 1124 /* Validate buffer, compute number of datums */ 1125 1126 Status = AcpiExCommonBufferSetup (ObjDesc, BufferLength, &DatumCount); 1127 if (ACPI_FAILURE (Status)) 1128 { 1129 return_ACPI_STATUS (Status); 1130 } 1131 1132 /* 1133 * Break the request into up to three parts (similar to an I/O request): 1134 * 1) non-aligned part at start 1135 * 2) aligned part in middle 1136 * 3) non-aligned part at the end 1137 */ 1138 FieldDatumByteOffset = 0; 1139 DatumOffset= 0; 1140 1141 /* Get a single datum from the caller's buffer */ 1142 1143 AcpiExGetBufferDatum (&PreviousRawDatum, Buffer, BufferLength, 1144 ObjDesc->CommonField.AccessByteWidth, DatumOffset); 1145 1146 /* 1147 * Part1: 1148 * Write a partial field datum if field does not begin on a datum boundary 1149 * Note: The code in this section also handles the aligned case 1150 * 1151 * Construct Mask with 1 bits where the field is, 0 bits elsewhere 1152 * (Only the bottom 5 bits of BitLength are valid for a shift operation) 1153 * 1154 * Mask off bits that are "below" the field (if any) 1155 */ 1156 Mask = ACPI_MASK_BITS_BELOW (ObjDesc->CommonField.StartFieldBitOffset); 1157 1158 /* If the field fits in one datum, may need to mask upper bits */ 1159 1160 if ((ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM) && 1161 ObjDesc->CommonField.EndFieldValidBits) 1162 { 1163 /* There are bits above the field, mask them off also */ 1164 1165 Mask &= ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); 1166 } 1167 1168 /* Shift and mask the value into the field position */ 1169 1170 MergedDatum = (PreviousRawDatum << ObjDesc->CommonField.StartFieldBitOffset); 1171 MergedDatum &= Mask; 1172 1173 /* Apply the update rule (if necessary) and write the datum to the field */ 1174 1175 Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, 1176 FieldDatumByteOffset); 1177 if (ACPI_FAILURE (Status)) 1178 { 1179 return_ACPI_STATUS (Status); 1180 } 1181 1182 /* We just wrote the first datum */ 1183 1184 DatumOffset++; 1185 1186 /* If the entire field fits within one datum, we are done. */ 1187 1188 if ((DatumCount == 1) && 1189 (ObjDesc->CommonField.Flags & AOPOBJ_SINGLE_DATUM)) 1190 { 1191 return_ACPI_STATUS (AE_OK); 1192 } 1193 1194 /* 1195 * Part2: 1196 * Write the aligned data. 1197 * 1198 * We don't need to worry about the update rule for these data, because 1199 * all of the bits in each datum are part of the field. 1200 * 1201 * The last datum must be special cased because it might contain bits 1202 * that are not part of the field -- therefore the "update rule" must be 1203 * applied in Part3 below. 1204 */ 1205 while (DatumOffset < DatumCount) 1206 { 1207 FieldDatumByteOffset += ObjDesc->CommonField.AccessByteWidth; 1208 1209 /* 1210 * Get the next raw buffer datum. It may contain bits of the previous 1211 * field datum 1212 */ 1213 AcpiExGetBufferDatum (&ThisRawDatum, Buffer, BufferLength, 1214 ObjDesc->CommonField.AccessByteWidth, DatumOffset); 1215 1216 /* Create the field datum based on the field alignment */ 1217 1218 if (ObjDesc->CommonField.StartFieldBitOffset != 0) 1219 { 1220 /* 1221 * Put together appropriate bits of the two raw buffer data to make 1222 * a single complete field datum 1223 */ 1224 MergedDatum = 1225 (PreviousRawDatum >> ObjDesc->CommonField.DatumValidBits) | 1226 (ThisRawDatum << ObjDesc->CommonField.StartFieldBitOffset); 1227 } 1228 else 1229 { 1230 /* Field began aligned on datum boundary */ 1231 1232 MergedDatum = ThisRawDatum; 1233 } 1234 1235 /* 1236 * Special handling for the last datum if the field does NOT end on 1237 * a datum boundary. Update Rule must be applied to the bits outside 1238 * the field. 1239 */ 1240 DatumOffset++; 1241 if ((DatumOffset == DatumCount) && 1242 (ObjDesc->CommonField.EndFieldValidBits)) 1243 { 1244 /* 1245 * If there are dangling non-aligned bits, perform one more merged write 1246 * Else - field is aligned at the end, no need for any more writes 1247 */ 1248 1249 /* 1250 * Part3: 1251 * This is the last datum and the field does not end on a datum boundary. 1252 * Build the partial datum and write with the update rule. 1253 * 1254 * Mask off the unused bits above (after) the end-of-field 1255 */ 1256 Mask = ACPI_MASK_BITS_ABOVE (ObjDesc->CommonField.EndFieldValidBits); 1257 MergedDatum &= Mask; 1258 1259 /* Write the last datum with the update rule */ 1260 1261 Status = AcpiExWriteWithUpdateRule (ObjDesc, Mask, MergedDatum, 1262 FieldDatumByteOffset); 1263 if (ACPI_FAILURE (Status)) 1264 { 1265 return_ACPI_STATUS (Status); 1266 } 1267 } 1268 else 1269 { 1270 /* Normal (aligned) case -- write the completed datum */ 1271 1272 Status = AcpiExFieldDatumIo (ObjDesc, FieldDatumByteOffset, 1273 &MergedDatum, ACPI_WRITE); 1274 if (ACPI_FAILURE (Status)) 1275 { 1276 return_ACPI_STATUS (Status); 1277 } 1278 } 1279 1280 /* 1281 * Save the most recent datum since it may contain bits of the *next* 1282 * field datum. Update current byte offset. 1283 */ 1284 PreviousRawDatum = ThisRawDatum; 1285 } 1286 1287 return_ACPI_STATUS (Status); 1288} 1289 1290 1291