1 /******************************************************************************
2  *
3  * Module Name: aeregion - Handler for operation regions
4  *
5  *****************************************************************************/
6 
7 /******************************************************************************
8  *
9  * 1. Copyright Notice
10  *
11  * Some or all of this work - Copyright (c) 1999 - 2018, Intel Corp.
12  * All rights reserved.
13  *
14  * 2. License
15  *
16  * 2.1. This is your license from Intel Corp. under its intellectual property
17  * rights. You may have additional license terms from the party that provided
18  * you this software, covering your right to use that party's intellectual
19  * property rights.
20  *
21  * 2.2. Intel grants, free of charge, to any person ("Licensee") obtaining a
22  * copy of the source code appearing in this file ("Covered Code") an
23  * irrevocable, perpetual, worldwide license under Intel's copyrights in the
24  * base code distributed originally by Intel ("Original Intel Code") to copy,
25  * make derivatives, distribute, use and display any portion of the Covered
26  * Code in any form, with the right to sublicense such rights; and
27  *
28  * 2.3. Intel grants Licensee a non-exclusive and non-transferable patent
29  * license (with the right to sublicense), under only those claims of Intel
30  * patents that are infringed by the Original Intel Code, to make, use, sell,
31  * offer to sell, and import the Covered Code and derivative works thereof
32  * solely to the minimum extent necessary to exercise the above copyright
33  * license, and in no event shall the patent license extend to any additions
34  * to or modifications of the Original Intel Code. No other license or right
35  * is granted directly or by implication, estoppel or otherwise;
36  *
37  * The above copyright and patent license is granted only if the following
38  * conditions are met:
39  *
40  * 3. Conditions
41  *
42  * 3.1. Redistribution of Source with Rights to Further Distribute Source.
43  * Redistribution of source code of any substantial portion of the Covered
44  * Code or modification with rights to further distribute source must include
45  * the above Copyright Notice, the above License, this list of Conditions,
46  * and the following Disclaimer and Export Compliance provision. In addition,
47  * Licensee must cause all Covered Code to which Licensee contributes to
48  * contain a file documenting the changes Licensee made to create that Covered
49  * Code and the date of any change. Licensee must include in that file the
50  * documentation of any changes made by any predecessor Licensee. Licensee
51  * must include a prominent statement that the modification is derived,
52  * directly or indirectly, from Original Intel Code.
53  *
54  * 3.2. Redistribution of Source with no Rights to Further Distribute Source.
55  * Redistribution of source code of any substantial portion of the Covered
56  * Code or modification without rights to further distribute source must
57  * include the following Disclaimer and Export Compliance provision in the
58  * documentation and/or other materials provided with distribution. In
59  * addition, Licensee may not authorize further sublicense of source of any
60  * portion of the Covered Code, and must include terms to the effect that the
61  * license from Licensee to its licensee is limited to the intellectual
62  * property embodied in the software Licensee provides to its licensee, and
63  * not to intellectual property embodied in modifications its licensee may
64  * make.
65  *
66  * 3.3. Redistribution of Executable. Redistribution in executable form of any
67  * substantial portion of the Covered Code or modification must reproduce the
68  * above Copyright Notice, and the following Disclaimer and Export Compliance
69  * provision in the documentation and/or other materials provided with the
70  * distribution.
71  *
72  * 3.4. Intel retains all right, title, and interest in and to the Original
73  * Intel Code.
74  *
75  * 3.5. Neither the name Intel nor any other trademark owned or controlled by
76  * Intel shall be used in advertising or otherwise to promote the sale, use or
77  * other dealings in products derived from or relating to the Covered Code
78  * without prior written authorization from Intel.
79  *
80  * 4. Disclaimer and Export Compliance
81  *
82  * 4.1. INTEL MAKES NO WARRANTY OF ANY KIND REGARDING ANY SOFTWARE PROVIDED
83  * HERE. ANY SOFTWARE ORIGINATING FROM INTEL OR DERIVED FROM INTEL SOFTWARE
84  * IS PROVIDED "AS IS," AND INTEL WILL NOT PROVIDE ANY SUPPORT, ASSISTANCE,
85  * INSTALLATION, TRAINING OR OTHER SERVICES. INTEL WILL NOT PROVIDE ANY
86  * UPDATES, ENHANCEMENTS OR EXTENSIONS. INTEL SPECIFICALLY DISCLAIMS ANY
87  * IMPLIED WARRANTIES OF MERCHANTABILITY, NONINFRINGEMENT AND FITNESS FOR A
88  * PARTICULAR PURPOSE.
89  *
90  * 4.2. IN NO EVENT SHALL INTEL HAVE ANY LIABILITY TO LICENSEE, ITS LICENSEES
91  * OR ANY OTHER THIRD PARTY, FOR ANY LOST PROFITS, LOST DATA, LOSS OF USE OR
92  * COSTS OF PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES, OR FOR ANY INDIRECT,
93  * SPECIAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THIS AGREEMENT, UNDER ANY
94  * CAUSE OF ACTION OR THEORY OF LIABILITY, AND IRRESPECTIVE OF WHETHER INTEL
95  * HAS ADVANCE NOTICE OF THE POSSIBILITY OF SUCH DAMAGES. THESE LIMITATIONS
96  * SHALL APPLY NOTWITHSTANDING THE FAILURE OF THE ESSENTIAL PURPOSE OF ANY
97  * LIMITED REMEDY.
98  *
99  * 4.3. Licensee shall not export, either directly or indirectly, any of this
100  * software or system incorporating such software without first obtaining any
101  * required license or other approval from the U. S. Department of Commerce or
102  * any other agency or department of the United States Government. In the
103  * event Licensee exports any such software from the United States or
104  * re-exports any such software from a foreign destination, Licensee shall
105  * ensure that the distribution and export/re-export of the software is in
106  * compliance with all laws, regulations, orders, or other restrictions of the
107  * U.S. Export Administration Regulations. Licensee agrees that neither it nor
108  * any of its subsidiaries will export/re-export any technical data, process,
109  * software, or service, directly or indirectly, to any country for which the
110  * United States government or any agency thereof requires an export license,
111  * other governmental approval, or letter of assurance, without first obtaining
112  * such license, approval or letter.
113  *
114  *****************************************************************************
115  *
116  * Alternatively, you may choose to be licensed under the terms of the
117  * following license:
118  *
119  * Redistribution and use in source and binary forms, with or without
120  * modification, are permitted provided that the following conditions
121  * are met:
122  * 1. Redistributions of source code must retain the above copyright
123  *    notice, this list of conditions, and the following disclaimer,
124  *    without modification.
125  * 2. Redistributions in binary form must reproduce at minimum a disclaimer
126  *    substantially similar to the "NO WARRANTY" disclaimer below
127  *    ("Disclaimer") and any redistribution must be conditioned upon
128  *    including a substantially similar Disclaimer requirement for further
129  *    binary redistribution.
130  * 3. Neither the names of the above-listed copyright holders nor the names
131  *    of any contributors may be used to endorse or promote products derived
132  *    from this software without specific prior written permission.
133  *
134  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
135  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
136  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
137  * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
138  * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
139  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
140  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
141  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
142  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
143  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
144  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
145  *
146  * Alternatively, you may choose to be licensed under the terms of the
147  * GNU General Public License ("GPL") version 2 as published by the Free
148  * Software Foundation.
149  *
150  *****************************************************************************/
151 
152 #include "aecommon.h"
153 
154 #define _COMPONENT          ACPI_TOOLS
155         ACPI_MODULE_NAME    ("aeregion")
156 
157 
158 static AE_DEBUG_REGIONS     AeRegions;
159 
160 
161 /******************************************************************************
162  *
163  * FUNCTION:    AeRegionHandler
164  *
165  * PARAMETERS:  Standard region handler parameters
166  *
167  * RETURN:      Status
168  *
169  * DESCRIPTION: Test handler - Handles some dummy regions via memory that can
170  *              be manipulated in Ring 3. Simulates actual reads and writes.
171  *
172  *****************************************************************************/
173 
174 ACPI_STATUS
175 AeRegionHandler (
176     UINT32                  Function,
177     ACPI_PHYSICAL_ADDRESS   Address,
178     UINT32                  BitWidth,
179     UINT64                  *Value,
180     void                    *HandlerContext,
181     void                    *RegionContext)
182 {
183 
184     ACPI_OPERAND_OBJECT     *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext);
185     UINT8                   *Buffer = ACPI_CAST_PTR (UINT8, Value);
186     UINT8                   *OldBuffer;
187     UINT8                   *NewBuffer;
188     ACPI_PHYSICAL_ADDRESS   BaseAddress;
189     ACPI_PHYSICAL_ADDRESS   BaseAddressEnd;
190     ACPI_PHYSICAL_ADDRESS   RegionAddress;
191     ACPI_PHYSICAL_ADDRESS   RegionAddressEnd;
192     ACPI_SIZE               Length;
193     BOOLEAN                 BufferExists;
194     BOOLEAN                 BufferResize;
195     AE_REGION               *RegionElement;
196     void                    *BufferValue;
197     ACPI_STATUS             Status;
198     UINT32                  ByteWidth;
199     UINT32                  RegionLength;
200     UINT32                  i;
201     UINT8                   SpaceId;
202     ACPI_CONNECTION_INFO    *MyContext;
203     UINT32                  Value1;
204     UINT32                  Value2;
205     ACPI_RESOURCE           *Resource;
206 
207 
208     ACPI_FUNCTION_NAME (AeRegionHandler);
209 
210     /*
211      * If the object is not a region, simply return
212      */
213     if (RegionObject->Region.Type != ACPI_TYPE_REGION)
214     {
215         return (AE_OK);
216     }
217 
218     /* Check that we actually got back our context parameter */
219 
220     if (HandlerContext != &AeMyContext)
221     {
222         printf ("Region handler received incorrect context %p, should be %p\n",
223             HandlerContext, &AeMyContext);
224     }
225 
226     MyContext = ACPI_CAST_PTR (ACPI_CONNECTION_INFO, HandlerContext);
227 
228     /*
229      * Find the region's address space and length before searching
230      * the linked list.
231      */
232     BaseAddress = RegionObject->Region.Address;
233     Length = (ACPI_SIZE) RegionObject->Region.Length;
234     SpaceId = RegionObject->Region.SpaceId;
235 
236     ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
237         "Operation Region request on %s at 0x%X, BitWidth 0x%X, RegionLength 0x%X\n",
238         AcpiUtGetRegionName (RegionObject->Region.SpaceId),
239         (UINT32) Address, BitWidth, (UINT32) Length));
240 
241     /*
242      * Region support can be disabled with the -do option.
243      * We use this to support dynamically loaded tables where we pass a valid
244      * address to the AML.
245      */
246     if (AcpiGbl_DbOpt_NoRegionSupport)
247     {
248         BufferValue = ACPI_TO_POINTER (Address);
249         ByteWidth = (BitWidth / 8);
250 
251         if (BitWidth % 8)
252         {
253             ByteWidth += 1;
254         }
255         goto DoFunction;
256     }
257 
258     switch (SpaceId)
259     {
260     case ACPI_ADR_SPACE_SYSTEM_IO:
261         /*
262          * For I/O space, exercise the port validation
263          * Note: ReadPort currently always returns all ones, length=BitLength
264          */
265         switch (Function & ACPI_IO_MASK)
266         {
267         case ACPI_READ:
268 
269             if (BitWidth == 64)
270             {
271                 /* Split the 64-bit request into two 32-bit requests */
272 
273                 Status = AcpiHwReadPort (Address, &Value1, 32);
274                 ACPI_CHECK_OK (AcpiHwReadPort, Status);
275                 Status = AcpiHwReadPort (Address+4, &Value2, 32);
276                 ACPI_CHECK_OK (AcpiHwReadPort, Status);
277 
278                 *Value = Value1 | ((UINT64) Value2 << 32);
279             }
280             else
281             {
282                 Status = AcpiHwReadPort (Address, &Value1, BitWidth);
283                 ACPI_CHECK_OK (AcpiHwReadPort, Status);
284                 *Value = (UINT64) Value1;
285             }
286             break;
287 
288         case ACPI_WRITE:
289 
290             if (BitWidth == 64)
291             {
292                 /* Split the 64-bit request into two 32-bit requests */
293 
294                 Status = AcpiHwWritePort (Address, ACPI_LODWORD (*Value), 32);
295                 ACPI_CHECK_OK (AcpiHwWritePort, Status);
296                 Status = AcpiHwWritePort (Address+4, ACPI_HIDWORD (*Value), 32);
297                 ACPI_CHECK_OK (AcpiHwWritePort, Status);
298             }
299             else
300             {
301                 Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth);
302                 ACPI_CHECK_OK (AcpiHwWritePort, Status);
303             }
304             break;
305 
306         default:
307 
308             Status = AE_BAD_PARAMETER;
309             break;
310         }
311 
312         if (ACPI_FAILURE (Status))
313         {
314             return (Status);
315         }
316 
317         /* Now go ahead and simulate the hardware */
318         break;
319 
320     /*
321      * SMBus and GenericSerialBus support the various bidirectional
322      * protocols.
323      */
324     case ACPI_ADR_SPACE_SMBUS:
325     case ACPI_ADR_SPACE_GSBUS:  /* ACPI 5.0 */
326 
327         Length = 0;
328 
329         switch (Function & ACPI_IO_MASK)
330         {
331         case ACPI_READ:
332 
333             switch (Function >> 16)
334             {
335             case AML_FIELD_ATTRIB_QUICK:
336 
337                 Length = 0;
338                 break;
339 
340             case AML_FIELD_ATTRIB_SEND_RCV:
341             case AML_FIELD_ATTRIB_BYTE:
342 
343                 Length = 1;
344                 break;
345 
346             case AML_FIELD_ATTRIB_WORD:
347             case AML_FIELD_ATTRIB_WORD_CALL:
348 
349                 Length = 2;
350                 break;
351 
352             case AML_FIELD_ATTRIB_BLOCK:
353             case AML_FIELD_ATTRIB_BLOCK_CALL:
354 
355                 Length = 32;
356                 break;
357 
358             case AML_FIELD_ATTRIB_MULTIBYTE:
359             case AML_FIELD_ATTRIB_RAW_BYTES:
360             case AML_FIELD_ATTRIB_RAW_PROCESS:
361 
362                 Length = MyContext->AccessLength;
363                 break;
364 
365             default:
366 
367                 break;
368             }
369             break;
370 
371         case ACPI_WRITE:
372 
373             switch (Function >> 16)
374             {
375             case AML_FIELD_ATTRIB_QUICK:
376             case AML_FIELD_ATTRIB_SEND_RCV:
377             case AML_FIELD_ATTRIB_BYTE:
378             case AML_FIELD_ATTRIB_WORD:
379             case AML_FIELD_ATTRIB_BLOCK:
380 
381                 Length = 0;
382                 break;
383 
384             case AML_FIELD_ATTRIB_WORD_CALL:
385                 Length = 2;
386                 break;
387 
388             case AML_FIELD_ATTRIB_BLOCK_CALL:
389                 Length = 32;
390                 break;
391 
392             case AML_FIELD_ATTRIB_MULTIBYTE:
393             case AML_FIELD_ATTRIB_RAW_BYTES:
394             case AML_FIELD_ATTRIB_RAW_PROCESS:
395 
396                 Length = MyContext->AccessLength;
397                 break;
398 
399             default:
400 
401                 break;
402             }
403             break;
404 
405         default:
406 
407             break;
408         }
409 
410         if (AcpiGbl_DisplayRegionAccess)
411         {
412             AcpiOsPrintf ("AcpiExec: %s "
413                 "%s: Attr %X Addr %.4X BaseAddr %.4X Length %.2X BitWidth %X BufLen %X",
414                 AcpiUtGetRegionName (SpaceId),
415                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
416                 (UINT32) (Function >> 16),
417                 (UINT32) Address, (UINT32) BaseAddress,
418                 Length, BitWidth, Buffer[1]);
419 
420             /* GenericSerialBus has a Connection() parameter */
421 
422             if (SpaceId == ACPI_ADR_SPACE_GSBUS)
423             {
424                 Status = AcpiBufferToResource (MyContext->Connection,
425                     MyContext->Length, &Resource);
426 
427                 AcpiOsPrintf (" [AccessLength %.2X Connnection %p]",
428                     MyContext->AccessLength, MyContext->Connection);
429             }
430             AcpiOsPrintf ("\n");
431         }
432 
433         /* Setup the return buffer. Note: ASLTS depends on these fill values */
434 
435         for (i = 0; i < Length; i++)
436         {
437             Buffer[i+2] = (UINT8) (0xA0 + i);
438         }
439 
440         Buffer[0] = 0x7A;
441         Buffer[1] = (UINT8) Length;
442         return (AE_OK);
443 
444 
445     case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */
446 
447         if (AcpiGbl_DisplayRegionAccess)
448         {
449             AcpiOsPrintf ("AcpiExec: IPMI "
450                 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X\n",
451                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
452                 (UINT32) (Function >> 16), (UINT32) Address, (UINT32) BaseAddress,
453                 Length, BitWidth, Buffer[1]);
454         }
455 
456         /*
457          * Regardless of a READ or WRITE, this handler is passed a 66-byte
458          * buffer in which to return the IPMI status/length/data.
459          *
460          * Return some example data to show use of the bidirectional buffer
461          */
462         Buffer[0] = 0;       /* Status byte */
463         Buffer[1] = 64;      /* Return buffer data length */
464         Buffer[2] = 0;       /* Completion code */
465         Buffer[3] = 0;       /* Reserved */
466 
467         /*
468          * Fill the 66-byte buffer with the return data.
469          * Note: ASLTS depends on these fill values.
470          */
471         for (i = 4; i < 66; i++)
472         {
473             Buffer[i] = (UINT8) (i);
474         }
475         return (AE_OK);
476 
477     /*
478      * GPIO has some special semantics:
479      * 1) Address is the pin number index into the Connection() pin list
480      * 2) BitWidth is the actual number of bits (pins) defined by the field
481      */
482     case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
483 
484         if (AcpiGbl_DisplayRegionAccess)
485         {
486             AcpiOsPrintf ("AcpiExec: GPIO "
487                 "%s: Addr %.4X Width %X Conn %p\n",
488                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
489                 (UINT32) Address, BitWidth, MyContext->Connection);
490         }
491         return (AE_OK);
492 
493     default:
494         break;
495     }
496 
497     /*
498      * Search through the linked list for this region's buffer
499      */
500     BufferExists = FALSE;
501     BufferResize = FALSE;
502     RegionElement = AeRegions.RegionList;
503 
504     if (AeRegions.NumberOfRegions)
505     {
506         BaseAddressEnd = BaseAddress + Length - 1;
507         while (!BufferExists && RegionElement)
508         {
509             RegionAddress = RegionElement->Address;
510             RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1;
511             RegionLength = RegionElement->Length;
512 
513             /*
514              * Overlapping Region Support
515              *
516              * While searching through the region buffer list, determine if an
517              * overlap exists between the requested buffer space and the current
518              * RegionElement space. If there is an overlap then replace the old
519              * buffer with a new buffer of increased size before continuing to
520              * do the read or write
521              */
522             if (RegionElement->SpaceId != SpaceId ||
523                 BaseAddressEnd < RegionAddress ||
524                 BaseAddress > RegionAddressEnd)
525             {
526                 /*
527                  * Requested buffer is outside of the current RegionElement
528                  * bounds
529                  */
530                 RegionElement = RegionElement->NextRegion;
531             }
532             else
533             {
534                 /*
535                  * Some amount of buffer space sharing exists. There are 4 cases
536                  * to consider:
537                  *
538                  * 1. Right overlap
539                  * 2. Left overlap
540                  * 3. Left and right overlap
541                  * 4. Fully contained - no resizing required
542                  */
543                 BufferExists = TRUE;
544 
545                 if ((BaseAddress >= RegionAddress) &&
546                     (BaseAddress <= RegionAddressEnd) &&
547                     (BaseAddressEnd > RegionAddressEnd))
548                 {
549                     /* Right overlap */
550 
551                     RegionElement->Length = (UINT32) (BaseAddress -
552                         RegionAddress + Length);
553                     BufferResize = TRUE;
554                 }
555 
556                 else if ((BaseAddressEnd >= RegionAddress) &&
557                          (BaseAddressEnd <= RegionAddressEnd) &&
558                          (BaseAddress < RegionAddress))
559                 {
560                     /* Left overlap */
561 
562                     RegionElement->Address = BaseAddress;
563                     RegionElement->Length = (UINT32) (RegionAddress -
564                         BaseAddress + RegionElement->Length);
565                     BufferResize = TRUE;
566                 }
567 
568                 else if ((BaseAddress < RegionAddress) &&
569                          (BaseAddressEnd > RegionAddressEnd))
570                 {
571                     /* Left and right overlap */
572 
573                     RegionElement->Address = BaseAddress;
574                     RegionElement->Length = Length;
575                     BufferResize = TRUE;
576                 }
577 
578                 /*
579                  * only remaining case is fully contained for which we don't
580                  * need to do anything
581                  */
582                 if (BufferResize)
583                 {
584                     NewBuffer = AcpiOsAllocate (RegionElement->Length);
585                     if (!NewBuffer)
586                     {
587                         return (AE_NO_MEMORY);
588                     }
589 
590                     OldBuffer = RegionElement->Buffer;
591                     RegionElement->Buffer = NewBuffer;
592                     NewBuffer = NULL;
593 
594                     /* Initialize the region with the default fill value */
595 
596                     memset (RegionElement->Buffer,
597                         AcpiGbl_RegionFillValue, RegionElement->Length);
598 
599                     /*
600                      * Get BufferValue to point (within the new buffer) to the
601                      * base address of the old buffer
602                      */
603                     BufferValue = (UINT8 *) RegionElement->Buffer +
604                         (UINT64) RegionAddress -
605                         (UINT64) RegionElement->Address;
606 
607                     /*
608                      * Copy the old buffer to its same location within the new
609                      * buffer
610                      */
611                     memcpy (BufferValue, OldBuffer, RegionLength);
612                     AcpiOsFree (OldBuffer);
613                 }
614             }
615         }
616     }
617 
618     /*
619      * If the Region buffer does not exist, create it now
620      */
621     if (!BufferExists)
622     {
623         /* Do the memory allocations first */
624 
625         RegionElement = AcpiOsAllocate (sizeof (AE_REGION));
626         if (!RegionElement)
627         {
628             return (AE_NO_MEMORY);
629         }
630 
631         RegionElement->Buffer = AcpiOsAllocate (Length);
632         if (!RegionElement->Buffer)
633         {
634             AcpiOsFree (RegionElement);
635             return (AE_NO_MEMORY);
636         }
637 
638         /* Initialize the region with the default fill value */
639 
640         memset (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length);
641 
642         RegionElement->Address      = BaseAddress;
643         RegionElement->Length       = Length;
644         RegionElement->SpaceId      = SpaceId;
645         RegionElement->NextRegion   = NULL;
646 
647         /*
648          * Increment the number of regions and put this one
649          * at the head of the list as it will probably get accessed
650          * more often anyway.
651          */
652         AeRegions.NumberOfRegions += 1;
653 
654         if (AeRegions.RegionList)
655         {
656             RegionElement->NextRegion = AeRegions.RegionList;
657         }
658 
659         AeRegions.RegionList = RegionElement;
660     }
661 
662     /* Calculate the size of the memory copy */
663 
664     ByteWidth = (BitWidth / 8);
665 
666     if (BitWidth % 8)
667     {
668         ByteWidth += 1;
669     }
670 
671     /*
672      * The buffer exists and is pointed to by RegionElement.
673      * We now need to verify the request is valid and perform the operation.
674      *
675      * NOTE: RegionElement->Length is in bytes, therefore it we compare against
676      * ByteWidth (see above)
677      */
678     if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) &&
679         ((UINT64) Address + ByteWidth) >
680         ((UINT64)(RegionElement->Address) + RegionElement->Length))
681     {
682         ACPI_WARNING ((AE_INFO,
683             "Request on [%4.4s] is beyond region limit "
684             "Req-0x%X+0x%X, Base=0x%X, Len-0x%X",
685             (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address,
686             ByteWidth, (UINT32)(RegionElement->Address),
687             RegionElement->Length));
688 
689         return (AE_AML_REGION_LIMIT);
690     }
691 
692     /*
693      * Get BufferValue to point to the "address" in the buffer
694      */
695     BufferValue = ((UINT8 *) RegionElement->Buffer +
696         ((UINT64) Address - (UINT64) RegionElement->Address));
697 
698 DoFunction:
699     /*
700      * Perform a read or write to the buffer space
701      */
702     switch (Function)
703     {
704     case ACPI_READ:
705         /*
706          * Set the pointer Value to whatever is in the buffer
707          */
708         memcpy (Value, BufferValue, ByteWidth);
709         break;
710 
711     case ACPI_WRITE:
712         /*
713          * Write the contents of Value to the buffer
714          */
715         memcpy (BufferValue, Value, ByteWidth);
716         break;
717 
718     default:
719 
720         return (AE_BAD_PARAMETER);
721     }
722 
723     if (AcpiGbl_DisplayRegionAccess)
724     {
725         switch (SpaceId)
726         {
727         case ACPI_ADR_SPACE_SYSTEM_MEMORY:
728 
729             AcpiOsPrintf ("AcpiExec: SystemMemory "
730                 "%s: Val %.8X Addr %.4X Width %X [REGION: BaseAddr %.4X Len %.2X]\n",
731                 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
732                 (UINT32) *Value, (UINT32) Address, BitWidth, (UINT32) BaseAddress, Length);
733             break;
734 
735         case ACPI_ADR_SPACE_GPIO:   /* ACPI 5.0 */
736 
737             /* This space is required to always be ByteAcc */
738 
739             Status = AcpiBufferToResource (MyContext->Connection,
740                 MyContext->Length, &Resource);
741 
742             AcpiOsPrintf ("AcpiExec: GeneralPurposeIo "
743                 "%s: Val %.8X Addr %.4X BaseAddr %.4X Len %.2X Width %X AccLen %.2X Conn %p\n",
744                 (Function & ACPI_IO_MASK) ? "Write" : "Read ", (UINT32) *Value,
745                 (UINT32) Address, (UINT32) BaseAddress, Length, BitWidth,
746                 MyContext->AccessLength, MyContext->Connection);
747             break;
748 
749         default:
750 
751             break;
752         }
753     }
754 
755     return (AE_OK);
756 }
757