Skip to content

Commit

Permalink
boot: Overhaul of boot code
Browse files Browse the repository at this point in the history
This makes the boot code more modular, it's even possible to completley
disable the core boot protocol through Kconfig and insert a custom
version.

The new boot code is split in four different modules
 - boot/boot.c          - Core boot functionallity
 - boot/ab_state.c      - Optional A/B state, rollback logic
 - boot/linux.c         - Linux specific helpers (dtb, ramdisk etc)
 - boot/image_helpers.c - BPAK image helpers

This is also one step in the right direction when it comes to
abstracting the boot image format. In the future it should be possible
to use something other than BPAK files for booting. This is however a
larger change that affects the tooling as well.
  • Loading branch information
jonasblixt committed Mar 22, 2023
1 parent 4723437 commit 92921ee
Show file tree
Hide file tree
Showing 24 changed files with 1,669 additions and 1,323 deletions.
1 change: 0 additions & 1 deletion Makefile
Expand Up @@ -74,7 +74,6 @@ cflags-y += -Waggregate-return

# Bootloader
src-y = src/main.c
src-y += src/boot.c
src-y += keystore.c
src-y += src/delay.c
src-$(CONFIG_ENABLE_TIMESTAMPING) += src/timestamp.c
Expand Down
84 changes: 84 additions & 0 deletions include/boot/ab_state.h
@@ -0,0 +1,84 @@
/**
* Punch BOOT
*
* Copyright (C) 2023 Jonas Blixt <jonpe960@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
* This module provides a block io backed state for A/B partition selection
* and rollback logic.
*
*
*/

#include <uuid.h>
#include <drivers/block/bio.h>

enum ab_rollback_mode
{
AB_ROLLBACK_MODE_NORMAL,
AB_ROLLBACK_MODE_SPECULATIVE,
};

struct boot_ab_state_config
{
const unsigned char *primary_state_part_uu;
const unsigned char *backup_state_part_uu;
const unsigned char *sys_a_uu;
const unsigned char *sys_b_uu;
enum ab_rollback_mode rollback_mode;
};

/**
* Initialize the module
*
* @param[in] cfg Module configuration
*
* @return PB_OK on success
* -PB_ERR_PARAM, bad block device UUID's
* -PB_ERR_IO, on read/write errors
* -PB_ERR_NOT_FOUND, when can't partitions can't be found
*/
int boot_ab_state_init(const struct boot_ab_state_config *cfg);

/**
* Compute which block device that should be used for booting.
* This advances the boot counters if needed and may trigger rollback
* on un-verified partitions.
*
* @return A valid block device on success,
* -PB_ERR_PARAM, bad block device UUID's
* -PB_ERR_IO, on read/write errors
* -PB_ERR_NOT_FOUND, when can't partitions can't be found
*/
bio_dev_t boot_ab_state_get(void);

/**
* For partition 'part_uu' to be active and verified.
*
* @param[in] part_uu Partition to activate
*
* @return PB_OK on success,
* -PB_ERR_PARAM, bad block device UUID's
* -PB_ERR_IO, on read/write errors
* -PB_ERR_NOT_FOUND, when can't partitions can't be found
*/
int boot_ab_state_set_boot_partition(uuid_t part_uu);

/**
* Get current active boot partition
*
* @param[out] part_uu Active partition or empty UUID
*/
void boot_ab_state_get_boot_partition(uuid_t part_uu);

/**
* Returns textual representation of 'part_uu' partition
*
* @param[in] part_uu Partition UUID to translate
*
* @return "A", when System A is active
* "B", when System B is active
* "?", All other states
*/
const char *boot_ab_part_uu_to_name(uuid_t part_uu);
154 changes: 154 additions & 0 deletions include/boot/boot.h
@@ -0,0 +1,154 @@
/**
* Punch BOOT
*
* Copyright (C) 2023 Jonas Blixt <jonpe960@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/

#ifndef INCLUDE_BOOT_H
#define INCLUDE_BOOT_H

#include <pb/utils.h>
#include <uuid.h>
#include <bpak/bpak.h>
#include <drivers/block/bio.h>

/* TODO: Write a note about the bpak block size of 512 bytes */
typedef int (*boot_read_cb_t)(int block_offset, size_t length, uintptr_t buf);
typedef int (*boot_result_cb_t)(int result);

