1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 #include <assert.h>
6 #include <hyptypes.h>
7 
8 #include <hypregisters.h>
9 
10 #include <cpulocal.h>
11 
12 #include <events/debug.h>
13 
14 #include <asm/barrier.h>
15 
16 #include "debug_bps.h"
17 #include "event_handlers.h"
18 
19 static asm_ordering_dummy_t debug_asm_order;
20 
21 static void
debug_os_unlock(void)22 debug_os_unlock(void)
23 {
24 	OSLAR_EL1_t oslar = OSLAR_EL1_default();
25 	OSLAR_EL1_set_oslk(&oslar, false);
26 	register_OSLAR_EL1_write_ordered(oslar, &debug_asm_order);
27 	OSDLR_EL1_t osdlr = OSDLR_EL1_default();
28 	OSDLR_EL1_set_dlk(&osdlr, false);
29 	register_OSDLR_EL1_write_ordered(osdlr, &debug_asm_order);
30 	asm_context_sync_ordered(&debug_asm_order);
31 }
32 
33 void
debug_handle_boot_cpu_warm_init(void)34 debug_handle_boot_cpu_warm_init(void)
35 {
36 	debug_os_unlock();
37 }
38 
39 #if PLATFORM_DEBUG_SAVE_STATE
40 
41 CPULOCAL_DECLARE_STATIC(debug_ext_state_t, debug_ext_state);
42 
43 static void
debug_os_lock(void)44 debug_os_lock(void)
45 {
46 	OSLAR_EL1_t oslar = OSLAR_EL1_default();
47 	OSLAR_EL1_set_oslk(&oslar, true);
48 	register_OSLAR_EL1_write_ordered(oslar, &debug_asm_order);
49 	asm_context_sync_ordered(&debug_asm_order);
50 }
51 
52 static inline bool
debug_force_save_ext(void)53 debug_force_save_ext(void)
54 {
55 	return PLATFORM_DEBUG_SAVE_STATE > 1U;
56 }
57 
58 void
debug_handle_power_cpu_offline(void)59 debug_handle_power_cpu_offline(void)
60 {
61 	(void)debug_handle_power_cpu_suspend(true);
62 }
63 
64 error_t
debug_handle_power_cpu_suspend(bool may_poweroff)65 debug_handle_power_cpu_suspend(bool may_poweroff)
66 {
67 	if (may_poweroff) {
68 		debug_ext_state_t *state = &CPULOCAL(debug_ext_state);
69 
70 		debug_os_lock();
71 
72 #if defined(PLATFORM_HAS_NO_DBGCLAIM_EL1) && PLATFORM_HAS_NO_DBGCLAIM_EL1
73 		state->dbgclaim = DBGCLAIM_EL1_default();
74 #else
75 		state->dbgclaim =
76 			register_DBGCLAIMCLR_EL1_read_ordered(&debug_asm_order);
77 #endif
78 
79 		if (debug_force_save_ext() ||
80 		    DBGCLAIM_EL1_get_debug_ext(&state->dbgclaim)) {
81 			state->mdccint = register_MDCCINT_EL1_read_ordered(
82 				&debug_asm_order);
83 			debug_save_common(&state->common, &debug_asm_order);
84 			state->dtrrx = register_OSDTRRX_EL1_read_ordered(
85 				&debug_asm_order);
86 			state->dtrtx = register_OSDTRTX_EL1_read_ordered(
87 				&debug_asm_order);
88 			state->eccr = register_OSECCR_EL1_read_ordered(
89 				&debug_asm_order);
90 		}
91 	}
92 
93 	return OK;
94 }
95 
96 void
debug_unwind_power_cpu_suspend(bool may_poweroff)97 debug_unwind_power_cpu_suspend(bool may_poweroff)
98 {
99 	if (may_poweroff) {
100 		debug_os_unlock();
101 	}
102 }
103 
104 void
debug_handle_power_cpu_resume(bool was_poweroff)105 debug_handle_power_cpu_resume(bool was_poweroff)
106 {
107 	if (was_poweroff) {
108 		debug_ext_state_t *state = &CPULOCAL(debug_ext_state);
109 
110 		if (debug_force_save_ext() ||
111 		    DBGCLAIM_EL1_get_debug_ext(&state->dbgclaim)) {
112 			// Lock just in case; the lock should already be set
113 			debug_os_lock();
114 
115 			register_DBGCLAIMSET_EL1_write_ordered(
116 				state->dbgclaim, &debug_asm_order);
117 			register_MDCCINT_EL1_write_ordered(state->mdccint,
118 							   &debug_asm_order);
119 			debug_load_common(&state->common, &debug_asm_order);
120 			register_OSDTRRX_EL1_write_ordered(state->dtrrx,
121 							   &debug_asm_order);
122 			register_OSDTRTX_EL1_write_ordered(state->dtrtx,
123 							   &debug_asm_order);
124 			register_OSECCR_EL1_write_ordered(state->eccr,
125 							  &debug_asm_order);
126 			asm_context_sync_ordered(&debug_asm_order);
127 		}
128 	}
129 
130 	debug_os_unlock();
131 }
132 #endif
133