aeregion.c revision 1.1 1 /******************************************************************************
2 *
3 * Module Name: aeregion - Operation region support for acpiexec
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2014, 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, "Operation Region request on %s at 0x%X\n",
377 AcpiUtGetRegionName (RegionObject->Region.SpaceId),
378 (UINT32) Address));
379
380 /*
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.
384 */
385 if (AcpiGbl_DbOpt_NoRegionSupport)
386 {
387 BufferValue = ACPI_TO_POINTER (Address);
388 ByteWidth = (BitWidth / 8);
389
390 if (BitWidth % 8)
391 {
392 ByteWidth += 1;
393 }
394 goto DoFunction;
395 }
396
397 switch (SpaceId)
398 {
399 case ACPI_ADR_SPACE_SYSTEM_IO:
400 /*
401 * For I/O space, exercise the port validation
402 * Note: ReadPort currently always returns all ones, length=BitLength
403 */
404 switch (Function & ACPI_IO_MASK)
405 {
406 case ACPI_READ:
407
408 if (BitWidth == 64)
409 {
410 /* Split the 64-bit request into two 32-bit requests */
411
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);
416
417 *Value = Value1 | ((UINT64) Value2 << 32);
418 }
419 else
420 {
421 Status = AcpiHwReadPort (Address, &Value1, BitWidth);
422 AE_CHECK_OK (AcpiHwReadPort, Status);
423 *Value = (UINT64) Value1;
424 }
425 break;
426
427 case ACPI_WRITE:
428
429 if (BitWidth == 64)
430 {
431 /* Split the 64-bit request into two 32-bit requests */
432
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);
437 }
438 else
439 {
440 Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth);
441 AE_CHECK_OK (AcpiHwWritePort, Status);
442 }
443 break;
444
445 default:
446
447 Status = AE_BAD_PARAMETER;
448 break;
449 }
450
451 if (ACPI_FAILURE (Status))
452 {
453 return (Status);
454 }
455
456 /* Now go ahead and simulate the hardware */
457 break;
458
459 /*
460 * SMBus and GenericSerialBus support the various bidirectional
461 * protocols.
462 */
463 case ACPI_ADR_SPACE_SMBUS:
464 case ACPI_ADR_SPACE_GSBUS: /* ACPI 5.0 */
465
466 Length = 0;
467
468 switch (Function & ACPI_IO_MASK)
469 {
470 case ACPI_READ:
471
472 switch (Function >> 16)
473 {
474 case AML_FIELD_ATTRIB_QUICK:
475
476 Length = 0;
477 break;
478
479 case AML_FIELD_ATTRIB_SEND_RCV:
480 case AML_FIELD_ATTRIB_BYTE:
481
482 Length = 1;
483 break;
484
485 case AML_FIELD_ATTRIB_WORD:
486 case AML_FIELD_ATTRIB_WORD_CALL:
487
488 Length = 2;
489 break;
490
491 case AML_FIELD_ATTRIB_BLOCK:
492 case AML_FIELD_ATTRIB_BLOCK_CALL:
493
494 Length = 32;
495 break;
496
497 case AML_FIELD_ATTRIB_MULTIBYTE:
498 case AML_FIELD_ATTRIB_RAW_BYTES:
499 case AML_FIELD_ATTRIB_RAW_PROCESS:
500
501 Length = MyContext->AccessLength;
502 break;
503
504 default:
505
506 break;
507 }
508 break;
509
510 case ACPI_WRITE:
511
512 switch (Function >> 16)
513 {
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:
519
520 Length = 0;
521 break;
522
523 case AML_FIELD_ATTRIB_WORD_CALL:
524 Length = 2;
525 break;
526
527 case AML_FIELD_ATTRIB_BLOCK_CALL:
528 Length = 32;
529 break;
530
531 case AML_FIELD_ATTRIB_MULTIBYTE:
532 case AML_FIELD_ATTRIB_RAW_BYTES:
533 case AML_FIELD_ATTRIB_RAW_PROCESS:
534
535 Length = MyContext->AccessLength;
536 break;
537
538 default:
539
540 break;
541 }
542 break;
543
544 default:
545
546 break;
547 }
548
549 if (AcpiGbl_DisplayRegionAccess)
550 {
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]);
558
559 /* GenericSerialBus has a Connection() parameter */
560
561 if (SpaceId == ACPI_ADR_SPACE_GSBUS)
562 {
563 Status = AcpiBufferToResource (MyContext->Connection,
564 MyContext->Length, &Resource);
565
566 AcpiOsPrintf (" [AccLen %.2X Conn %p]",
567 MyContext->AccessLength, MyContext->Connection);
568 }
569 AcpiOsPrintf ("\n");
570 }
571
572 /* Setup the return buffer. Note: ASLTS depends on these fill values */
573
574 for (i = 0; i < Length; i++)
575 {
576 Buffer[i+2] = (UINT8) (0xA0 + i);
577 }
578
579 Buffer[0] = 0x7A;
580 Buffer[1] = (UINT8) Length;
581 return (AE_OK);
582
583
584 case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */
585
586 if (AcpiGbl_DisplayRegionAccess)
587 {
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]);
593 }
594
595 /*
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.
598 *
599 * Return some example data to show use of the bidirectional buffer
600 */
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 */
605
606 /*
607 * Fill the 66-byte buffer with the return data.
608 * Note: ASLTS depends on these fill values.
609 */
610 for (i = 4; i < 66; i++)
611 {
612 Buffer[i] = (UINT8) (i);
613 }
614 return (AE_OK);
615
616 /*
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
620 */
621 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
622
623 if (AcpiGbl_DisplayRegionAccess)
624 {
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);
629 }
630 return (AE_OK);
631
632 default:
633 break;
634 }
635
636 /*
637 * Search through the linked list for this region's buffer
638 */
639 BufferExists = FALSE;
640 BufferResize = FALSE;
641 RegionElement = AeRegions.RegionList;
642
643 if (AeRegions.NumberOfRegions)
644 {
645 BaseAddressEnd = BaseAddress + Length - 1;
646 while (!BufferExists && RegionElement)
647 {
648 RegionAddress = RegionElement->Address;
649 RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1;
650 RegionLength = RegionElement->Length;
651
652 /*
653 * Overlapping Region Support
654 *
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
660 */
661 if (RegionElement->SpaceId != SpaceId ||
662 BaseAddressEnd < RegionAddress ||
663 BaseAddress > RegionAddressEnd)
664 {
665 /*
666 * Requested buffer is outside of the current RegionElement
667 * bounds
668 */
669 RegionElement = RegionElement->NextRegion;
670 }
671 else
672 {
673 /*
674 * Some amount of buffer space sharing exists. There are 4 cases
675 * to consider:
676 *
677 * 1. Right overlap
678 * 2. Left overlap
679 * 3. Left and right overlap
680 * 4. Fully contained - no resizing required
681 */
682 BufferExists = TRUE;
683
684 if ((BaseAddress >= RegionAddress) &&
685 (BaseAddress <= RegionAddressEnd) &&
686 (BaseAddressEnd > RegionAddressEnd))
687 {
688 /* Right overlap */
689
690 RegionElement->Length = BaseAddress -
691 RegionAddress + Length;
692 BufferResize = TRUE;
693 }
694
695 else if ((BaseAddressEnd >= RegionAddress) &&
696 (BaseAddressEnd <= RegionAddressEnd) &&
697 (BaseAddress < RegionAddress))
698 {
699 /* Left overlap */
700
701 RegionElement->Address = BaseAddress;
702 RegionElement->Length = RegionAddress -
703 BaseAddress + RegionElement->Length;
704 BufferResize = TRUE;
705 }
706
707 else if ((BaseAddress < RegionAddress) &&
708 (BaseAddressEnd > RegionAddressEnd))
709 {
710 /* Left and right overlap */
711
712 RegionElement->Address = BaseAddress;
713 RegionElement->Length = Length;
714 BufferResize = TRUE;
715 }
716
717 /*
718 * only remaining case is fully contained for which we don't
719 * need to do anything
720 */
721 if (BufferResize)
722 {
723 NewBuffer = AcpiOsAllocate (RegionElement->Length);
724 if (!NewBuffer)
725 {
726 return (AE_NO_MEMORY);
727 }
728
729 OldBuffer = RegionElement->Buffer;
730 RegionElement->Buffer = NewBuffer;
731 NewBuffer = NULL;
732
733 /* Initialize the region with the default fill value */
734
735 ACPI_MEMSET (RegionElement->Buffer,
736 AcpiGbl_RegionFillValue, RegionElement->Length);
737
738 /*
739 * Get BufferValue to point (within the new buffer) to the
740 * base address of the old buffer
741 */
742 BufferValue = (UINT8 *) RegionElement->Buffer +
743 (UINT64) RegionAddress -
744 (UINT64) RegionElement->Address;
745
746 /*
747 * Copy the old buffer to its same location within the new
748 * buffer
749 */
750 ACPI_MEMCPY (BufferValue, OldBuffer, RegionLength);
751 AcpiOsFree (OldBuffer);
752 }
753 }
754 }
755 }
756
757 /*
758 * If the Region buffer does not exist, create it now
759 */
760 if (!BufferExists)
761 {
762 /* Do the memory allocations first */
763
764 RegionElement = AcpiOsAllocate (sizeof (AE_REGION));
765 if (!RegionElement)
766 {
767 return (AE_NO_MEMORY);
768 }
769
770 RegionElement->Buffer = AcpiOsAllocate (Length);
771 if (!RegionElement->Buffer)
772 {
773 AcpiOsFree (RegionElement);
774 return (AE_NO_MEMORY);
775 }
776
777 /* Initialize the region with the default fill value */
778
779 ACPI_MEMSET (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length);
780
781 RegionElement->Address = BaseAddress;
782 RegionElement->Length = Length;
783 RegionElement->SpaceId = SpaceId;
784 RegionElement->NextRegion = NULL;
785
786 /*
787 * Increment the number of regions and put this one
788 * at the head of the list as it will probably get accessed
789 * more often anyway.
790 */
791 AeRegions.NumberOfRegions += 1;
792
793 if (AeRegions.RegionList)
794 {
795 RegionElement->NextRegion = AeRegions.RegionList;
796 }
797
798 AeRegions.RegionList = RegionElement;
799 }
800
801 /* Calculate the size of the memory copy */
802
803 ByteWidth = (BitWidth / 8);
804
805 if (BitWidth % 8)
806 {
807 ByteWidth += 1;
808 }
809
810 /*
811 * The buffer exists and is pointed to by RegionElement.
812 * We now need to verify the request is valid and perform the operation.
813 *
814 * NOTE: RegionElement->Length is in bytes, therefore it we compare against
815 * ByteWidth (see above)
816 */
817 if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) &&
818 ((UINT64) Address + ByteWidth) >
819 ((UINT64)(RegionElement->Address) + RegionElement->Length))
820 {
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));
826
827 return (AE_AML_REGION_LIMIT);
828 }
829
830 /*
831 * Get BufferValue to point to the "address" in the buffer
832 */
833 BufferValue = ((UINT8 *) RegionElement->Buffer +
834 ((UINT64) Address - (UINT64) RegionElement->Address));
835
836 DoFunction:
837 /*
838 * Perform a read or write to the buffer space
839 */
840 switch (Function)
841 {
842 case ACPI_READ:
843 /*
844 * Set the pointer Value to whatever is in the buffer
845 */
846 ACPI_MEMCPY (Value, BufferValue, ByteWidth);
847 break;
848
849 case ACPI_WRITE:
850 /*
851 * Write the contents of Value to the buffer
852 */
853 ACPI_MEMCPY (BufferValue, Value, ByteWidth);
854 break;
855
856 default:
857
858 return (AE_BAD_PARAMETER);
859 }
860
861 if (AcpiGbl_DisplayRegionAccess)
862 {
863 switch (SpaceId)
864 {
865 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
866
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);
871 break;
872
873 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
874
875 /* This space is required to always be ByteAcc */
876
877 Status = AcpiBufferToResource (MyContext->Connection,
878 MyContext->Length, &Resource);
879
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);
885 break;
886
887 default:
888
889 break;
890 }
891 }
892
893 return (AE_OK);
894 }
895