[RFC PATCH v2 2/2] board: ad401: example of fastboot oem board realization
Mattijs Korpershoek
mkorpershoek at baylibre.com
Thu Feb 15 10:24:11 CET 2024
On jeu., févr. 01, 2024 at 12:20, Alexey Romanov <avromanov at salutedevices.com> wrote:
> An example of how we use fastboot oeam board subcommand
> for Sean Anderson.
>
> 1 - OEM_BOARD_WRITE_BOOTLOADER_CMD:
>
> We use it for custom Amlogic bootloader + tpl
> flashing protocol.
>
> 2 - OEM_BOARD_ERASE_CMD:
>
> Custom logic for erasing the env-emulated partition,
> which isn't in the mtd markup map.
>
> Example of the script which completely flashes the device:
>
> $ fastboot erase bootloader
> $ fastboot stage u-boot.bin
> $ fastboot oem board:write_bootloader
> $ fastboot reboot-bootloader
> $ fastboot oem board:erase_env
> $ fastboot erase misc
> $ fastboot erase super
> $ fastboot flash super rootfs
> $ fastboot reboot
>
> Signed-off-by: Alexey Romanov <avromanov at salutedevices.com>
> ---
> board/amlogic/ad401/fastboot.c | 222 +++++++++++++++++++++++++++++++++
> 1 file changed, 222 insertions(+)
> create mode 100644 board/amlogic/ad401/fastboot.c
>
> diff --git a/board/amlogic/ad401/fastboot.c b/board/amlogic/ad401/fastboot.c
> new file mode 100644
> index 0000000000..01da8efa5b
> --- /dev/null
> +++ b/board/amlogic/ad401/fastboot.c
> @@ -0,0 +1,222 @@
> +// SPDX-License-Identifier: GPL-2.0+
> +/*
> + * (C) Copyright 2023 SaluteDevices, Inc.
> + */
> +
> +#include <common.h>
> +#include <env.h>
> +#include <fastboot.h>
> +#include <nand.h>
> +#include <asm/arch/nand.h>
> +#include <jffs2/load_kernel.h>
> +#include <linux/sizes.h>
> +#include <linux/types.h>
> +#include <linux/mtd/mtd.h>
> +
> +enum {
> + OEM_BOARD_ERASE_CMD,
> + OEM_BOARD_WRITE_BOOTLOADER_CMD,
> +};
> +
> +struct defenv {
> + char *name;
> + char value[256];
> +};
> +
> +static void save_defenv(struct defenv *e, size_t cnt)
> +{
> + int i;
> +
> + for (i = 0; i < cnt; i++) {
> + const char *env_val = env_get(e[i].name);
> +
> + if (env_val)
> + strlcpy(e[i].value, env_val, sizeof(e[i].value));
> + else
> + e[i].value[0] = '\0';
> + }
> +}
> +
> +static void set_defenv(struct defenv *e, size_t cnt)
> +{
> + int i;
> +
> + for (i = 0; i < cnt; i++)
> + env_set(e[i].name, e[i].value);
> +}
> +
> +static int fastboot_erase_env(void)
> +{
> + char *const defenv_names[] = { "lock", "mtdparts", "mtdids" };
> + struct defenv env[ARRAY_SIZE(defenv_names)];
> + int err, i;
> +
> + for (i = 0; i < ARRAY_SIZE(env); i++)
> + env[i].name = defenv_names[i];
> +
> + printf("ENV is being erased...\n");
> +
> + /*
> + * Reset environment to the default, excluding 'lock' variable,
> + * because it reflects the fastboot's state after execution of
> + * 'flashing unlock' command, hence it must survive the env-erasing.
> + * Otherwise, further erase commands will fail on check_lock().
> + *
> + * Also, we have to save 'mtdparts' and 'mtdids' variables
> + * because they are necessary to obtain partition map.
> + */
> +
> + save_defenv(env, ARRAY_SIZE(env));
> + env_set_default(NULL, 0);
> + set_defenv(env, ARRAY_SIZE(env));
> +
> + err = env_save();
> + if (err) {
> + pr_err("Can't overwrite ENV-partition\n");
> + return err;
> + }
Hmm so the fastboot locked state is saved in the U-Boot environment.
There is probably a good reason for this (no secure storage for
example). But this does not feel board specific.
Wouldn't it be better if we could just run "fastboot erase bootenv" and
that the generic fastboot code does the right thing?
(which is env default, and ignoring some magic/specific variables)
> +
> + return 0;
> +}
> +
> +static int fastboot_nand_write_tpl(struct mtd_info *mtd, void *buffer,
> + u32 offset, size_t size, int flags)
> +{
> + int boot_cpy_num = meson_bootloader_copy_num(BOOT_TPL);
> + u64 size_per_copy = meson_bootloader_copy_size(mtd, BOOT_TPL);
> + int i;
> +
> + for (i = 0; i < boot_cpy_num; i++) {
> + size_t retlen, len = size;
> + int ret;
> +
> + ret = nand_write_skip_bad(mtd, offset + (i * size_per_copy),
> + &len, &retlen, offset + size_per_copy,
> + buffer, flags);
> + if (ret)
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +static int fastboot_nand_write_bl2(struct mtd_info *mtd, void *buffer,
> + u32 offset, size_t size, int flags)
> +{
> + int boot_cpy_num = meson_bootloader_copy_num(BOOT_BL2);
> + u64 size_per_copy = meson_bootloader_copy_size(mtd, BOOT_BL2);
> + int i;
> +
> + for (i = 0; i < boot_cpy_num; i++) {
> + int ret;
> +
> + ret = meson_bootloader_write_bl2(mtd, buffer,
> + offset + (i * size_per_copy),
> + size, flags);
> + if (ret)
> + return ret;
> + }
> +
> + return meson_bootloader_write_info_pages();
> +}
> +
> +static int fastboot_nand_write_bootloader(void *buffer, u32 size)
> +{
> + struct part_info *part;
> + struct mtd_info *mtd = NULL;
> + struct mtd_device *dev;
> + u8 pnum;
> + int ret;
> +
> + if (size < BL2_SIZE)
> + return 0;
> +
> + if (!buffer)
> + return -EINVAL;
> +
> + ret = mtdparts_init();
> + if (ret) {
> + pr_err("Cannot initialize MTD partitions\n");
> + return ret;
> + }
> +
> + ret = find_dev_and_part("bootloader", &dev, &pnum, &part);
> + if (ret) {
> + pr_err("cannot find 'bootloader' partition\n");
> + return ret;
> + }
> +
> + mtd = get_nand_dev_by_index(dev->id->num);
> + if (!mtd)
> + return -EINVAL;
> +
> + ret = fastboot_nand_write_bl2(mtd, buffer, part->offset,
> + BL2_SIZE, WITH_WR_VERIFY);
> + if (ret) {
> + pr_err("fastboot: failed to write BL2\n");
> + return ret;
> + }
> +
> + ret = find_dev_and_part("tpl", &dev, &pnum, &part);
> + if (ret) {
> + pr_err("cannot find 'bootloader' partition\n");
> + return ret;
> + }
> +
> + mtd = get_nand_dev_by_index(dev->id->num);
> + if (!mtd)
> + return -EINVAL;
> +
> + ret = fastboot_nand_write_tpl(mtd, buffer + BL2_SIZE, part->offset,
> + size - BL2_SIZE, WITH_WR_VERIFY);
> + if (ret) {
> + pr_err("fastboot: failed to write TPL\n");
> + return ret;
> + }
> +
> + return 0;
> +}
> +
> +int get_oem_board_command(const char *cmd)
> +{
> + const char *oem_commands[] = {
> + [OEM_BOARD_ERASE_CMD] = "erase_env",
> + [OEM_BOARD_WRITE_BOOTLOADER_CMD] = "write_bootloader",
> + };
> + int i;
> +
> + for (i = 0; i < ARRAY_SIZE(oem_commands); i++)
> + if (!strcmp(cmd, oem_commands[i]))
> + return i;
> +
> + return -EINVAL;
> +}
> +
> +void fastboot_oem_board(const char *cmd_parameter, void *data, u32 size,
> + char *response)
> +{
> + char buf[128] = { 0 };
> + int ret, cmd;
> +
> + cmd = get_oem_board_command(cmd_parameter);
> +
> + switch (cmd) {
> + case OEM_BOARD_ERASE_CMD:
> + ret = fastboot_erase_env();
> + break;
> + case OEM_BOARD_WRITE_BOOTLOADER_CMD:
> + ret = fastboot_nand_write_bootloader(data, size);
> + break;
> + default:
> + snprintf(buf, sizeof(buf),
> + "Command 'oem board %s' not supported",
> + cmd_parameter);
> + fastboot_fail(buf, response);
> + return;
> + }
> +
> + if (ret < 0)
> + fastboot_fail("Failed to erase env partition", response);
> + else
> + fastboot_okay(NULL, response);
> +}
> --
> 2.30.1
More information about the U-Boot
mailing list