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