1 /****************************************************************************** 2 * 3 * Module Name: aeregion - Operation region support for acpiexec 4 * 5 *****************************************************************************/ 6 7 /* 8 * Copyright (C) 2000 - 2015, 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 #include "aecommon.h" 45 46 #define _COMPONENT ACPI_TOOLS 47 ACPI_MODULE_NAME ("aeregion") 48 49 50 /* Local prototypes */ 51 52 static ACPI_STATUS 53 AeRegionInit ( 54 ACPI_HANDLE RegionHandle, 55 UINT32 Function, 56 void *HandlerContext, 57 void **RegionContext); 58 59 static ACPI_STATUS 60 AeInstallEcHandler ( 61 ACPI_HANDLE ObjHandle, 62 UINT32 Level, 63 void *Context, 64 void **ReturnValue); 65 66 static ACPI_STATUS 67 AeInstallPciHandler ( 68 ACPI_HANDLE ObjHandle, 69 UINT32 Level, 70 void *Context, 71 void **ReturnValue); 72 73 74 static AE_DEBUG_REGIONS AeRegions; 75 BOOLEAN AcpiGbl_DisplayRegionAccess = FALSE; 76 ACPI_CONNECTION_INFO AeMyContext; 77 78 79 /* 80 * We will override some of the default region handlers, especially 81 * the SystemMemory handler, which must be implemented locally. 82 * These handlers are installed "early" - before any _REG methods 83 * are executed - since they are special in the sense that the ACPI spec 84 * declares that they must "always be available". Cannot override the 85 * DataTable region handler either -- needed for test execution. 86 * 87 * NOTE: The local region handler will simulate access to these address 88 * spaces by creating a memory buffer behind each operation region. 89 */ 90 static ACPI_ADR_SPACE_TYPE DefaultSpaceIdList[] = 91 { 92 ACPI_ADR_SPACE_SYSTEM_MEMORY, 93 ACPI_ADR_SPACE_SYSTEM_IO, 94 ACPI_ADR_SPACE_PCI_CONFIG, 95 ACPI_ADR_SPACE_EC 96 }; 97 98 /* 99 * We will install handlers for some of the various address space IDs. 100 * Test one user-defined address space (used by aslts). 101 */ 102 #define ACPI_ADR_SPACE_USER_DEFINED1 0x80 103 #define ACPI_ADR_SPACE_USER_DEFINED2 0xE4 104 105 static ACPI_ADR_SPACE_TYPE SpaceIdList[] = 106 { 107 ACPI_ADR_SPACE_SMBUS, 108 ACPI_ADR_SPACE_CMOS, 109 ACPI_ADR_SPACE_PCI_BAR_TARGET, 110 ACPI_ADR_SPACE_IPMI, 111 ACPI_ADR_SPACE_GPIO, 112 ACPI_ADR_SPACE_GSBUS, 113 ACPI_ADR_SPACE_FIXED_HARDWARE, 114 ACPI_ADR_SPACE_USER_DEFINED1, 115 ACPI_ADR_SPACE_USER_DEFINED2 116 }; 117 118 119 /****************************************************************************** 120 * 121 * FUNCTION: AeRegionInit 122 * 123 * PARAMETERS: Region init handler 124 * 125 * RETURN: Status 126 * 127 * DESCRIPTION: Opregion init function. 128 * 129 *****************************************************************************/ 130 131 static ACPI_STATUS 132 AeRegionInit ( 133 ACPI_HANDLE RegionHandle, 134 UINT32 Function, 135 void *HandlerContext, 136 void **RegionContext) 137 { 138 139 if (Function == ACPI_REGION_DEACTIVATE) 140 { 141 *RegionContext = NULL; 142 } 143 else 144 { 145 *RegionContext = RegionHandle; 146 } 147 148 return (AE_OK); 149 } 150 151 152 void 153 AeInstallRegionHandlers ( 154 void) 155 { 156 UINT32 i; 157 ACPI_STATUS Status; 158 159 /* 160 * Install handlers for some of the "device driver" address spaces 161 * such as SMBus, etc. 162 */ 163 for (i = 0; i < ACPI_ARRAY_LENGTH (SpaceIdList); i++) 164 { 165 /* Install handler at the root object */ 166 167 Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT, 168 SpaceIdList[i], AeRegionHandler, 169 AeRegionInit, &AeMyContext); 170 if (ACPI_FAILURE (Status)) 171 { 172 ACPI_EXCEPTION ((AE_INFO, Status, 173 "Could not install an OpRegion handler for %s space(%u)", 174 AcpiUtGetRegionName((UINT8) SpaceIdList[i]), SpaceIdList[i])); 175 return; 176 } 177 } 178 } 179 180 181 void 182 AeOverrideRegionHandlers ( 183 void) 184 { 185 UINT32 i; 186 ACPI_STATUS Status; 187 188 /* 189 * Install handlers that will override the default handlers for some of 190 * the space IDs. 191 */ 192 for (i = 0; i < ACPI_ARRAY_LENGTH (DefaultSpaceIdList); i++) 193 { 194 /* Install handler at the root object */ 195 196 Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT, 197 DefaultSpaceIdList[i], AeRegionHandler, 198 AeRegionInit, &AeMyContext); 199 if (ACPI_FAILURE (Status)) 200 { 201 ACPI_EXCEPTION ((AE_INFO, Status, 202 "Could not install a default OpRegion handler for %s space(%u)", 203 AcpiUtGetRegionName ((UINT8) DefaultSpaceIdList[i]), 204 DefaultSpaceIdList[i])); 205 return; 206 } 207 } 208 } 209 210 211 /******************************************************************************* 212 * 213 * FUNCTION: AeInstallDeviceHandlers, 214 * AeInstallEcHandler, 215 * AeInstallPciHandler 216 * 217 * PARAMETERS: ACPI_WALK_NAMESPACE callback 218 * 219 * RETURN: Status 220 * 221 * DESCRIPTION: Walk entire namespace, install a handler for every EC 222 * and PCI device found. 223 * 224 ******************************************************************************/ 225 226 static ACPI_STATUS 227 AeInstallEcHandler ( 228 ACPI_HANDLE ObjHandle, 229 UINT32 Level, 230 void *Context, 231 void **ReturnValue) 232 { 233 ACPI_STATUS Status; 234 235 236 /* Install the handler for this EC device */ 237 238 Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_EC, 239 AeRegionHandler, AeRegionInit, &AeMyContext); 240 if (ACPI_FAILURE (Status)) 241 { 242 ACPI_EXCEPTION ((AE_INFO, Status, 243 "Could not install an OpRegion handler for EC device (%p)", 244 ObjHandle)); 245 } 246 247 return (Status); 248 } 249 250 251 static ACPI_STATUS 252 AeInstallPciHandler ( 253 ACPI_HANDLE ObjHandle, 254 UINT32 Level, 255 void *Context, 256 void **ReturnValue) 257 { 258 ACPI_STATUS Status; 259 260 261 /* Install memory and I/O handlers for the PCI device */ 262 263 Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_IO, 264 AeRegionHandler, AeRegionInit, &AeMyContext); 265 if (ACPI_FAILURE (Status)) 266 { 267 ACPI_EXCEPTION ((AE_INFO, Status, 268 "Could not install an OpRegion handler for PCI device (%p)", 269 ObjHandle)); 270 } 271 272 Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_MEMORY, 273 AeRegionHandler, AeRegionInit, &AeMyContext); 274 if (ACPI_FAILURE (Status)) 275 { 276 ACPI_EXCEPTION ((AE_INFO, Status, 277 "Could not install an OpRegion handler for PCI device (%p)", 278 ObjHandle)); 279 } 280 281 return (AE_CTRL_TERMINATE); 282 } 283 284 285 ACPI_STATUS 286 AeInstallDeviceHandlers ( 287 void) 288 { 289 290 /* Find all Embedded Controller devices */ 291 292 AcpiGetDevices ("PNP0C09", AeInstallEcHandler, NULL, NULL); 293 294 /* Install a PCI handler */ 295 296 AcpiGetDevices ("PNP0A08", AeInstallPciHandler, NULL, NULL); 297 return (AE_OK); 298 } 299 300 301 /****************************************************************************** 302 * 303 * FUNCTION: AeRegionHandler 304 * 305 * PARAMETERS: Standard region handler parameters 306 * 307 * RETURN: Status 308 * 309 * DESCRIPTION: Test handler - Handles some dummy regions via memory that can 310 * be manipulated in Ring 3. Simulates actual reads and writes. 311 * 312 *****************************************************************************/ 313 314 ACPI_STATUS 315 AeRegionHandler ( 316 UINT32 Function, 317 ACPI_PHYSICAL_ADDRESS Address, 318 UINT32 BitWidth, 319 UINT64 *Value, 320 void *HandlerContext, 321 void *RegionContext) 322 { 323 324 ACPI_OPERAND_OBJECT *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext); 325 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Value); 326 UINT8 *OldBuffer; 327 UINT8 *NewBuffer; 328 ACPI_PHYSICAL_ADDRESS BaseAddress; 329 ACPI_PHYSICAL_ADDRESS BaseAddressEnd; 330 ACPI_PHYSICAL_ADDRESS RegionAddress; 331 ACPI_PHYSICAL_ADDRESS RegionAddressEnd; 332 ACPI_SIZE Length; 333 BOOLEAN BufferExists; 334 BOOLEAN BufferResize; 335 AE_REGION *RegionElement; 336 void *BufferValue; 337 ACPI_STATUS Status; 338 UINT32 ByteWidth; 339 UINT32 RegionLength; 340 UINT32 i; 341 UINT8 SpaceId; 342 ACPI_CONNECTION_INFO *MyContext; 343 UINT32 Value1; 344 UINT32 Value2; 345 ACPI_RESOURCE *Resource; 346 347 348 ACPI_FUNCTION_NAME (AeRegionHandler); 349 350 /* 351 * If the object is not a region, simply return 352 */ 353 if (RegionObject->Region.Type != ACPI_TYPE_REGION) 354 { 355 return (AE_OK); 356 } 357 358 /* Check that we actually got back our context parameter */ 359 360 if (HandlerContext != &AeMyContext) 361 { 362 printf ("Region handler received incorrect context %p, should be %p\n", 363 HandlerContext, &AeMyContext); 364 } 365 366 MyContext = ACPI_CAST_PTR (ACPI_CONNECTION_INFO, HandlerContext); 367 368 /* 369 * Find the region's address space and length before searching 370 * the linked list. 371 */ 372 BaseAddress = RegionObject->Region.Address; 373 Length = (ACPI_SIZE) RegionObject->Region.Length; 374 SpaceId = RegionObject->Region.SpaceId; 375 376 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, 377 "Operation Region request on %s at 0x%X\n", 378 AcpiUtGetRegionName (RegionObject->Region.SpaceId), 379 (UINT32) Address)); 380 381 /* 382 * Region support can be disabled with the -do option. 383 * We use this to support dynamically loaded tables where we pass a valid 384 * address to the AML. 385 */ 386 if (AcpiGbl_DbOpt_NoRegionSupport) 387 { 388 BufferValue = ACPI_TO_POINTER (Address); 389 ByteWidth = (BitWidth / 8); 390 391 if (BitWidth % 8) 392 { 393 ByteWidth += 1; 394 } 395 goto DoFunction; 396 } 397 398 switch (SpaceId) 399 { 400 case ACPI_ADR_SPACE_SYSTEM_IO: 401 /* 402 * For I/O space, exercise the port validation 403 * Note: ReadPort currently always returns all ones, length=BitLength 404 */ 405 switch (Function & ACPI_IO_MASK) 406 { 407 case ACPI_READ: 408 409 if (BitWidth == 64) 410 { 411 /* Split the 64-bit request into two 32-bit requests */ 412 413 Status = AcpiHwReadPort (Address, &Value1, 32); 414 ACPI_CHECK_OK (AcpiHwReadPort, Status); 415 Status = AcpiHwReadPort (Address+4, &Value2, 32); 416 ACPI_CHECK_OK (AcpiHwReadPort, Status); 417 418 *Value = Value1 | ((UINT64) Value2 << 32); 419 } 420 else 421 { 422 Status = AcpiHwReadPort (Address, &Value1, BitWidth); 423 ACPI_CHECK_OK (AcpiHwReadPort, Status); 424 *Value = (UINT64) Value1; 425 } 426 break; 427 428 case ACPI_WRITE: 429 430 if (BitWidth == 64) 431 { 432 /* Split the 64-bit request into two 32-bit requests */ 433 434 Status = AcpiHwWritePort (Address, ACPI_LODWORD (*Value), 32); 435 ACPI_CHECK_OK (AcpiHwWritePort, Status); 436 Status = AcpiHwWritePort (Address+4, ACPI_HIDWORD (*Value), 32); 437 ACPI_CHECK_OK (AcpiHwWritePort, Status); 438 } 439 else 440 { 441 Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth); 442 ACPI_CHECK_OK (AcpiHwWritePort, Status); 443 } 444 break; 445 446 default: 447 448 Status = AE_BAD_PARAMETER; 449 break; 450 } 451 452 if (ACPI_FAILURE (Status)) 453 { 454 return (Status); 455 } 456 457 /* Now go ahead and simulate the hardware */ 458 break; 459 460 /* 461 * SMBus and GenericSerialBus support the various bidirectional 462 * protocols. 463 */ 464 case ACPI_ADR_SPACE_SMBUS: 465 case ACPI_ADR_SPACE_GSBUS: /* ACPI 5.0 */ 466 467 Length = 0; 468 469 switch (Function & ACPI_IO_MASK) 470 { 471 case ACPI_READ: 472 473 switch (Function >> 16) 474 { 475 case AML_FIELD_ATTRIB_QUICK: 476 477 Length = 0; 478 break; 479 480 case AML_FIELD_ATTRIB_SEND_RCV: 481 case AML_FIELD_ATTRIB_BYTE: 482 483 Length = 1; 484 break; 485 486 case AML_FIELD_ATTRIB_WORD: 487 case AML_FIELD_ATTRIB_WORD_CALL: 488 489 Length = 2; 490 break; 491 492 case AML_FIELD_ATTRIB_BLOCK: 493 case AML_FIELD_ATTRIB_BLOCK_CALL: 494 495 Length = 32; 496 break; 497 498 case AML_FIELD_ATTRIB_MULTIBYTE: 499 case AML_FIELD_ATTRIB_RAW_BYTES: 500 case AML_FIELD_ATTRIB_RAW_PROCESS: 501 502 Length = MyContext->AccessLength; 503 break; 504 505 default: 506 507 break; 508 } 509 break; 510 511 case ACPI_WRITE: 512 513 switch (Function >> 16) 514 { 515 case AML_FIELD_ATTRIB_QUICK: 516 case AML_FIELD_ATTRIB_SEND_RCV: 517 case AML_FIELD_ATTRIB_BYTE: 518 case AML_FIELD_ATTRIB_WORD: 519 case AML_FIELD_ATTRIB_BLOCK: 520 521 Length = 0; 522 break; 523 524 case AML_FIELD_ATTRIB_WORD_CALL: 525 Length = 2; 526 break; 527 528 case AML_FIELD_ATTRIB_BLOCK_CALL: 529 Length = 32; 530 break; 531 532 case AML_FIELD_ATTRIB_MULTIBYTE: 533 case AML_FIELD_ATTRIB_RAW_BYTES: 534 case AML_FIELD_ATTRIB_RAW_PROCESS: 535 536 Length = MyContext->AccessLength; 537 break; 538 539 default: 540 541 break; 542 } 543 break; 544 545 default: 546 547 break; 548 } 549 550 if (AcpiGbl_DisplayRegionAccess) 551 { 552 AcpiOsPrintf ("AcpiExec: %s " 553 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X", 554 AcpiUtGetRegionName (SpaceId), 555 (Function & ACPI_IO_MASK) ? "Write" : "Read ", 556 (UINT32) (Function >> 16), 557 (UINT32) Address, (UINT32) BaseAddress, 558 Length, BitWidth, Buffer[1]); 559 560 /* GenericSerialBus has a Connection() parameter */ 561 562 if (SpaceId == ACPI_ADR_SPACE_GSBUS) 563 { 564 Status = AcpiBufferToResource (MyContext->Connection, 565 MyContext->Length, &Resource); 566 567 AcpiOsPrintf (" [AccLen %.2X Conn %p]", 568 MyContext->AccessLength, MyContext->Connection); 569 } 570 AcpiOsPrintf ("\n"); 571 } 572 573 /* Setup the return buffer. Note: ASLTS depends on these fill values */ 574 575 for (i = 0; i < Length; i++) 576 { 577 Buffer[i+2] = (UINT8) (0xA0 + i); 578 } 579 580 Buffer[0] = 0x7A; 581 Buffer[1] = (UINT8) Length; 582 return (AE_OK); 583 584 585 case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */ 586 587 if (AcpiGbl_DisplayRegionAccess) 588 { 589 AcpiOsPrintf ("AcpiExec: IPMI " 590 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X\n", 591 (Function & ACPI_IO_MASK) ? "Write" : "Read ", 592 (UINT32) (Function >> 16), (UINT32) Address, (UINT32) BaseAddress, 593 Length, BitWidth, Buffer[1]); 594 } 595 596 /* 597 * Regardless of a READ or WRITE, this handler is passed a 66-byte 598 * buffer in which to return the IPMI status/length/data. 599 * 600 * Return some example data to show use of the bidirectional buffer 601 */ 602 Buffer[0] = 0; /* Status byte */ 603 Buffer[1] = 64; /* Return buffer data length */ 604 Buffer[2] = 0; /* Completion code */ 605 Buffer[3] = 0; /* Reserved */ 606 607 /* 608 * Fill the 66-byte buffer with the return data. 609 * Note: ASLTS depends on these fill values. 610 */ 611 for (i = 4; i < 66; i++) 612 { 613 Buffer[i] = (UINT8) (i); 614 } 615 return (AE_OK); 616 617 /* 618 * GPIO has some special semantics: 619 * 1) Address is the pin number index into the Connection() pin list 620 * 2) BitWidth is the actual number of bits (pins) defined by the field 621 */ 622 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */ 623 624 if (AcpiGbl_DisplayRegionAccess) 625 { 626 AcpiOsPrintf ("AcpiExec: GPIO " 627 "%s: Addr %.4X Width %X Conn %p\n", 628 (Function & ACPI_IO_MASK) ? "Write" : "Read ", 629 (UINT32) Address, BitWidth, MyContext->Connection); 630 } 631 return (AE_OK); 632 633 default: 634 break; 635 } 636 637 /* 638 * Search through the linked list for this region's buffer 639 */ 640 BufferExists = FALSE; 641 BufferResize = FALSE; 642 RegionElement = AeRegions.RegionList; 643 644 if (AeRegions.NumberOfRegions) 645 { 646 BaseAddressEnd = BaseAddress + Length - 1; 647 while (!BufferExists && RegionElement) 648 { 649 RegionAddress = RegionElement->Address; 650 RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1; 651 RegionLength = RegionElement->Length; 652 653 /* 654 * Overlapping Region Support 655 * 656 * While searching through the region buffer list, determine if an 657 * overlap exists between the requested buffer space and the current 658 * RegionElement space. If there is an overlap then replace the old 659 * buffer with a new buffer of increased size before continuing to 660 * do the read or write 661 */ 662 if (RegionElement->SpaceId != SpaceId || 663 BaseAddressEnd < RegionAddress || 664 BaseAddress > RegionAddressEnd) 665 { 666 /* 667 * Requested buffer is outside of the current RegionElement 668 * bounds 669 */ 670 RegionElement = RegionElement->NextRegion; 671 } 672 else 673 { 674 /* 675 * Some amount of buffer space sharing exists. There are 4 cases 676 * to consider: 677 * 678 * 1. Right overlap 679 * 2. Left overlap 680 * 3. Left and right overlap 681 * 4. Fully contained - no resizing required 682 */ 683 BufferExists = TRUE; 684 685 if ((BaseAddress >= RegionAddress) && 686 (BaseAddress <= RegionAddressEnd) && 687 (BaseAddressEnd > RegionAddressEnd)) 688 { 689 /* Right overlap */ 690 691 RegionElement->Length = (UINT32) (BaseAddress - 692 RegionAddress + Length); 693 BufferResize = TRUE; 694 } 695 696 else if ((BaseAddressEnd >= RegionAddress) && 697 (BaseAddressEnd <= RegionAddressEnd) && 698 (BaseAddress < RegionAddress)) 699 { 700 /* Left overlap */ 701 702 RegionElement->Address = BaseAddress; 703 RegionElement->Length = (UINT32) (RegionAddress - 704 BaseAddress + RegionElement->Length); 705 BufferResize = TRUE; 706 } 707 708 else if ((BaseAddress < RegionAddress) && 709 (BaseAddressEnd > RegionAddressEnd)) 710 { 711 /* Left and right overlap */ 712 713 RegionElement->Address = BaseAddress; 714 RegionElement->Length = Length; 715 BufferResize = TRUE; 716 } 717 718 /* 719 * only remaining case is fully contained for which we don't 720 * need to do anything 721 */ 722 if (BufferResize) 723 { 724 NewBuffer = AcpiOsAllocate (RegionElement->Length); 725 if (!NewBuffer) 726 { 727 return (AE_NO_MEMORY); 728 } 729 730 OldBuffer = RegionElement->Buffer; 731 RegionElement->Buffer = NewBuffer; 732 NewBuffer = NULL; 733 734 /* Initialize the region with the default fill value */ 735 736 memset (RegionElement->Buffer, 737 AcpiGbl_RegionFillValue, RegionElement->Length); 738 739 /* 740 * Get BufferValue to point (within the new buffer) to the 741 * base address of the old buffer 742 */ 743 BufferValue = (UINT8 *) RegionElement->Buffer + 744 (UINT64) RegionAddress - 745 (UINT64) RegionElement->Address; 746 747 /* 748 * Copy the old buffer to its same location within the new 749 * buffer 750 */ 751 memcpy (BufferValue, OldBuffer, RegionLength); 752 AcpiOsFree (OldBuffer); 753 } 754 } 755 } 756 } 757 758 /* 759 * If the Region buffer does not exist, create it now 760 */ 761 if (!BufferExists) 762 { 763 /* Do the memory allocations first */ 764 765 RegionElement = AcpiOsAllocate (sizeof (AE_REGION)); 766 if (!RegionElement) 767 { 768 return (AE_NO_MEMORY); 769 } 770 771 RegionElement->Buffer = AcpiOsAllocate (Length); 772 if (!RegionElement->Buffer) 773 { 774 AcpiOsFree (RegionElement); 775 return (AE_NO_MEMORY); 776 } 777 778 /* Initialize the region with the default fill value */ 779 780 memset (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length); 781 782 RegionElement->Address = BaseAddress; 783 RegionElement->Length = Length; 784 RegionElement->SpaceId = SpaceId; 785 RegionElement->NextRegion = NULL; 786 787 /* 788 * Increment the number of regions and put this one 789 * at the head of the list as it will probably get accessed 790 * more often anyway. 791 */ 792 AeRegions.NumberOfRegions += 1; 793 794 if (AeRegions.RegionList) 795 { 796 RegionElement->NextRegion = AeRegions.RegionList; 797 } 798 799 AeRegions.RegionList = RegionElement; 800 } 801 802 /* Calculate the size of the memory copy */ 803 804 ByteWidth = (BitWidth / 8); 805 806 if (BitWidth % 8) 807 { 808 ByteWidth += 1; 809 } 810 811 /* 812 * The buffer exists and is pointed to by RegionElement. 813 * We now need to verify the request is valid and perform the operation. 814 * 815 * NOTE: RegionElement->Length is in bytes, therefore it we compare against 816 * ByteWidth (see above) 817 */ 818 if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) && 819 ((UINT64) Address + ByteWidth) > 820 ((UINT64)(RegionElement->Address) + RegionElement->Length)) 821 { 822 ACPI_WARNING ((AE_INFO, 823 "Request on [%4.4s] is beyond region limit " 824 "Req-0x%X+0x%X, Base=0x%X, Len-0x%X", 825 (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address, 826 ByteWidth, (UINT32)(RegionElement->Address), 827 RegionElement->Length)); 828 829 return (AE_AML_REGION_LIMIT); 830 } 831 832 /* 833 * Get BufferValue to point to the "address" in the buffer 834 */ 835 BufferValue = ((UINT8 *) RegionElement->Buffer + 836 ((UINT64) Address - (UINT64) RegionElement->Address)); 837 838 DoFunction: 839 /* 840 * Perform a read or write to the buffer space 841 */ 842 switch (Function) 843 { 844 case ACPI_READ: 845 /* 846 * Set the pointer Value to whatever is in the buffer 847 */ 848 memcpy (Value, BufferValue, ByteWidth); 849 break; 850 851 case ACPI_WRITE: 852 /* 853 * Write the contents of Value to the buffer 854 */ 855 memcpy (BufferValue, Value, ByteWidth); 856 break; 857 858 default: 859 860 return (AE_BAD_PARAMETER); 861 } 862 863 if (AcpiGbl_DisplayRegionAccess) 864 { 865 switch (SpaceId) 866 { 867 case ACPI_ADR_SPACE_SYSTEM_MEMORY: 868 869 AcpiOsPrintf ("AcpiExec: SystemMemory " 870 "%s: Val %.8X Addr %.4X Width %X [REGION: BaseAddr %.4X Len %.2X]\n", 871 (Function & ACPI_IO_MASK) ? "Write" : "Read ", 872 (UINT32) *Value, (UINT32) Address, BitWidth, (UINT32) BaseAddress, Length); 873 break; 874 875 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */ 876 877 /* This space is required to always be ByteAcc */ 878 879 Status = AcpiBufferToResource (MyContext->Connection, 880 MyContext->Length, &Resource); 881 882 AcpiOsPrintf ("AcpiExec: GeneralPurposeIo " 883 "%s: Val %.8X Addr %.4X BaseAddr %.4X Len %.2X Width %X AccLen %.2X Conn %p\n", 884 (Function & ACPI_IO_MASK) ? "Write" : "Read ", (UINT32) *Value, 885 (UINT32) Address, (UINT32) BaseAddress, Length, BitWidth, 886 MyContext->AccessLength, MyContext->Connection); 887 break; 888 889 default: 890 891 break; 892 } 893 } 894 895 return (AE_OK); 896 } 897