1 | // SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0 |
2 | /****************************************************************************** |
3 | * |
4 | * Module Name: dswstate - Dispatcher parse tree walk management routines |
5 | * |
6 | * Copyright (C) 2000 - 2023, Intel Corp. |
7 | * |
8 | *****************************************************************************/ |
9 | |
10 | #include <acpi/acpi.h> |
11 | #include "accommon.h" |
12 | #include "acparser.h" |
13 | #include "acdispat.h" |
14 | #include "acnamesp.h" |
15 | |
16 | #define _COMPONENT ACPI_DISPATCHER |
17 | ACPI_MODULE_NAME("dswstate" ) |
18 | |
19 | /* Local prototypes */ |
20 | static acpi_status |
21 | acpi_ds_result_stack_push(struct acpi_walk_state *walk_state); |
22 | static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state); |
23 | |
24 | /******************************************************************************* |
25 | * |
26 | * FUNCTION: acpi_ds_result_pop |
27 | * |
28 | * PARAMETERS: object - Where to return the popped object |
29 | * walk_state - Current Walk state |
30 | * |
31 | * RETURN: Status |
32 | * |
33 | * DESCRIPTION: Pop an object off the top of this walk's result stack |
34 | * |
35 | ******************************************************************************/ |
36 | |
37 | acpi_status |
38 | acpi_ds_result_pop(union acpi_operand_object **object, |
39 | struct acpi_walk_state *walk_state) |
40 | { |
41 | u32 index; |
42 | union acpi_generic_state *state; |
43 | acpi_status status; |
44 | |
45 | ACPI_FUNCTION_NAME(ds_result_pop); |
46 | |
47 | state = walk_state->results; |
48 | |
49 | /* Incorrect state of result stack */ |
50 | |
51 | if (state && !walk_state->result_count) { |
52 | ACPI_ERROR((AE_INFO, "No results on result stack" )); |
53 | return (AE_AML_INTERNAL); |
54 | } |
55 | |
56 | if (!state && walk_state->result_count) { |
57 | ACPI_ERROR((AE_INFO, "No result state for result stack" )); |
58 | return (AE_AML_INTERNAL); |
59 | } |
60 | |
61 | /* Empty result stack */ |
62 | |
63 | if (!state) { |
64 | ACPI_ERROR((AE_INFO, "Result stack is empty! State=%p" , |
65 | walk_state)); |
66 | return (AE_AML_NO_RETURN_VALUE); |
67 | } |
68 | |
69 | /* Return object of the top element and clean that top element result stack */ |
70 | |
71 | walk_state->result_count--; |
72 | index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; |
73 | |
74 | *object = state->results.obj_desc[index]; |
75 | if (!*object) { |
76 | ACPI_ERROR((AE_INFO, |
77 | "No result objects on result stack, State=%p" , |
78 | walk_state)); |
79 | return (AE_AML_NO_RETURN_VALUE); |
80 | } |
81 | |
82 | state->results.obj_desc[index] = NULL; |
83 | if (index == 0) { |
84 | status = acpi_ds_result_stack_pop(walk_state); |
85 | if (ACPI_FAILURE(status)) { |
86 | return (status); |
87 | } |
88 | } |
89 | |
90 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
91 | "Obj=%p [%s] Index=%X State=%p Num=%X\n" , *object, |
92 | acpi_ut_get_object_type_name(*object), |
93 | index, walk_state, walk_state->result_count)); |
94 | |
95 | return (AE_OK); |
96 | } |
97 | |
98 | /******************************************************************************* |
99 | * |
100 | * FUNCTION: acpi_ds_result_push |
101 | * |
102 | * PARAMETERS: object - Where to return the popped object |
103 | * walk_state - Current Walk state |
104 | * |
105 | * RETURN: Status |
106 | * |
107 | * DESCRIPTION: Push an object onto the current result stack |
108 | * |
109 | ******************************************************************************/ |
110 | |
111 | acpi_status |
112 | acpi_ds_result_push(union acpi_operand_object *object, |
113 | struct acpi_walk_state *walk_state) |
114 | { |
115 | union acpi_generic_state *state; |
116 | acpi_status status; |
117 | u32 index; |
118 | |
119 | ACPI_FUNCTION_NAME(ds_result_push); |
120 | |
121 | if (walk_state->result_count > walk_state->result_size) { |
122 | ACPI_ERROR((AE_INFO, "Result stack is full" )); |
123 | return (AE_AML_INTERNAL); |
124 | } else if (walk_state->result_count == walk_state->result_size) { |
125 | |
126 | /* Extend the result stack */ |
127 | |
128 | status = acpi_ds_result_stack_push(walk_state); |
129 | if (ACPI_FAILURE(status)) { |
130 | ACPI_ERROR((AE_INFO, |
131 | "Failed to extend the result stack" )); |
132 | return (status); |
133 | } |
134 | } |
135 | |
136 | if (!(walk_state->result_count < walk_state->result_size)) { |
137 | ACPI_ERROR((AE_INFO, "No free elements in result stack" )); |
138 | return (AE_AML_INTERNAL); |
139 | } |
140 | |
141 | state = walk_state->results; |
142 | if (!state) { |
143 | ACPI_ERROR((AE_INFO, "No result stack frame during push" )); |
144 | return (AE_AML_INTERNAL); |
145 | } |
146 | |
147 | if (!object) { |
148 | ACPI_ERROR((AE_INFO, |
149 | "Null Object! State=%p Num=%u" , |
150 | walk_state, walk_state->result_count)); |
151 | return (AE_BAD_PARAMETER); |
152 | } |
153 | |
154 | /* Assign the address of object to the top free element of result stack */ |
155 | |
156 | index = (u32)walk_state->result_count % ACPI_RESULTS_FRAME_OBJ_NUM; |
157 | state->results.obj_desc[index] = object; |
158 | walk_state->result_count++; |
159 | |
160 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p Num=%X Cur=%X\n" , |
161 | object, |
162 | acpi_ut_get_object_type_name((union |
163 | acpi_operand_object *) |
164 | object), walk_state, |
165 | walk_state->result_count, |
166 | walk_state->current_result)); |
167 | |
168 | return (AE_OK); |
169 | } |
170 | |
171 | /******************************************************************************* |
172 | * |
173 | * FUNCTION: acpi_ds_result_stack_push |
174 | * |
175 | * PARAMETERS: walk_state - Current Walk state |
176 | * |
177 | * RETURN: Status |
178 | * |
179 | * DESCRIPTION: Push an object onto the walk_state result stack |
180 | * |
181 | ******************************************************************************/ |
182 | |
183 | static acpi_status acpi_ds_result_stack_push(struct acpi_walk_state *walk_state) |
184 | { |
185 | union acpi_generic_state *state; |
186 | |
187 | ACPI_FUNCTION_NAME(ds_result_stack_push); |
188 | |
189 | /* Check for stack overflow */ |
190 | |
191 | if (((u32) walk_state->result_size + ACPI_RESULTS_FRAME_OBJ_NUM) > |
192 | ACPI_RESULTS_OBJ_NUM_MAX) { |
193 | ACPI_ERROR((AE_INFO, "Result stack overflow: State=%p Num=%u" , |
194 | walk_state, walk_state->result_size)); |
195 | return (AE_STACK_OVERFLOW); |
196 | } |
197 | |
198 | state = acpi_ut_create_generic_state(); |
199 | if (!state) { |
200 | return (AE_NO_MEMORY); |
201 | } |
202 | |
203 | state->common.descriptor_type = ACPI_DESC_TYPE_STATE_RESULT; |
204 | acpi_ut_push_generic_state(list_head: &walk_state->results, state); |
205 | |
206 | /* Increase the length of the result stack by the length of frame */ |
207 | |
208 | walk_state->result_size += ACPI_RESULTS_FRAME_OBJ_NUM; |
209 | |
210 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Results=%p State=%p\n" , |
211 | state, walk_state)); |
212 | |
213 | return (AE_OK); |
214 | } |
215 | |
216 | /******************************************************************************* |
217 | * |
218 | * FUNCTION: acpi_ds_result_stack_pop |
219 | * |
220 | * PARAMETERS: walk_state - Current Walk state |
221 | * |
222 | * RETURN: Status |
223 | * |
224 | * DESCRIPTION: Pop an object off of the walk_state result stack |
225 | * |
226 | ******************************************************************************/ |
227 | |
228 | static acpi_status acpi_ds_result_stack_pop(struct acpi_walk_state *walk_state) |
229 | { |
230 | union acpi_generic_state *state; |
231 | |
232 | ACPI_FUNCTION_NAME(ds_result_stack_pop); |
233 | |
234 | /* Check for stack underflow */ |
235 | |
236 | if (walk_state->results == NULL) { |
237 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
238 | "Result stack underflow - State=%p\n" , |
239 | walk_state)); |
240 | return (AE_AML_NO_OPERAND); |
241 | } |
242 | |
243 | if (walk_state->result_size < ACPI_RESULTS_FRAME_OBJ_NUM) { |
244 | ACPI_ERROR((AE_INFO, "Insufficient result stack size" )); |
245 | return (AE_AML_INTERNAL); |
246 | } |
247 | |
248 | state = acpi_ut_pop_generic_state(list_head: &walk_state->results); |
249 | acpi_ut_delete_generic_state(state); |
250 | |
251 | /* Decrease the length of result stack by the length of frame */ |
252 | |
253 | walk_state->result_size -= ACPI_RESULTS_FRAME_OBJ_NUM; |
254 | |
255 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, |
256 | "Result=%p RemainingResults=%X State=%p\n" , |
257 | state, walk_state->result_count, walk_state)); |
258 | |
259 | return (AE_OK); |
260 | } |
261 | |
262 | /******************************************************************************* |
263 | * |
264 | * FUNCTION: acpi_ds_obj_stack_push |
265 | * |
266 | * PARAMETERS: object - Object to push |
267 | * walk_state - Current Walk state |
268 | * |
269 | * RETURN: Status |
270 | * |
271 | * DESCRIPTION: Push an object onto this walk's object/operand stack |
272 | * |
273 | ******************************************************************************/ |
274 | |
275 | acpi_status |
276 | acpi_ds_obj_stack_push(void *object, struct acpi_walk_state *walk_state) |
277 | { |
278 | ACPI_FUNCTION_NAME(ds_obj_stack_push); |
279 | |
280 | /* Check for stack overflow */ |
281 | |
282 | if (walk_state->num_operands >= ACPI_OBJ_NUM_OPERANDS) { |
283 | ACPI_ERROR((AE_INFO, |
284 | "Object stack overflow! Obj=%p State=%p #Ops=%u" , |
285 | object, walk_state, walk_state->num_operands)); |
286 | return (AE_STACK_OVERFLOW); |
287 | } |
288 | |
289 | /* Put the object onto the stack */ |
290 | |
291 | walk_state->operands[walk_state->operand_index] = object; |
292 | walk_state->num_operands++; |
293 | |
294 | /* For the usual order of filling the operand stack */ |
295 | |
296 | walk_state->operand_index++; |
297 | |
298 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Obj=%p [%s] State=%p #Ops=%X\n" , |
299 | object, |
300 | acpi_ut_get_object_type_name((union |
301 | acpi_operand_object *) |
302 | object), walk_state, |
303 | walk_state->num_operands)); |
304 | |
305 | return (AE_OK); |
306 | } |
307 | |
308 | /******************************************************************************* |
309 | * |
310 | * FUNCTION: acpi_ds_obj_stack_pop |
311 | * |
312 | * PARAMETERS: pop_count - Number of objects/entries to pop |
313 | * walk_state - Current Walk state |
314 | * |
315 | * RETURN: Status |
316 | * |
317 | * DESCRIPTION: Pop this walk's object stack. Objects on the stack are NOT |
318 | * deleted by this routine. |
319 | * |
320 | ******************************************************************************/ |
321 | |
322 | acpi_status |
323 | acpi_ds_obj_stack_pop(u32 pop_count, struct acpi_walk_state *walk_state) |
324 | { |
325 | u32 i; |
326 | |
327 | ACPI_FUNCTION_NAME(ds_obj_stack_pop); |
328 | |
329 | for (i = 0; i < pop_count; i++) { |
330 | |
331 | /* Check for stack underflow */ |
332 | |
333 | if (walk_state->num_operands == 0) { |
334 | ACPI_ERROR((AE_INFO, |
335 | "Object stack underflow! Count=%X State=%p #Ops=%u" , |
336 | pop_count, walk_state, |
337 | walk_state->num_operands)); |
338 | return (AE_STACK_UNDERFLOW); |
339 | } |
340 | |
341 | /* Just set the stack entry to null */ |
342 | |
343 | walk_state->num_operands--; |
344 | walk_state->operands[walk_state->num_operands] = NULL; |
345 | } |
346 | |
347 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%u\n" , |
348 | pop_count, walk_state, walk_state->num_operands)); |
349 | |
350 | return (AE_OK); |
351 | } |
352 | |
353 | /******************************************************************************* |
354 | * |
355 | * FUNCTION: acpi_ds_obj_stack_pop_and_delete |
356 | * |
357 | * PARAMETERS: pop_count - Number of objects/entries to pop |
358 | * walk_state - Current Walk state |
359 | * |
360 | * RETURN: Status |
361 | * |
362 | * DESCRIPTION: Pop this walk's object stack and delete each object that is |
363 | * popped off. |
364 | * |
365 | ******************************************************************************/ |
366 | |
367 | void |
368 | acpi_ds_obj_stack_pop_and_delete(u32 pop_count, |
369 | struct acpi_walk_state *walk_state) |
370 | { |
371 | s32 i; |
372 | union acpi_operand_object *obj_desc; |
373 | |
374 | ACPI_FUNCTION_NAME(ds_obj_stack_pop_and_delete); |
375 | |
376 | if (pop_count == 0) { |
377 | return; |
378 | } |
379 | |
380 | for (i = (s32)pop_count - 1; i >= 0; i--) { |
381 | if (walk_state->num_operands == 0) { |
382 | return; |
383 | } |
384 | |
385 | /* Pop the stack and delete an object if present in this stack entry */ |
386 | |
387 | walk_state->num_operands--; |
388 | obj_desc = walk_state->operands[i]; |
389 | if (obj_desc) { |
390 | acpi_ut_remove_reference(object: walk_state->operands[i]); |
391 | walk_state->operands[i] = NULL; |
392 | } |
393 | } |
394 | |
395 | ACPI_DEBUG_PRINT((ACPI_DB_EXEC, "Count=%X State=%p #Ops=%X\n" , |
396 | pop_count, walk_state, walk_state->num_operands)); |
397 | } |
398 | |
399 | /******************************************************************************* |
400 | * |
401 | * FUNCTION: acpi_ds_get_current_walk_state |
402 | * |
403 | * PARAMETERS: thread - Get current active state for this Thread |
404 | * |
405 | * RETURN: Pointer to the current walk state |
406 | * |
407 | * DESCRIPTION: Get the walk state that is at the head of the list (the "current" |
408 | * walk state.) |
409 | * |
410 | ******************************************************************************/ |
411 | |
412 | struct acpi_walk_state *acpi_ds_get_current_walk_state(struct acpi_thread_state |
413 | *thread) |
414 | { |
415 | ACPI_FUNCTION_NAME(ds_get_current_walk_state); |
416 | |
417 | if (!thread) { |
418 | return (NULL); |
419 | } |
420 | |
421 | ACPI_DEBUG_PRINT((ACPI_DB_PARSE, "Current WalkState %p\n" , |
422 | thread->walk_state_list)); |
423 | |
424 | return (thread->walk_state_list); |
425 | } |
426 | |
427 | /******************************************************************************* |
428 | * |
429 | * FUNCTION: acpi_ds_push_walk_state |
430 | * |
431 | * PARAMETERS: walk_state - State to push |
432 | * thread - Thread state object |
433 | * |
434 | * RETURN: None |
435 | * |
436 | * DESCRIPTION: Place the Thread state at the head of the state list |
437 | * |
438 | ******************************************************************************/ |
439 | |
440 | void |
441 | acpi_ds_push_walk_state(struct acpi_walk_state *walk_state, |
442 | struct acpi_thread_state *thread) |
443 | { |
444 | ACPI_FUNCTION_TRACE(ds_push_walk_state); |
445 | |
446 | walk_state->next = thread->walk_state_list; |
447 | thread->walk_state_list = walk_state; |
448 | |
449 | return_VOID; |
450 | } |
451 | |
452 | /******************************************************************************* |
453 | * |
454 | * FUNCTION: acpi_ds_pop_walk_state |
455 | * |
456 | * PARAMETERS: thread - Current thread state |
457 | * |
458 | * RETURN: A walk_state object popped from the thread's stack |
459 | * |
460 | * DESCRIPTION: Remove and return the walkstate object that is at the head of |
461 | * the walk stack for the given walk list. NULL indicates that |
462 | * the list is empty. |
463 | * |
464 | ******************************************************************************/ |
465 | |
466 | struct acpi_walk_state *acpi_ds_pop_walk_state(struct acpi_thread_state *thread) |
467 | { |
468 | struct acpi_walk_state *walk_state; |
469 | |
470 | ACPI_FUNCTION_TRACE(ds_pop_walk_state); |
471 | |
472 | walk_state = thread->walk_state_list; |
473 | |
474 | if (walk_state) { |
475 | |
476 | /* Next walk state becomes the current walk state */ |
477 | |
478 | thread->walk_state_list = walk_state->next; |
479 | |
480 | /* |
481 | * Don't clear the NEXT field, this serves as an indicator |
482 | * that there is a parent WALK STATE |
483 | * Do Not: walk_state->Next = NULL; |
484 | */ |
485 | } |
486 | |
487 | return_PTR(walk_state); |
488 | } |
489 | |
490 | /******************************************************************************* |
491 | * |
492 | * FUNCTION: acpi_ds_create_walk_state |
493 | * |
494 | * PARAMETERS: owner_id - ID for object creation |
495 | * origin - Starting point for this walk |
496 | * method_desc - Method object |
497 | * thread - Current thread state |
498 | * |
499 | * RETURN: Pointer to the new walk state. |
500 | * |
501 | * DESCRIPTION: Allocate and initialize a new walk state. The current walk |
502 | * state is set to this new state. |
503 | * |
504 | ******************************************************************************/ |
505 | |
506 | struct acpi_walk_state *acpi_ds_create_walk_state(acpi_owner_id owner_id, |
507 | union acpi_parse_object |
508 | *origin, |
509 | union acpi_operand_object |
510 | *method_desc, |
511 | struct acpi_thread_state |
512 | *thread) |
513 | { |
514 | struct acpi_walk_state *walk_state; |
515 | |
516 | ACPI_FUNCTION_TRACE(ds_create_walk_state); |
517 | |
518 | walk_state = ACPI_ALLOCATE_ZEROED(sizeof(struct acpi_walk_state)); |
519 | if (!walk_state) { |
520 | return_PTR(NULL); |
521 | } |
522 | |
523 | walk_state->descriptor_type = ACPI_DESC_TYPE_WALK; |
524 | walk_state->method_desc = method_desc; |
525 | walk_state->owner_id = owner_id; |
526 | walk_state->origin = origin; |
527 | walk_state->thread = thread; |
528 | |
529 | walk_state->parser_state.start_op = origin; |
530 | |
531 | /* Init the method args/local */ |
532 | |
533 | #ifndef ACPI_CONSTANT_EVAL_ONLY |
534 | acpi_ds_method_data_init(walk_state); |
535 | #endif |
536 | |
537 | /* Put the new state at the head of the walk list */ |
538 | |
539 | if (thread) { |
540 | acpi_ds_push_walk_state(walk_state, thread); |
541 | } |
542 | |
543 | return_PTR(walk_state); |
544 | } |
545 | |
546 | /******************************************************************************* |
547 | * |
548 | * FUNCTION: acpi_ds_init_aml_walk |
549 | * |
550 | * PARAMETERS: walk_state - New state to be initialized |
551 | * op - Current parse op |
552 | * method_node - Control method NS node, if any |
553 | * aml_start - Start of AML |
554 | * aml_length - Length of AML |
555 | * info - Method info block (params, etc.) |
556 | * pass_number - 1, 2, or 3 |
557 | * |
558 | * RETURN: Status |
559 | * |
560 | * DESCRIPTION: Initialize a walk state for a pass 1 or 2 parse tree walk |
561 | * |
562 | ******************************************************************************/ |
563 | |
564 | acpi_status |
565 | acpi_ds_init_aml_walk(struct acpi_walk_state *walk_state, |
566 | union acpi_parse_object *op, |
567 | struct acpi_namespace_node *method_node, |
568 | u8 * aml_start, |
569 | u32 aml_length, |
570 | struct acpi_evaluate_info *info, u8 pass_number) |
571 | { |
572 | acpi_status status; |
573 | struct acpi_parse_state *parser_state = &walk_state->parser_state; |
574 | union acpi_parse_object *; |
575 | |
576 | ACPI_FUNCTION_TRACE(ds_init_aml_walk); |
577 | |
578 | walk_state->parser_state.aml = |
579 | walk_state->parser_state.aml_start = |
580 | walk_state->parser_state.aml_end = |
581 | walk_state->parser_state.pkg_end = aml_start; |
582 | /* Avoid undefined behavior: applying zero offset to null pointer */ |
583 | if (aml_length != 0) { |
584 | walk_state->parser_state.aml_end += aml_length; |
585 | walk_state->parser_state.pkg_end += aml_length; |
586 | } |
587 | |
588 | /* The next_op of the next_walk will be the beginning of the method */ |
589 | |
590 | walk_state->next_op = NULL; |
591 | walk_state->pass_number = pass_number; |
592 | |
593 | if (info) { |
594 | walk_state->params = info->parameters; |
595 | walk_state->caller_return_desc = &info->return_object; |
596 | } |
597 | |
598 | status = acpi_ps_init_scope(parser_state: &walk_state->parser_state, root: op); |
599 | if (ACPI_FAILURE(status)) { |
600 | return_ACPI_STATUS(status); |
601 | } |
602 | |
603 | if (method_node) { |
604 | walk_state->parser_state.start_node = method_node; |
605 | walk_state->walk_type = ACPI_WALK_METHOD; |
606 | walk_state->method_node = method_node; |
607 | walk_state->method_desc = |
608 | acpi_ns_get_attached_object(node: method_node); |
609 | |
610 | /* Push start scope on scope stack and make it current */ |
611 | |
612 | status = |
613 | acpi_ds_scope_stack_push(node: method_node, ACPI_TYPE_METHOD, |
614 | walk_state); |
615 | if (ACPI_FAILURE(status)) { |
616 | return_ACPI_STATUS(status); |
617 | } |
618 | |
619 | /* Init the method arguments */ |
620 | |
621 | status = acpi_ds_method_data_init_args(params: walk_state->params, |
622 | ACPI_METHOD_NUM_ARGS, |
623 | walk_state); |
624 | if (ACPI_FAILURE(status)) { |
625 | return_ACPI_STATUS(status); |
626 | } |
627 | } else { |
628 | /* |
629 | * Setup the current scope. |
630 | * Find a Named Op that has a namespace node associated with it. |
631 | * search upwards from this Op. Current scope is the first |
632 | * Op with a namespace node. |
633 | */ |
634 | extra_op = parser_state->start_op; |
635 | while (extra_op && !extra_op->common.node) { |
636 | extra_op = extra_op->common.parent; |
637 | } |
638 | |
639 | if (!extra_op) { |
640 | parser_state->start_node = NULL; |
641 | } else { |
642 | parser_state->start_node = extra_op->common.node; |
643 | } |
644 | |
645 | if (parser_state->start_node) { |
646 | |
647 | /* Push start scope on scope stack and make it current */ |
648 | |
649 | status = |
650 | acpi_ds_scope_stack_push(node: parser_state->start_node, |
651 | type: parser_state->start_node-> |
652 | type, walk_state); |
653 | if (ACPI_FAILURE(status)) { |
654 | return_ACPI_STATUS(status); |
655 | } |
656 | } |
657 | } |
658 | |
659 | status = acpi_ds_init_callbacks(walk_state, pass_number); |
660 | return_ACPI_STATUS(status); |
661 | } |
662 | |
663 | /******************************************************************************* |
664 | * |
665 | * FUNCTION: acpi_ds_delete_walk_state |
666 | * |
667 | * PARAMETERS: walk_state - State to delete |
668 | * |
669 | * RETURN: Status |
670 | * |
671 | * DESCRIPTION: Delete a walk state including all internal data structures |
672 | * |
673 | ******************************************************************************/ |
674 | |
675 | void acpi_ds_delete_walk_state(struct acpi_walk_state *walk_state) |
676 | { |
677 | union acpi_generic_state *state; |
678 | |
679 | ACPI_FUNCTION_TRACE_PTR(ds_delete_walk_state, walk_state); |
680 | |
681 | if (!walk_state) { |
682 | return_VOID; |
683 | } |
684 | |
685 | if (walk_state->descriptor_type != ACPI_DESC_TYPE_WALK) { |
686 | ACPI_ERROR((AE_INFO, "%p is not a valid walk state" , |
687 | walk_state)); |
688 | return_VOID; |
689 | } |
690 | |
691 | /* There should not be any open scopes */ |
692 | |
693 | if (walk_state->parser_state.scope) { |
694 | ACPI_ERROR((AE_INFO, "%p walk still has a scope list" , |
695 | walk_state)); |
696 | acpi_ps_cleanup_scope(state: &walk_state->parser_state); |
697 | } |
698 | |
699 | /* Always must free any linked control states */ |
700 | |
701 | while (walk_state->control_state) { |
702 | state = walk_state->control_state; |
703 | walk_state->control_state = state->common.next; |
704 | |
705 | acpi_ut_delete_generic_state(state); |
706 | } |
707 | |
708 | /* Always must free any linked parse states */ |
709 | |
710 | while (walk_state->scope_info) { |
711 | state = walk_state->scope_info; |
712 | walk_state->scope_info = state->common.next; |
713 | |
714 | acpi_ut_delete_generic_state(state); |
715 | } |
716 | |
717 | /* Always must free any stacked result states */ |
718 | |
719 | while (walk_state->results) { |
720 | state = walk_state->results; |
721 | walk_state->results = state->common.next; |
722 | |
723 | acpi_ut_delete_generic_state(state); |
724 | } |
725 | |
726 | ACPI_FREE(walk_state); |
727 | return_VOID; |
728 | } |
729 | |