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