aeregion.c revision 1.1.1.5 1 /******************************************************************************
2 *
3 * Module Name: aeregion - Operation region support for acpiexec
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2017, 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