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