From 30de5c4c249c5715d5ae998e278d3da499ac430b Mon Sep 17 00:00:00 2001 From: Gerard Swiderski Date: Tue, 25 Jun 2024 18:38:16 +0200 Subject: [PATCH] wip: cmds: introduce ptable command --- cmds/Makefile | 2 +- cmds/ptable.c | 152 ++++++++++++++++++++ hal/armv7m/imxrt/10xx/105x/Makefile | 2 +- hal/armv7m/imxrt/10xx/106x/Makefile | 2 +- hal/armv7m/imxrt/117x/Makefile | 2 +- lib/Makefile | 2 +- lib/ctype.c | 6 + lib/ctype.h | 3 + lib/lib.h | 3 + lib/ptable.c | 213 ++++++++++++++++++++++++++++ lib/ptable.h | 82 +++++++++++ 11 files changed, 464 insertions(+), 5 deletions(-) create mode 100644 cmds/ptable.c create mode 100644 lib/ptable.c create mode 100644 lib/ptable.h diff --git a/cmds/Makefile b/cmds/Makefile index 9dac02b1..632c569f 100644 --- a/cmds/Makefile +++ b/cmds/Makefile @@ -8,7 +8,7 @@ PLO_ALLCOMMANDS = alias app bankswitch bitstream blob bootcm4 bootrom bridge call console \ copy devices dump echo erase go help jffs2 kernel kernelimg lspci map mem mpu otp phfs \ - reboot script stop test-dev test-ddr wait + ptable reboot script stop test-dev test-ddr wait PLO_COMMANDS ?= $(PLO_ALLCOMMANDS) PLO_APPLETS = $(filter $(PLO_ALLCOMMANDS), $(PLO_COMMANDS)) diff --git a/cmds/ptable.c b/cmds/ptable.c new file mode 100644 index 00000000..33f9080f --- /dev/null +++ b/cmds/ptable.c @@ -0,0 +1,152 @@ +/* + * Phoenix-RTOS + * + * Operating system loader + * + * partition table tool + * + * Copyright 2024 Phoenix Systems + * Author: Gerard Swiderski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "cmd.h" + +#include +#include +#include + +#include + +#define CSI_RESET "\033[0m" +#define CSI_BOLD "\033[1m" + +#define PTABLE_HEADER_FORMAT "%2s %-10s %10s %10s %10s %10s %-8s\n" +#define PTABLE_ENTRY_FORMAT "%2u %-10s %10u %10u %10u %10u %-12s\n" + + +static struct { + u32 memsz; + u32 blksz; + ptable_t ptable[1024]; +} ptable_common; + + +static void cmd_ptableInfo(void) +{ + lib_printf("print partition table, usage: ptable []"); +} + + +static int partPrint(ptable_t *p) +{ + unsigned int i = p->count; + unsigned int j = 0; + + lib_printf( + "\n" CSI_BOLD PTABLE_HEADER_FORMAT CSI_RESET, + "#", "Name", "Start", "End", "Blocks", "Size", "Type"); + + while (i-- != 0) { + ptable_part_t *entry = &p->parts[i]; + lib_printf( + PTABLE_ENTRY_FORMAT, + ++j, entry->name, entry->offset, entry->offset + entry->size, + entry->size / ptable_common.blksz, entry->size, + ptable_typeName(entry->type)); + } + + return 0; +} + + +static int partRead(handler_t h, addr_t offs) +{ + u32 partCount; + size_t ptableSize; + + int res = phfs_read(h, offs, &partCount, sizeof(partCount)); + if (res < 0) { + log_error("\nCan't read data"); + return res; + } + + if (partCount == 0) { + log_error("\nNo partitions at offset 0x%x", offs); + return 0; + } + + ptableSize = ptable_size(partCount); + if (ptableSize > sizeof(ptable_common.ptable)) { + log_error("\nIncorrect partition table at offset 0x%x", offs); + return -1; + } + + res = phfs_read(h, offs, ptable_common.ptable, ptableSize); + if (res < 0) { + log_error("\nCan't read data"); + return res; + } + + res = ptable_deserialize(ptable_common.ptable, ptable_common.memsz, ptable_common.blksz); + if (res < 0) { + log_error("\nIncorrect partition table at offset 0x%x", offs); + return res; + } + + + return (int)partCount; +} + + +static int cmd_ptable(int argc, char *argv[]) +{ + int res; + addr_t offs = 0; + char *endptr = NULL; + handler_t h; + + /* FIXME: add info to phfs */ + ptable_common.memsz = 32 * 1024 * 1024; + ptable_common.blksz = 4096; + + if ((argc != 2) && (argc != 3)) { + log_error("\n%s: Wrong argument count", argv[0]); + return -EINVAL; + } + + if (argc > 2) { + offs = lib_strtoul(argv[2], &endptr, 0); + if (argv[2] == endptr) { + log_error("\n%s: Wrong arguments", argv[0]); + return -EINVAL; + } + } + + if (phfs_open(argv[1], NULL, PHFS_OPEN_RAWONLY, &h) < 0) { + lib_printf("\n%s: Invalid phfs name provided: %s\n", argv[0], argv[1]); + return CMD_EXIT_FAILURE; + } + + res = partRead(h, offs); + + (void)phfs_close(h); + + if (res <= 0) { + return CMD_EXIT_FAILURE; + } + + if (res > 0) { + partPrint(ptable_common.ptable); + } + + return CMD_EXIT_SUCCESS; +} + + +static const cmd_t ptable_cmd __attribute__((section("commands"), used)) = { + .name = "ptable", .run = cmd_ptable, .info = cmd_ptableInfo +}; diff --git a/hal/armv7m/imxrt/10xx/105x/Makefile b/hal/armv7m/imxrt/10xx/105x/Makefile index 001c1dfd..e0b523a8 100644 --- a/hal/armv7m/imxrt/10xx/105x/Makefile +++ b/hal/armv7m/imxrt/10xx/105x/Makefile @@ -13,7 +13,7 @@ CFLAGS:=$(filter-out -mfloat-abi% , $(CFLAGS)) CFLAGS+= -mfloat-abi=soft PLO_COMMANDS ?= alias app blob bridge call console copy devices dump echo erase go help kernel \ - kernelimg map mem mpu otp phfs reboot script stop wait + kernelimg map mem mpu otp phfs ptable reboot script stop wait # pipe-rtt is disabled due to small amount of space in DTCM; RTT_ADDR is not defined for this architecture PLO_ALLDEVICES := usbc-cdc uart-imxrt106x flash-imxrt diff --git a/hal/armv7m/imxrt/10xx/106x/Makefile b/hal/armv7m/imxrt/10xx/106x/Makefile index 313074fd..e5a8ba40 100644 --- a/hal/armv7m/imxrt/10xx/106x/Makefile +++ b/hal/armv7m/imxrt/10xx/106x/Makefile @@ -13,7 +13,7 @@ CFLAGS:=$(filter-out -mfloat-abi% , $(CFLAGS)) CFLAGS+= -mfloat-abi=soft PLO_COMMANDS ?= alias app blob bootrom bridge call console copy devices dump echo erase go \ - help kernel kernelimg map mem mpu otp phfs reboot script stop wait + help kernel kernelimg map mem mpu otp phfs ptable reboot script stop wait PLO_ALLDEVICES := pipe-rtt usbc-cdc uart-imxrt106x flash-imxrt diff --git a/hal/armv7m/imxrt/117x/Makefile b/hal/armv7m/imxrt/117x/Makefile index 4510b50a..54001272 100644 --- a/hal/armv7m/imxrt/117x/Makefile +++ b/hal/armv7m/imxrt/117x/Makefile @@ -13,7 +13,7 @@ CFLAGS := $(filter-out -mfloat-abi% , $(CFLAGS)) CFLAGS += -mfloat-abi=soft PLO_COMMANDS ?= alias app blob bootcm4 bridge bootrom call console copy devices dump echo erase go \ - help kernel kernelimg map mem mpu otp phfs reboot script stop wait + help kernel kernelimg map mem mpu otp phfs ptable reboot script stop wait PLO_ALLDEVICES := pipe-rtt usbc-cdc uart-imxrt117x flash-imxrt diff --git a/lib/Makefile b/lib/Makefile index 7c6a4d8b..7425da46 100644 --- a/lib/Makefile +++ b/lib/Makefile @@ -6,4 +6,4 @@ # %LICENSE% # -OBJS += $(addprefix $(PREFIX_O)lib/, console.o ctype.o crc32.o cbuffer.o format.o getopt.o list.o log.o printf.o prompt.o sprintf.o strtoul.o) +OBJS += $(addprefix $(PREFIX_O)lib/, console.o ctype.o crc32.o cbuffer.o format.o getopt.o list.o log.o printf.o prompt.o ptable.o sprintf.o strtoul.o) diff --git a/lib/ctype.c b/lib/ctype.c index c75c1e03..3565c40c 100644 --- a/lib/ctype.c +++ b/lib/ctype.c @@ -40,6 +40,12 @@ int lib_isdigit(int c) } +int lib_isalnum(int c) +{ + return lib_islower(c) || lib_isupper(c) || lib_isdigit(c); +} + + int lib_isblank(int c) { return (c == ' ') || (c == '\t'); diff --git a/lib/ctype.h b/lib/ctype.h index 90157b61..b31cad34 100644 --- a/lib/ctype.h +++ b/lib/ctype.h @@ -26,6 +26,9 @@ extern int lib_isupper(int c); extern int lib_isalpha(int c); +extern int lib_isalnum(int c); + + extern int lib_isdigit(int c); diff --git a/lib/lib.h b/lib/lib.h index 96d11499..a5087ca9 100644 --- a/lib/lib.h +++ b/lib/lib.h @@ -26,6 +26,7 @@ #include "stdarg.h" #include "prompt.h" #include "crc32.h" +#include "ptable.h" #define min(a, b) ({ \ @@ -41,6 +42,8 @@ _a > _b ? _a : _b; \ }) +#define offsetof(a, b) ((size_t)(&(((a *)(0))->b))) + extern int lib_printf(const char *fmt, ...); diff --git a/lib/ptable.c b/lib/ptable.c new file mode 100644 index 00000000..8e02db51 --- /dev/null +++ b/lib/ptable.c @@ -0,0 +1,213 @@ +/* + * Phoenix-RTOS + * + * Partition table + * + * Copyright 2020, 2023 Phoenix Systems + * Author: Hubert Buczynski, Lukasz Kosinski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#include "lib.h" + + +#define le32toh(a) (a) +#define htole32(a) (a) + + +const char *ptable_typeName(int type) +{ + switch (type) { + case ptable_raw: return "raw"; + case ptable_jffs2: return "jffs2"; + case ptable_meterfs: return "meterfs"; + default: return "unknown"; + } +} + + +static inline u32 ptable_crc32(const void *data, size_t len) +{ + return ~lib_crc32(data, len, 0xffffffff); +} + + +static int ptable_partVerify(const ptable_t *ptable, const ptable_part_t *part, u32 memsz, u32 blksz, int crcCheck) +{ + const ptable_part_t *p; + size_t i; + u32 size = le32toh(part->size); + u32 offset = le32toh(part->offset); + + /* Verify partition checksum */ + if ((crcCheck != 0) && (le32toh(part->crc) != ptable_crc32(part, offsetof(ptable_part_t, crc)))) { + return -1; + } + + /* Verify offset and size */ + if (size == 0) { + return -1; + } + + if (size % blksz != 0) { + return -1; + } + + if (offset % blksz != 0) { + return -1; + } + + if (offset + size > memsz) { + return -1; + } + + /* Check for overflow */ + if (offset + size < offset) { + return -1; + } + + /* Verify partition type */ + switch (part->type) { + case ptable_raw: + case ptable_jffs2: + case ptable_meterfs: + break; + + default: + return -1; + } + + /* Verify partition name */ + for (i = 0; i < sizeof(part->name); i++) { + if (!lib_isalnum(part->name[i])) { + break; + } + } + + if ((i == 0) || (i >= sizeof(part->name)) || (part->name[i] != '\0')) { + return -1; + } + + /* Compare against previous partitions */ + for (p = ptable->parts; p != part; p++) { + /* Check for range overlap */ + if ((offset <= le32toh(p->offset) + le32toh(p->size) - 1) && (offset + size - 1 >= le32toh(p->offset))) { + return -1; + } + + /* Check for name duplicate */ + if (hal_strcmp((const char *)part->name, (const char *)p->name) == 0) { + return -1; + } + } + + return 0; +} + + +static int ptable_verify(const ptable_t *ptable, u32 memsz, u32 blksz) +{ + u32 size, i; + int crcCheck = 1; + u32 count = le32toh(ptable->count); + + if (ptable->version == 0 || ptable->version == 1 || ptable->version == 0xff) { + /* Disable CRC check for legacy ptables */ + crcCheck = 0; + } + + if (crcCheck != 0) { + /* Verify header checksum */ + if (le32toh(ptable->crc) != ptable_crc32(ptable, offsetof(ptable_t, crc))) { + return -1; + } + } + + /* Verify partition table size */ + size = ptable_size(count); + if (size > blksz) { + return -1; + } + + /* Verify magic signature */ + if (hal_memcmp((const u8 *)ptable + size - sizeof(ptable_magic), ptable_magic, sizeof(ptable_magic)) != 0) { + return -1; + } + + /* Verify partitions */ + for (i = 0; i < count; i++) { + if (ptable_partVerify(ptable, ptable->parts + i, memsz, blksz, crcCheck) < 0) { + return -1; + } + } + + return 0; +} + + +int ptable_deserialize(ptable_t *ptable, u32 memsz, u32 blksz) +{ + int ret; + u32 i; + + if (ptable == NULL) { + return -1; + } + + /* CRC must be verified with data in little endian */ + ret = ptable_verify(ptable, memsz, blksz); + if (ret < 0) { + return ret; + } + + ptable->count = le32toh(ptable->count); + ptable->crc = le32toh(ptable->crc); + + for (i = 0; i < ptable->count; i++) { + ptable->parts[i].offset = le32toh(ptable->parts[i].offset); + ptable->parts[i].size = le32toh(ptable->parts[i].size); + ptable->parts[i].crc = le32toh(ptable->parts[i].crc); + } + + + return ret; +} + + +int ptable_serialize(ptable_t *ptable, u32 memsz, u32 blksz) +{ + u32 i; + + if (ptable == NULL) { + return -1; + } + + ptable->version = PTABLE_VERSION; + + /* Calculate checksums */ + ptable->crc = ptable_crc32(ptable, offsetof(ptable_t, crc)); + for (i = 0; i < ptable->count; i++) { + ptable->parts[i].crc = ptable_crc32(ptable->parts + i, offsetof(ptable_part_t, crc)); + } + + /* Add magic signature */ + hal_memcpy((u8 *)ptable + ptable_size(ptable->count) - sizeof(ptable_magic), ptable_magic, sizeof(ptable_magic)); + + if (ptable_verify(ptable, memsz, blksz) < 0) { + return -1; + } + + for (i = 0; i < ptable->count; i++) { + ptable->parts[i].offset = htole32(ptable->parts[i].offset); + ptable->parts[i].size = htole32(ptable->parts[i].size); + ptable->parts[i].crc = htole32(ptable->parts[i].crc); + } + + ptable->count = htole32(ptable->count); + ptable->crc = htole32(ptable->crc); + + return 0; +} diff --git a/lib/ptable.h b/lib/ptable.h new file mode 100644 index 00000000..849a34f7 --- /dev/null +++ b/lib/ptable.h @@ -0,0 +1,82 @@ +/* + * Phoenix-RTOS + * + * Partition table + * + * Copyright 2020, 2023 Phoenix Systems + * Author: Hubert Buczynski, Lukasz Kosinski + * + * This file is part of Phoenix-RTOS. + * + * %LICENSE% + */ + +#ifndef _LIB_PTABLE_H_ +#define _LIB_PTABLE_H_ + +/* Changelog: + * version 2: Add checksum and version fields + */ +#define PTABLE_VERSION 2 + + +/* Structure of partition table + * _________________________________________________________________________ + * | 28 B | 32 B * n | 4 B | + * |-----------------|-----------------------------------------|-------------| + * | ptable_t header | ptable_part_t 0 | ... | ptable_part_t n | magic bytes | + * ------------------------------------------------------------------------- + * + * NOTE: data in partition table should be stored in little endian + */ + +/* clang-format off */ + +/* Partition table magic signature */ +static const u8 ptable_magic[] = { 0xde, 0xad, 0xfc, 0xbe }; + + +/* Supported partition types */ +enum { ptable_raw = 0x51, ptable_jffs2 = 0x72, ptable_meterfs = 0x75 }; + +/* clang-format on */ + + +typedef struct { + u8 name[8]; /* Partition name */ + u32 offset; /* Partition offset (in bytes) */ + u32 size; /* Partition size (in bytes) */ + u8 type; /* Partition type */ + u8 reserved[11]; /* Reserved bytes */ + u32 crc; /* Partition checksum */ +} ptable_part_t; + + +typedef struct { + u32 count; /* Number of partitions */ + u8 version; /* Ptable struct version */ + u8 reserved[19]; /* Reserved bytes */ + u32 crc; /* Header checksum */ + ptable_part_t parts[0]; /* Partitions */ +} ptable_t; + + +/* Returns partition table size provided partition count */ +static inline u32 ptable_size(u32 count) +{ + return sizeof(ptable_t) + count * sizeof(ptable_part_t) + sizeof(ptable_magic); +} + + +extern const char *ptable_typeName(int type); + + +/* Converts partition table to host endianness and verifies it */ +extern int ptable_deserialize(ptable_t *ptable, u32 memsz, u32 blksz); + + +/* Verifies partition table and converts it to little endian */ +extern int ptable_serialize(ptable_t *ptable, u32 memsz, u32 blksz); + + +#endif