1 // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
2 /*******************************************************************************
3  *
4  * Module Name: dbutils - AML debugger utilities
5  *
6  ******************************************************************************/
7 
8 #include <acpi/acpi.h>
9 #include "accommon.h"
10 #include "acnamesp.h"
11 #include "acdebug.h"
12 
13 #define _COMPONENT          ACPI_CA_DEBUGGER
14 ACPI_MODULE_NAME("dbutils")
15 
16 /* Local prototypes */
17 #ifdef ACPI_OBSOLETE_FUNCTIONS
18 acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root);
19 
20 void acpi_db_dump_buffer(u32 address);
21 #endif
22 
23 /*******************************************************************************
24  *
25  * FUNCTION:    acpi_db_match_argument
26  *
27  * PARAMETERS:  user_argument           - User command line
28  *              arguments               - Array of commands to match against
29  *
30  * RETURN:      Index into command array or ACPI_TYPE_NOT_FOUND if not found
31  *
32  * DESCRIPTION: Search command array for a command match
33  *
34  ******************************************************************************/
35 
36 acpi_object_type
acpi_db_match_argument(char * user_argument,struct acpi_db_argument_info * arguments)37 acpi_db_match_argument(char *user_argument,
38 		       struct acpi_db_argument_info *arguments)
39 {
40 	u32 i;
41 
42 	if (!user_argument || user_argument[0] == 0) {
43 		return (ACPI_TYPE_NOT_FOUND);
44 	}
45 
46 	for (i = 0; arguments[i].name; i++) {
47 		if (strstr(ACPI_CAST_PTR(char, arguments[i].name),
48 			   ACPI_CAST_PTR(char,
49 					 user_argument)) == arguments[i].name) {
50 			return (i);
51 		}
52 	}
53 
54 	/* Argument not recognized */
55 
56 	return (ACPI_TYPE_NOT_FOUND);
57 }
58 
59 /*******************************************************************************
60  *
61  * FUNCTION:    acpi_db_set_output_destination
62  *
63  * PARAMETERS:  output_flags        - Current flags word
64  *
65  * RETURN:      None
66  *
67  * DESCRIPTION: Set the current destination for debugger output. Also sets
68  *              the debug output level accordingly.
69  *
70  ******************************************************************************/
71 
acpi_db_set_output_destination(u32 output_flags)72 void acpi_db_set_output_destination(u32 output_flags)
73 {
74 
75 	acpi_gbl_db_output_flags = (u8)output_flags;
76 
77 	if ((output_flags & ACPI_DB_REDIRECTABLE_OUTPUT) &&
78 	    acpi_gbl_db_output_to_file) {
79 		acpi_dbg_level = acpi_gbl_db_debug_level;
80 	} else {
81 		acpi_dbg_level = acpi_gbl_db_console_debug_level;
82 	}
83 }
84 
85 /*******************************************************************************
86  *
87  * FUNCTION:    acpi_db_dump_external_object
88  *
89  * PARAMETERS:  obj_desc        - External ACPI object to dump
90  *              level           - Nesting level.
91  *
92  * RETURN:      None
93  *
94  * DESCRIPTION: Dump the contents of an ACPI external object
95  *
96  ******************************************************************************/
97 
acpi_db_dump_external_object(union acpi_object * obj_desc,u32 level)98 void acpi_db_dump_external_object(union acpi_object *obj_desc, u32 level)
99 {
100 	u32 i;
101 
102 	if (!obj_desc) {
103 		acpi_os_printf("[Null Object]\n");
104 		return;
105 	}
106 
107 	for (i = 0; i < level; i++) {
108 		acpi_os_printf(" ");
109 	}
110 
111 	switch (obj_desc->type) {
112 	case ACPI_TYPE_ANY:
113 
114 		acpi_os_printf("[Null Object] (Type=0)\n");
115 		break;
116 
117 	case ACPI_TYPE_INTEGER:
118 
119 		acpi_os_printf("[Integer] = %8.8X%8.8X\n",
120 			       ACPI_FORMAT_UINT64(obj_desc->integer.value));
121 		break;
122 
123 	case ACPI_TYPE_STRING:
124 
125 		acpi_os_printf("[String] Length %.2X = ",
126 			       obj_desc->string.length);
127 		acpi_ut_print_string(obj_desc->string.pointer, ACPI_UINT8_MAX);
128 		acpi_os_printf("\n");
129 		break;
130 
131 	case ACPI_TYPE_BUFFER:
132 
133 		acpi_os_printf("[Buffer] Length %.2X = ",
134 			       obj_desc->buffer.length);
135 		if (obj_desc->buffer.length) {
136 			if (obj_desc->buffer.length > 16) {
137 				acpi_os_printf("\n");
138 			}
139 
140 			acpi_ut_debug_dump_buffer(ACPI_CAST_PTR
141 						  (u8,
142 						   obj_desc->buffer.pointer),
143 						  obj_desc->buffer.length,
144 						  DB_BYTE_DISPLAY, _COMPONENT);
145 		} else {
146 			acpi_os_printf("\n");
147 		}
148 		break;
149 
150 	case ACPI_TYPE_PACKAGE:
151 
152 		acpi_os_printf("[Package] Contains %u Elements:\n",
153 			       obj_desc->package.count);
154 
155 		for (i = 0; i < obj_desc->package.count; i++) {
156 			acpi_db_dump_external_object(&obj_desc->package.
157 						     elements[i], level + 1);
158 		}
159 		break;
160 
161 	case ACPI_TYPE_LOCAL_REFERENCE:
162 
163 		acpi_os_printf("[Object Reference] = ");
164 		acpi_db_display_internal_object(obj_desc->reference.handle,
165 						NULL);
166 		break;
167 
168 	case ACPI_TYPE_PROCESSOR:
169 
170 		acpi_os_printf("[Processor]\n");
171 		break;
172 
173 	case ACPI_TYPE_POWER:
174 
175 		acpi_os_printf("[Power Resource]\n");
176 		break;
177 
178 	default:
179 
180 		acpi_os_printf("[Unknown Type] %X\n", obj_desc->type);
181 		break;
182 	}
183 }
184 
185 /*******************************************************************************
186  *
187  * FUNCTION:    acpi_db_prep_namestring
188  *
189  * PARAMETERS:  name            - String to prepare
190  *
191  * RETURN:      None
192  *
193  * DESCRIPTION: Translate all forward slashes and dots to backslashes.
194  *
195  ******************************************************************************/
196 
acpi_db_prep_namestring(char * name)197 void acpi_db_prep_namestring(char *name)
198 {
199 
200 	if (!name) {
201 		return;
202 	}
203 
204 	acpi_ut_strupr(name);
205 
206 	/* Convert a leading forward slash to a backslash */
207 
208 	if (*name == '/') {
209 		*name = '\\';
210 	}
211 
212 	/* Ignore a leading backslash, this is the root prefix */
213 
214 	if (ACPI_IS_ROOT_PREFIX(*name)) {
215 		name++;
216 	}
217 
218 	/* Convert all slash path separators to dots */
219 
220 	while (*name) {
221 		if ((*name == '/') || (*name == '\\')) {
222 			*name = '.';
223 		}
224 
225 		name++;
226 	}
227 }
228 
229 /*******************************************************************************
230  *
231  * FUNCTION:    acpi_db_local_ns_lookup
232  *
233  * PARAMETERS:  name            - Name to lookup
234  *
235  * RETURN:      Pointer to a namespace node, null on failure
236  *
237  * DESCRIPTION: Lookup a name in the ACPI namespace
238  *
239  * Note: Currently begins search from the root. Could be enhanced to use
240  * the current prefix (scope) node as the search beginning point.
241  *
242  ******************************************************************************/
243 
acpi_db_local_ns_lookup(char * name)244 struct acpi_namespace_node *acpi_db_local_ns_lookup(char *name)
245 {
246 	char *internal_path;
247 	acpi_status status;
248 	struct acpi_namespace_node *node = NULL;
249 
250 	acpi_db_prep_namestring(name);
251 
252 	/* Build an internal namestring */
253 
254 	status = acpi_ns_internalize_name(name, &internal_path);
255 	if (ACPI_FAILURE(status)) {
256 		acpi_os_printf("Invalid namestring: %s\n", name);
257 		return (NULL);
258 	}
259 
260 	/*
261 	 * Lookup the name.
262 	 * (Uses root node as the search starting point)
263 	 */
264 	status = acpi_ns_lookup(NULL, internal_path, ACPI_TYPE_ANY,
265 				ACPI_IMODE_EXECUTE,
266 				ACPI_NS_NO_UPSEARCH | ACPI_NS_DONT_OPEN_SCOPE,
267 				NULL, &node);
268 	if (ACPI_FAILURE(status)) {
269 		acpi_os_printf("Could not locate name: %s, %s\n",
270 			       name, acpi_format_exception(status));
271 	}
272 
273 	ACPI_FREE(internal_path);
274 	return (node);
275 }
276 
277 /*******************************************************************************
278  *
279  * FUNCTION:    acpi_db_uint32_to_hex_string
280  *
281  * PARAMETERS:  value           - The value to be converted to string
282  *              buffer          - Buffer for result (not less than 11 bytes)
283  *
284  * RETURN:      None
285  *
286  * DESCRIPTION: Convert the unsigned 32-bit value to the hexadecimal image
287  *
288  * NOTE: It is the caller's responsibility to ensure that the length of buffer
289  *       is sufficient.
290  *
291  ******************************************************************************/
292 
acpi_db_uint32_to_hex_string(u32 value,char * buffer)293 void acpi_db_uint32_to_hex_string(u32 value, char *buffer)
294 {
295 	int i;
296 
297 	if (value == 0) {
298 		strcpy(buffer, "0");
299 		return;
300 	}
301 
302 	buffer[8] = '\0';
303 
304 	for (i = 7; i >= 0; i--) {
305 		buffer[i] = acpi_gbl_upper_hex_digits[value & 0x0F];
306 		value = value >> 4;
307 	}
308 }
309 
310 #ifdef ACPI_OBSOLETE_FUNCTIONS
311 /*******************************************************************************
312  *
313  * FUNCTION:    acpi_db_second_pass_parse
314  *
315  * PARAMETERS:  root            - Root of the parse tree
316  *
317  * RETURN:      Status
318  *
319  * DESCRIPTION: Second pass parse of the ACPI tables. We need to wait until
320  *              second pass to parse the control methods
321  *
322  ******************************************************************************/
323 
acpi_db_second_pass_parse(union acpi_parse_object * root)324 acpi_status acpi_db_second_pass_parse(union acpi_parse_object *root)
325 {
326 	union acpi_parse_object *op = root;
327 	union acpi_parse_object *method;
328 	union acpi_parse_object *search_op;
329 	union acpi_parse_object *start_op;
330 	acpi_status status = AE_OK;
331 	u32 base_aml_offset;
332 	struct acpi_walk_state *walk_state;
333 
334 	ACPI_FUNCTION_ENTRY();
335 
336 	acpi_os_printf("Pass two parse ....\n");
337 
338 	while (op) {
339 		if (op->common.aml_opcode == AML_METHOD_OP) {
340 			method = op;
341 
342 			/* Create a new walk state for the parse */
343 
344 			walk_state =
345 			    acpi_ds_create_walk_state(0, NULL, NULL, NULL);
346 			if (!walk_state) {
347 				return (AE_NO_MEMORY);
348 			}
349 
350 			/* Init the Walk State */
351 
352 			walk_state->parser_state.aml =
353 			    walk_state->parser_state.aml_start =
354 			    method->named.data;
355 			walk_state->parser_state.aml_end =
356 			    walk_state->parser_state.pkg_end =
357 			    method->named.data + method->named.length;
358 			walk_state->parser_state.start_scope = op;
359 
360 			walk_state->descending_callback =
361 			    acpi_ds_load1_begin_op;
362 			walk_state->ascending_callback = acpi_ds_load1_end_op;
363 
364 			/* Perform the AML parse */
365 
366 			status = acpi_ps_parse_aml(walk_state);
367 
368 			base_aml_offset =
369 			    (method->common.value.arg)->common.aml_offset + 1;
370 			start_op = (method->common.value.arg)->common.next;
371 			search_op = start_op;
372 
373 			while (search_op) {
374 				search_op->common.aml_offset += base_aml_offset;
375 				search_op =
376 				    acpi_ps_get_depth_next(start_op, search_op);
377 			}
378 		}
379 
380 		if (op->common.aml_opcode == AML_REGION_OP) {
381 
382 			/* TBD: [Investigate] this isn't quite the right thing to do! */
383 			/*
384 			 *
385 			 * Method = (ACPI_DEFERRED_OP *) Op;
386 			 * Status = acpi_ps_parse_aml (Op, Method->Body, Method->body_length);
387 			 */
388 		}
389 
390 		if (ACPI_FAILURE(status)) {
391 			break;
392 		}
393 
394 		op = acpi_ps_get_depth_next(root, op);
395 	}
396 
397 	return (status);
398 }
399 
400 /*******************************************************************************
401  *
402  * FUNCTION:    acpi_db_dump_buffer
403  *
404  * PARAMETERS:  address             - Pointer to the buffer
405  *
406  * RETURN:      None
407  *
408  * DESCRIPTION: Print a portion of a buffer
409  *
410  ******************************************************************************/
411 
acpi_db_dump_buffer(u32 address)412 void acpi_db_dump_buffer(u32 address)
413 {
414 
415 	acpi_os_printf("\nLocation %X:\n", address);
416 
417 	acpi_dbg_level |= ACPI_LV_TABLES;
418 	acpi_ut_debug_dump_buffer(ACPI_TO_POINTER(address), 64, DB_BYTE_DISPLAY,
419 				  ACPI_UINT32_MAX);
420 }
421 #endif
422