From d3979a57b6f9da24abc31548a3e217a8c265486f Mon Sep 17 00:00:00 2001 From: David Lawrence Date: Wed, 12 Apr 2017 11:15:50 -0400 Subject: [PATCH 1/2] Add LPC command to read out unique ID from target. This commit modifies lpc_iap_call() to work with IAP commands that return additional data. If the "result" argument is non-null, 16 bytes of data (the maximum returned by any IAP command) are copied to the specified address. --- src/target/lpc11xx.c | 23 +++++++++++++++++++++++ src/target/lpc15xx.c | 21 +++++++++++++++++++++ src/target/lpc43xx.c | 8 ++++---- src/target/lpc_common.c | 24 +++++++++++++++--------- src/target/lpc_common.h | 3 ++- 5 files changed, 65 insertions(+), 14 deletions(-) diff --git a/src/target/lpc11xx.c b/src/target/lpc11xx.c index 30143bac..47226ca0 100644 --- a/src/target/lpc11xx.c +++ b/src/target/lpc11xx.c @@ -35,6 +35,26 @@ #define LPC11XX_DEVICE_ID 0x400483F4 #define LPC8XX_DEVICE_ID 0x400483F8 +static bool lpc11xx_read_uid(target *t, int argc, const char *argv[]) +{ + (void)argc; + (void)argv; + struct lpc_flash *f = (struct lpc_flash *)t->flash; + uint8_t uid[16]; + if (lpc_iap_call(f, uid, IAP_CMD_READUID)) + return false; + tc_printf(t, "UID: 0x"); + for (uint32_t i = 0; i < sizeof(uid); ++i) + tc_printf(t, "%02x", uid[i]); + tc_printf(t, "\n"); + return true; +} + +const struct command_s lpc11xx_cmd_list[] = { + {"readuid", lpc11xx_read_uid, "Read out the 16-byte UID."}, + {NULL, NULL, NULL} +}; + void lpc11xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize) { struct lpc_flash *lf = lpc_add_flash(t, addr, len); @@ -89,6 +109,7 @@ lpc11xx_probe(target *t) t->driver = "LPC11xx"; target_add_ram(t, 0x10000000, 0x2000); lpc11xx_add_flash(t, 0x00000000, 0x20000, 0x1000); + target_add_commands(t, lpc11xx_cmd_list, "LPC11xx"); return true; case 0x0A24902B: @@ -109,6 +130,7 @@ lpc11xx_probe(target *t) t->driver = "LPC81x"; target_add_ram(t, 0x10000000, 0x1000); lpc11xx_add_flash(t, 0x00000000, 0x4000, 0x400); + target_add_commands(t, lpc11xx_cmd_list, "LPC81x"); return true; case 0x00008221: /* LPC822M101JHI33 */ case 0x00008222: /* LPC822M101JDH20 */ @@ -117,6 +139,7 @@ lpc11xx_probe(target *t) t->driver = "LPC82x"; target_add_ram(t, 0x10000000, 0x2000); lpc11xx_add_flash(t, 0x00000000, 0x8000, 0x400); + target_add_commands(t, lpc11xx_cmd_list, "LPC82x"); return true; case 0x0003D440: /* LPC11U34/311 */ case 0x0001cc40: /* LPC11U34/421 */ diff --git a/src/target/lpc15xx.c b/src/target/lpc15xx.c index 7b86d42f..66074091 100644 --- a/src/target/lpc15xx.c +++ b/src/target/lpc15xx.c @@ -35,6 +35,26 @@ #define LPC15XX_DEVICE_ID 0x400743F8 +static bool lpc15xx_read_uid(target *t, int argc, const char *argv[]) +{ + (void)argc; + (void)argv; + struct lpc_flash *f = (struct lpc_flash *)t->flash; + uint8_t uid[16]; + if (lpc_iap_call(f, uid, IAP_CMD_READUID)) + return false; + tc_printf(t, "UID: 0x"); + for (uint32_t i = 0; i < sizeof(uid); ++i) + tc_printf(t, "%02x", uid[i]); + tc_printf(t, "\n"); + return true; +} + +const struct command_s lpc15xx_cmd_list[] = { + {"readuid", lpc15xx_read_uid, "Read out the 16-byte UID."}, + {NULL, NULL, NULL} +}; + void lpc15xx_add_flash(target *t, uint32_t addr, size_t len, size_t erasesize) { struct lpc_flash *lf = lpc_add_flash(t, addr, len); @@ -72,6 +92,7 @@ lpc15xx_probe(target *t) t->driver = "LPC15xx"; target_add_ram(t, 0x02000000, ram_size); lpc15xx_add_flash(t, 0x00000000, 0x40000, 0x1000); + target_add_commands(t, lpc15xx_cmd_list, "LPC15xx"); return true; } diff --git a/src/target/lpc43xx.c b/src/target/lpc43xx.c index f08c4f8f..a1fb2145 100644 --- a/src/target/lpc43xx.c +++ b/src/target/lpc43xx.c @@ -164,11 +164,11 @@ static bool lpc43xx_cmd_erase(target *t, int argc, const char *argv[]) for (int bank = 0; bank < FLASH_NUM_BANK; bank++) { struct lpc_flash *f = (struct lpc_flash *)t->flash; - if (lpc_iap_call(f, IAP_CMD_PREPARE, + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, 0, FLASH_NUM_SECTOR-1, bank)) return false; - if (lpc_iap_call(f, IAP_CMD_ERASE, + if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, 0, FLASH_NUM_SECTOR-1, CPU_CLK_KHZ, bank)) return false; } @@ -188,7 +188,7 @@ static int lpc43xx_flash_init(target *t) /* Initialize flash IAP */ struct lpc_flash *f = (struct lpc_flash *)t->flash; - if (lpc_iap_call(f, IAP_CMD_INIT)) + if (lpc_iap_call(f, NULL, IAP_CMD_INIT)) return -1; return 0; @@ -234,7 +234,7 @@ static bool lpc43xx_cmd_mkboot(target *t, int argc, const char *argv[]) /* special command to compute/write magic vector for signature */ struct lpc_flash *f = (struct lpc_flash *)t->flash; - if (lpc_iap_call(f, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) { + if (lpc_iap_call(f, NULL, IAP_CMD_SET_ACTIVE_BANK, bank, CPU_CLK_KHZ)) { tc_printf(t, "Set bootable failed.\n"); return false; } diff --git a/src/target/lpc_common.c b/src/target/lpc_common.c index fa486ef4..c7331382 100644 --- a/src/target/lpc_common.c +++ b/src/target/lpc_common.c @@ -29,7 +29,8 @@ struct flash_param { uint16_t pad0; uint32_t command; uint32_t words[4]; - uint32_t result; + uint32_t status; + uint32_t result[4]; } __attribute__((aligned(4))); @@ -53,7 +54,7 @@ struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length) return lf; } -enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...) +enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd, ...) { target *t = f->f.t; struct flash_param param = { @@ -79,7 +80,7 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...) uint32_t regs[t->regs_size / sizeof(uint32_t)]; target_regs_read(t, regs); regs[0] = f->iap_ram + offsetof(struct flash_param, command); - regs[1] = f->iap_ram + offsetof(struct flash_param, result); + regs[1] = f->iap_ram + offsetof(struct flash_param, status); regs[REG_MSP] = f->iap_msp; regs[REG_LR] = f->iap_ram | 1; regs[REG_PC] = f->iap_entry; @@ -91,7 +92,12 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...) /* copy back just the parameters structure */ target_mem_read(t, ¶m, f->iap_ram, sizeof(param)); - return param.result; + + /* if the user expected a result, set the result (16 bytes). */ + if (result != NULL) + memcpy(result, param.result, sizeof(param.result)); + + return param.status; } static uint8_t lpc_sector_for_addr(struct lpc_flash *f, uint32_t addr) @@ -105,15 +111,15 @@ int lpc_flash_erase(struct target_flash *tf, target_addr addr, size_t len) uint32_t start = lpc_sector_for_addr(f, addr); uint32_t end = lpc_sector_for_addr(f, addr + len - 1); - if (lpc_iap_call(f, IAP_CMD_PREPARE, start, end, f->bank)) + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, start, end, f->bank)) return -1; /* and now erase them */ - if (lpc_iap_call(f, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank)) + if (lpc_iap_call(f, NULL, IAP_CMD_ERASE, start, end, CPU_CLK_KHZ, f->bank)) return -2; /* check erase ok */ - if (lpc_iap_call(f, IAP_CMD_BLANKCHECK, start, end, f->bank)) + if (lpc_iap_call(f, NULL, IAP_CMD_BLANKCHECK, start, end, f->bank)) return -3; return 0; @@ -125,7 +131,7 @@ int lpc_flash_write(struct target_flash *tf, struct lpc_flash *f = (struct lpc_flash *)tf; /* prepare... */ uint32_t sector = lpc_sector_for_addr(f, dest); - if (lpc_iap_call(f, IAP_CMD_PREPARE, sector, sector, f->bank)) + if (lpc_iap_call(f, NULL, IAP_CMD_PREPARE, sector, sector, f->bank)) return -1; /* Write payload to target ram */ @@ -133,7 +139,7 @@ int lpc_flash_write(struct target_flash *tf, target_mem_write(f->f.t, bufaddr, src, len); /* set the destination address and program */ - if (lpc_iap_call(f, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ)) + if (lpc_iap_call(f, NULL, IAP_CMD_PROGRAM, dest, bufaddr, len, CPU_CLK_KHZ)) return -2; return 0; diff --git a/src/target/lpc_common.h b/src/target/lpc_common.h index 5b132263..3130e96b 100644 --- a/src/target/lpc_common.h +++ b/src/target/lpc_common.h @@ -27,6 +27,7 @@ enum iap_cmd { IAP_CMD_ERASE = 52, IAP_CMD_BLANKCHECK = 53, IAP_CMD_PARTID = 54, + IAP_CMD_READUID = 58, IAP_CMD_SET_ACTIVE_BANK = 60, }; @@ -60,7 +61,7 @@ struct lpc_flash { }; struct lpc_flash *lpc_add_flash(target *t, target_addr addr, size_t length); -enum iap_status lpc_iap_call(struct lpc_flash *f, enum iap_cmd cmd, ...); +enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd, ...); int lpc_flash_erase(struct target_flash *f, target_addr addr, size_t len); int lpc_flash_write(struct target_flash *f, target_addr dest, const void *src, size_t len); From 880613d6414b73fb3f096f540ec7f23cca42c4e3 Mon Sep 17 00:00:00 2001 From: Alexander Zhang Date: Fri, 24 May 2019 10:02:29 -0400 Subject: [PATCH 2/2] lpc_common: restore RAM and registers after IAP call Restore the RAM and registers which are clobbered by an LPC IAP call. This does not restore any additional RAM which might be clobbered by a *particular* IAP call. (For example, flash programming always clobbers the last page of RAM.) --- src/target/lpc_common.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/target/lpc_common.c b/src/target/lpc_common.c index c7331382..2a35bb54 100644 --- a/src/target/lpc_common.c +++ b/src/target/lpc_common.c @@ -66,6 +66,14 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd if (f->wdt_kick) f->wdt_kick(t); + /* save IAP RAM to restore after IAP call */ + struct flash_param backup_param; + target_mem_read(t, &backup_param, f->iap_ram, sizeof(backup_param)); + + /* save registers to restore after IAP call */ + uint32_t backup_regs[t->regs_size / sizeof(uint32_t)]; + target_regs_read(t, backup_regs); + /* fill out the remainder of the parameters */ va_list ap; va_start(ap, cmd); @@ -93,6 +101,10 @@ enum iap_status lpc_iap_call(struct lpc_flash *f, void *result, enum iap_cmd cmd /* copy back just the parameters structure */ target_mem_read(t, ¶m, f->iap_ram, sizeof(param)); + /* restore the original data in RAM and registers */ + target_mem_write(t, f->iap_ram, &backup_param, sizeof(param)); + target_regs_write(t, backup_regs); + /* if the user expected a result, set the result (16 bytes). */ if (result != NULL) memcpy(result, param.result, sizeof(param.result));