1 /*
2  * Arm SCP/MCP Software
3  * Copyright (c) 2020-2021, Arm Limited and Contributors. All rights reserved.
4  *
5  * SPDX-License-Identifier: BSD-3-Clause
6  */
7 
8 #include <checkpoint.h>
9 #include <cli.h>
10 
11 #include <fwk_status.h>
12 
13 #include <stdbool.h>
14 #include <stdlib.h>
15 #include <string.h>
16 
17 checkpoint_st checkpoint_table[CHECKPOINT_NUM] = {0};
18 
19 /* Reset value for bypass. */
20 static volatile int32_t bypass_reset = CHECKPOINT_DISABLED;
21 
checkpoint_enable_all(void)22 void checkpoint_enable_all(void)
23 {
24     uint32_t i = 0;
25 
26     for (i = 0; i < CHECKPOINT_NUM; i++) {
27         /*
28          * Bypass set to 0 to ensure thread stops at the next checkpoint. Tag
29          * is set to empty string to keep things clean.
30          */
31         checkpoint_table[i].bypass = CHECKPOINT_ENABLED;
32         checkpoint_table[i].tag[0] = 0;
33     }
34 
35     /* Changing reset value to enabled by default. */
36     bypass_reset = CHECKPOINT_ENABLED;
37 }
38 
checkpoint_disable_all(void)39 void checkpoint_disable_all(void)
40 {
41     uint32_t i = 0;
42 
43     for (i = 0; i < CHECKPOINT_NUM; i++) {
44         /*
45          * Bypass is set to -1 and tag is set to an empty string so checkpoint
46          * will be skipped.
47          */
48         checkpoint_table[i].bypass = CHECKPOINT_DISABLED;
49         checkpoint_table[i].tag[0] = 0;
50     }
51 }
52 
checkpoint_register(checkpoint_st ** c,char * name)53 int32_t checkpoint_register(checkpoint_st **c, char *name)
54 {
55     uint32_t i = 0;
56 
57     for (i = 0; i < CHECKPOINT_NUM; i++) {
58         if (checkpoint_table[i].in_use == false) {
59             checkpoint_table[i].in_use = true;
60             checkpoint_table[i].index = i;
61             strncpy(checkpoint_table[i].name, name, CHECKPOINT_NAME_LEN);
62             checkpoint_table[i].name[CHECKPOINT_NAME_LEN - 1] = 0;
63             checkpoint_table[i].bypass = bypass_reset;
64             *c = &checkpoint_table[i];
65             return FWK_SUCCESS;
66         }
67     }
68 
69     return FWK_E_NOMEM;
70 }
71 
checkpoint(checkpoint_st * c,char * file,int32_t line,char * tag)72 void checkpoint(checkpoint_st *c, char *file, int32_t line, char *tag)
73 {
74     /* If tags match or if bypass == 0, stop here. */
75     if ((c->bypass == CHECKPOINT_ENABLED) ||
76         ((tag != NULL) && (strncmp(tag, c->tag, CHECKPOINT_TAG_LEN) == 0))) {
77         cli_printf(NONE,
78             "SCP Debugger has stopped at a checkpoint.\n"
79             "Tag: %s\n  File: %s\n  Line: %d\n",
80             tag,
81             file,
82             line);
83 
84         c->tag[0] = 0;
85         c->bypass = CHECKPOINT_ENABLED;
86 
87         cli_start();
88 
89         cli_printf(NONE,
90             "SCP execution resume at a checkpoint.\n"
91             "Tag: %s\n  File: %s\n  Line: %d\n",
92             tag,
93             file,
94             line);
95 
96         return;
97     }
98 
99     /* If bypass is less than 0 (-1), checkpoint is disabled so return. */
100     if (c->bypass == CHECKPOINT_DISABLED)
101         return;
102     else {
103         /* If bypass is greater than 0, decrement and return. */
104         c->bypass = c->bypass - 1;
105         return;
106     }
107 }
108