162306a36Sopenharmony_ci// SPDX-License-Identifier: BSD-3-Clause OR GPL-2.0
262306a36Sopenharmony_ci/******************************************************************************
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Module Name: extrace - Support for interpreter execution tracing
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * Copyright (C) 2000 - 2023, Intel Corp.
762306a36Sopenharmony_ci *
862306a36Sopenharmony_ci *****************************************************************************/
962306a36Sopenharmony_ci
1062306a36Sopenharmony_ci#include <acpi/acpi.h>
1162306a36Sopenharmony_ci#include "accommon.h"
1262306a36Sopenharmony_ci#include "acnamesp.h"
1362306a36Sopenharmony_ci#include "acinterp.h"
1462306a36Sopenharmony_ci
1562306a36Sopenharmony_ci#define _COMPONENT          ACPI_EXECUTER
1662306a36Sopenharmony_ciACPI_MODULE_NAME("extrace")
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_cistatic union acpi_operand_object *acpi_gbl_trace_method_object = NULL;
1962306a36Sopenharmony_ci
2062306a36Sopenharmony_ci/* Local prototypes */
2162306a36Sopenharmony_ci
2262306a36Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT
2362306a36Sopenharmony_cistatic const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type);
2462306a36Sopenharmony_ci#endif
2562306a36Sopenharmony_ci
2662306a36Sopenharmony_ci/*******************************************************************************
2762306a36Sopenharmony_ci *
2862306a36Sopenharmony_ci * FUNCTION:    acpi_ex_interpreter_trace_enabled
2962306a36Sopenharmony_ci *
3062306a36Sopenharmony_ci * PARAMETERS:  name                - Whether method name should be matched,
3162306a36Sopenharmony_ci *                                    this should be checked before starting
3262306a36Sopenharmony_ci *                                    the tracer
3362306a36Sopenharmony_ci *
3462306a36Sopenharmony_ci * RETURN:      TRUE if interpreter trace is enabled.
3562306a36Sopenharmony_ci *
3662306a36Sopenharmony_ci * DESCRIPTION: Check whether interpreter trace is enabled
3762306a36Sopenharmony_ci *
3862306a36Sopenharmony_ci ******************************************************************************/
3962306a36Sopenharmony_ci
4062306a36Sopenharmony_cistatic u8 acpi_ex_interpreter_trace_enabled(char *name)
4162306a36Sopenharmony_ci{
4262306a36Sopenharmony_ci
4362306a36Sopenharmony_ci	/* Check if tracing is enabled */
4462306a36Sopenharmony_ci
4562306a36Sopenharmony_ci	if (!(acpi_gbl_trace_flags & ACPI_TRACE_ENABLED)) {
4662306a36Sopenharmony_ci		return (FALSE);
4762306a36Sopenharmony_ci	}
4862306a36Sopenharmony_ci
4962306a36Sopenharmony_ci	/*
5062306a36Sopenharmony_ci	 * Check if tracing is filtered:
5162306a36Sopenharmony_ci	 *
5262306a36Sopenharmony_ci	 * 1. If the tracer is started, acpi_gbl_trace_method_object should have
5362306a36Sopenharmony_ci	 *    been filled by the trace starter
5462306a36Sopenharmony_ci	 * 2. If the tracer is not started, acpi_gbl_trace_method_name should be
5562306a36Sopenharmony_ci	 *    matched if it is specified
5662306a36Sopenharmony_ci	 * 3. If the tracer is oneshot style, acpi_gbl_trace_method_name should
5762306a36Sopenharmony_ci	 *    not be cleared by the trace stopper during the first match
5862306a36Sopenharmony_ci	 */
5962306a36Sopenharmony_ci	if (acpi_gbl_trace_method_object) {
6062306a36Sopenharmony_ci		return (TRUE);
6162306a36Sopenharmony_ci	}
6262306a36Sopenharmony_ci
6362306a36Sopenharmony_ci	if (name &&
6462306a36Sopenharmony_ci	    (acpi_gbl_trace_method_name &&
6562306a36Sopenharmony_ci	     strcmp(acpi_gbl_trace_method_name, name))) {
6662306a36Sopenharmony_ci		return (FALSE);
6762306a36Sopenharmony_ci	}
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci	if ((acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) &&
7062306a36Sopenharmony_ci	    !acpi_gbl_trace_method_name) {
7162306a36Sopenharmony_ci		return (FALSE);
7262306a36Sopenharmony_ci	}
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	return (TRUE);
7562306a36Sopenharmony_ci}
7662306a36Sopenharmony_ci
7762306a36Sopenharmony_ci/*******************************************************************************
7862306a36Sopenharmony_ci *
7962306a36Sopenharmony_ci * FUNCTION:    acpi_ex_get_trace_event_name
8062306a36Sopenharmony_ci *
8162306a36Sopenharmony_ci * PARAMETERS:  type            - Trace event type
8262306a36Sopenharmony_ci *
8362306a36Sopenharmony_ci * RETURN:      Trace event name.
8462306a36Sopenharmony_ci *
8562306a36Sopenharmony_ci * DESCRIPTION: Used to obtain the full trace event name.
8662306a36Sopenharmony_ci *
8762306a36Sopenharmony_ci ******************************************************************************/
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci#ifdef ACPI_DEBUG_OUTPUT
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_cistatic const char *acpi_ex_get_trace_event_name(acpi_trace_event_type type)
9262306a36Sopenharmony_ci{
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci	switch (type) {
9562306a36Sopenharmony_ci	case ACPI_TRACE_AML_METHOD:
9662306a36Sopenharmony_ci
9762306a36Sopenharmony_ci		return "Method";
9862306a36Sopenharmony_ci
9962306a36Sopenharmony_ci	case ACPI_TRACE_AML_OPCODE:
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_ci		return "Opcode";
10262306a36Sopenharmony_ci
10362306a36Sopenharmony_ci	case ACPI_TRACE_AML_REGION:
10462306a36Sopenharmony_ci
10562306a36Sopenharmony_ci		return "Region";
10662306a36Sopenharmony_ci
10762306a36Sopenharmony_ci	default:
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci		return "";
11062306a36Sopenharmony_ci	}
11162306a36Sopenharmony_ci}
11262306a36Sopenharmony_ci
11362306a36Sopenharmony_ci#endif
11462306a36Sopenharmony_ci
11562306a36Sopenharmony_ci/*******************************************************************************
11662306a36Sopenharmony_ci *
11762306a36Sopenharmony_ci * FUNCTION:    acpi_ex_trace_point
11862306a36Sopenharmony_ci *
11962306a36Sopenharmony_ci * PARAMETERS:  type                - Trace event type
12062306a36Sopenharmony_ci *              begin               - TRUE if before execution
12162306a36Sopenharmony_ci *              aml                 - Executed AML address
12262306a36Sopenharmony_ci *              pathname            - Object path
12362306a36Sopenharmony_ci *
12462306a36Sopenharmony_ci * RETURN:      None
12562306a36Sopenharmony_ci *
12662306a36Sopenharmony_ci * DESCRIPTION: Internal interpreter execution trace.
12762306a36Sopenharmony_ci *
12862306a36Sopenharmony_ci ******************************************************************************/
12962306a36Sopenharmony_ci
13062306a36Sopenharmony_civoid
13162306a36Sopenharmony_ciacpi_ex_trace_point(acpi_trace_event_type type,
13262306a36Sopenharmony_ci		    u8 begin, u8 *aml, char *pathname)
13362306a36Sopenharmony_ci{
13462306a36Sopenharmony_ci
13562306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ex_trace_point);
13662306a36Sopenharmony_ci
13762306a36Sopenharmony_ci	if (pathname) {
13862306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT,
13962306a36Sopenharmony_ci				  "%s %s [0x%p:%s] execution.\n",
14062306a36Sopenharmony_ci				  acpi_ex_get_trace_event_name(type),
14162306a36Sopenharmony_ci				  begin ? "Begin" : "End", aml, pathname));
14262306a36Sopenharmony_ci	} else {
14362306a36Sopenharmony_ci		ACPI_DEBUG_PRINT((ACPI_DB_TRACE_POINT,
14462306a36Sopenharmony_ci				  "%s %s [0x%p] execution.\n",
14562306a36Sopenharmony_ci				  acpi_ex_get_trace_event_name(type),
14662306a36Sopenharmony_ci				  begin ? "Begin" : "End", aml));
14762306a36Sopenharmony_ci	}
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*******************************************************************************
15162306a36Sopenharmony_ci *
15262306a36Sopenharmony_ci * FUNCTION:    acpi_ex_start_trace_method
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * PARAMETERS:  method_node         - Node of the method
15562306a36Sopenharmony_ci *              obj_desc            - The method object
15662306a36Sopenharmony_ci *              walk_state          - current state, NULL if not yet executing
15762306a36Sopenharmony_ci *                                    a method.
15862306a36Sopenharmony_ci *
15962306a36Sopenharmony_ci * RETURN:      None
16062306a36Sopenharmony_ci *
16162306a36Sopenharmony_ci * DESCRIPTION: Start control method execution trace
16262306a36Sopenharmony_ci *
16362306a36Sopenharmony_ci ******************************************************************************/
16462306a36Sopenharmony_ci
16562306a36Sopenharmony_civoid
16662306a36Sopenharmony_ciacpi_ex_start_trace_method(struct acpi_namespace_node *method_node,
16762306a36Sopenharmony_ci			   union acpi_operand_object *obj_desc,
16862306a36Sopenharmony_ci			   struct acpi_walk_state *walk_state)
16962306a36Sopenharmony_ci{
17062306a36Sopenharmony_ci	char *pathname = NULL;
17162306a36Sopenharmony_ci	u8 enabled = FALSE;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ex_start_trace_method);
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci	if (method_node) {
17662306a36Sopenharmony_ci		pathname = acpi_ns_get_normalized_pathname(method_node, TRUE);
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	enabled = acpi_ex_interpreter_trace_enabled(pathname);
18062306a36Sopenharmony_ci	if (enabled && !acpi_gbl_trace_method_object) {
18162306a36Sopenharmony_ci		acpi_gbl_trace_method_object = obj_desc;
18262306a36Sopenharmony_ci		acpi_gbl_original_dbg_level = acpi_dbg_level;
18362306a36Sopenharmony_ci		acpi_gbl_original_dbg_layer = acpi_dbg_layer;
18462306a36Sopenharmony_ci		acpi_dbg_level = ACPI_TRACE_LEVEL_ALL;
18562306a36Sopenharmony_ci		acpi_dbg_layer = ACPI_TRACE_LAYER_ALL;
18662306a36Sopenharmony_ci
18762306a36Sopenharmony_ci		if (acpi_gbl_trace_dbg_level) {
18862306a36Sopenharmony_ci			acpi_dbg_level = acpi_gbl_trace_dbg_level;
18962306a36Sopenharmony_ci		}
19062306a36Sopenharmony_ci
19162306a36Sopenharmony_ci		if (acpi_gbl_trace_dbg_layer) {
19262306a36Sopenharmony_ci			acpi_dbg_layer = acpi_gbl_trace_dbg_layer;
19362306a36Sopenharmony_ci		}
19462306a36Sopenharmony_ci	}
19562306a36Sopenharmony_ci
19662306a36Sopenharmony_ci	if (enabled) {
19762306a36Sopenharmony_ci		ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, TRUE,
19862306a36Sopenharmony_ci				 obj_desc ? obj_desc->method.aml_start : NULL,
19962306a36Sopenharmony_ci				 pathname);
20062306a36Sopenharmony_ci	}
20162306a36Sopenharmony_ci
20262306a36Sopenharmony_ci	if (pathname) {
20362306a36Sopenharmony_ci		ACPI_FREE(pathname);
20462306a36Sopenharmony_ci	}
20562306a36Sopenharmony_ci}
20662306a36Sopenharmony_ci
20762306a36Sopenharmony_ci/*******************************************************************************
20862306a36Sopenharmony_ci *
20962306a36Sopenharmony_ci * FUNCTION:    acpi_ex_stop_trace_method
21062306a36Sopenharmony_ci *
21162306a36Sopenharmony_ci * PARAMETERS:  method_node         - Node of the method
21262306a36Sopenharmony_ci *              obj_desc            - The method object
21362306a36Sopenharmony_ci *              walk_state          - current state, NULL if not yet executing
21462306a36Sopenharmony_ci *                                    a method.
21562306a36Sopenharmony_ci *
21662306a36Sopenharmony_ci * RETURN:      None
21762306a36Sopenharmony_ci *
21862306a36Sopenharmony_ci * DESCRIPTION: Stop control method execution trace
21962306a36Sopenharmony_ci *
22062306a36Sopenharmony_ci ******************************************************************************/
22162306a36Sopenharmony_ci
22262306a36Sopenharmony_civoid
22362306a36Sopenharmony_ciacpi_ex_stop_trace_method(struct acpi_namespace_node *method_node,
22462306a36Sopenharmony_ci			  union acpi_operand_object *obj_desc,
22562306a36Sopenharmony_ci			  struct acpi_walk_state *walk_state)
22662306a36Sopenharmony_ci{
22762306a36Sopenharmony_ci	char *pathname = NULL;
22862306a36Sopenharmony_ci	u8 enabled;
22962306a36Sopenharmony_ci
23062306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ex_stop_trace_method);
23162306a36Sopenharmony_ci
23262306a36Sopenharmony_ci	if (method_node) {
23362306a36Sopenharmony_ci		pathname = acpi_ns_get_normalized_pathname(method_node, TRUE);
23462306a36Sopenharmony_ci	}
23562306a36Sopenharmony_ci
23662306a36Sopenharmony_ci	enabled = acpi_ex_interpreter_trace_enabled(NULL);
23762306a36Sopenharmony_ci
23862306a36Sopenharmony_ci	if (enabled) {
23962306a36Sopenharmony_ci		ACPI_TRACE_POINT(ACPI_TRACE_AML_METHOD, FALSE,
24062306a36Sopenharmony_ci				 obj_desc ? obj_desc->method.aml_start : NULL,
24162306a36Sopenharmony_ci				 pathname);
24262306a36Sopenharmony_ci	}
24362306a36Sopenharmony_ci
24462306a36Sopenharmony_ci	/* Check whether the tracer should be stopped */
24562306a36Sopenharmony_ci
24662306a36Sopenharmony_ci	if (acpi_gbl_trace_method_object == obj_desc) {
24762306a36Sopenharmony_ci
24862306a36Sopenharmony_ci		/* Disable further tracing if type is one-shot */
24962306a36Sopenharmony_ci
25062306a36Sopenharmony_ci		if (acpi_gbl_trace_flags & ACPI_TRACE_ONESHOT) {
25162306a36Sopenharmony_ci			acpi_gbl_trace_method_name = NULL;
25262306a36Sopenharmony_ci		}
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci		acpi_dbg_level = acpi_gbl_original_dbg_level;
25562306a36Sopenharmony_ci		acpi_dbg_layer = acpi_gbl_original_dbg_layer;
25662306a36Sopenharmony_ci		acpi_gbl_trace_method_object = NULL;
25762306a36Sopenharmony_ci	}
25862306a36Sopenharmony_ci
25962306a36Sopenharmony_ci	if (pathname) {
26062306a36Sopenharmony_ci		ACPI_FREE(pathname);
26162306a36Sopenharmony_ci	}
26262306a36Sopenharmony_ci}
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci/*******************************************************************************
26562306a36Sopenharmony_ci *
26662306a36Sopenharmony_ci * FUNCTION:    acpi_ex_start_trace_opcode
26762306a36Sopenharmony_ci *
26862306a36Sopenharmony_ci * PARAMETERS:  op                  - The parser opcode object
26962306a36Sopenharmony_ci *              walk_state          - current state, NULL if not yet executing
27062306a36Sopenharmony_ci *                                    a method.
27162306a36Sopenharmony_ci *
27262306a36Sopenharmony_ci * RETURN:      None
27362306a36Sopenharmony_ci *
27462306a36Sopenharmony_ci * DESCRIPTION: Start opcode execution trace
27562306a36Sopenharmony_ci *
27662306a36Sopenharmony_ci ******************************************************************************/
27762306a36Sopenharmony_ci
27862306a36Sopenharmony_civoid
27962306a36Sopenharmony_ciacpi_ex_start_trace_opcode(union acpi_parse_object *op,
28062306a36Sopenharmony_ci			   struct acpi_walk_state *walk_state)
28162306a36Sopenharmony_ci{
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ex_start_trace_opcode);
28462306a36Sopenharmony_ci
28562306a36Sopenharmony_ci	if (acpi_ex_interpreter_trace_enabled(NULL) &&
28662306a36Sopenharmony_ci	    (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) {
28762306a36Sopenharmony_ci		ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, TRUE,
28862306a36Sopenharmony_ci				 op->common.aml, op->common.aml_op_name);
28962306a36Sopenharmony_ci	}
29062306a36Sopenharmony_ci}
29162306a36Sopenharmony_ci
29262306a36Sopenharmony_ci/*******************************************************************************
29362306a36Sopenharmony_ci *
29462306a36Sopenharmony_ci * FUNCTION:    acpi_ex_stop_trace_opcode
29562306a36Sopenharmony_ci *
29662306a36Sopenharmony_ci * PARAMETERS:  op                  - The parser opcode object
29762306a36Sopenharmony_ci *              walk_state          - current state, NULL if not yet executing
29862306a36Sopenharmony_ci *                                    a method.
29962306a36Sopenharmony_ci *
30062306a36Sopenharmony_ci * RETURN:      None
30162306a36Sopenharmony_ci *
30262306a36Sopenharmony_ci * DESCRIPTION: Stop opcode execution trace
30362306a36Sopenharmony_ci *
30462306a36Sopenharmony_ci ******************************************************************************/
30562306a36Sopenharmony_ci
30662306a36Sopenharmony_civoid
30762306a36Sopenharmony_ciacpi_ex_stop_trace_opcode(union acpi_parse_object *op,
30862306a36Sopenharmony_ci			  struct acpi_walk_state *walk_state)
30962306a36Sopenharmony_ci{
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_ci	ACPI_FUNCTION_NAME(ex_stop_trace_opcode);
31262306a36Sopenharmony_ci
31362306a36Sopenharmony_ci	if (acpi_ex_interpreter_trace_enabled(NULL) &&
31462306a36Sopenharmony_ci	    (acpi_gbl_trace_flags & ACPI_TRACE_OPCODE)) {
31562306a36Sopenharmony_ci		ACPI_TRACE_POINT(ACPI_TRACE_AML_OPCODE, FALSE,
31662306a36Sopenharmony_ci				 op->common.aml, op->common.aml_op_name);
31762306a36Sopenharmony_ci	}
31862306a36Sopenharmony_ci}
319