flash/nor/rp2040: fix memory leak of target stack workarea
[fw/openocd] / src / flash / nor / rp2040.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 "imp.h"
8 #include <helper/binarybuffer.h>
9 #include <target/algorithm.h>
10 #include <target/armv7m.h>
11 #include "spi.h"
12
13 /* NOTE THAT THIS CODE REQUIRES FLASH ROUTINES in BOOTROM WITH FUNCTION TABLE PTR AT 0x00000010
14    Your gdbinit should load the bootrom.elf if appropriate */
15
16 /* this is 'M' 'u', 1 (version) */
17 #define BOOTROM_MAGIC 0x01754d
18 #define BOOTROM_MAGIC_ADDR 0x00000010
19
20 /* Call a ROM function via the debug trampoline
21    Up to four arguments passed in r0...r3 as per ABI
22    Function address is passed in r7
23    the trampoline is needed because OpenOCD "algorithm" code insists on sw breakpoints. */
24
25 #define MAKE_TAG(a, b) (((b)<<8) | a)
26 #define FUNC_DEBUG_TRAMPOLINE       MAKE_TAG('D', 'T')
27 #define FUNC_DEBUG_TRAMPOLINE_END   MAKE_TAG('D', 'E')
28 #define FUNC_FLASH_EXIT_XIP         MAKE_TAG('E', 'X')
29 #define FUNC_CONNECT_INTERNAL_FLASH MAKE_TAG('I', 'F')
30 #define FUNC_FLASH_RANGE_ERASE      MAKE_TAG('R', 'E')
31 #define FUNC_FLASH_RANGE_PROGRAM    MAKE_TAG('R', 'P')
32 #define FUNC_FLASH_FLUSH_CACHE      MAKE_TAG('F', 'C')
33 #define FUNC_FLASH_ENTER_CMD_XIP    MAKE_TAG('C', 'X')
34
35 struct rp2040_flash_bank {
36         /* flag indicating successful flash probe */
37         bool probed;
38         /* stack used by Boot ROM calls */
39         struct working_area *stack;
40         /* function jump table populated by rp2040_flash_probe() */
41         uint16_t jump_debug_trampoline;
42         uint16_t jump_debug_trampoline_end;
43         uint16_t jump_flash_exit_xip;
44         uint16_t jump_connect_internal_flash;
45         uint16_t jump_flash_range_erase;
46         uint16_t jump_flash_range_program;
47         uint16_t jump_flush_cache;
48         uint16_t jump_enter_cmd_xip;
49         /* detected model of SPI flash */
50         const struct flash_device *dev;
51 };
52
53 static uint32_t rp2040_lookup_symbol(struct target *target, uint32_t tag, uint16_t *symbol)
54 {
55         uint32_t magic;
56         int err = target_read_u32(target, BOOTROM_MAGIC_ADDR, &magic);
57         if (err != ERROR_OK)
58                 return err;
59
60         magic &= 0xffffff; /* ignore bootrom version */
61         if (magic != BOOTROM_MAGIC) {
62                 if (!((magic ^ BOOTROM_MAGIC)&0xffff))
63                         LOG_ERROR("Incorrect RP2040 BOOT ROM version");
64                 else
65                         LOG_ERROR("RP2040 BOOT ROM not found");
66                 return ERROR_FAIL;
67         }
68
69         /* dereference the table pointer */
70         uint16_t table_entry;
71         err = target_read_u16(target, BOOTROM_MAGIC_ADDR + 4, &table_entry);
72         if (err != ERROR_OK)
73                 return err;
74
75         uint16_t entry_tag;
76         do {
77                 err = target_read_u16(target, table_entry, &entry_tag);
78                 if (err != ERROR_OK)
79                         return err;
80                 if (entry_tag == tag) {
81                         /* 16 bit symbol is next */
82                         return target_read_u16(target, table_entry + 2, symbol);
83                 }
84                 table_entry += 4;
85         } while (entry_tag);
86         return ERROR_FAIL;
87 }
88
89 static int rp2040_call_rom_func(struct target *target, struct rp2040_flash_bank *priv,
90                 uint16_t func_offset, uint32_t argdata[], unsigned int n_args)
91 {
92         char *regnames[4] = { "r0", "r1", "r2", "r3" };
93
94         assert(n_args <= ARRAY_SIZE(regnames)); /* only allow register arguments */
95
96         if (!priv->stack) {
97                 LOG_ERROR("no stack for flash programming code");
98                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
99         }
100         target_addr_t stacktop = priv->stack->address + priv->stack->size;
101
102         LOG_DEBUG("Calling ROM func @0x%" PRIx16 " with %d arguments", func_offset, n_args);
103         LOG_DEBUG("Calling on core \"%s\"", target->cmd_name);
104
105         struct reg_param args[ARRAY_SIZE(regnames) + 2];
106         struct armv7m_algorithm alg_info;
107
108         for (unsigned int i = 0; i < n_args; ++i) {
109                 init_reg_param(&args[i], regnames[i], 32, PARAM_OUT);
110                 buf_set_u32(args[i].value, 0, 32, argdata[i]);
111         }
112         /* Pass function pointer in r7 */
113         init_reg_param(&args[n_args], "r7", 32, PARAM_OUT);
114         buf_set_u32(args[n_args].value, 0, 32, func_offset);
115         init_reg_param(&args[n_args + 1], "sp", 32, PARAM_OUT);
116         buf_set_u32(args[n_args + 1].value, 0, 32, stacktop);
117
118
119         for (unsigned int i = 0; i < n_args + 2; ++i)
120                 LOG_DEBUG("Set %s = 0x%" PRIx32, args[i].reg_name, buf_get_u32(args[i].value, 0, 32));
121
122         /* Actually call the function */
123         alg_info.common_magic = ARMV7M_COMMON_MAGIC;
124         alg_info.core_mode = ARM_MODE_THREAD;
125         int err = target_run_algorithm(
126                 target,
127                 0, NULL,          /* No memory arguments */
128                 n_args + 1, args, /* User arguments + r7 */
129                 priv->jump_debug_trampoline, priv->jump_debug_trampoline_end,
130                 3000, /* 3s timeout */
131                 &alg_info
132         );
133         for (unsigned int i = 0; i < n_args + 2; ++i)
134                 destroy_reg_param(&args[i]);
135         if (err != ERROR_OK)
136                 LOG_ERROR("Failed to invoke ROM function @0x%" PRIx16 "\n", func_offset);
137         return err;
138
139 }
140
141 /* Finalize flash write/erase/read ID
142  * - flush cache
143  * - enters memory-mapped (XIP) mode to make flash data visible
144  * - deallocates target ROM func stack if previously allocated
145  */
146 static int rp2040_finalize_stack_free(struct flash_bank *bank)
147 {
148         struct rp2040_flash_bank *priv = bank->driver_priv;
149         struct target *target = bank->target;
150
151         /* Always flush before returning to execute-in-place, to invalidate stale
152          * cache contents. The flush call also restores regular hardware-controlled
153          * chip select following a rp2040_flash_exit_xip().
154          */
155         LOG_DEBUG("Flushing flash cache after write behind");
156         int err = rp2040_call_rom_func(target, priv, priv->jump_flush_cache, NULL, 0);
157         if (err != ERROR_OK) {
158                 LOG_ERROR("Failed to flush flash cache");
159                 /* Intentionally continue after error and try to setup xip anyway */
160         }
161
162         LOG_DEBUG("Configuring SSI for execute-in-place");
163         err = rp2040_call_rom_func(target, priv, priv->jump_enter_cmd_xip, NULL, 0);
164         if (err != ERROR_OK)
165                 LOG_ERROR("Failed to set SSI to XIP mode");
166
167         target_free_working_area(target, priv->stack);
168         priv->stack = NULL;
169         return err;
170 }
171
172 /* Prepare flash write/erase/read ID
173  * - allocates a stack for target ROM func
174  * - switches the SPI interface from memory-mapped mode to direct command mode
175  * Always pair with a call of rp2040_finalize_stack_free()
176  * after flash operation finishes or fails.
177  */
178 static int rp2040_stack_grab_and_prep(struct flash_bank *bank)
179 {
180         struct rp2040_flash_bank *priv = bank->driver_priv;
181         struct target *target = bank->target;
182
183         /* target_alloc_working_area always allocates multiples of 4 bytes, so no worry about alignment */
184         const int STACK_SIZE = 256;
185         int err = target_alloc_working_area(target, STACK_SIZE, &priv->stack);
186         if (err != ERROR_OK) {
187                 LOG_ERROR("Could not allocate stack for flash programming code");
188                 return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
189         }
190
191         LOG_DEBUG("Connecting internal flash");
192         err = rp2040_call_rom_func(target, priv, priv->jump_connect_internal_flash, NULL, 0);
193         if (err != ERROR_OK) {
194                 LOG_ERROR("Failed to connect internal flash");
195                 return err;
196         }
197
198         LOG_DEBUG("Kicking flash out of XIP mode");
199         err = rp2040_call_rom_func(target, priv, priv->jump_flash_exit_xip, NULL, 0);
200         if (err != ERROR_OK) {
201                 LOG_ERROR("Failed to exit flash XIP mode");
202                 return err;
203         }
204
205         return ERROR_OK;
206 }
207
208 static int rp2040_flash_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count)
209 {
210         LOG_DEBUG("Writing %d bytes starting at 0x%" PRIx32, count, offset);
211
212         struct rp2040_flash_bank *priv = bank->driver_priv;
213         struct target *target = bank->target;
214         struct working_area *bounce = NULL;
215
216         int err = rp2040_stack_grab_and_prep(bank);
217         if (err != ERROR_OK)
218                 goto cleanup;
219
220         const unsigned int chunk_size = target_get_working_area_avail(target);
221         err = target_alloc_working_area(target, chunk_size, &bounce);
222         if (err != ERROR_OK) {
223                 LOG_ERROR("Could not allocate bounce buffer for flash programming. Can't continue");
224                 goto cleanup;
225         }
226
227         LOG_DEBUG("Allocated flash bounce buffer @" TARGET_ADDR_FMT, bounce->address);
228
229         while (count > 0) {
230                 uint32_t write_size = count > chunk_size ? chunk_size : count;
231                 LOG_DEBUG("Writing %d bytes to offset 0x%" PRIx32, write_size, offset);
232                 err = target_write_buffer(target, bounce->address, write_size, buffer);
233                 if (err != ERROR_OK) {
234                         LOG_ERROR("Could not load data into target bounce buffer");
235                         break;
236                 }
237                 uint32_t args[3] = {
238                         offset, /* addr */
239                         bounce->address, /* data */
240                         write_size /* count */
241                 };
242                 err = rp2040_call_rom_func(target, priv, priv->jump_flash_range_program, args, ARRAY_SIZE(args));
243                 if (err != ERROR_OK) {
244                         LOG_ERROR("Failed to invoke flash programming code on target");
245                         break;
246                 }
247
248                 buffer += write_size;
249                 offset += write_size;
250                 count -= write_size;
251         }
252
253 cleanup:
254         target_free_working_area(target, bounce);
255
256         rp2040_finalize_stack_free(bank);
257
258         return err;
259 }
260
261 static int rp2040_flash_erase(struct flash_bank *bank, unsigned int first, unsigned int last)
262 {
263         struct rp2040_flash_bank *priv = bank->driver_priv;
264         uint32_t start_addr = bank->sectors[first].offset;
265         uint32_t length = bank->sectors[last].offset + bank->sectors[last].size - start_addr;
266         LOG_DEBUG("RP2040 erase %d bytes starting at 0x%" PRIx32, length, start_addr);
267
268         int err = rp2040_stack_grab_and_prep(bank);
269         if (err != ERROR_OK)
270                 goto cleanup;
271
272         LOG_DEBUG("Remote call flash_range_erase");
273
274         uint32_t args[4] = {
275                 bank->sectors[first].offset, /* addr */
276                 bank->sectors[last].offset + bank->sectors[last].size - bank->sectors[first].offset, /* count */
277                 priv->dev->sectorsize, /* block_size */
278                 priv->dev->erase_cmd /* block_cmd */
279         };
280
281         /*
282         The RP2040 Boot ROM provides a _flash_range_erase() API call documented in Section 2.8.3.1.3:
283         https://datasheets.raspberrypi.org/rp2040/rp2040-datasheet.pdf
284         and the particular source code for said Boot ROM function can be found here:
285         https://github.com/raspberrypi/pico-bootrom/blob/master/bootrom/program_flash_generic.c
286
287         In theory, the function algorithm provides for erasing both a smaller "sector" (4096 bytes) and
288         an optional larger "block" (size and command provided in args).
289         */
290
291         err = rp2040_call_rom_func(bank->target, priv, priv->jump_flash_range_erase, args, ARRAY_SIZE(args));
292
293 cleanup:
294         rp2040_finalize_stack_free(bank);
295
296         return err;
297 }
298
299 /* -----------------------------------------------------------------------------
300    Driver probing etc */
301
302 static int rp2040_ssel_active(struct target *target, bool active)
303 {
304         const target_addr_t qspi_ctrl_addr = 0x4001800c;
305         const uint32_t qspi_ctrl_outover_low  = 2UL << 8;
306         const uint32_t qspi_ctrl_outover_high = 3UL << 8;
307         uint32_t state = (active) ? qspi_ctrl_outover_low : qspi_ctrl_outover_high;
308         uint32_t val;
309
310         int err = target_read_u32(target, qspi_ctrl_addr, &val);
311         if (err != ERROR_OK)
312                 return err;
313
314         val = (val & ~qspi_ctrl_outover_high) | state;
315
316         err = target_write_u32(target, qspi_ctrl_addr, val);
317         if (err != ERROR_OK)
318                 return err;
319
320         return ERROR_OK;
321 }
322
323 static int rp2040_spi_read_flash_id(struct target *target, uint32_t *devid)
324 {
325         uint32_t device_id = 0;
326         const target_addr_t ssi_dr0 = 0x18000060;
327
328         int err = rp2040_ssel_active(target, true);
329
330         /* write RDID request into SPI peripheral's FIFO */
331         for (int count = 0; (count < 4) && (err == ERROR_OK); count++)
332                 err = target_write_u32(target, ssi_dr0, SPIFLASH_READ_ID);
333
334         /* by this time, there is a receive FIFO entry for every write */
335         for (int count = 0; (count < 4) && (err == ERROR_OK); count++) {
336                 uint32_t status;
337                 err = target_read_u32(target, ssi_dr0, &status);
338
339                 device_id >>= 8;
340                 device_id |= (status & 0xFF) << 24;
341         }
342
343         if (err == ERROR_OK)
344                 *devid = device_id >> 8;
345
346         int err2 = rp2040_ssel_active(target, false);
347         if (err2 != ERROR_OK)
348                 LOG_ERROR("SSEL inactive failed");
349
350         return err;
351 }
352
353 static int rp2040_flash_probe(struct flash_bank *bank)
354 {
355         struct rp2040_flash_bank *priv = bank->driver_priv;
356         struct target *target = bank->target;
357
358         int err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE, &priv->jump_debug_trampoline);
359         if (err != ERROR_OK) {
360                 LOG_ERROR("Debug trampoline not found in RP2040 ROM.");
361                 return err;
362         }
363         priv->jump_debug_trampoline &= ~1u; /* mask off thumb bit */
364
365         err = rp2040_lookup_symbol(target, FUNC_DEBUG_TRAMPOLINE_END, &priv->jump_debug_trampoline_end);
366         if (err != ERROR_OK) {
367                 LOG_ERROR("Debug trampoline end not found in RP2040 ROM.");
368                 return err;
369         }
370         priv->jump_debug_trampoline_end &= ~1u; /* mask off thumb bit */
371
372         err = rp2040_lookup_symbol(target, FUNC_FLASH_EXIT_XIP, &priv->jump_flash_exit_xip);
373         if (err != ERROR_OK) {
374                 LOG_ERROR("Function FUNC_FLASH_EXIT_XIP not found in RP2040 ROM.");
375                 return err;
376         }
377
378         err = rp2040_lookup_symbol(target, FUNC_CONNECT_INTERNAL_FLASH, &priv->jump_connect_internal_flash);
379         if (err != ERROR_OK) {
380                 LOG_ERROR("Function FUNC_CONNECT_INTERNAL_FLASH not found in RP2040 ROM.");
381                 return err;
382         }
383
384         err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_ERASE, &priv->jump_flash_range_erase);
385         if (err != ERROR_OK) {
386                 LOG_ERROR("Function FUNC_FLASH_RANGE_ERASE not found in RP2040 ROM.");
387                 return err;
388         }
389
390         err = rp2040_lookup_symbol(target, FUNC_FLASH_RANGE_PROGRAM, &priv->jump_flash_range_program);
391         if (err != ERROR_OK) {
392                 LOG_ERROR("Function FUNC_FLASH_RANGE_PROGRAM not found in RP2040 ROM.");
393                 return err;
394         }
395
396         err = rp2040_lookup_symbol(target, FUNC_FLASH_FLUSH_CACHE, &priv->jump_flush_cache);
397         if (err != ERROR_OK) {
398                 LOG_ERROR("Function FUNC_FLASH_FLUSH_CACHE not found in RP2040 ROM.");
399                 return err;
400         }
401
402         err = rp2040_lookup_symbol(target, FUNC_FLASH_ENTER_CMD_XIP, &priv->jump_enter_cmd_xip);
403         if (err != ERROR_OK) {
404                 LOG_ERROR("Function FUNC_FLASH_ENTER_CMD_XIP not found in RP2040 ROM.");
405                 return err;
406         }
407
408         err = rp2040_stack_grab_and_prep(bank);
409
410         uint32_t device_id = 0;
411         if (err == ERROR_OK)
412                 err = rp2040_spi_read_flash_id(target, &device_id);
413
414         rp2040_finalize_stack_free(bank);
415
416         if (err != ERROR_OK)
417                 return err;
418
419         /* search for a SPI flash Device ID match */
420         priv->dev = NULL;
421         for (const struct flash_device *p = flash_devices; p->name ; p++)
422                 if (p->device_id == device_id) {
423                         priv->dev = p;
424                         break;
425                 }
426
427         if (!priv->dev) {
428                 LOG_ERROR("Unknown flash device (ID 0x%08" PRIx32 ")", device_id);
429                 return ERROR_FAIL;
430         }
431
432         LOG_INFO("Found flash device \'%s\' (ID 0x%08" PRIx32 ")",
433                 priv->dev->name, priv->dev->device_id);
434
435         /* the Boot ROM flash_range_program() routine requires page alignment */
436         bank->write_start_alignment = priv->dev->pagesize;
437         bank->write_end_alignment = priv->dev->pagesize;
438
439         bank->size = priv->dev->size_in_bytes;
440
441         bank->num_sectors = bank->size / priv->dev->sectorsize;
442         LOG_INFO("RP2040 B0 Flash Probe: %d bytes @" TARGET_ADDR_FMT ", in %d sectors\n",
443                 bank->size, bank->base, bank->num_sectors);
444         bank->sectors = alloc_block_array(0, priv->dev->sectorsize, bank->num_sectors);
445         if (!bank->sectors)
446                 return ERROR_FAIL;
447
448         if (err == ERROR_OK)
449                 priv->probed = true;
450
451         return err;
452 }
453
454 static int rp2040_flash_auto_probe(struct flash_bank *bank)
455 {
456         struct rp2040_flash_bank *priv = bank->driver_priv;
457
458         if (priv->probed)
459                 return ERROR_OK;
460
461         return rp2040_flash_probe(bank);
462 }
463
464 static void rp2040_flash_free_driver_priv(struct flash_bank *bank)
465 {
466         free(bank->driver_priv);
467         bank->driver_priv = NULL;
468 }
469
470 /* -----------------------------------------------------------------------------
471    Driver boilerplate */
472
473 FLASH_BANK_COMMAND_HANDLER(rp2040_flash_bank_command)
474 {
475         struct rp2040_flash_bank *priv;
476         priv = malloc(sizeof(struct rp2040_flash_bank));
477         priv->probed = false;
478
479         /* Set up driver_priv */
480         bank->driver_priv = priv;
481
482         return ERROR_OK;
483 }
484
485 struct flash_driver rp2040_flash = {
486         .name = "rp2040_flash",
487         .flash_bank_command = rp2040_flash_bank_command,
488         .erase =  rp2040_flash_erase,
489         .write = rp2040_flash_write,
490         .read = default_flash_read,
491         .probe = rp2040_flash_probe,
492         .auto_probe = rp2040_flash_auto_probe,
493         .erase_check = default_flash_blank_check,
494         .free_driver_priv = rp2040_flash_free_driver_priv
495 };