target/riscv: Add null pointer check before right shift for bscan tunneling.
[openocd.git] / src / target / riscv / batch.c
1 // SPDX-License-Identifier: GPL-2.0-or-later
2
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
6
7 #include "batch.h"
8 #include "debug_defines.h"
9 #include "riscv.h"
10
11 #define get_field(reg, mask) (((reg) & (mask)) / ((mask) & ~((mask) << 1)))
12 #define set_field(reg, mask, val) (((reg) & ~(mask)) | (((val) * ((mask) & ~((mask) << 1))) & (mask)))
13
14 #define DTM_DMI_MAX_ADDRESS_LENGTH ((1<<DTM_DTMCS_ABITS_LENGTH)-1)
15 #define DMI_SCAN_MAX_BIT_LENGTH (DTM_DMI_MAX_ADDRESS_LENGTH + DTM_DMI_DATA_LENGTH + DTM_DMI_OP_LENGTH)
16 #define DMI_SCAN_BUF_SIZE (DIV_ROUND_UP(DMI_SCAN_MAX_BIT_LENGTH, 8))
17
18 static void dump_field(int idle, const struct scan_field *field);
19
20 struct riscv_batch *riscv_batch_alloc(struct target *target, size_t scans, size_t idle)
21 {
22 scans += 4;
23 struct riscv_batch *out = calloc(1, sizeof(*out));
24 if (!out)
25 goto error0;
26 out->target = target;
27 out->allocated_scans = scans;
28 out->idle_count = idle;
29 out->data_out = malloc(sizeof(*out->data_out) * (scans) * DMI_SCAN_BUF_SIZE);
30 if (!out->data_out) {
31 LOG_ERROR("Failed to allocate data_out in RISC-V batch.");
32 goto error1;
33 };
34 out->data_in = malloc(sizeof(*out->data_in) * (scans) * DMI_SCAN_BUF_SIZE);
35 if (!out->data_in) {
36 LOG_ERROR("Failed to allocate data_in in RISC-V batch.");
37 goto error2;
38 }
39 out->fields = malloc(sizeof(*out->fields) * (scans));
40 if (!out->fields) {
41 LOG_ERROR("Failed to allocate fields in RISC-V batch.");
42 goto error3;
43 }
44 if (bscan_tunnel_ir_width != 0) {
45 out->bscan_ctxt = malloc(sizeof(*out->bscan_ctxt) * (scans));
46 if (!out->bscan_ctxt) {
47 LOG_ERROR("Failed to allocate bscan_ctxt in RISC-V batch.");
48 goto error4;
49 }
50 }
51 out->last_scan = RISCV_SCAN_TYPE_INVALID;
52 out->read_keys = malloc(sizeof(*out->read_keys) * (scans));
53 if (!out->read_keys) {
54 LOG_ERROR("Failed to allocate read_keys in RISC-V batch.");
55 goto error5;
56 }
57 return out;
58
59 error5:
60 free(out->bscan_ctxt);
61 error4:
62 free(out->fields);
63 error3:
64 free(out->data_in);
65 error2:
66 free(out->data_out);
67 error1:
68 free(out);
69 error0:
70 return NULL;
71 }
72
73 void riscv_batch_free(struct riscv_batch *batch)
74 {
75 free(batch->data_in);
76 free(batch->data_out);
77 free(batch->fields);
78 free(batch->bscan_ctxt);
79 free(batch->read_keys);
80 free(batch);
81 }
82
83 bool riscv_batch_full(struct riscv_batch *batch)
84 {
85 return batch->used_scans > (batch->allocated_scans - 4);
86 }
87
88 int riscv_batch_run(struct riscv_batch *batch)
89 {
90 if (batch->used_scans == 0) {
91 LOG_DEBUG("Ignoring empty batch.");
92 return ERROR_OK;
93 }
94
95 riscv_batch_add_nop(batch);
96
97 for (size_t i = 0; i < batch->used_scans; ++i) {
98 if (bscan_tunnel_ir_width != 0)
99 riscv_add_bscan_tunneled_scan(batch->target, batch->fields+i, batch->bscan_ctxt+i);
100 else
101 jtag_add_dr_scan(batch->target->tap, 1, batch->fields + i, TAP_IDLE);
102
103 if (batch->idle_count > 0)
104 jtag_add_runtest(batch->idle_count, TAP_IDLE);
105 }
106
107 keep_alive();
108
109 if (jtag_execute_queue() != ERROR_OK) {
110 LOG_ERROR("Unable to execute JTAG queue");
111 return ERROR_FAIL;
112 }
113
114 keep_alive();
115
116 if (bscan_tunnel_ir_width != 0) {
117 /* need to right-shift "in" by one bit, because of clock skew between BSCAN TAP and DM TAP */
118 for (size_t i = 0; i < batch->used_scans; ++i) {
119 if ((batch->fields + i)->in_value)
120 buffer_shr((batch->fields + i)->in_value, DMI_SCAN_BUF_SIZE, 1);
121 }
122 }
123
124 for (size_t i = 0; i < batch->used_scans; ++i)
125 dump_field(batch->idle_count, batch->fields + i);
126
127 return ERROR_OK;
128 }
129
130 void riscv_batch_add_dmi_write(struct riscv_batch *batch, unsigned address, uint64_t data)
131 {
132 assert(batch->used_scans < batch->allocated_scans);
133 struct scan_field *field = batch->fields + batch->used_scans;
134 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
135 field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
136 field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
137 riscv_fill_dmi_write_u64(batch->target, (char *)field->out_value, address, data);
138 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
139 batch->last_scan = RISCV_SCAN_TYPE_WRITE;
140 batch->used_scans++;
141 }
142
143 size_t riscv_batch_add_dmi_read(struct riscv_batch *batch, unsigned address)
144 {
145 assert(batch->used_scans < batch->allocated_scans);
146 struct scan_field *field = batch->fields + batch->used_scans;
147 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
148 field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
149 field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
150 riscv_fill_dmi_read_u64(batch->target, (char *)field->out_value, address);
151 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
152 batch->last_scan = RISCV_SCAN_TYPE_READ;
153 batch->used_scans++;
154
155 batch->read_keys[batch->read_keys_used] = batch->used_scans;
156 return batch->read_keys_used++;
157 }
158
159 unsigned riscv_batch_get_dmi_read_op(struct riscv_batch *batch, size_t key)
160 {
161 assert(key < batch->read_keys_used);
162 size_t index = batch->read_keys[key];
163 assert(index <= batch->used_scans);
164 uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
165 /* extract "op" field from the DMI read result */
166 return (unsigned)buf_get_u32(base, DTM_DMI_OP_OFFSET, DTM_DMI_OP_LENGTH);
167 }
168
169 uint32_t riscv_batch_get_dmi_read_data(struct riscv_batch *batch, size_t key)
170 {
171 assert(key < batch->read_keys_used);
172 size_t index = batch->read_keys[key];
173 assert(index <= batch->used_scans);
174 uint8_t *base = batch->data_in + DMI_SCAN_BUF_SIZE * index;
175 /* extract "data" field from the DMI read result */
176 return buf_get_u32(base, DTM_DMI_DATA_OFFSET, DTM_DMI_DATA_LENGTH);
177 }
178
179 void riscv_batch_add_nop(struct riscv_batch *batch)
180 {
181 assert(batch->used_scans < batch->allocated_scans);
182 struct scan_field *field = batch->fields + batch->used_scans;
183 field->num_bits = riscv_dmi_write_u64_bits(batch->target);
184 field->out_value = (void *)(batch->data_out + batch->used_scans * DMI_SCAN_BUF_SIZE);
185 field->in_value = (void *)(batch->data_in + batch->used_scans * DMI_SCAN_BUF_SIZE);
186 riscv_fill_dmi_nop_u64(batch->target, (char *)field->out_value);
187 riscv_fill_dmi_nop_u64(batch->target, (char *)field->in_value);
188 batch->last_scan = RISCV_SCAN_TYPE_NOP;
189 batch->used_scans++;
190 }
191
192 void dump_field(int idle, const struct scan_field *field)
193 {
194 static const char * const op_string[] = {"-", "r", "w", "?"};
195 static const char * const status_string[] = {"+", "?", "F", "b"};
196
197 if (debug_level < LOG_LVL_DEBUG)
198 return;
199
200 assert(field->out_value);
201 uint64_t out = buf_get_u64(field->out_value, 0, field->num_bits);
202 unsigned int out_op = get_field(out, DTM_DMI_OP);
203 unsigned int out_data = get_field(out, DTM_DMI_DATA);
204 unsigned int out_address = out >> DTM_DMI_ADDRESS_OFFSET;
205
206 if (field->in_value) {
207 uint64_t in = buf_get_u64(field->in_value, 0, field->num_bits);
208 unsigned int in_op = get_field(in, DTM_DMI_OP);
209 unsigned int in_data = get_field(in, DTM_DMI_DATA);
210 unsigned int in_address = in >> DTM_DMI_ADDRESS_OFFSET;
211
212 log_printf_lf(LOG_LVL_DEBUG,
213 __FILE__, __LINE__, __PRETTY_FUNCTION__,
214 "%db %s %08x @%02x -> %s %08x @%02x; %di",
215 field->num_bits, op_string[out_op], out_data, out_address,
216 status_string[in_op], in_data, in_address, idle);
217 } else {
218 log_printf_lf(LOG_LVL_DEBUG,
219 __FILE__, __LINE__, __PRETTY_FUNCTION__, "%db %s %08x @%02x -> ?; %di",
220 field->num_bits, op_string[out_op], out_data, out_address, idle);
221 }
222 }
223
224 size_t riscv_batch_available_scans(struct riscv_batch *batch)
225 {
226 return batch->allocated_scans - batch->used_scans - 4;
227 }

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)