From 43bf41b6b7c2665eb80a6490560250c33dd17a89 Mon Sep 17 00:00:00 2001 From: Tim Hardisty <56726697+TimJTi@users.noreply.github.com> Date: Thu, 24 Apr 2025 11:15:26 +0100 Subject: [PATCH 1/2] apps/boot/nxboot: Enhancements to add progress messages and copy-to-RAM feature This adds Kconfig-enabled progress messages that are output to stdout. It also adds Kconfig-enabled option to copy the validated and bootable image to RAM Signed-off by: Tim Hardisty --- boot/nxboot/Kconfig | 36 +++++++++ boot/nxboot/include/nxboot.h | 63 +++++++++++++-- boot/nxboot/loader/boot.c | 89 ++++++++++++++++++++- boot/nxboot/loader/flash.c | 9 ++- boot/nxboot/nxboot_main.c | 147 ++++++++++++++++++++++++++++++++++- 5 files changed, 326 insertions(+), 18 deletions(-) diff --git a/boot/nxboot/Kconfig b/boot/nxboot/Kconfig index f8e817b5ac5..4f294d0758e 100644 --- a/boot/nxboot/Kconfig +++ b/boot/nxboot/Kconfig @@ -64,6 +64,36 @@ config NXBOOT_BOOTLOADER if NXBOOT_BOOTLOADER +config NXBOOT_COPY_TO_RAM + bool "Copy bootable image to RAM before calling board boot-image function" + default n + ---help--- + The is a board and/or arch specific option that may be used when running + directly from flash, especially if external flash, even in XIP mode, is too + slow. + Running from RAM usually results in faster execution but the board must, of + course, have sufficient RAM available for the application image, stack + and heap. + +config NXBOOT_RAMSTART + hex "Start address in RAM that the application is to be loaded" + default 0x0 + depends on NXBOOT_COPY_TO_RAM + ---help--- + This will be board specific. A check of the board's linker script + may be informative. For example the SAMA5D2-XULT eval board's uboot + linker script - boards/arm/sama5/sama5d2-xult/scripts/uboot.ld - has: + + sdram (W!RX) : ORIGIN = 0x20008000, LENGTH = 256M - 32K + + This shows the load address to be 0x20008000 and would be the address + to use here if the same linker script is to be be used for NXboot. + + Typically the address is the base address of the RAM to be used, plus the + size of the NXboot image itself. The example above has reserved + 32KiB (0x8000) for this from the 256MiB available on the board at + address 0x20000000. + config NXBOOT_SWRESET_ONLY bool "Perform update/revert only on SW reset" default n @@ -92,6 +122,12 @@ config NXBOOT_PREVENT_DOWNGRADE WARNING: NXboot currently implements preferences only for MAJOR.MINOR.PATCH and ignores prerelease. +config NXBOOT_PRINTF_PROGRESS + bool "Enable progress messages to be sent to STDOUT" + default y + ---help--- + Note: the NXboot binary will be approximately 1.5KiB larger with this enabled. + endif # NXBOOT_BOOTLOADER endif # BOOT_NXBOOT diff --git a/boot/nxboot/include/nxboot.h b/boot/nxboot/include/nxboot.h index 5370c2ee6f8..1c2c7b22dba 100644 --- a/boot/nxboot/include/nxboot.h +++ b/boot/nxboot/include/nxboot.h @@ -117,6 +117,7 @@ struct nxboot_img_header struct nxboot_img_version img_version; /* Image version */ }; + static_assert(CONFIG_NXBOOT_HEADER_SIZE > sizeof(struct nxboot_img_header), "CONFIG_NXBOOT_HEADER_SIZE has to be larger than" "sizeof(struct nxboot_img_header)"); @@ -131,10 +132,41 @@ struct nxboot_state enum nxboot_update_type next_boot; /* nxboot_update_type with next operation */ }; +enum progress_type_e +{ + nxboot_info = 0, /* Prefixes arg. string with "INFO:" */ + nxboot_error, /* Prefixes arg. string with "ERR:" */ + nxboot_progress_start, /* Prints arg. string with no newline to allow ..... sequence to follow */ + nxboot_progress_dot, /* Prints of a "." to the ..... progress sequence */ + nxboot_progress_end, /* Flags end of a "..." progrees sequence and prints newline */ +}; + +enum progress_msg_e +{ + startup_msg = 0, + power_reset, + soft_reset, + found_bootable_image, + no_bootable_image, + boardioc_image_boot_fail, + ramcopy_started, + recovery_revert, + recovery_create, + update_from_update, + validate_primary, + validate_recovery, + validate_update, + recovery_created, + recovery_invalid, + update_failed, +}; + /**************************************************************************** * Public Function Prototypes ****************************************************************************/ +void nxboot_progress(enum progress_type_e type, ...); + /**************************************************************************** * Name: nxboot_get_state * @@ -148,7 +180,7 @@ struct nxboot_state * state: The pointer to nxboot_state structure. The state is stored here. * * Returned Value: - * 0 on success, -1 and sets errno on failure. + * OK (0) on success, ERROR (-1) and sets errno on failure. * ****************************************************************************/ @@ -164,7 +196,7 @@ int nxboot_get_state(struct nxboot_state *state); * if afterwards. * * Returned Value: - * Valid file descriptor on success, -1 and sets errno on failure. + * Valid file descriptor on success, ERROR (-1) and sets errno on failure. * ****************************************************************************/ @@ -180,7 +212,7 @@ int nxboot_open_update_partition(void); * state of the bootloader. * * Returned Value: - * 1 means confirmed, 0 not confirmed, -1 and sets errno on failure. + * 1 if confirmed, OK (0) on success, ERROR (-1) and sets errno on failure. * ****************************************************************************/ @@ -194,14 +226,14 @@ int nxboot_get_confirm(void); * its copy in update partition as a recovery. * * Returned Value: - * 0 on success, -1 and sets errno on failure. + * OK (0) on success, ERROR (-1) and sets errno on failure. * ****************************************************************************/ int nxboot_confirm(void); /**************************************************************************** - * Name: nxboot_perform_swap + * Name: nxboot_perform_update * * Description: * Checks for the possible firmware update and performs it by copying @@ -216,10 +248,29 @@ int nxboot_confirm(void); * check_only: Only repairs corrupted update, but do not start another one * * Returned Value: - * 0 on success, -1 and sets errno on failure. + * OK (0) on success, ERROR (-1) and sets errno on failure. * ****************************************************************************/ int nxboot_perform_update(bool check_only); +/**************************************************************************** + * Name: nxboot_ramcopy + * + * Description: + * Copies the (already) validate bootable image to RAM memory + * + * NOTE - no checking that the RAM location is correct, nor that the + * image size is appropriate for that RAM address! + * + * Input parameters: + * none + * + * Returned Value: + * OK (0) on success, ERROR (-1) on fail + * + ****************************************************************************/ + +int nxboot_ramcopy(void); + #endif /* __BOOT_NXBOOT_INCLUDE_NXBOOT_H */ diff --git a/boot/nxboot/loader/boot.c b/boot/nxboot/loader/boot.c index 9a43f4cb67e..4a330840026 100644 --- a/boot/nxboot/loader/boot.c +++ b/boot/nxboot/loader/boot.c @@ -106,6 +106,10 @@ static uint32_t calculate_crc(int fd, struct nxboot_img_header *header) off += readsiz; remain -= readsiz; crc = crc32part((uint8_t *)buf, readsiz, crc); + if ((remain % 25) == 0) + { + nxboot_progress(nxboot_progress_dot); + } } free(buf); @@ -202,6 +206,10 @@ static int copy_partition(int from, int where, struct nxboot_state *state, off += readsiz; remain -= readsiz; + if ((remain % 25) == 0) + { + nxboot_progress(nxboot_progress_dot); + } } free(buf); @@ -218,6 +226,7 @@ static bool validate_image(int fd) return false; } + syslog(LOG_INFO, "Validating image.\n"); return calculate_crc(fd, &header) == header.crc; } @@ -268,18 +277,24 @@ static enum nxboot_update_type struct nxboot_img_header *update_header, struct nxboot_img_header *recovery_header) { + nxboot_progress(nxboot_progress_start, validate_primary); bool primary_valid = validate_image(primary); + nxboot_progress(nxboot_progress_end); + nxboot_progress(nxboot_progress_start, validate_update); if (update_header->magic == NXBOOT_HEADER_MAGIC && validate_image(update)) { if (primary_header->crc != update_header->crc || !compare_versions(&primary_header->img_version, &update_header->img_version) || !primary_valid) { + nxboot_progress(nxboot_progress_end); return NXBOOT_UPDATE_TYPE_UPDATE; } } + nxboot_progress(nxboot_progress_end); + if (IS_INTERNAL_MAGIC(recovery_header->magic) && state->recovery_valid && ((IS_INTERNAL_MAGIC(primary_header->magic) && !state->primary_confirmed) || !primary_valid)) @@ -292,6 +307,7 @@ static enum nxboot_update_type static int perform_update(struct nxboot_state *state, bool check_only) { + int successful; int update; int recovery; int primary; @@ -331,18 +347,25 @@ static int perform_update(struct nxboot_state *state, bool check_only) recovery = secondary; } + nxboot_progress(nxboot_progress_start, validate_primary); if (state->next_boot == NXBOOT_UPDATE_TYPE_REVERT && (!check_only || !validate_image(primary))) { + nxboot_progress(nxboot_progress_end); if (state->recovery_valid) { syslog(LOG_INFO, "Reverting image to recovery.\n"); + nxboot_progress(nxboot_progress_start, recovery_revert); copy_partition(recovery, primary, state, false); + nxboot_progress(nxboot_progress_end); } } else { + nxboot_progress(nxboot_progress_end); + nxboot_progress(nxboot_progress_start, validate_primary); primary_valid = validate_image(primary); + nxboot_progress(nxboot_progress_end); if (primary_valid && check_only) { /* Skip if primary image is valid (does not mather whether @@ -368,21 +391,33 @@ static int perform_update(struct nxboot_state *state, bool check_only) */ syslog(LOG_INFO, "Creating recovery image.\n"); + nxboot_progress(nxboot_progress_start, recovery_create); copy_partition(primary, recovery, state, false); - if (!validate_image(recovery)) + nxboot_progress(nxboot_progress_end); + nxboot_progress(nxboot_progress_start, validate_recovery); + successful = validate_image(recovery); + nxboot_progress(nxboot_progress_end); + if (!successful) { - syslog(LOG_INFO, "New recovery is not valid, stop update.\n"); + syslog(LOG_INFO, + "New recovery is not valid,stop update.\n"); + nxboot_progress(nxboot_info, recovery_invalid); goto perform_update_done; } syslog(LOG_INFO, "Recovery image created.\n"); + nxboot_progress(nxboot_info, recovery_created); } - if (validate_image(update)) + nxboot_progress(nxboot_progress_start, validate_update); + successful = validate_image(update); + nxboot_progress(nxboot_progress_end); + if (successful) { /* Perform update only if update slot contains valid image. */ syslog(LOG_INFO, "Updating from update image.\n"); + nxboot_progress(nxboot_progress_start, update_from_update); if (copy_partition(update, primary, state, true) >= 0) { /* Erase the first sector of update partition. This marks the @@ -393,6 +428,8 @@ static int perform_update(struct nxboot_state *state, bool check_only) flash_partition_erase_first_sector(update); } + + nxboot_progress(nxboot_progress_end); } } @@ -403,6 +440,46 @@ static int perform_update(struct nxboot_state *state, bool check_only) return OK; } +#ifdef CONFIG_NXBOOT_COPY_TO_RAM +int nxboot_ramcopy(void) +{ + int ret = OK; + int primary; + struct nxboot_img_header header; + ssize_t bytes; + static uint8_t *buf; + + primary = flash_partition_open(CONFIG_NXBOOT_PRIMARY_SLOT_PATH); + if (primary < 0) + { + return ERROR; + } + + get_image_header(primary, &header); + buf = malloc(header.size); + if (!buf) + { + ret = ERROR; + goto exit_with_error; + } + + bytes = pread(primary, buf, header.size, header.header_size); + if (bytes != header.size) + { + ret = ERROR; + goto exit_with_error; + } + + memcpy((uint32_t *)CONFIG_NXBOOT_RAMSTART, buf, header.size); + +exit_with_error: + flash_partition_close(primary); + free(buf); + + return ret; +} +#endif + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -528,7 +605,9 @@ int nxboot_get_state(struct nxboot_state *state) state->update = NXBOOT_TERTIARY_SLOT_NUM; } + nxboot_progress(nxboot_progress_start, validate_recovery); state->recovery_valid = validate_image(recovery); + nxboot_progress(nxboot_progress_end); state->recovery_present = primary_header.crc == recovery_header->crc; /* The image is confirmed if it has either NXBOOT_HEADER_MAGIC or a @@ -611,7 +690,7 @@ int nxboot_get_confirm(void) int recovery; int recovery_pointer; char *path; - int ret = 0; + int ret = OK; struct nxboot_img_header primary_header; struct nxboot_img_header recovery_header; @@ -799,6 +878,7 @@ int nxboot_perform_update(bool check_only) */ syslog(LOG_ERR, "Update process failed: %s\n", strerror(errno)); + nxboot_progress(nxboot_error, update_failed); } } @@ -823,3 +903,4 @@ int nxboot_perform_update(bool check_only) return ret; } + diff --git a/boot/nxboot/loader/flash.c b/boot/nxboot/loader/flash.c index e7a53b83c16..fdbab4bb99d 100644 --- a/boot/nxboot/loader/flash.c +++ b/boot/nxboot/loader/flash.c @@ -202,8 +202,8 @@ int flash_partition_read(int fd, void *buf, size_t count, off_t off) nbytes = read(fd, buf, count); if (nbytes != count) { - syslog(LOG_ERR, "Read from offset %ld failed %s\n", - off, strerror(errno)); + syslog(LOG_ERR, "Read from offset %ld failed %s\n", off, + strerror(errno)); return ERROR; } @@ -265,7 +265,7 @@ int flash_partition_erase_first_sector(int fd) if (ret < 0) { syslog(LOG_ERR, "Could not erase the partition: %s\n", - strerror(errno)); + strerror(errno)); return ERROR; } @@ -295,7 +295,8 @@ int flash_partition_info(int fd, struct flash_partition_info *info) ret = ioctl(fd, MTDIOC_GEOMETRY, (unsigned long)((uintptr_t)&geometry)); if (ret < 0) { - syslog(LOG_ERR, "ioctl MTDIOC_GEOMETRY failed: %s\n", strerror(errno)); + syslog(LOG_ERR, "ioctl MTDIOC_GEOMETRY failed: %s\n", + strerror(errno)); return ERROR; } diff --git a/boot/nxboot/nxboot_main.c b/boot/nxboot/nxboot_main.c index 09e556b2b1b..388fe5bf96f 100644 --- a/boot/nxboot/nxboot_main.c +++ b/boot/nxboot/nxboot_main.c @@ -32,24 +32,146 @@ #include #include +/**************************************************************************** + * Public Data + ****************************************************************************/ + +bool progress_dots_started = false; + +/**************************************************************************** + * Private Data + ****************************************************************************/ + +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS +static const char *g_progress_txt[] = +{ + /* Text that will be printed ...from... enum progress_msg_e */ + + "*** nxboot ***", /* startup_msg */ + "Power Reset detected, check images only", /* power_reset */ + "Soft reset detected, check for update", /* soft_reset */ + "Found bootable image, boot from primary", /* found_bootable_image */ + "No bootable image found", /* no_bootable_image */ + "Board failed to boot bootable image", /* boardioc_image_boot_fail */ + "Copying bootable image to RAM", /* ramcopy_started */ + "Reverting image to recovery", /* recovery_revert */ + "Creating recovery image", /* recovery_create */ + "Updating from update image", /* update_from_update */ + "Validating primary image", /* validate_primary */ + "Validating recovery image", /* validate_recovery */ + "Validating update image", /* validate_update */ + "Recovery image created", /* recovery_created */ + "Recovery image invalid, update stopped", /* recovery_invalid */ + "Update failed", /* update_failed */ +}; +#endif + +/**************************************************************************** + * Private Functions + ****************************************************************************/ + /**************************************************************************** * Public Functions ****************************************************************************/ +/**************************************************************************** + * Name: nxboot_progress + * + * Description: + * If enabled, thos function prints progress messages to stdout. + * Messages are handled via integer enums, allowing this function to be + * easily replaced if required with no changes needed to the underlying + * code + * + ****************************************************************************/ + +void nxboot_progress(enum progress_type_e type, ...) +{ +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS + va_list args; + + va_start(args, type); + + switch (type) + { + case nxboot_info: + { + int idx = va_arg(args, int); + const char *msg = g_progress_txt[idx]; + dprintf(STDOUT_FILENO, "%s\n", msg); + } + break; + case nxboot_error: + { + int idx = va_arg(args, int); + const char *msg = g_progress_txt[idx]; + dprintf(STDOUT_FILENO, "ERROR: %s\n", msg); + } + break; + case nxboot_progress_start: + { + int idx = va_arg(args, int); + const char *msg = g_progress_txt[idx]; + dprintf(STDOUT_FILENO, "%s", msg); + progress_dots_started = true; + } + break; + case nxboot_progress_dot: + { + assert(progress_dots_started); + if (!progress_dots_started) + { + printf("Progress dot requested " + "but no previous progress start\n"); + } + else + { + dprintf(STDOUT_FILENO, "."); + } + } + break; + case nxboot_progress_end: + { + assert(progress_dots_started == false); + if (!progress_dots_started) + { + printf("Progress dot stop requested " + "but no previous progress start\n"); + } + else + { + dprintf(STDOUT_FILENO, "\n"); + } + + progress_dots_started = false; + } + break; + default: + { + assert(false); + dprintf(STDOUT_FILENO, "progress: unknown type!\n"); + } + break; + } + + va_end(args); +#endif /* CONFIG_NXBOOT_PRINTF_PROGRESS */ +} + /**************************************************************************** * Name: nxboot_main * * Description: - * NuttX bootlaoder entry point. + * NuttX bootloader entry point. * ****************************************************************************/ int main(int argc, FAR char *argv[]) { + int ret; struct boardioc_boot_info_s info; bool check_only; #ifdef CONFIG_NXBOOT_SWRESET_ONLY - int ret; FAR struct boardioc_reset_cause_s cause; #endif @@ -66,6 +188,7 @@ int main(int argc, FAR char *argv[]) #endif syslog(LOG_INFO, "*** nxboot ***\n"); + nxboot_progress(nxboot_info, startup_msg); #ifdef CONFIG_NXBOOT_SWRESET_ONLY check_only = true; @@ -77,10 +200,12 @@ int main(int argc, FAR char *argv[]) cause.cause == BOARDIOC_RESETCAUSE_PIN) { check_only = false; + nxboot_progress(nxboot_info, soft_reset); } else { syslog(LOG_INFO, "Power reset detected, performing check only.\n"); + nxboot_progress(nxboot_info, power_reset); } } #else @@ -90,15 +215,29 @@ int main(int argc, FAR char *argv[]) if (nxboot_perform_update(check_only) < 0) { syslog(LOG_ERR, "Could not find bootable image.\n"); - return 0; + nxboot_progress(nxboot_error, no_bootable_image); + return OK; } syslog(LOG_INFO, "Found bootable image, boot from primary.\n"); + nxboot_progress(nxboot_info, found_bootable_image); + +#ifdef CONFIG_NXBOOT_COPY_TO_RAM + syslog(LOG_INFO, "Copying image to RAM.\n"); + nxboot_ramcopy(); +#endif /* Call board specific image boot */ info.path = CONFIG_NXBOOT_PRIMARY_SLOT_PATH; info.header_size = CONFIG_NXBOOT_HEADER_SIZE; - return boardctl(BOARDIOC_BOOT_IMAGE, (uintptr_t)&info); + ret = boardctl(BOARDIOC_BOOT_IMAGE, (uintptr_t)&info); + + /* Only get here if the board boot fails */ + + nxboot_progress(nxboot_error, boardioc_image_boot_fail); + + return ret; } + From cb60545c833d38e998b01fba39b3cfefb9b3565d Mon Sep 17 00:00:00 2001 From: Tim Hardisty <56726697+TimJTi@users.noreply.github.com> Date: Thu, 15 May 2025 12:30:35 +0100 Subject: [PATCH 2/2] Ready for another review --- boot/nxboot/Kconfig | 19 ++++- boot/nxboot/include/nxboot.h | 13 +-- boot/nxboot/loader/boot.c | 22 ++++++ boot/nxboot/nxboot_main.c | 149 +++++++++++++++++++++++++++-------- 4 files changed, 164 insertions(+), 39 deletions(-) diff --git a/boot/nxboot/Kconfig b/boot/nxboot/Kconfig index 4f294d0758e..50d1da9012c 100644 --- a/boot/nxboot/Kconfig +++ b/boot/nxboot/Kconfig @@ -126,7 +126,24 @@ config NXBOOT_PRINTF_PROGRESS bool "Enable progress messages to be sent to STDOUT" default y ---help--- - Note: the NXboot binary will be approximately 1.5KiB larger with this enabled. + This will display progress during typically lengthy operations: + - Calculating checksums + - copying images between slots + + Note: the NXboot binary will be approximately 2KiB larger with this enabled. + +choice + prompt "Choose preferred progress indication type" + depends on NXBOOT_PRINTF_PROGRESS + default NXBOOT_PRINTF_PROGRESS_PERCENT + +config NXBOOT_PRINTF_PROGRESS_DOTS + bool "Display progress using sequential dots" + +config NXBOOT_PRINTF_PROGRESS_PERCENT + bool "Display progress using percentage remaining" + +endchoice endif # NXBOOT_BOOTLOADER diff --git a/boot/nxboot/include/nxboot.h b/boot/nxboot/include/nxboot.h index 1c2c7b22dba..6c4a89b3257 100644 --- a/boot/nxboot/include/nxboot.h +++ b/boot/nxboot/include/nxboot.h @@ -35,6 +35,8 @@ * Pre-processor Definitions ****************************************************************************/ +#define ERROR -1 + #define NXBOOT_PRIMARY_SLOT_NUM (0) #define NXBOOT_SECONDARY_SLOT_NUM (1) #define NXBOOT_TERTIARY_SLOT_NUM (2) @@ -134,11 +136,12 @@ struct nxboot_state enum progress_type_e { - nxboot_info = 0, /* Prefixes arg. string with "INFO:" */ - nxboot_error, /* Prefixes arg. string with "ERR:" */ - nxboot_progress_start, /* Prints arg. string with no newline to allow ..... sequence to follow */ - nxboot_progress_dot, /* Prints of a "." to the ..... progress sequence */ - nxboot_progress_end, /* Flags end of a "..." progrees sequence and prints newline */ + nxboot_info = 0, /* Prefixes arg. string with "INFO:" */ + nxboot_error, /* Prefixes arg. string with "ERR:" */ + nxboot_progress_start, /* Prints arg. string with no newline to allow ..... sequence to follow */ + nxboot_progress_dot, /* Prints of a "." to the ..... progress sequence */ + nxboot_progress_percent, /* Displays progress as % remaining */ + nxboot_progress_end, /* Flags end of a "..." progrees sequence and prints newline */ }; enum progress_msg_e diff --git a/boot/nxboot/loader/boot.c b/boot/nxboot/loader/boot.c index 4a330840026..9364ba16f94 100644 --- a/boot/nxboot/loader/boot.c +++ b/boot/nxboot/loader/boot.c @@ -79,6 +79,9 @@ static uint32_t calculate_crc(int fd, struct nxboot_img_header *header) off_t off; uint32_t crc; struct flash_partition_info info; +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + int total_size; +#endif if (flash_partition_info(fd, &info) < 0) { @@ -94,6 +97,9 @@ static uint32_t calculate_crc(int fd, struct nxboot_img_header *header) crc = 0xffffffff; off = offsetof(struct nxboot_img_header, crc) + sizeof crc; remain = header->size + header->header_size - off; +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + total_size = remain; +#endif while (remain > 0) { readsiz = remain > info.blocksize ? info.blocksize : remain; @@ -108,7 +114,12 @@ static uint32_t calculate_crc(int fd, struct nxboot_img_header *header) crc = crc32part((uint8_t *)buf, readsiz, crc); if ((remain % 25) == 0) { +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + nxboot_progress(nxboot_progress_percent, + ((total_size - remain) * 100) / total_size); +#else nxboot_progress(nxboot_progress_dot); +#endif } } @@ -128,6 +139,9 @@ static int copy_partition(int from, int where, struct nxboot_state *state, int blocksize; off_t off; char *buf; +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + int total_size; +#endif get_image_header(from, &header); @@ -147,6 +161,9 @@ static int copy_partition(int from, int where, struct nxboot_state *state, return ERROR; } +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + total_size = remain * 100; +#endif blocksize = MAX(info_from.blocksize, info_where.blocksize); buf = malloc(blocksize); @@ -208,7 +225,12 @@ static int copy_partition(int from, int where, struct nxboot_state *state, remain -= readsiz; if ((remain % 25) == 0) { +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + nxboot_progress(nxboot_progress_percent, + ((total_size - remain) * 100) / total_size); +#else nxboot_progress(nxboot_progress_dot); +#endif } } diff --git a/boot/nxboot/nxboot_main.c b/boot/nxboot/nxboot_main.c index 388fe5bf96f..fe30f3b5efa 100644 --- a/boot/nxboot/nxboot_main.c +++ b/boot/nxboot/nxboot_main.c @@ -28,48 +28,86 @@ #include #include +#include +#include #include #include +/**************************************************************************** + * Private Types + ****************************************************************************/ + +typedef struct progress_msgs_s +{ + enum progress_msg_e idx; /* Index to the message */ + const char *msg; /* Corresponsing text message */ +} progress_msgs_t; + /**************************************************************************** * Public Data ****************************************************************************/ bool progress_dots_started = false; +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT +bool progress_percent_started = false; +#endif /**************************************************************************** * Private Data ****************************************************************************/ #ifdef CONFIG_NXBOOT_PRINTF_PROGRESS -static const char *g_progress_txt[] = + +# ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT +static const char backtab[] = { - /* Text that will be printed ...from... enum progress_msg_e */ - - "*** nxboot ***", /* startup_msg */ - "Power Reset detected, check images only", /* power_reset */ - "Soft reset detected, check for update", /* soft_reset */ - "Found bootable image, boot from primary", /* found_bootable_image */ - "No bootable image found", /* no_bootable_image */ - "Board failed to boot bootable image", /* boardioc_image_boot_fail */ - "Copying bootable image to RAM", /* ramcopy_started */ - "Reverting image to recovery", /* recovery_revert */ - "Creating recovery image", /* recovery_create */ - "Updating from update image", /* update_from_update */ - "Validating primary image", /* validate_primary */ - "Validating recovery image", /* validate_recovery */ - "Validating update image", /* validate_update */ - "Recovery image created", /* recovery_created */ - "Recovery image invalid, update stopped", /* recovery_invalid */ - "Update failed", /* update_failed */ + ASCII_BS, ASCII_BS, ASCII_BS, ASCII_BS, '\0', }; -#endif +# endif + +static const progress_msgs_t progress_msgs[] = + { + {startup_msg, "*** nxboot ***"}, + {power_reset, "Power Reset detected, check images only"}, + {soft_reset, "Soft reset detected, check for update"}, + {found_bootable_image, "Found bootable image, boot from primary"}, + {no_bootable_image, "No bootable image found"}, + {boardioc_image_boot_fail, "Board failed to boot bootable image"}, + {ramcopy_started, "Copying bootable image to RAM"}, + {recovery_revert, "Reverting image to recovery"}, + {recovery_create, "Creating recovery image"}, + {update_from_update, "Updating from update image"}, + {validate_primary, "Validating primary image"}, + {validate_recovery, "Validating recovery image"}, + {validate_update, "Validating update image"}, + {recovery_created, "Recovery image created"}, + {recovery_invalid, "Recovery image invalid, update stopped"}, + {update_failed, "Update failed"}, + {(-1), NULL}, + }; +#endif /* CONFIG_NXBOOT_PRINTF_PROGRESS */ + +/**************************************************************************** + * Private Function Prototypes + ****************************************************************************/ + +const char *get_msg(enum progress_msg_e idx, const progress_msgs_t *txt); /**************************************************************************** * Private Functions ****************************************************************************/ +const char *get_msg(enum progress_msg_e idx, const progress_msgs_t *msg) +{ + while (msg->idx != idx && msg->msg != NULL) + { + msg++; + } + + return msg->msg; +} + /**************************************************************************** * Public Functions ****************************************************************************/ @@ -78,41 +116,56 @@ static const char *g_progress_txt[] = * Name: nxboot_progress * * Description: - * If enabled, thos function prints progress messages to stdout. + * If enabled, this function prints progress messages to stdout. * Messages are handled via integer enums, allowing this function to be * easily replaced if required with no changes needed to the underlying * code * + * Input Parameters: + * type - the progress message type to be printed, as per progress_type_e: + * - nxboot_info: Prefixes arg. string with "INFO:" + * - nxboot_error: Prefixes arg. string with "ERR:" + * - nxboot_progress_start: Prints arg. string with no newline + * to allow a ..... sequence + * or % remaining to follow + * - nxboot_progress_dot: Prints a "." to the ..... sequence + * - nxboot_progress_percent: Displays progress as % remaining + * - nxboot_progress_end, Flags end of a progrees sequence + * + * ... - variadic argument: + * - the enum (int) reference to the message string or + * - the % remaining in the case of type: nxboot_progress_percent + * + * Returned Value: + * None + * ****************************************************************************/ void nxboot_progress(enum progress_type_e type, ...) { #ifdef CONFIG_NXBOOT_PRINTF_PROGRESS - va_list args; + va_list arg; - va_start(args, type); + va_start(arg, type); switch (type) { case nxboot_info: { - int idx = va_arg(args, int); - const char *msg = g_progress_txt[idx]; - dprintf(STDOUT_FILENO, "%s\n", msg); + int idx = va_arg(arg, int); + dprintf(STDOUT_FILENO, "%s\n", get_msg(idx, progress_msgs)); } break; case nxboot_error: { - int idx = va_arg(args, int); - const char *msg = g_progress_txt[idx]; - dprintf(STDOUT_FILENO, "ERROR: %s\n", msg); + int idx = va_arg(arg, int); + dprintf(STDOUT_FILENO, "ERROR: %s\n", get_msg(idx, progress_msgs)); } break; case nxboot_progress_start: { - int idx = va_arg(args, int); - const char *msg = g_progress_txt[idx]; - dprintf(STDOUT_FILENO, "%s", msg); + int idx = va_arg(arg, int); + dprintf(STDOUT_FILENO, "%s", get_msg(idx, progress_msgs)); progress_dots_started = true; } break; @@ -130,6 +183,33 @@ void nxboot_progress(enum progress_type_e type, ...) } } break; +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + case nxboot_progress_percent: + { + assert(progress_dots_started); + if (!progress_dots_started) + { + printf("Progress percent requested " + "but no previous progress start\n"); + } + else + { + int percent = va_arg(arg, int); + if (!progress_percent_started) + { + progress_percent_started = true; + dprintf(STDOUT_FILENO, ": "); + } + else + { + dprintf(STDOUT_FILENO, "%s", backtab); + } + + dprintf(STDOUT_FILENO, "%3d%%", MIN(percent, 100)); + } + } + break; +#endif case nxboot_progress_end: { assert(progress_dots_started == false); @@ -144,6 +224,9 @@ void nxboot_progress(enum progress_type_e type, ...) } progress_dots_started = false; +#ifdef CONFIG_NXBOOT_PRINTF_PROGRESS_PERCENT + progress_percent_started = false; +#endif } break; default: @@ -154,7 +237,7 @@ void nxboot_progress(enum progress_type_e type, ...) break; } - va_end(args); + va_end(arg); #endif /* CONFIG_NXBOOT_PRINTF_PROGRESS */ }