aeregion.c revision 1.1.1.7 1 /******************************************************************************
2 *
3 * Module Name: aeregion - Handler for operation regions
4 *
5 *****************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2018, 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 static AE_DEBUG_REGIONS AeRegions;
51
52
53 /******************************************************************************
54 *
55 * FUNCTION: AeRegionHandler
56 *
57 * PARAMETERS: Standard region handler parameters
58 *
59 * RETURN: Status
60 *
61 * DESCRIPTION: Test handler - Handles some dummy regions via memory that can
62 * be manipulated in Ring 3. Simulates actual reads and writes.
63 *
64 *****************************************************************************/
65
66 ACPI_STATUS
67 AeRegionHandler (
68 UINT32 Function,
69 ACPI_PHYSICAL_ADDRESS Address,
70 UINT32 BitWidth,
71 UINT64 *Value,
72 void *HandlerContext,
73 void *RegionContext)
74 {
75
76 ACPI_OPERAND_OBJECT *RegionObject = ACPI_CAST_PTR (ACPI_OPERAND_OBJECT, RegionContext);
77 UINT8 *Buffer = ACPI_CAST_PTR (UINT8, Value);
78 UINT8 *OldBuffer;
79 UINT8 *NewBuffer;
80 ACPI_PHYSICAL_ADDRESS BaseAddress;
81 ACPI_PHYSICAL_ADDRESS BaseAddressEnd;
82 ACPI_PHYSICAL_ADDRESS RegionAddress;
83 ACPI_PHYSICAL_ADDRESS RegionAddressEnd;
84 ACPI_SIZE Length;
85 BOOLEAN BufferExists;
86 BOOLEAN BufferResize;
87 AE_REGION *RegionElement;
88 void *BufferValue;
89 ACPI_STATUS Status;
90 UINT32 ByteWidth;
91 UINT32 RegionLength;
92 UINT32 i;
93 UINT8 SpaceId;
94 ACPI_CONNECTION_INFO *MyContext;
95 UINT32 Value1;
96 UINT32 Value2;
97 ACPI_RESOURCE *Resource;
98
99
100 ACPI_FUNCTION_NAME (AeRegionHandler);
101
102 /*
103 * If the object is not a region, simply return
104 */
105 if (RegionObject->Region.Type != ACPI_TYPE_REGION)
106 {
107 return (AE_OK);
108 }
109
110 /* Check that we actually got back our context parameter */
111
112 if (HandlerContext != &AeMyContext)
113 {
114 printf ("Region handler received incorrect context %p, should be %p\n",
115 HandlerContext, &AeMyContext);
116 }
117
118 MyContext = ACPI_CAST_PTR (ACPI_CONNECTION_INFO, HandlerContext);
119
120 /*
121 * Find the region's address space and length before searching
122 * the linked list.
123 */
124 BaseAddress = RegionObject->Region.Address;
125 Length = (ACPI_SIZE) RegionObject->Region.Length;
126 SpaceId = RegionObject->Region.SpaceId;
127
128 ACPI_DEBUG_PRINT ((ACPI_DB_OPREGION,
129 "Operation Region request on %s at 0x%X\n",
130 AcpiUtGetRegionName (RegionObject->Region.SpaceId),
131 (UINT32) Address));
132
133 /*
134 * Region support can be disabled with the -do option.
135 * We use this to support dynamically loaded tables where we pass a valid
136 * address to the AML.
137 */
138 if (AcpiGbl_DbOpt_NoRegionSupport)
139 {
140 BufferValue = ACPI_TO_POINTER (Address);
141 ByteWidth = (BitWidth / 8);
142
143 if (BitWidth % 8)
144 {
145 ByteWidth += 1;
146 }
147 goto DoFunction;
148 }
149
150 switch (SpaceId)
151 {
152 case ACPI_ADR_SPACE_SYSTEM_IO:
153 /*
154 * For I/O space, exercise the port validation
155 * Note: ReadPort currently always returns all ones, length=BitLength
156 */
157 switch (Function & ACPI_IO_MASK)
158 {
159 case ACPI_READ:
160
161 if (BitWidth == 64)
162 {
163 /* Split the 64-bit request into two 32-bit requests */
164
165 Status = AcpiHwReadPort (Address, &Value1, 32);
166 ACPI_CHECK_OK (AcpiHwReadPort, Status);
167 Status = AcpiHwReadPort (Address+4, &Value2, 32);
168 ACPI_CHECK_OK (AcpiHwReadPort, Status);
169
170 *Value = Value1 | ((UINT64) Value2 << 32);
171 }
172 else
173 {
174 Status = AcpiHwReadPort (Address, &Value1, BitWidth);
175 ACPI_CHECK_OK (AcpiHwReadPort, Status);
176 *Value = (UINT64) Value1;
177 }
178 break;
179
180 case ACPI_WRITE:
181
182 if (BitWidth == 64)
183 {
184 /* Split the 64-bit request into two 32-bit requests */
185
186 Status = AcpiHwWritePort (Address, ACPI_LODWORD (*Value), 32);
187 ACPI_CHECK_OK (AcpiHwWritePort, Status);
188 Status = AcpiHwWritePort (Address+4, ACPI_HIDWORD (*Value), 32);
189 ACPI_CHECK_OK (AcpiHwWritePort, Status);
190 }
191 else
192 {
193 Status = AcpiHwWritePort (Address, (UINT32) *Value, BitWidth);
194 ACPI_CHECK_OK (AcpiHwWritePort, Status);
195 }
196 break;
197
198 default:
199
200 Status = AE_BAD_PARAMETER;
201 break;
202 }
203
204 if (ACPI_FAILURE (Status))
205 {
206 return (Status);
207 }
208
209 /* Now go ahead and simulate the hardware */
210 break;
211
212 /*
213 * SMBus and GenericSerialBus support the various bidirectional
214 * protocols.
215 */
216 case ACPI_ADR_SPACE_SMBUS:
217 case ACPI_ADR_SPACE_GSBUS: /* ACPI 5.0 */
218
219 Length = 0;
220
221 switch (Function & ACPI_IO_MASK)
222 {
223 case ACPI_READ:
224
225 switch (Function >> 16)
226 {
227 case AML_FIELD_ATTRIB_QUICK:
228
229 Length = 0;
230 break;
231
232 case AML_FIELD_ATTRIB_SEND_RCV:
233 case AML_FIELD_ATTRIB_BYTE:
234
235 Length = 1;
236 break;
237
238 case AML_FIELD_ATTRIB_WORD:
239 case AML_FIELD_ATTRIB_WORD_CALL:
240
241 Length = 2;
242 break;
243
244 case AML_FIELD_ATTRIB_BLOCK:
245 case AML_FIELD_ATTRIB_BLOCK_CALL:
246
247 Length = 32;
248 break;
249
250 case AML_FIELD_ATTRIB_MULTIBYTE:
251 case AML_FIELD_ATTRIB_RAW_BYTES:
252 case AML_FIELD_ATTRIB_RAW_PROCESS:
253
254 Length = MyContext->AccessLength;
255 break;
256
257 default:
258
259 break;
260 }
261 break;
262
263 case ACPI_WRITE:
264
265 switch (Function >> 16)
266 {
267 case AML_FIELD_ATTRIB_QUICK:
268 case AML_FIELD_ATTRIB_SEND_RCV:
269 case AML_FIELD_ATTRIB_BYTE:
270 case AML_FIELD_ATTRIB_WORD:
271 case AML_FIELD_ATTRIB_BLOCK:
272
273 Length = 0;
274 break;
275
276 case AML_FIELD_ATTRIB_WORD_CALL:
277 Length = 2;
278 break;
279
280 case AML_FIELD_ATTRIB_BLOCK_CALL:
281 Length = 32;
282 break;
283
284 case AML_FIELD_ATTRIB_MULTIBYTE:
285 case AML_FIELD_ATTRIB_RAW_BYTES:
286 case AML_FIELD_ATTRIB_RAW_PROCESS:
287
288 Length = MyContext->AccessLength;
289 break;
290
291 default:
292
293 break;
294 }
295 break;
296
297 default:
298
299 break;
300 }
301
302 if (AcpiGbl_DisplayRegionAccess)
303 {
304 AcpiOsPrintf ("AcpiExec: %s "
305 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X",
306 AcpiUtGetRegionName (SpaceId),
307 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
308 (UINT32) (Function >> 16),
309 (UINT32) Address, (UINT32) BaseAddress,
310 Length, BitWidth, Buffer[1]);
311
312 /* GenericSerialBus has a Connection() parameter */
313
314 if (SpaceId == ACPI_ADR_SPACE_GSBUS)
315 {
316 Status = AcpiBufferToResource (MyContext->Connection,
317 MyContext->Length, &Resource);
318
319 AcpiOsPrintf (" [AccLen %.2X Conn %p]",
320 MyContext->AccessLength, MyContext->Connection);
321 }
322 AcpiOsPrintf ("\n");
323 }
324
325 /* Setup the return buffer. Note: ASLTS depends on these fill values */
326
327 for (i = 0; i < Length; i++)
328 {
329 Buffer[i+2] = (UINT8) (0xA0 + i);
330 }
331
332 Buffer[0] = 0x7A;
333 Buffer[1] = (UINT8) Length;
334 return (AE_OK);
335
336
337 case ACPI_ADR_SPACE_IPMI: /* ACPI 4.0 */
338
339 if (AcpiGbl_DisplayRegionAccess)
340 {
341 AcpiOsPrintf ("AcpiExec: IPMI "
342 "%s: Attr %X Addr %.4X BaseAddr %.4X Len %.2X Width %X BufLen %X\n",
343 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
344 (UINT32) (Function >> 16), (UINT32) Address, (UINT32) BaseAddress,
345 Length, BitWidth, Buffer[1]);
346 }
347
348 /*
349 * Regardless of a READ or WRITE, this handler is passed a 66-byte
350 * buffer in which to return the IPMI status/length/data.
351 *
352 * Return some example data to show use of the bidirectional buffer
353 */
354 Buffer[0] = 0; /* Status byte */
355 Buffer[1] = 64; /* Return buffer data length */
356 Buffer[2] = 0; /* Completion code */
357 Buffer[3] = 0; /* Reserved */
358
359 /*
360 * Fill the 66-byte buffer with the return data.
361 * Note: ASLTS depends on these fill values.
362 */
363 for (i = 4; i < 66; i++)
364 {
365 Buffer[i] = (UINT8) (i);
366 }
367 return (AE_OK);
368
369 /*
370 * GPIO has some special semantics:
371 * 1) Address is the pin number index into the Connection() pin list
372 * 2) BitWidth is the actual number of bits (pins) defined by the field
373 */
374 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
375
376 if (AcpiGbl_DisplayRegionAccess)
377 {
378 AcpiOsPrintf ("AcpiExec: GPIO "
379 "%s: Addr %.4X Width %X Conn %p\n",
380 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
381 (UINT32) Address, BitWidth, MyContext->Connection);
382 }
383 return (AE_OK);
384
385 default:
386 break;
387 }
388
389 /*
390 * Search through the linked list for this region's buffer
391 */
392 BufferExists = FALSE;
393 BufferResize = FALSE;
394 RegionElement = AeRegions.RegionList;
395
396 if (AeRegions.NumberOfRegions)
397 {
398 BaseAddressEnd = BaseAddress + Length - 1;
399 while (!BufferExists && RegionElement)
400 {
401 RegionAddress = RegionElement->Address;
402 RegionAddressEnd = RegionElement->Address + RegionElement->Length - 1;
403 RegionLength = RegionElement->Length;
404
405 /*
406 * Overlapping Region Support
407 *
408 * While searching through the region buffer list, determine if an
409 * overlap exists between the requested buffer space and the current
410 * RegionElement space. If there is an overlap then replace the old
411 * buffer with a new buffer of increased size before continuing to
412 * do the read or write
413 */
414 if (RegionElement->SpaceId != SpaceId ||
415 BaseAddressEnd < RegionAddress ||
416 BaseAddress > RegionAddressEnd)
417 {
418 /*
419 * Requested buffer is outside of the current RegionElement
420 * bounds
421 */
422 RegionElement = RegionElement->NextRegion;
423 }
424 else
425 {
426 /*
427 * Some amount of buffer space sharing exists. There are 4 cases
428 * to consider:
429 *
430 * 1. Right overlap
431 * 2. Left overlap
432 * 3. Left and right overlap
433 * 4. Fully contained - no resizing required
434 */
435 BufferExists = TRUE;
436
437 if ((BaseAddress >= RegionAddress) &&
438 (BaseAddress <= RegionAddressEnd) &&
439 (BaseAddressEnd > RegionAddressEnd))
440 {
441 /* Right overlap */
442
443 RegionElement->Length = (UINT32) (BaseAddress -
444 RegionAddress + Length);
445 BufferResize = TRUE;
446 }
447
448 else if ((BaseAddressEnd >= RegionAddress) &&
449 (BaseAddressEnd <= RegionAddressEnd) &&
450 (BaseAddress < RegionAddress))
451 {
452 /* Left overlap */
453
454 RegionElement->Address = BaseAddress;
455 RegionElement->Length = (UINT32) (RegionAddress -
456 BaseAddress + RegionElement->Length);
457 BufferResize = TRUE;
458 }
459
460 else if ((BaseAddress < RegionAddress) &&
461 (BaseAddressEnd > RegionAddressEnd))
462 {
463 /* Left and right overlap */
464
465 RegionElement->Address = BaseAddress;
466 RegionElement->Length = Length;
467 BufferResize = TRUE;
468 }
469
470 /*
471 * only remaining case is fully contained for which we don't
472 * need to do anything
473 */
474 if (BufferResize)
475 {
476 NewBuffer = AcpiOsAllocate (RegionElement->Length);
477 if (!NewBuffer)
478 {
479 return (AE_NO_MEMORY);
480 }
481
482 OldBuffer = RegionElement->Buffer;
483 RegionElement->Buffer = NewBuffer;
484 NewBuffer = NULL;
485
486 /* Initialize the region with the default fill value */
487
488 memset (RegionElement->Buffer,
489 AcpiGbl_RegionFillValue, RegionElement->Length);
490
491 /*
492 * Get BufferValue to point (within the new buffer) to the
493 * base address of the old buffer
494 */
495 BufferValue = (UINT8 *) RegionElement->Buffer +
496 (UINT64) RegionAddress -
497 (UINT64) RegionElement->Address;
498
499 /*
500 * Copy the old buffer to its same location within the new
501 * buffer
502 */
503 memcpy (BufferValue, OldBuffer, RegionLength);
504 AcpiOsFree (OldBuffer);
505 }
506 }
507 }
508 }
509
510 /*
511 * If the Region buffer does not exist, create it now
512 */
513 if (!BufferExists)
514 {
515 /* Do the memory allocations first */
516
517 RegionElement = AcpiOsAllocate (sizeof (AE_REGION));
518 if (!RegionElement)
519 {
520 return (AE_NO_MEMORY);
521 }
522
523 RegionElement->Buffer = AcpiOsAllocate (Length);
524 if (!RegionElement->Buffer)
525 {
526 AcpiOsFree (RegionElement);
527 return (AE_NO_MEMORY);
528 }
529
530 /* Initialize the region with the default fill value */
531
532 memset (RegionElement->Buffer, AcpiGbl_RegionFillValue, Length);
533
534 RegionElement->Address = BaseAddress;
535 RegionElement->Length = Length;
536 RegionElement->SpaceId = SpaceId;
537 RegionElement->NextRegion = NULL;
538
539 /*
540 * Increment the number of regions and put this one
541 * at the head of the list as it will probably get accessed
542 * more often anyway.
543 */
544 AeRegions.NumberOfRegions += 1;
545
546 if (AeRegions.RegionList)
547 {
548 RegionElement->NextRegion = AeRegions.RegionList;
549 }
550
551 AeRegions.RegionList = RegionElement;
552 }
553
554 /* Calculate the size of the memory copy */
555
556 ByteWidth = (BitWidth / 8);
557
558 if (BitWidth % 8)
559 {
560 ByteWidth += 1;
561 }
562
563 /*
564 * The buffer exists and is pointed to by RegionElement.
565 * We now need to verify the request is valid and perform the operation.
566 *
567 * NOTE: RegionElement->Length is in bytes, therefore it we compare against
568 * ByteWidth (see above)
569 */
570 if ((RegionObject->Region.SpaceId != ACPI_ADR_SPACE_GPIO) &&
571 ((UINT64) Address + ByteWidth) >
572 ((UINT64)(RegionElement->Address) + RegionElement->Length))
573 {
574 ACPI_WARNING ((AE_INFO,
575 "Request on [%4.4s] is beyond region limit "
576 "Req-0x%X+0x%X, Base=0x%X, Len-0x%X",
577 (RegionObject->Region.Node)->Name.Ascii, (UINT32) Address,
578 ByteWidth, (UINT32)(RegionElement->Address),
579 RegionElement->Length));
580
581 return (AE_AML_REGION_LIMIT);
582 }
583
584 /*
585 * Get BufferValue to point to the "address" in the buffer
586 */
587 BufferValue = ((UINT8 *) RegionElement->Buffer +
588 ((UINT64) Address - (UINT64) RegionElement->Address));
589
590 DoFunction:
591 /*
592 * Perform a read or write to the buffer space
593 */
594 switch (Function)
595 {
596 case ACPI_READ:
597 /*
598 * Set the pointer Value to whatever is in the buffer
599 */
600 memcpy (Value, BufferValue, ByteWidth);
601 break;
602
603 case ACPI_WRITE:
604 /*
605 * Write the contents of Value to the buffer
606 */
607 memcpy (BufferValue, Value, ByteWidth);
608 break;
609
610 default:
611
612 return (AE_BAD_PARAMETER);
613 }
614
615 if (AcpiGbl_DisplayRegionAccess)
616 {
617 switch (SpaceId)
618 {
619 case ACPI_ADR_SPACE_SYSTEM_MEMORY:
620
621 AcpiOsPrintf ("AcpiExec: SystemMemory "
622 "%s: Val %.8X Addr %.4X Width %X [REGION: BaseAddr %.4X Len %.2X]\n",
623 (Function & ACPI_IO_MASK) ? "Write" : "Read ",
624 (UINT32) *Value, (UINT32) Address, BitWidth, (UINT32) BaseAddress, Length);
625 break;
626
627 case ACPI_ADR_SPACE_GPIO: /* ACPI 5.0 */
628
629 /* This space is required to always be ByteAcc */
630
631 Status = AcpiBufferToResource (MyContext->Connection,
632 MyContext->Length, &Resource);
633
634 AcpiOsPrintf ("AcpiExec: GeneralPurposeIo "
635 "%s: Val %.8X Addr %.4X BaseAddr %.4X Len %.2X Width %X AccLen %.2X Conn %p\n",
636 (Function & ACPI_IO_MASK) ? "Write" : "Read ", (UINT32) *Value,
637 (UINT32) Address, (UINT32) BaseAddress, Length, BitWidth,
638 MyContext->AccessLength, MyContext->Connection);
639 break;
640
641 default:
642
643 break;
644 }
645 }
646
647 return (AE_OK);
648 }
649