/** Boot sources */
enum boot_source {
BOOT_SOURCE_INVALID = 0, /*!< Invalid boot mode */
BOOT_SOURCE_BIO, /*!< Load from block device */
BOOT_SOURCE_IN_MEM, /*!< Authenticate and verify a pre-loaded image */
BOOT_SOURCE_CB, /*!< Load through callback functions */
BOOT_SOURCE_END,
};

/**
* Boot flags
*
* \def BOOT_FLAG_CMD
* Set when boot was initiated through the command mode interface.
*
* \def BOOT_FLAG_VERBOSE
* Set to 1 to request verbose output during boot
*
*/
#define BOOT_FLAG_CMD BIT(0)
#define BOOT_FLAG_VERBOSE BIT(1)

struct boot_driver
{
enum boot_source default_boot_source;
int (*early_boot_cb)(void);
bio_dev_t (*get_boot_bio_device)(void);
int (*set_boot_partition)(uuid_t part_uu);
void (*get_boot_partition)(uuid_t part_uu);
int (*get_in_mem_image)(struct bpak_header **header);
int (*prepare)(struct bpak_header *header, uuid_t boot_part_uu);
int (*late_boot_cb)(struct bpak_header *header, uuid_t boot_part_uu);
void (*jump)(void);
};

/**
* Initializes the boot module
*
* @param[in] driver Configuration input
*
* @return PB_OK on success
* -PB_ERR_PARAM on invalid configuration
*/
int boot_init(const struct boot_driver *driver);

/**
* Configure boot source
*
* @param[in] source Boot source
*
* @return PB_OK on success
* -PB_ERR_PARAM on invalid boot source
*
*/
int boot_set_source(enum boot_source source);

/**
* Configure read/result callbacks for boot source: 'BOOT_SOURCE_CB'
*
* When the boot source is set to 'BOOT_SOURCE_CB' the boot module
* will call these functions in the following order
*
* 1. read_f(-4096, 4096) To read the BPAK header
* 2. result_f with the result from the header validation/authenticatoin
* 3. read_f(<offset>, <chunk sz>) Repetedly to transfer chunks of parts
* 4. result_f When the chunked transfer of one part is complete
*
* Steps 3 and 4 are repeted until all parts are transfered
*
* 5. result_f When payload has been verified
*
* @param[in] read_f Read function callback
* @param[in] result_f Optional result function callback
*
*/
void boot_configure_load_cb(boot_read_cb_t read_f,
boot_result_cb_t result_f);

/**
* Clear and/or Set flags
*
* These bits are available through out the boot flow and can control
* board specific behaviour.
*
* The lower 16 bit's are reserved for punchboot and the upper 16 bit's
* can be used by board code.
*
* @param[in] clear Bit flags to clear
* @param[in] set Bit flags to set
*
*/
void boot_clear_set_flags(uint32_t clear, uint32_t set);

/**
* Read current boot flags
*
* @return Current boot flags
*/
uint32_t boot_get_flags(void);

/**
* Proxy function to set/activate a boot partition. This function will
* call the 'set_boot_partition' callback in the config struct if it's
* populated.
*
* @param[in] part_uu UUID of partition to set as active
*
* @return PB_OK on success all other codes are errors
*/
int boot_set_boot_partition(uuid_t part_uu);

/**
* Proxy function to get active boot partition. This function will
* call the 'get_boot_partition' callback in the config struct if it's
* populated.
*
* @param[out] part_uu UUID of active partition
*
* @return PB_OK on success all other codes are errors
*/
void boot_get_boot_partition(uuid_t part_uu);

