diff mbox series

[RFC,v2,2/2] board: ad401: example of fastboot oem board realization

Message ID 20240201092027.6258-3-avromanov@salutedevices.com
State RFC
Delegated to: Mattijs Korpershoek
Headers show
Series Introduce fastboot oem board command | expand

Commit Message

Alexey Romanov Feb. 1, 2024, 9:20 a.m. UTC
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@salutedevices.com>
---
 board/amlogic/ad401/fastboot.c | 222 +++++++++++++++++++++++++++++++++
 1 file changed, 222 insertions(+)
 create mode 100644 board/amlogic/ad401/fastboot.c

Comments

Dan Carpenter Feb. 1, 2024, 1:56 p.m. UTC | #1
On Thu, Feb 01, 2024 at 12:20:27PM +0300, Alexey Romanov wrote:
> +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,
                                                         ^^^^^^^^^^^^^^^^^^^^^^
Sorry if I'm missing something obvious, but why is the limit
"offset + size_per_copy"?  I would have expected it to be just
"size_per_copy" or maybe some kind of limit minus the offset...

> +					  buffer, flags);
> +		if (ret)
> +			return ret;
> +	}
> +
> +	return 0;
> +}

regards,
dan carpenter
Alexey Romanov Feb. 1, 2024, 2:54 p.m. UTC | #2
Hi,

On Thu, Feb 01, 2024 at 04:56:34PM +0300, Dan Carpenter wrote:
> On Thu, Feb 01, 2024 at 12:20:27PM +0300, Alexey Romanov wrote:
> > +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,
>                                                          ^^^^^^^^^^^^^^^^^^^^^^
> Sorry if I'm missing something obvious, but why is the limit
> "offset + size_per_copy"?  I would have expected it to be just
> "size_per_copy" or maybe some kind of limit minus the offset...

Yeah, this is incorrect. Should be size_per_copy. 

But this patch is just an example of realization.

> 
> > +					  buffer, flags);
> > +		if (ret)
> > +			return ret;
> > +	}
> > +
> > +	return 0;
> > +}
> 
> regards,
> dan carpenter
>
Mattijs Korpershoek Feb. 15, 2024, 9:24 a.m. UTC | #3
On jeu., févr. 01, 2024 at 12:20, Alexey Romanov <avromanov@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@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
Alexey Romanov March 4, 2024, 2:03 p.m. UTC | #4
Hello Mattijs,

On Thu, Feb 15, 2024 at 10:24:11AM +0100, Mattijs Korpershoek wrote:
> On jeu., f'evr. 01, 2024 at 12:20, Alexey Romanov <avromanov@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@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?

Are you proposing to modify the code of fastboot in such a way
that if user send 'erase bootenv' string, then we call generic
function to cleanup environment, instead of try to search (and erase)
in partition schema 'bootenv' partition?

> (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
Mattijs Korpershoek April 5, 2024, 9:02 a.m. UTC | #5
Hi Alexey,

On lun., mars 04, 2024 at 14:03, Alexey Romanov <avromanov@salutedevices.com> wrote:

> Hello Mattijs,
>
> On Thu, Feb 15, 2024 at 10:24:11AM +0100, Mattijs Korpershoek wrote:
>> On jeu., f'evr. 01, 2024 at 12:20, Alexey Romanov <avromanov@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@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?
>
> Are you proposing to modify the code of fastboot in such a way
> that if user send 'erase bootenv' string, then we call generic
> function to cleanup environment, instead of try to search (and erase)
> in partition schema 'bootenv' partition?

I would have liked to have a generic "erase bootenv" command yes, but
your solution seems fine so no need to do something different.

Thank you for your patience with this !

>
>> (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
>
> -- 
> Thank you,
> Alexey
diff mbox series

Patch

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;
+	}
+
+	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);
+}