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