Skip to content

Commit f296605

Browse files
committed
feat: add .rpd file support for boundary-set command
The boundary-set command now accepts --file to load TrustZone boundary settings from Renesas Partition Data files. These files are generated by e2studio, Zephyr (via gen_rpd.py), and other toolchains. The parser reads FLASH_S_SIZE, FLASH_C_SIZE, RAM_S_SIZE, RAM_C_SIZE, and DATA_FLASH_S_SIZE fields, converting bytes to KB for CFS1/CFS2/SRS1/SRS2/DFS settings. Signed-off-by: Vincent Jardin <vjardin@free.fr>
1 parent 3b5e25f commit f296605

File tree

2 files changed

+149
-23
lines changed

2 files changed

+149
-23
lines changed

radfu.h2m

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -394,6 +394,7 @@ radfu crc -a 0x0 -s 0x10000
394394
radfu osis
395395
radfu config-read
396396
radfu boundary-set --cfs1 0 --cfs2 0 --dfs 0 --srs1 0 --srs2 0
397+
radfu boundary-set --file zephyr.rpd # Load from .rpd file
397398
radfu -u -p /dev/ttyUSB0 info # UART via USB-UART adapter
398399
radfu write -q firmware.bin # Write without progress bar
399400
.fi
@@ -409,6 +410,33 @@ Writing: [###############...............] 50% (32768/65536) 125.3 KB/s ETA 2s
409410
The \\fB-q\\fR (\\fB--quiet\\fR) option suppresses progress output. This is useful
410411
for scripting or when running operations in the background.
411412

413+
[boundary file support]
414+
The \\fBboundary-set\\fR command can load TrustZone boundary settings from
415+
a Renesas Partition Data (.rpd) file using \\fB--file\\fR. This format is
416+
generated by e2studio, Zephyr, and other toolchains.
417+
418+
.SS RPD File Format
419+
The .rpd file is a text file with key=value pairs:
420+
421+
.nf
422+
FLASH_S_SIZE=0x8000 # Secure code flash (bytes) -> CFS1
423+
FLASH_C_SIZE=0x10000 # Code flash with NSC (bytes) -> CFS2
424+
DATA_FLASH_S_SIZE=0x1000 # Secure data flash (bytes) -> DFS
425+
RAM_S_SIZE=0x4000 # Secure SRAM (bytes) -> SRS1
426+
RAM_C_SIZE=0x8000 # SRAM with NSC (bytes) -> SRS2
427+
.fi
428+
429+
Values are in bytes with 0x prefix and automatically converted to KB.
430+
431+
.SS Example
432+
.nf
433+
radfu boundary-set --file build/zephyr/zephyr.rpd
434+
Loaded boundary settings from build/zephyr/zephyr.rpd:
435+
CFS1: 32 KB, CFS2: 64 KB, DFS: 8 KB
436+
SRS1: 16 KB, SRS2: 32 KB
437+
Boundary settings stored successfully
438+
.fi
439+
412440
[warnings]
413441
.B USE AT YOUR OWN RISK
414442

src/main.c

Lines changed: 121 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ usage(int status) {
4242
" dlm-auth <state> <key> Authenticated DLM transition (ssd/nsecsd/rma_req)\n"
4343
" Key format: file:<path> or hex:<32_hex_chars>\n"
4444
" boundary Show secure/non-secure boundary settings\n"
45-
" boundary-set Set TrustZone boundaries (requires --cfs1/--cfs2/--dfs/--srs1/--srs2)\n"
45+
" boundary-set Set TrustZone boundaries (--file <rpd> or explicit options)\n"
4646
" param Show device parameter (initialization command)\n"
4747
" param-set <enable|disable> Enable/disable initialization command\n"
4848
" init Initialize device (factory reset to SSD state)\n"
@@ -71,6 +71,7 @@ usage(int status) {
7171
" --dfs <KB> Data flash secure region size\n"
7272
" --srs1 <KB> SRAM secure region size without NSC\n"
7373
" --srs2 <KB> SRAM secure region size (total)\n"
74+
" --file <rpd> Load boundary settings from .rpd file\n"
7475
" -h, --help Show this help message\n"
7576
" -V, --version Show version\n"
7677
"\n"
@@ -287,6 +288,82 @@ parse_auth_key(const char *str, uint8_t *key) {
287288
}
288289
}
289290

291+
/*
292+
* Parse .rpd (Renesas Partition Data) file for TrustZone boundary settings
293+
* Format: key=value lines where values are hex (with 0x prefix) in bytes
294+
* Keys: FLASH_S_SIZE, FLASH_C_SIZE, RAM_S_SIZE, RAM_C_SIZE, DATA_FLASH_S_SIZE
295+
* Converts bytes to KB for boundary settings
296+
* Returns: 0 on success, -1 on error
297+
*/
298+
static int
299+
parse_rpd_file(const char *filename, ra_boundary_t *bnd) {
300+
FILE *f = fopen(filename, "r");
301+
if (!f) {
302+
warn("failed to open boundary file: %s", filename);
303+
return -1;
304+
}
305+
306+
char line[256];
307+
bool found_cfs1 = false, found_cfs2 = false, found_dfs = false;
308+
bool found_srs1 = false, found_srs2 = false;
309+
310+
while (fgets(line, sizeof(line), f)) {
311+
char *eq = strchr(line, '=');
312+
if (!eq)
313+
continue;
314+
315+
*eq = '\0';
316+
const char *key = line;
317+
const char *val = eq + 1;
318+
319+
/* Skip 0x prefix if present */
320+
if (val[0] == '0' && (val[1] == 'x' || val[1] == 'X'))
321+
val += 2;
322+
323+
char *endptr;
324+
unsigned long bytes = strtoul(val, &endptr, 16);
325+
326+
/* Convert bytes to KB */
327+
uint16_t kb = (uint16_t)(bytes / 1024);
328+
329+
if (strcmp(key, "FLASH_S_SIZE") == 0) {
330+
bnd->cfs1 = kb;
331+
found_cfs1 = true;
332+
} else if (strcmp(key, "FLASH_C_SIZE") == 0) {
333+
bnd->cfs2 = kb;
334+
found_cfs2 = true;
335+
} else if (strcmp(key, "RAM_S_SIZE") == 0) {
336+
bnd->srs1 = kb;
337+
found_srs1 = true;
338+
} else if (strcmp(key, "RAM_C_SIZE") == 0) {
339+
bnd->srs2 = kb;
340+
found_srs2 = true;
341+
} else if (strcmp(key, "DATA_FLASH_S_SIZE") == 0) {
342+
bnd->dfs = kb;
343+
found_dfs = true;
344+
}
345+
}
346+
347+
fclose(f);
348+
349+
if (!found_cfs1 || !found_cfs2 || !found_dfs || !found_srs1 || !found_srs2) {
350+
warnx("incomplete .rpd file: missing required fields");
351+
if (!found_cfs1)
352+
warnx(" missing FLASH_S_SIZE (CFS1)");
353+
if (!found_cfs2)
354+
warnx(" missing FLASH_C_SIZE (CFS2)");
355+
if (!found_dfs)
356+
warnx(" missing DATA_FLASH_S_SIZE (DFS)");
357+
if (!found_srs1)
358+
warnx(" missing RAM_S_SIZE (SRS1)");
359+
if (!found_srs2)
360+
warnx(" missing RAM_C_SIZE (SRS2)");
361+
return -1;
362+
}
363+
364+
return 0;
365+
}
366+
290367
/*
291368
* Parse key type from string: accepts numeric (1,2,3) or keywords
292369
* Keywords: secdbg, nonsecdbg, rma (case-insensitive)
@@ -318,28 +395,30 @@ parse_key_type(const char *str) {
318395
#define OPT_SRS1 259
319396
#define OPT_SRS2 260
320397
#define OPT_AREA 261
398+
#define OPT_BOUNDARY_FILE 262
321399

322400
static const struct option longopts[] = {
323-
{ "port", required_argument, NULL, 'p' },
324-
{ "address", required_argument, NULL, 'a' },
325-
{ "size", required_argument, NULL, 's' },
326-
{ "baudrate", required_argument, NULL, 'b' },
327-
{ "id", required_argument, NULL, 'i' },
328-
{ "erase-all", no_argument, NULL, 'e' },
329-
{ "verify", no_argument, NULL, 'v' },
330-
{ "input-format", required_argument, NULL, 'f' },
331-
{ "output-format", required_argument, NULL, 'F' },
332-
{ "uart", no_argument, NULL, 'u' },
333-
{ "quiet", no_argument, NULL, 'q' },
334-
{ "cfs1", required_argument, NULL, OPT_CFS1 },
335-
{ "cfs2", required_argument, NULL, OPT_CFS2 },
336-
{ "dfs", required_argument, NULL, OPT_DFS },
337-
{ "srs1", required_argument, NULL, OPT_SRS1 },
338-
{ "srs2", required_argument, NULL, OPT_SRS2 },
339-
{ "area", required_argument, NULL, OPT_AREA },
340-
{ "help", no_argument, NULL, 'h' },
341-
{ "version", no_argument, NULL, 'V' },
342-
{ NULL, 0, NULL, 0 }
401+
{ "port", required_argument, NULL, 'p' },
402+
{ "address", required_argument, NULL, 'a' },
403+
{ "size", required_argument, NULL, 's' },
404+
{ "baudrate", required_argument, NULL, 'b' },
405+
{ "id", required_argument, NULL, 'i' },
406+
{ "erase-all", no_argument, NULL, 'e' },
407+
{ "verify", no_argument, NULL, 'v' },
408+
{ "input-format", required_argument, NULL, 'f' },
409+
{ "output-format", required_argument, NULL, 'F' },
410+
{ "uart", no_argument, NULL, 'u' },
411+
{ "quiet", no_argument, NULL, 'q' },
412+
{ "cfs1", required_argument, NULL, OPT_CFS1 },
413+
{ "cfs2", required_argument, NULL, OPT_CFS2 },
414+
{ "dfs", required_argument, NULL, OPT_DFS },
415+
{ "srs1", required_argument, NULL, OPT_SRS1 },
416+
{ "srs2", required_argument, NULL, OPT_SRS2 },
417+
{ "area", required_argument, NULL, OPT_AREA },
418+
{ "file", required_argument, NULL, OPT_BOUNDARY_FILE },
419+
{ "help", no_argument, NULL, 'h' },
420+
{ "version", no_argument, NULL, 'V' },
421+
{ NULL, 0, NULL, 0 }
343422
};
344423

345424
int
@@ -365,6 +444,7 @@ main(int argc, char *argv[]) {
365444
ra_boundary_t bnd = { 0 };
366445
bool bnd_cfs1_set = false, bnd_cfs2_set = false, bnd_dfs_set = false;
367446
bool bnd_srs1_set = false, bnd_srs2_set = false;
447+
const char *boundary_file = NULL;
368448
int8_t area_koa = -1; /* -1 = not set, 0/1/2 = code/data/config */
369449
write_entry_t write_entries[MAX_WRITE_FILES];
370450
int write_count = 0;
@@ -459,6 +539,9 @@ main(int argc, char *argv[]) {
459539
area_koa = (int8_t)val;
460540
}
461541
break;
542+
case OPT_BOUNDARY_FILE:
543+
boundary_file = optarg;
544+
break;
462545
case 'h':
463546
usage(EXIT_SUCCESS);
464547
break;
@@ -566,8 +649,23 @@ main(int argc, char *argv[]) {
566649
cmd = CMD_BOUNDARY;
567650
} else if (strcmp(command, "boundary-set") == 0) {
568651
cmd = CMD_BOUNDARY_SET;
569-
if (!bnd_cfs1_set || !bnd_cfs2_set || !bnd_dfs_set || !bnd_srs1_set || !bnd_srs2_set)
570-
errx(EXIT_FAILURE, "boundary-set requires all options: --cfs1 --cfs2 --dfs --srs1 --srs2");
652+
if (boundary_file) {
653+
/* Parse .rpd file */
654+
if (parse_rpd_file(boundary_file, &bnd) < 0)
655+
exit(EXIT_FAILURE);
656+
printf("Loaded boundary settings from %s:\n"
657+
" CFS1: %u KB, CFS2: %u KB, DFS: %u KB\n"
658+
" SRS1: %u KB, SRS2: %u KB\n",
659+
boundary_file,
660+
bnd.cfs1,
661+
bnd.cfs2,
662+
bnd.dfs,
663+
bnd.srs1,
664+
bnd.srs2);
665+
} else if (!bnd_cfs1_set || !bnd_cfs2_set || !bnd_dfs_set || !bnd_srs1_set || !bnd_srs2_set) {
666+
errx(EXIT_FAILURE,
667+
"boundary-set requires --file <rpd> or all options: --cfs1 --cfs2 --dfs --srs1 --srs2");
668+
}
571669
} else if (strcmp(command, "param") == 0) {
572670
cmd = CMD_PARAM;
573671
} else if (strcmp(command, "param-set") == 0) {

0 commit comments

Comments
 (0)