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