1 /*
2 * Arm SCP/MCP Software
3 * Copyright (c) 2020-2022, Arm Limited and Contributors. All rights reserved.
4 *
5 * SPDX-License-Identifier: BSD-3-Clause
6 */
7
8 #include <cli.h>
9 #include <cli_platform.h>
10
11 #include <mod_debugger_cli.h>
12 #include <mod_timer.h>
13
14 #include <fwk_assert.h>
15 #include <fwk_core.h>
16 #include <fwk_module.h>
17 #include <fwk_status.h>
18
19 enum debugger_cli_internal_event_idx {
20 DEBUGGER_CLI_INTERNAL_EVENT_IDX_ENTER_DEBUGGER,
21 DEBUGGER_CLI_INTERNAL_EVENT_IDX_COUNT
22 };
23
24 static const fwk_id_t debugger_cli_event_id_request =
25 FWK_ID_EVENT_INIT(FWK_MODULE_IDX_DEBUGGER_CLI,
26 DEBUGGER_CLI_INTERNAL_EVENT_IDX_ENTER_DEBUGGER);
27
28 static struct mod_timer_alarm_api *alarm_api;
29
alarm_callback(uintptr_t module_idx)30 static void alarm_callback(uintptr_t module_idx)
31 {
32 int status;
33 char ch = 0;
34 struct fwk_event *event;
35
36 /* Get the pending character (if any) from the UART without blocking */
37 status = fwk_io_getch(fwk_io_stdin, &ch);
38
39 if (status == FWK_SUCCESS) {
40 /* Ctrl-E has been pressed */
41 if (ch == 0x05) {
42 /* Send out an event to start the CLI not inside an ISR */
43 event = &((struct fwk_event){
44 .source_id = FWK_ID_MODULE(module_idx),
45 .target_id = FWK_ID_MODULE(module_idx),
46 .id = debugger_cli_event_id_request
47 });
48
49 status = fwk_put_event(event);
50
51 fwk_assert(status == FWK_SUCCESS);
52 }
53 }
54 }
55
start_alarm(fwk_id_t id)56 static int start_alarm(fwk_id_t id)
57 {
58 const struct mod_debugger_cli_module_config *module_config;
59
60 /* Retrieve the module config as specified by the platform config.c file */
61 module_config = fwk_module_get_data(id);
62
63 /* Start the UART polling alarm, recurring with the given time period */
64 return alarm_api->start(module_config->alarm_id, module_config->poll_period,
65 MOD_TIMER_ALARM_TYPE_PERIODIC, alarm_callback,
66 fwk_id_get_module_idx(id));
67 }
68
stop_alarm(fwk_id_t id)69 static int stop_alarm(fwk_id_t id)
70 {
71 const struct mod_debugger_cli_module_config *module_config;
72
73 /* Retrieve the module config as specified by the platform config.c file */
74 module_config = fwk_module_get_data(id);
75
76 /* Stop the UART polling alarm */
77 return alarm_api->stop(module_config->alarm_id);
78 }
79
debugger_cli_init(fwk_id_t module_id,unsigned int element_count,const void * data)80 static int debugger_cli_init(fwk_id_t module_id, unsigned int element_count,
81 const void *data)
82 {
83 return FWK_SUCCESS;
84 }
85
debugger_cli_element_init(fwk_id_t element_id,unsigned int unused,const void * data)86 static int debugger_cli_element_init(fwk_id_t element_id, unsigned int unused,
87 const void *data)
88 {
89 return FWK_SUCCESS;
90 }
91
debugger_cli_bind(fwk_id_t id,unsigned int round)92 static int debugger_cli_bind(fwk_id_t id, unsigned int round)
93 {
94 const struct mod_debugger_cli_module_config *module_config;
95
96 /* Only bind in the first round of calls */
97 if (round > 0)
98 return FWK_SUCCESS;
99
100 /* Retrieve the module config as specified by the platform config.c file */
101 module_config = fwk_module_get_data(id);
102
103 /* Bind to the specified alarm in order to poll the UART */
104 return fwk_module_bind(module_config->alarm_id, MOD_TIMER_API_ID_ALARM,
105 &alarm_api);
106 }
107
debugger_cli_start(fwk_id_t id)108 static int debugger_cli_start(fwk_id_t id)
109 {
110 return start_alarm(id);
111 }
112
debugger_cli_process_event(const struct fwk_event * event,struct fwk_event * resp_event)113 static int debugger_cli_process_event(const struct fwk_event *event,
114 struct fwk_event *resp_event)
115 {
116 int status;
117 int start_alarm_status;
118
119 switch (event->id.event.event_idx) {
120 case DEBUGGER_CLI_INTERNAL_EVENT_IDX_ENTER_DEBUGGER:
121 /* Start the CLI, blocking the rest of the event queue */
122 cli_print("[CLI_DEBUGGER_MODULE] Entering CLI\n");
123
124 status = stop_alarm(event->target_id);
125 if (status != FWK_SUCCESS) {
126 goto exit_cli;
127 }
128
129 status = cli_start();
130
131 /* start the alarm regardless of the cli's return status */
132 start_alarm_status = start_alarm(event->target_id);
133 if (status == FWK_SUCCESS) {
134 status = start_alarm_status;
135 }
136
137 exit_cli:
138 cli_print("\n[CLI_DEBUGGER_MODULE] Exiting CLI\n");
139 return status;
140 default:
141 return FWK_E_PARAM;
142 }
143 }
144
145 const struct fwk_module module_debugger_cli = {
146 .type = FWK_MODULE_TYPE_SERVICE,
147 .event_count = DEBUGGER_CLI_INTERNAL_EVENT_IDX_COUNT,
148 .api_count = 0,
149 .init = debugger_cli_init,
150 .element_init = debugger_cli_element_init,
151 .bind = debugger_cli_bind,
152 .start = debugger_cli_start,
153 .process_event = debugger_cli_process_event
154 };
155