[RESEND PATCH v2 2/3] sunxi: eMMC: Improve automatic boot source detection

Jaehoon Chung jh80.chung at samsung.com
Mon Jul 12 12:57:04 CEST 2021


Hi Andre,

On 7/12/21 7:06 PM, Andre Przywara wrote:
> When the Allwinner BROM loads the SPL from an eMMC boot partition, it
> sets the boot source byte to the same value as when booting from the
> user data partition. This prevents us from determining the boot source
> to load U-Boot proper from the proper partition for sure.
> 
> The generic SPL MMC code already looks at the enabled boot partition
> number, to load U-Boot proper from the same partition, but this fails
> if there is nothing bootable in this partition, as the BROM then
> silently falls back to the user data partition, which the SPL misses.
> 
> To learn about the actual boot source anyway, we repeat the algorithm
> the BROM used to select the boot partition in the first place:
> - Test EXT_CSD[179] to check if an eMMC boot partition is enabled.
> - Test EXT_CSD[177] to check for valid MMC interface settings.
> - Check if BOOT_ACK is enabled.
> - Check the beginning of the first sector for a valid eGON signature.
> - Load the whole SPL.
> - Recalculate the checksum to verify the SPL is valid.
> 
> If one of those steps fails, we bail out and continue loading from the
> user data partition. Otherwise we load from the selected boot partition.
> 
> Since the boot source is needed twice in the boot process, we cache the
> result of this test to avoid doing this costly test multiple times.
> 
> This allows the very same image file to be put onto an SD card, into the
> eMMC user data partition or into the eMMC boot partition, and safely
> loads the whole of U-Boot from there.
> 
> Signed-off-by: Andre Przywara <andre.przywara at arm.com>
> ---
> 
> (resent to also include forgotten U-Boot list)
> 
>  arch/arm/mach-sunxi/board.c | 80 +++++++++++++++++++++++++++++++++++++
>  1 file changed, 80 insertions(+)
> 
> diff --git a/arch/arm/mach-sunxi/board.c b/arch/arm/mach-sunxi/board.c
> index e979e426dd1..2552c34733b 100644
> --- a/arch/arm/mach-sunxi/board.c
> +++ b/arch/arm/mach-sunxi/board.c
> @@ -334,6 +334,86 @@ u32 spl_boot_device(void)
>  	return sunxi_get_boot_device();
>  }
>  
> +/*
> + * When booting from an eMMC boot partition, the SPL puts the same boot
> + * source code into SRAM A1 as when loading the SPL from the normal
> + * eMMC user data partition: 0x2. So to know where we have been loaded
> + * from, we repeat the BROM algorithm here: checking for a valid eGON boot
> + * image at offset 0 of a (potentially) selected boot partition.
> + * If any of the conditions is not met, it must have been the eMMC user
> + * data partition.
> + */
> +static bool sunxi_valid_emmc_boot(struct mmc *mmc)
> +{
> +	struct blk_desc *bd = mmc_get_blk_desc(mmc);
> +	uint32_t *buffer = (void *)(uintptr_t)CONFIG_SYS_TEXT_BASE;
> +	int bootpart = EXT_CSD_EXTRACT_BOOT_PART(mmc->part_config);
> +	uint32_t spl_size, emmc_checksum, chksum = 0;
> +	ulong count;
> +
> +	/* The BROM requires BOOT_ACK to be enabled. */
> +	if (!EXT_CSD_EXTRACT_BOOT_ACK(mmc->part_config))
> +		return false;
> +
> +	/*
> +	 * The BOOT_BUS_CONDITION register must be 4-bit SDR, with (0x09)
> +	 * or without (0x01) high speed timings.
> +	 */
> +	if ((mmc->ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & 0x1b) != 0x01 &&
> +	    (mmc->ext_csd[EXT_CSD_BOOT_BUS_WIDTH] & 0x1b) != 0x09)
> +		return false;
> +
> +	/* Partition 0 is the user data partition, bootpart must be 1 or 2. */
> +	if (bootpart != 1 && bootpart != 2)
> +		return false;
> +
> +	mmc_switch_part(mmc, bootpart);

It can be failed to switch to bootpart. Doesn't need to control error?

Best Regards,
Jaehoon Chung

> +
> +	/* Read the first block to do some sanity checks on the eGON header. */
> +	count = blk_dread(bd, 0, 1, buffer);
> +	if (count != 1 || !is_boot0_magic(buffer + 1))
> +		return false;
> +
> +	/* Read the rest of the SPL now we know it's halfway sane. */
> +	spl_size = buffer[4];
> +	count = blk_dread(bd, 1, DIV_ROUND_UP(spl_size, bd->blksz) - 1,
> +			  buffer + bd->blksz / 4);
> +
> +	/* Save the checksum and replace it with the "stamp value". */
> +	emmc_checksum = buffer[3];
> +	buffer[3] = 0x5f0a6c39;
> +
> +	/* The checksum is a simple ignore-carry addition of all words. */
> +	for (count = 0; count < spl_size / 4; count++)
> +		chksum += buffer[count];
> +
> +	debug("eMMC boot part SPL checksum: stored: 0x%08x, computed: 0x%08x\n",
> +	       emmc_checksum, chksum);
> +
> +	return emmc_checksum == chksum;
> +}
> +
> +u32 spl_mmc_boot_mode(struct mmc *mmc, const u32 boot_device)
> +{
> +	static u32 result = ~0;
> +
> +	if (result != ~0)
> +		return result;
> +
> +	result = MMCSD_MODE_RAW;
> +	if (!IS_SD(mmc) && IS_ENABLED(CONFIG_SUPPORT_EMMC_BOOT)) {
> +		if (sunxi_valid_emmc_boot(mmc))
> +			result = MMCSD_MODE_EMMCBOOT;
> +		else
> +			mmc_switch_part(mmc, 0);
> +	}
> +
> +	debug("%s(): %s part\n", __func__,
> +	      result == MMCSD_MODE_RAW ? "user" : "boot");
> +
> +	return result;
> +}
> +
>  void board_init_f(ulong dummy)
>  {
>  	spl_init();
> 



More information about the U-Boot mailing list