1 /******************************************************************************
3 * Module Name: aeregion - Operation region support for acpiexec
5 *****************************************************************************/
8 * Copyright (C) 2000 - 2015, Intel Corp.
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
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.
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.
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.
46 #define _COMPONENT ACPI_TOOLS
47 ACPI_MODULE_NAME ("aeregion")
50 /* Local prototypes */
54 ACPI_HANDLE RegionHandle,
57 void **RegionContext);
61 ACPI_HANDLE ObjHandle,
68 ACPI_HANDLE ObjHandle,
74 static AE_DEBUG_REGIONS AeRegions;
75 BOOLEAN AcpiGbl_DisplayRegionAccess = FALSE;
76 ACPI_CONNECTION_INFO AeMyContext;
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.
87 * NOTE: The local region handler will simulate access to these address
88 * spaces by creating a memory buffer behind each operation region.
90 static ACPI_ADR_SPACE_TYPE DefaultSpaceIdList[] =
92 ACPI_ADR_SPACE_SYSTEM_MEMORY,
93 ACPI_ADR_SPACE_SYSTEM_IO,
94 ACPI_ADR_SPACE_PCI_CONFIG,
99 * We will install handlers for some of the various address space IDs.
100 * Test one user-defined address space (used by aslts).
102 #define ACPI_ADR_SPACE_USER_DEFINED1 0x80
103 #define ACPI_ADR_SPACE_USER_DEFINED2 0xE4
105 static ACPI_ADR_SPACE_TYPE SpaceIdList[] =
107 ACPI_ADR_SPACE_SMBUS,
109 ACPI_ADR_SPACE_PCI_BAR_TARGET,
112 ACPI_ADR_SPACE_GSBUS,
113 ACPI_ADR_SPACE_FIXED_HARDWARE,
114 ACPI_ADR_SPACE_USER_DEFINED1,
115 ACPI_ADR_SPACE_USER_DEFINED2
119 /******************************************************************************
121 * FUNCTION: AeRegionInit
123 * PARAMETERS: Region init handler
127 * DESCRIPTION: Opregion init function.
129 *****************************************************************************/
133 ACPI_HANDLE RegionHandle,
135 void *HandlerContext,
136 void **RegionContext)
139 if (Function == ACPI_REGION_DEACTIVATE)
141 *RegionContext = NULL;
145 *RegionContext = RegionHandle;
153 AeInstallRegionHandlers (
160 * Install handlers for some of the "device driver" address spaces
161 * such as SMBus, etc.
163 for (i = 0; i < ACPI_ARRAY_LENGTH (SpaceIdList); i++)
165 /* Install handler at the root object */
167 Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT,
168 SpaceIdList[i], AeRegionHandler,
169 AeRegionInit, &AeMyContext);
170 if (ACPI_FAILURE (Status))
172 ACPI_EXCEPTION ((AE_INFO, Status,
173 "Could not install an OpRegion handler for %s space(%u)",
174 AcpiUtGetRegionName((UINT8) SpaceIdList[i]), SpaceIdList[i]));
182 AeOverrideRegionHandlers (
189 * Install handlers that will override the default handlers for some of
192 for (i = 0; i < ACPI_ARRAY_LENGTH (DefaultSpaceIdList); i++)
194 /* Install handler at the root object */
196 Status = AcpiInstallAddressSpaceHandler (ACPI_ROOT_OBJECT,
197 DefaultSpaceIdList[i], AeRegionHandler,
198 AeRegionInit, &AeMyContext);
199 if (ACPI_FAILURE (Status))
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]));
211 /*******************************************************************************
213 * FUNCTION: AeInstallDeviceHandlers,
214 * AeInstallEcHandler,
215 * AeInstallPciHandler
217 * PARAMETERS: ACPI_WALK_NAMESPACE callback
221 * DESCRIPTION: Walk entire namespace, install a handler for every EC
222 * and PCI device found.
224 ******************************************************************************/
228 ACPI_HANDLE ObjHandle,
236 /* Install the handler for this EC device */
238 Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_EC,
239 AeRegionHandler, AeRegionInit, &AeMyContext);
240 if (ACPI_FAILURE (Status))
242 ACPI_EXCEPTION ((AE_INFO, Status,
243 "Could not install an OpRegion handler for EC device (%p)",
252 AeInstallPciHandler (
253 ACPI_HANDLE ObjHandle,
261 /* Install memory and I/O handlers for the PCI device */
263 Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_IO,
264 AeRegionHandler, AeRegionInit, &AeMyContext);
265 if (ACPI_FAILURE (Status))
267 ACPI_EXCEPTION ((AE_INFO, Status,
268 "Could not install an OpRegion handler for PCI device (%p)",
272 Status = AcpiInstallAddressSpaceHandler (ObjHandle, ACPI_ADR_SPACE_SYSTEM_MEMORY,
273 AeRegionHandler, AeRegionInit, &AeMyContext);
274 if (ACPI_FAILURE (Status))
276 ACPI_EXCEPTION ((AE_INFO, Status,
277 "Could not install an OpRegion handler for PCI device (%p)",
281 return (AE_CTRL_TERMINATE);
286 AeInstallDeviceHandlers (
290 /* Find all Embedded Controller devices */
292 AcpiGetDevices ("PNP0C09", AeInstallEcHandler, NULL, NULL);
294 /* Install a PCI handler */
296 AcpiGetDevices ("PNP0A08", AeInstallPciHandler, NULL, NULL);
301 /******************************************************************************
303 * FUNCTION: AeRegionHandler
305 * PARAMETERS: Standard region handler parameters
309 * DESCRIPTION: Test handler - Handles some dummy regions via memory that can
310 * be manipulated in Ring 3. Simulates actual reads and writes.
312 *****************************************************************************/
317 ACPI_PHYSICAL_ADDRESS Address,
320 void *HandlerContext,
324 ACPI_OPERAND_OBJECT *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext);
325 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Value);
328 ACPI_PHYSICAL_ADDRESS BaseAddress;
329 ACPI_PHYSICAL_ADDRESS BaseAddressEnd;
330 ACPI_PHYSICAL_ADDRESS RegionAddress;
331 ACPI_PHYSICAL_ADDRESS RegionAddressEnd;
333 BOOLEAN BufferExists;
334 BOOLEAN BufferResize;
335 AE_REGION *RegionElement;
342 ACPI_CONNECTION_INFO *MyContext;
345 ACPI_RESOURCE *Resource;
348 ACPI_FUNCTION_NAME (AeRegionHandler);
351 * If the object is not a region, simply return
353 if (RegionObject->Region.Type != ACPI_TYPE_REGION)
358 /* Check that we actually got back our context parameter */
360 if (HandlerContext != &AeMyContext)
362 printf ("Region handler received incorrect context %p, should be %p\n",
363 HandlerContext, &AeMyContext);
366 MyContext = ACPI_CAST_PTR (ACPI_CONNECTION_INFO, HandlerContext);
369 * Find the region's address space and length before searching
372 BaseAddress = RegionObject->Region.Address;
373 Length = (ACPI_SIZE) RegionObject->Region.Length;
374 SpaceId = RegionObject->Region.SpaceId;
376 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION, "Operation Region request on %s at 0x%X\n",
377 AcpiUtGetRegionName (RegionObject->Region.SpaceId),
381 * Region support can be disabled with the -do option.
382 * We use this to support dynamically loaded tables where we pass a valid
383 * address to the AML.
385 if (AcpiGbl_DbOpt_NoRegionSupport)
387 BufferValue = ACPI_TO_POINTER (Address);
388 ByteWidth = (BitWidth / 8);
399 case ACPI_ADR_SPACE_SYSTEM_IO:
401 * For I/O space, exercise the port validation
402 * Note: ReadPort currently always returns all ones, length=BitLength
404 switch (Function & ACPI_IO_MASK)
410 /* Split the 64-bit request into two 32-bit requests */
412 Status = AcpiHwReadPort (Address, &Value1, 32);
413 AE_CHECK_OK (AcpiHwReadPort, Status);
414 Status = AcpiHwReadPort (Address+4, &Value2, 32);
415 AE_CHECK_OK (AcpiHwReadPort, Status);
417 *Value = Value1 | ((UINT64) Value2 << 32);
421 Status = AcpiHwReadPort (Address, &Value1, BitWidth);
422 AE_CHECK_OK (AcpiHwReadPort, Status);
423 *Value = (UINT64) Value1;
431 /* Split the 64-bit request into two 32-bit requests */
433 Status = AcpiHwWritePort (Address, ACPI_LODWORD (*Value), 32);
434 AE_CHECK_OK (AcpiHwWritePort, Status);
435 Status = AcpiHwWritePort (Address+4, ACPI_HIDWORD (*Value), 32);
436 AE_CHECK_OK (AcpiHwWritePort, Status);
440 Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth);
441 AE_CHECK_OK (AcpiHwWritePort, Status);
447 Status = AE_BAD_PARAMETER;
451 if (ACPI_FAILURE (Status))
456 /* Now go ahead and simulate the hardware */
460 * SMBus and GenericSerialBus support the various bidirectional
463 case ACPI_ADR_SPACE_SMBUS:
464 case ACPI_ADR_SPACE_GSBUS: /* ACPI 5.0 */
468 switch (Function & ACPI_IO_MASK)
472 switch (Function >> 16)
474 case AML_FIELD_ATTRIB_QUICK:
479 case AML_FIELD_ATTRIB_SEND_RCV:
480 case AML_FIELD_ATTRIB_BYTE:
485 case AML_FIELD_ATTRIB_WORD:
486 case AML_FIELD_ATTRIB_WORD_CALL:
491 case AML_FIELD_ATTRIB_BLOCK:
492 case AML_FIELD_ATTRIB_BLOCK_CALL:
497 case AML_FIELD_ATTRIB_MULTIBYTE:
498 case AML_FIELD_ATTRIB_RAW_BYTES:
499 case AML_FIELD_ATTRIB_RAW_PROCESS:
501 Length = MyContext->AccessLength;
512 switch (Function >> 16)
514 case AML_FIELD_ATTRIB_QUICK:
515 case AML_FIELD_ATTRIB_SEND_RCV:
516 case AML_FIELD_ATTRIB_BYTE:
517 case AML_FIELD_ATTRIB_WORD:
518 case AML_FIELD_ATTRIB_BLOCK:
523 case AML_FIELD_ATTRIB_WORD_CALL:
527 case AML_FIELD_ATTRIB_BLOCK_CALL:
531 case AML_FIELD_ATTRIB_MULTIBYTE:
532 case AML_FIELD_ATTRIB_RAW_BYTES:
533 case AML_FIELD_ATTRIB_RAW_PROCESS:
535 Length = MyContext->AccessLength;
549 if (AcpiGbl_DisplayRegionAccess)
551 AcpiOsPrintf ("AcpiExec: %s "
552 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X",
553 AcpiUtGetRegionName (SpaceId),
554 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
555 (UINT32) (Function >> 16),
556 (UINT32) Address, (UINT32) BaseAddress,
557 Length, BitWidth, Buffer[1]);
559 /* GenericSerialBus has a Connection() parameter */
561 if (SpaceId == ACPI_ADR_SPACE_GSBUS)
563 Status = AcpiBufferToResource (MyContext->Connection,
564 MyContext->Length, &Resource);
566 AcpiOsPrintf (" [AccLen %.2X Conn %p]",
567 MyContext->AccessLength, MyContext->Connection);
572 /* Setup the return buffer. Note: ASLTS depends on these fill values */
574 for (i = 0; i < Length; i++)
576 Buffer[i+2] = (UINT8) (0xA0 + i);
580 Buffer[1] = (UINT8) Length;
584 case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */
586 if (AcpiGbl_DisplayRegionAccess)
588 AcpiOsPrintf ("AcpiExec: IPMI "
589 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X\n",
590 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
591 (UINT32) (Function >> 16), (UINT32) Address, (UINT32) BaseAddress,
592 Length, BitWidth, Buffer[1]);
596 * Regardless of a READ or WRITE, this handler is passed a 66-byte
597 * buffer in which to return the IPMI status/length/data.
599 * Return some example data to show use of the bidirectional buffer
601 Buffer[0] = 0; /* Status byte */
602 Buffer[1] = 64; /* Return buffer data length */
603 Buffer[2] = 0; /* Completion code */
604 Buffer[3] = 0; /* Reserved */
607 * Fill the 66-byte buffer with the return data.
608 * Note: ASLTS depends on these fill values.
610 for (i = 4; i < 66; i++)
612 Buffer[i] = (UINT8) (i);
617 * GPIO has some special semantics:
618 * 1) Address is the pin number index into the Connection() pin list
619 * 2) BitWidth is the actual number of bits (pins) defined by the field
621 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
623 if (AcpiGbl_DisplayRegionAccess)
625 AcpiOsPrintf ("AcpiExec: GPIO "
626 "%s: Addr %.4X Width %X Conn %p\n",
627 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
628 (UINT32) Address, BitWidth, MyContext->Connection);
637 * Search through the linked list for this region's buffer
639 BufferExists = FALSE;
640 BufferResize = FALSE;
641 RegionElement = AeRegions.RegionList;
643 if (AeRegions.NumberOfRegions)
645 BaseAddressEnd = BaseAddress + Length - 1;
646 while (!BufferExists && RegionElement)
648 RegionAddress = RegionElement->Address;
649 RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1;
650 RegionLength = RegionElement->Length;
653 * Overlapping Region Support
655 * While searching through the region buffer list, determine if an
656 * overlap exists between the requested buffer space and the current
657 * RegionElement space. If there is an overlap then replace the old
658 * buffer with a new buffer of increased size before continuing to
659 * do the read or write
661 if (RegionElement->SpaceId != SpaceId ||
662 BaseAddressEnd < RegionAddress ||
663 BaseAddress > RegionAddressEnd)
666 * Requested buffer is outside of the current RegionElement
669 RegionElement = RegionElement->NextRegion;
674 * Some amount of buffer space sharing exists. There are 4 cases
679 * 3. Left and right overlap
680 * 4. Fully contained - no resizing required
684 if ((BaseAddress >= RegionAddress) &&
685 (BaseAddress <= RegionAddressEnd) &&
686 (BaseAddressEnd > RegionAddressEnd))
690 RegionElement->Length = (UINT32) (BaseAddress -
691 RegionAddress + Length);
695 else if ((BaseAddressEnd >= RegionAddress) &&
696 (BaseAddressEnd <= RegionAddressEnd) &&
697 (BaseAddress < RegionAddress))
701 RegionElement->Address = BaseAddress;
702 RegionElement->Length = (UINT32) (RegionAddress -
703 BaseAddress + RegionElement->Length);
707 else if ((BaseAddress < RegionAddress) &&
708 (BaseAddressEnd > RegionAddressEnd))
710 /* Left and right overlap */
712 RegionElement->Address = BaseAddress;
713 RegionElement->Length = Length;
718 * only remaining case is fully contained for which we don't
719 * need to do anything
723 NewBuffer = AcpiOsAllocate (RegionElement->Length);
726 return (AE_NO_MEMORY);
729 OldBuffer = RegionElement->Buffer;
730 RegionElement->Buffer = NewBuffer;
733 /* Initialize the region with the default fill value */
735 memset (RegionElement->Buffer,
736 AcpiGbl_RegionFillValue, RegionElement->Length);
739 * Get BufferValue to point (within the new buffer) to the
740 * base address of the old buffer
742 BufferValue = (UINT8 *) RegionElement->Buffer +
743 (UINT64) RegionAddress -
744 (UINT64) RegionElement->Address;
747 * Copy the old buffer to its same location within the new
750 memcpy (BufferValue, OldBuffer, RegionLength);
751 AcpiOsFree (OldBuffer);
758 * If the Region buffer does not exist, create it now
762 /* Do the memory allocations first */
764 RegionElement = AcpiOsAllocate (sizeof (AE_REGION));
767 return (AE_NO_MEMORY);
770 RegionElement->Buffer = AcpiOsAllocate (Length);
771 if (!RegionElement->Buffer)
773 AcpiOsFree (RegionElement);
774 return (AE_NO_MEMORY);
777 /* Initialize the region with the default fill value */
779 memset (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length);
781 RegionElement->Address = BaseAddress;
782 RegionElement->Length = Length;
783 RegionElement->SpaceId = SpaceId;
784 RegionElement->NextRegion = NULL;
787 * Increment the number of regions and put this one
788 * at the head of the list as it will probably get accessed
791 AeRegions.NumberOfRegions += 1;
793 if (AeRegions.RegionList)
795 RegionElement->NextRegion = AeRegions.RegionList;
798 AeRegions.RegionList = RegionElement;
801 /* Calculate the size of the memory copy */
803 ByteWidth = (BitWidth / 8);
811 * The buffer exists and is pointed to by RegionElement.
812 * We now need to verify the request is valid and perform the operation.
814 * NOTE: RegionElement->Length is in bytes, therefore it we compare against
815 * ByteWidth (see above)
817 if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) &&
818 ((UINT64) Address + ByteWidth) >
819 ((UINT64)(RegionElement->Address) + RegionElement->Length))
821 ACPI_WARNING ((AE_INFO,
822 "Request on [%4.4s] is beyond region limit Req-0x%X+0x%X, Base=0x%X, Len-0x%X",
823 (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address,
824 ByteWidth, (UINT32)(RegionElement->Address),
825 RegionElement->Length));
827 return (AE_AML_REGION_LIMIT);
831 * Get BufferValue to point to the "address" in the buffer
833 BufferValue = ((UINT8 *) RegionElement->Buffer +
834 ((UINT64) Address - (UINT64) RegionElement->Address));
838 * Perform a read or write to the buffer space
844 * Set the pointer Value to whatever is in the buffer
846 memcpy (Value, BufferValue, ByteWidth);
851 * Write the contents of Value to the buffer
853 memcpy (BufferValue, Value, ByteWidth);
858 return (AE_BAD_PARAMETER);
861 if (AcpiGbl_DisplayRegionAccess)
865 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
867 AcpiOsPrintf ("AcpiExec: SystemMemory "
868 "%s: Val %.8X Addr %.4X Width %X [REGION: BaseAddr %.4X Len %.2X]\n",
869 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
870 (UINT32) *Value, (UINT32) Address, BitWidth, (UINT32) BaseAddress, Length);
873 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
875 /* This space is required to always be ByteAcc */
877 Status = AcpiBufferToResource (MyContext->Connection,
878 MyContext->Length, &Resource);
880 AcpiOsPrintf ("AcpiExec: GeneralPurposeIo "
881 "%s: Val %.8X Addr %.4X BaseAddr %.4X Len %.2X Width %X AccLen %.2X Conn %p\n",
882 (Function & ACPI_IO_MASK) ? "Write" : "Read ", (UINT32) *Value,
883 (UINT32) Address, (UINT32) BaseAddress, Length, BitWidth,
884 MyContext->AccessLength, MyContext->Connection);