/**
* Boot the system
*
* @param[in] boot_part_override_uu Optional partition UUID to boot.
* Set this to NULL for default behaviour.
*
* @return This function will not return if successful
*/
int boot(uuid_t boot_part_override_uu);

#endif
44 changes: 44 additions & 0 deletions include/boot/image_helpers.h
@@ -0,0 +1,44 @@
/**
* Punch BOOT
*
* Copyright (C) 2023 Jonas Blixt <jonpe960@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/

#ifndef INCLUDE_BOOT_IMAGE_H
#define INCLUDE_BOOT_IMAGE_H

#include <bpak/bpak.h>
#include <boot/boot.h>

/**
* Authenticate a BPAK header
*
* This function will verify the signature of the supplied bpak header
*
* @param[in] hdr Pointer to header that should be verified
*
* @return PB_OK, on verification success
* -PB_ERR_BAD_HEADER, on bad header magic
* -PB_ERR_BAD_KEYSTORE, if keystore is invalid or unavailable
* -PB_ERR_KEY_NOT_FOUND, if the key id in the header is not found
* -PB_ERR_KEY_REVOKED, if key has been revoked
* -PB_ERR_UNKNOWN_HASH, Unknown hash
* -PB_ERR_MEM, If signature data is too large
* -PB_ERR_SIGNATURE, on signature verification failure
*/
int boot_image_auth_header(struct bpak_header *hdr);

int boot_image_load_and_hash(struct bpak_header *hdr,
size_t load_chunk_size,
boot_read_cb_t read_f,
boot_result_cb_t result_f,
uint8_t *payload_digest,
size_t payload_digest_size);

int boot_image_verify_payload(struct bpak_header *hdr,
uint8_t *payload_digest);

#endif
28 changes: 28 additions & 0 deletions include/boot/linux.h
@@ -0,0 +1,28 @@
/**
* Punch BOOT
*
* Copyright (C) 2023 Jonas Blixt <jonpe960@gmail.com>
*
* SPDX-License-Identifier: BSD-3-Clause
*
*/

#include <uuid.h>
#include <boot/boot.h>
#include <bpak/bpak.h>

typedef int (*boot_patch_dtb_cb_t) (void *fdt, int offset);

struct boot_driver_linux_config
{
bpak_id_t image_bpak_id; /*!< BPAK id of bootable part */
bpak_id_t dtb_bpak_id; /*!< Optional BPAK id of a device tree part */
bpak_id_t ramdisk_bpak_id; /*!< Optional BPAK id of a ramdisk part */
boot_patch_dtb_cb_t dtb_patch_cb; /*!< Optional DTB patch callback */
const char *(*resolve_part_name)(uuid_t part_uu);
bool set_dtb_boot_arg; /*!< Pass dtb address as first argument */
};

int boot_driver_linux_init(const struct boot_driver_linux_config *cfg);
int boot_driver_linux_prepare(struct bpak_header *hdr, uuid_t boot_part_uu);
void boot_driver_linux_jump(void);
9 changes: 0 additions & 9 deletions include/pb/board.h
Expand Up @@ -13,7 +13,6 @@
#include <stdint.h>
#include <stdbool.h>
#include <stddef.h>
#include <pb/boot.h>
/**
* Function: board_early_init
*
Expand All @@ -23,7 +22,6 @@
*/

int board_early_init(void *plat);
bool board_force_command_mode(void *plat);

int board_command(void *plat,
uint32_t command,
Expand All @@ -42,11 +40,4 @@ int board_command_mode_auth(char *password, size_t length);
const char *board_name(void);
void board_command_mode_enter(void);

/**
* All boards must implement this function to configure punchboots boot logic
*
* @return A pointer to the configuration struct for the boot logic
*/
const struct pb_boot_config * board_boot_config(void);

#endif // INCLUDE_PB_BOARD_H_

0 comments on commit 92921ee

Please sign in to comment.