1 /*******************************************************************************
2 *
3 * Module Name: dmresrc.c - Resource Descriptor disassembly
4 *
5 ******************************************************************************/
6
7 /*
8 * Copyright (C) 2000 - 2023, 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 MERCHANTABILITY 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 "acpi.h"
45 #include "accommon.h"
46 #include "amlcode.h"
47 #include "acdisasm.h"
48
49
50 #define _COMPONENT ACPI_CA_DEBUGGER
51 ACPI_MODULE_NAME ("dbresrc")
52
53
54 /* Dispatch tables for Resource disassembly functions */
55
56 static ACPI_RESOURCE_HANDLER AcpiGbl_DmResourceDispatch [] =
57 {
58 /* Small descriptors */
59
60 NULL, /* 0x00, Reserved */
61 NULL, /* 0x01, Reserved */
62 NULL, /* 0x02, Reserved */
63 NULL, /* 0x03, Reserved */
64 AcpiDmIrqDescriptor, /* 0x04, ACPI_RESOURCE_NAME_IRQ_FORMAT */
65 AcpiDmDmaDescriptor, /* 0x05, ACPI_RESOURCE_NAME_DMA_FORMAT */
66 AcpiDmStartDependentDescriptor, /* 0x06, ACPI_RESOURCE_NAME_START_DEPENDENT */
67 AcpiDmEndDependentDescriptor, /* 0x07, ACPI_RESOURCE_NAME_END_DEPENDENT */
68 AcpiDmIoDescriptor, /* 0x08, ACPI_RESOURCE_NAME_IO_PORT */
69 AcpiDmFixedIoDescriptor, /* 0x09, ACPI_RESOURCE_NAME_FIXED_IO_PORT */
70 AcpiDmFixedDmaDescriptor, /* 0x0A, ACPI_RESOURCE_NAME_FIXED_DMA */
71 NULL, /* 0x0B, Reserved */
72 NULL, /* 0x0C, Reserved */
73 NULL, /* 0x0D, Reserved */
74 AcpiDmVendorSmallDescriptor, /* 0x0E, ACPI_RESOURCE_NAME_SMALL_VENDOR */
75 NULL, /* 0x0F, ACPI_RESOURCE_NAME_END_TAG (not used) */
76
77 /* Large descriptors */
78
79 NULL, /* 0x00, Reserved */
80 AcpiDmMemory24Descriptor, /* 0x01, ACPI_RESOURCE_NAME_MEMORY_24 */
81 AcpiDmGenericRegisterDescriptor,/* 0x02, ACPI_RESOURCE_NAME_GENERIC_REGISTER */
82 NULL, /* 0x03, Reserved */
83 AcpiDmVendorLargeDescriptor, /* 0x04, ACPI_RESOURCE_NAME_LARGE_VENDOR */
84 AcpiDmMemory32Descriptor, /* 0x05, ACPI_RESOURCE_NAME_MEMORY_32 */
85 AcpiDmFixedMemory32Descriptor, /* 0x06, ACPI_RESOURCE_NAME_FIXED_MEMORY_32 */
86 AcpiDmDwordDescriptor, /* 0x07, ACPI_RESOURCE_NAME_DWORD_ADDRESS_SPACE */
87 AcpiDmWordDescriptor, /* 0x08, ACPI_RESOURCE_NAME_WORD_ADDRESS_SPACE */
88 AcpiDmInterruptDescriptor, /* 0x09, ACPI_RESOURCE_NAME_EXTENDED_XRUPT */
89 AcpiDmQwordDescriptor, /* 0x0A, ACPI_RESOURCE_NAME_QWORD_ADDRESS_SPACE */
90 AcpiDmExtendedDescriptor, /* 0x0B, ACPI_RESOURCE_NAME_EXTENDED_ADDRESS_SPACE */
91 AcpiDmGpioDescriptor, /* 0x0C, ACPI_RESOURCE_NAME_GPIO */
92 AcpiDmPinFunctionDescriptor, /* 0x0D, ACPI_RESOURCE_NAME_PIN_FUNCTION */
93 AcpiDmSerialBusDescriptor, /* 0x0E, ACPI_RESOURCE_NAME_SERIAL_BUS */
94 AcpiDmPinConfigDescriptor, /* 0x0F, ACPI_RESOURCE_NAME_PIN_CONFIG */
95 AcpiDmPinGroupDescriptor, /* 0x10, ACPI_RESOURCE_NAME_PIN_GROUP */
96 AcpiDmPinGroupFunctionDescriptor, /* 0x11, ACPI_RESOURCE_NAME_PIN_GROUP_FUNCTION */
97 AcpiDmPinGroupConfigDescriptor, /* 0x12, ACPI_RESOURCE_NAME_PIN_GROUP_CONFIG */
98 AcpiDmClockInputDescriptor, /* 0x13, ACPI_RESOURCE_NAME_CLOCK_INPUT */
99 };
100
101
102 /* Only used for single-threaded applications */
103 /* TBD: remove when name is passed as parameter to the dump functions */
104
105 static UINT32 ResourceName;
106
107
108 /*******************************************************************************
109 *
110 * FUNCTION: AcpiDmDescriptorName
111 *
112 * PARAMETERS: None
113 *
114 * RETURN: None
115 *
116 * DESCRIPTION: Emit a name for the descriptor if one is present (indicated
117 * by the name being changed from the default name.) A name is only
118 * emitted if a reference to the descriptor has been made somewhere
119 * in the original ASL code.
120 *
121 ******************************************************************************/
122
123 void
AcpiDmDescriptorName(void)124 AcpiDmDescriptorName (
125 void)
126 {
127
128 if (ResourceName == ACPI_DEFAULT_RESNAME)
129 {
130 return;
131 }
132
133 AcpiOsPrintf ("%4.4s", (char *) &ResourceName);
134 }
135
136
137 /*******************************************************************************
138 *
139 * FUNCTION: AcpiDmDumpInteger*
140 *
141 * PARAMETERS: Value - Value to emit
142 * Name - Associated name (emitted as a comment)
143 *
144 * RETURN: None
145 *
146 * DESCRIPTION: Integer output helper functions
147 *
148 ******************************************************************************/
149
150 void
AcpiDmDumpInteger8(UINT8 Value,const char * Name)151 AcpiDmDumpInteger8 (
152 UINT8 Value,
153 const char *Name)
154 {
155 AcpiOsPrintf ("0x%2.2X, // %s\n", Value, Name);
156 }
157
158 void
AcpiDmDumpInteger16(UINT16 Value,const char * Name)159 AcpiDmDumpInteger16 (
160 UINT16 Value,
161 const char *Name)
162 {
163 AcpiOsPrintf ("0x%4.4X, // %s\n", Value, Name);
164 }
165
166 void
AcpiDmDumpInteger32(UINT32 Value,const char * Name)167 AcpiDmDumpInteger32 (
168 UINT32 Value,
169 const char *Name)
170 {
171 AcpiOsPrintf ("0x%8.8X, // %s\n", Value, Name);
172 }
173
174 void
AcpiDmDumpInteger64(UINT64 Value,const char * Name)175 AcpiDmDumpInteger64 (
176 UINT64 Value,
177 const char *Name)
178 {
179 AcpiOsPrintf ("0x%8.8X%8.8X, // %s\n", ACPI_FORMAT_UINT64 (Value), Name);
180 }
181
182
183 /*******************************************************************************
184 *
185 * FUNCTION: AcpiDmBitList
186 *
187 * PARAMETERS: Mask - 16-bit value corresponding to 16 interrupt
188 * or DMA values
189 *
190 * RETURN: None
191 *
192 * DESCRIPTION: Dump a bit mask as a list of individual interrupt/DMA levels.
193 *
194 ******************************************************************************/
195
196 void
AcpiDmBitList(UINT16 Mask)197 AcpiDmBitList (
198 UINT16 Mask)
199 {
200 UINT32 i;
201 BOOLEAN Previous = FALSE;
202
203
204 /* Open the initializer list */
205
206 AcpiOsPrintf ("{");
207
208 /* Examine each bit */
209
210 for (i = 0; i < 16; i++)
211 {
212 /* Only interested in bits that are set to 1 */
213
214 if (Mask & 1)
215 {
216 if (Previous)
217 {
218 AcpiOsPrintf (",");
219 }
220
221 Previous = TRUE;
222 AcpiOsPrintf ("%u", i);
223 }
224
225 Mask >>= 1;
226 }
227
228 /* Close list */
229
230 AcpiOsPrintf ("}\n");
231 }
232
233
234 /*******************************************************************************
235 *
236 * FUNCTION: AcpiDmResourceTemplate
237 *
238 * PARAMETERS: Info - Current parse tree walk info
239 * ByteData - Pointer to the byte list data
240 * ByteCount - Length of the byte list
241 *
242 * RETURN: None
243 *
244 * DESCRIPTION: Dump the contents of a Resource Template containing a set of
245 * Resource Descriptors.
246 *
247 ******************************************************************************/
248
249 void
AcpiDmResourceTemplate(ACPI_OP_WALK_INFO * Info,ACPI_PARSE_OBJECT * Op,UINT8 * ByteData,UINT32 ByteCount)250 AcpiDmResourceTemplate (
251 ACPI_OP_WALK_INFO *Info,
252 ACPI_PARSE_OBJECT *Op,
253 UINT8 *ByteData,
254 UINT32 ByteCount)
255 {
256 ACPI_STATUS Status;
257 UINT32 CurrentByteOffset;
258 UINT8 ResourceType;
259 UINT32 ResourceLength;
260 void *Aml;
261 UINT32 Level;
262 BOOLEAN DependentFns = FALSE;
263 UINT8 ResourceIndex;
264 ACPI_NAMESPACE_NODE *Node;
265
266
267 if (Op->Asl.AmlOpcode != AML_FIELD_OP)
268 {
269 Info->MappingOp = Op;
270 }
271
272 Level = Info->Level;
273 ResourceName = ACPI_DEFAULT_RESNAME;
274 Node = Op->Common.Node;
275 if (Node)
276 {
277 Node = Node->Child;
278 }
279
280 for (CurrentByteOffset = 0; CurrentByteOffset < ByteCount;)
281 {
282 Aml = &ByteData[CurrentByteOffset];
283
284 /* Get the descriptor type and length */
285
286 ResourceType = AcpiUtGetResourceType (Aml);
287 ResourceLength = AcpiUtGetResourceLength (Aml);
288
289 /* Validate the Resource Type and Resource Length */
290
291 Status = AcpiUtValidateResource (NULL, Aml, &ResourceIndex);
292 if (ACPI_FAILURE (Status))
293 {
294 AcpiOsPrintf (
295 "/*** Could not validate Resource, type (%X) %s***/\n",
296 ResourceType, AcpiFormatException (Status));
297 return;
298 }
299
300 /* Point to next descriptor */
301
302 CurrentByteOffset += AcpiUtGetDescriptorLength (Aml);
303
304 /* Descriptor pre-processing */
305
306 switch (ResourceType)
307 {
308 case ACPI_RESOURCE_NAME_START_DEPENDENT:
309
310 /* Finish a previous StartDependentFns */
311
312 if (DependentFns)
313 {
314 Level--;
315 AcpiDmIndent (Level);
316 AcpiOsPrintf ("}\n");
317 }
318 break;
319
320 case ACPI_RESOURCE_NAME_END_DEPENDENT:
321
322 Level--;
323 DependentFns = FALSE;
324 break;
325
326 case ACPI_RESOURCE_NAME_END_TAG:
327
328 /* Normal exit, the resource list is finished */
329
330 if (DependentFns)
331 {
332 /*
333 * Close an open StartDependentDescriptor. This indicates a
334 * missing EndDependentDescriptor.
335 */
336 Level--;
337
338 /* Go ahead and insert EndDependentFn() */
339
340 AcpiDmEndDependentDescriptor (Info, Aml, ResourceLength, Level);
341
342 AcpiDmIndent (Level);
343 AcpiOsPrintf (
344 "/*** Disassembler: inserted "
345 "missing EndDependentFn () ***/\n");
346 }
347 return;
348
349 default:
350
351 break;
352 }
353
354 /* Disassemble the resource structure */
355
356 if (Node)
357 {
358 ResourceName = Node->Name.Integer;
359 Node = Node->Peer;
360 }
361
362 AcpiGbl_DmResourceDispatch [ResourceIndex] (
363 Info, Aml, ResourceLength, Level);
364
365 /* Descriptor post-processing */
366
367 if (ResourceType == ACPI_RESOURCE_NAME_START_DEPENDENT)
368 {
369 DependentFns = TRUE;
370 Level++;
371 }
372 }
373 }
374
375
376 /*******************************************************************************
377 *
378 * FUNCTION: AcpiDmIsResourceTemplate
379 *
380 * PARAMETERS: WalkState - Current walk info
381 * Op - Buffer Op to be examined
382 *
383 * RETURN: Status. AE_OK if valid template
384 *
385 * DESCRIPTION: Walk a byte list to determine if it consists of a valid set
386 * of resource descriptors. Nothing is output.
387 *
388 ******************************************************************************/
389
390 ACPI_STATUS
AcpiDmIsResourceTemplate(ACPI_WALK_STATE * WalkState,ACPI_PARSE_OBJECT * Op)391 AcpiDmIsResourceTemplate (
392 ACPI_WALK_STATE *WalkState,
393 ACPI_PARSE_OBJECT *Op)
394 {
395 ACPI_STATUS Status;
396 ACPI_PARSE_OBJECT *NextOp;
397 UINT8 *Aml;
398 UINT8 *EndAml;
399 UINT32 BufferLength;
400 UINT32 DeclaredBufferLength;
401
402
403 /* This op must be a buffer */
404
405 if (Op->Common.AmlOpcode != AML_BUFFER_OP)
406 {
407 return (AE_TYPE);
408 }
409
410 /*
411 * Get the declared length of the buffer.
412 * This is the nn in "Buffer (nn)"
413 */
414 NextOp = Op->Common.Value.Arg;
415 if (!NextOp)
416 {
417 AcpiOsPrintf ("NULL byte list in buffer\n");
418 return (AE_TYPE);
419 }
420
421 DeclaredBufferLength = NextOp->Common.Value.Size;
422
423 /* Get the length of the raw initialization byte list */
424
425 NextOp = NextOp->Common.Next;
426 if (!NextOp)
427 {
428 return (AE_TYPE);
429 }
430
431 Aml = NextOp->Named.Data;
432 BufferLength = NextOp->Common.Value.Size;
433
434 /*
435 * Any buffer smaller than one byte cannot possibly be a resource
436 * template. Two bytes could possibly be a "NULL" resource template
437 * with a lone end tag descriptor (as generated via
438 * "ResourceTemplate(){}"), but this would be an extremely unusual
439 * case, as the template would be essentially useless. The disassembler
440 * therefore does not recognize any two-byte buffer as a resource
441 * template.
442 */
443 if (BufferLength <= 2)
444 {
445 return (AE_TYPE);
446 }
447
448 /*
449 * Not a template if declared buffer length != actual length of the
450 * initialization byte list. Because the resource macros will create
451 * a buffer of the exact required length (buffer length will be equal
452 * to the actual length).
453 *
454 * NOTE (April 2017): Resource templates with this issue have been
455 * seen in the field. We still don't want to attempt to disassemble
456 * a buffer like this to a resource template because this output
457 * would not match the original input buffer (it would be shorter
458 * than the original when the disassembled code is recompiled).
459 * Basically, a buffer like this appears to be hand crafted in the
460 * first place, so just emitting a buffer object instead of a
461 * resource template more closely resembles the original ASL code.
462 */
463 if (DeclaredBufferLength != BufferLength)
464 {
465 return (AE_TYPE);
466 }
467
468 /* Walk the byte list, abort on any invalid descriptor type or length */
469
470 Status = AcpiUtWalkAmlResources (WalkState, Aml, BufferLength,
471 NULL, ACPI_CAST_INDIRECT_PTR (void, &EndAml));
472 if (ACPI_FAILURE (Status))
473 {
474 return (AE_TYPE);
475 }
476
477 /*
478 * For the resource template to be valid, one EndTag must appear
479 * at the very end of the ByteList, not before. (For proper disassembly
480 * of a ResourceTemplate, the buffer must not have any extra data after
481 * the EndTag.)
482 */
483 if ((Aml + BufferLength - sizeof (AML_RESOURCE_END_TAG)) != EndAml)
484 {
485 return (AE_AML_NO_RESOURCE_END_TAG);
486 }
487
488 /*
489 * All resource descriptors are valid, therefore this list appears
490 * to be a valid resource template
491 */
492 return (AE_OK);
493 }
494