[U-Boot] [PATCH] arm: socfpga: crc-protect SPL on warm boot
Marek Vasut
marex at denx.de
Wed Nov 21 21:14:20 UTC 2018
On 11/21/2018 10:07 PM, Simon Goldschmidt wrote:
> On 21.11.2018 15:08, Marek Vasut wrote:
>> On 11/21/2018 06:09 AM, Simon Goldschmidt wrote:
>>>
>>> Am Mi., 21. Nov. 2018, 00:11 hat Marek Vasut <marex at denx.de
>>> <mailto:marex at denx.de>> geschrieben:
>>>
>>> On 11/20/2018 09:54 PM, Simon Goldschmidt wrote:
>>> > On 20.11.2018 20:33, Marek Vasut wrote:
>>> >> On 11/20/2018 08:22 PM, Simon Goldschmidt wrote:
>>> >>> From: Simon Goldschmidt <sgoldschmidt at de.pepperl-fuchs.com
>>> <mailto:sgoldschmidt at de.pepperl-fuchs.com>>
>>> >>>
>>> >>> On socfpga gen5, a warm reboot from Linux currently triggers
>>> a warm
>>> >>> reset via reset manager ctrl register.
>>> >>>
>>> >>> This currently leads to the boot rom just jumping to onchip ram
>>> >>> executing the SPL that is supposed to still be there. This is
>>> >>> because we tell the boot rom to do so by writing a magin value
>>> >>> the warmramgrp_enable register in arch_early_init_r().
>>> >>>
>>> >>> However, this can lead to lockups on reboot if this register
>>> still
>>> >>> contains its magic value but the SPL is not intact any more
>>> (e.g.
>>> >>> partly overwritten onchip ram).
>>> >>>
>>> >>> To fis this, store a crc calculated over SPL in sysmgr
>>> registers to
>>> >>> let the boot rom check it on next warm boot. If the crc is
>>> still
>>> >>> correct, SPL can be executd from onchip ram. If the crc
>>> fails, SPL
>>> >>> is loaded from original boot source.
>>> >>>
>>> >>> The crc that is written to the warmramgrp_crc register is
>>> the crc
>>> >>> found in the SPL sfp image but with one addiional u32 added.
>>> For
>>> >>> this, we need to add a function to calculate the updated
>>> crc. This
>>> >>> is done as a bitwise calculation to keep the code increase
>>> small.
>>> >>>
>>> >>> This whole patch added 96 bytes to .text for SPL for
>>> >>> socfpga_socrates_defconfig.
>>> >>>
>>> >>> Signed-off-by: Simon Goldschmidt
>>> <simon.k.r.goldschmidt at gmail.com
>>> <mailto:simon.k.r.goldschmidt at gmail.com>>
>>> >>> ---
>>> >>>
>>> >>> arch/arm/mach-socfpga/misc_gen5.c | 9 ----
>>> >>> arch/arm/mach-socfpga/spl_gen5.c | 73
>>> +++++++++++++++++++++++++++++++
>>> >>> 2 files changed, 73 insertions(+), 9 deletions(-)
>>> >>>
>>> >>> diff --git a/arch/arm/mach-socfpga/misc_gen5.c
>>> >>> b/arch/arm/mach-socfpga/misc_gen5.c
>>> >>> index 5fa40937c4..492a3082de 100644
>>> >>> --- a/arch/arm/mach-socfpga/misc_gen5.c
>>> >>> +++ b/arch/arm/mach-socfpga/misc_gen5.c
>>> >>> @@ -204,15 +204,6 @@ int arch_early_init_r(void)
>>> >>> {
>>> >>> int i;
>>> >>> - /*
>>> >>> - * Write magic value into magic register to unlock
>>> support for
>>> >>> - * issuing warm reset. The ancient kernel code expects
>>> this
>>> >>> - * value to be written into the register by the
>>> bootloader, so
>>> >>> - * to support that old code, we write it here instead
>>> of in the
>>> >>> - * reset_cpu() function just before resetting the CPU.
>>> >>> - */
>>> >>> - writel(0xae9efebc,
>>> &sysmgr_regs->romcodegrp_warmramgrp_enable);
>>> >>> -
>>> >>> for (i = 0; i < 8; i++) /* Cache initial SW setting
>>> regs */
>>> >>> iswgrp_handoff[i] =
>>> readl(&sysmgr_regs->iswgrp_handoff[i]);
>>> >>> diff --git a/arch/arm/mach-socfpga/spl_gen5.c
>>> >>> b/arch/arm/mach-socfpga/spl_gen5.c
>>> >>> index ccdc661d05..3416e19f79 100644
>>> >>> --- a/arch/arm/mach-socfpga/spl_gen5.c
>>> >>> +++ b/arch/arm/mach-socfpga/spl_gen5.c
>>> >>> @@ -63,6 +63,76 @@ u32 spl_boot_mode(const u32 boot_device)
>>> >>> }
>>> >>> #endif
>>> >>> +/* This function calculates the CRC32 used by the Cyclone
>>> 5 SoC
>>> >>> Boot Rom */
>>> >>> +static u32 socfpga_boot_crc(u32 crc, const unsigned char
>>> *ptr, u32
>>> >>> length)
>>> >>> +{
>>> >>> + uint i;
>>> >>> + u8 bit;
>>> >>> + unsigned char data;
>>> >>> + const u32 poly = 0x02608edb;
>>> >>> +
>>> >>> + for (; length > 0; length--, ptr++) {
>>> >>> + data = *ptr;
>>> >>> + for (i = 0; i < 8; i++) {
>>> >>> + if (data & 0x80)
>>> >>> + bit = 1;
>>> >>> + else
>>> >>> + bit = 0;
>>> >>> +
>>> >>> + data = data << 1;
>>> >>> + if (crc & 0x80000000)
>>> >>> + bit = 1 - bit;
>>> >>> +
>>> >>> + if (bit) {
>>> >>> + crc ^= poly;
>>> >>> + crc = crc << 1;
>>> >>> + crc |= 1;
>>> >>> + } else {
>>> >>> + crc = crc << 1;
>>> >>> + }
>>> >>> + }
>>> >>> + }
>>> >>> + return crc;
>>> >>> +}
>>> >>> +
>>> >>> +/*
>>> >>> + * Write magic value into magic register to unlock support
>>> for the
>>> >>> boot rom to
>>> >>> + * execute spl from sram on warm reset. This may be
>>> required at
>>> >>> least on some
>>> >>> + * boards that start from qspi where the flash chip might
>>> be in a
>>> >>> state that
>>> >>> + * cannot be handled by the boot rom (e.g. 4 byte mode).
>>> >>> + *
>>> >>> + * To prevent just jumping to corrupted memory, a crc of
>>> the spl is
>>> >>> calculated.
>>> >>> + * This crc is loaded from the running image, but has to be
>>> extended
>>> >>> by the
>>> >>> + * modified contents of the "datastart" register (i.e.
>>> 0xffff0000).
>>> >>> + */
>>> >>> +static void spl_init_reboot_config(void)
>>> >>> +{
>>> >>> + u32 spl_crc, spl_length;
>>> >>> + const u32 spl_start = (u32)__image_copy_start;
>>> >>> + const u32 spl_start_16 = spl_start & 0xffff;
>>> >>> + u32 spl_length_u32;
>>> >>> +
>>> >>> + /* load image length from sfp header (includes crc) */
>>> >>> + spl_length_u32 = *(const u16 *)(spl_start + 0x46);
>>> >>> + /* subtract crc */
>>> >>> + spl_length_u32--;
>>> >>> + /* get length in bytes */
>>> >>> + spl_length = spl_length_u32 * 4;
>>> >>> + /* load crc */
>>> >>> + spl_crc = *(const u32 *)(spl_start + spl_length);
>>> >>> + /* undo xor */
>>> >>> + spl_crc ^= 0xffffffff;
>>> >>> + /* add contents of modified datastart register */
>>> >>> + spl_crc = socfpga_boot_crc(spl_crc, (const u8
>>> *)&spl_start, 4);
>>> >>> + /* finalize */
>>> >>> + spl_crc ^= 0xffffffff;
>>> >>> +
>>> >>> + writel(0xae9efebc,
>>> &sysmgr_regs->romcodegrp_warmramgrp_enable);
>>> >>> + writel(spl_start_16,
>>> >>> &sysmgr_regs->romcodegrp_warmramgrp_datastart);
>>> >>> + writel(spl_length,
>>> &sysmgr_regs->romcodegrp_warmramgrp_length);
>>> >>> + writel(spl_crc, &sysmgr_regs->romcodegrp_warmramgrp_crc);
>>> >>> +}
>>> >>> +
>>> >>> void board_init_f(ulong dummy)
>>> >>> {
>>> >>> const struct cm_config *cm_default_cfg =
>>> cm_get_default_config();
>>> >>> @@ -82,6 +152,9 @@ void board_init_f(ulong dummy)
>>> >>> writel(SYSMGR_ECC_OCRAM_DERR | SYSMGR_ECC_OCRAM_EN,
>>> >>> &sysmgr_regs->eccgrp_ocram);
>>> >>> + if (!socfpga_is_booting_from_fpga())
>>> >>> + spl_init_reboot_config();
>>> >>> +
>>> >>> memset(__bss_start, 0, __bss_end - __bss_start);
>>> >>> socfpga_sdram_remap_zero();
>>> >>>
>>> >> Can't we use the library CRC32 function instead ?
>>> >
>>> > No, unfortunately, it's bit-reversed. Plus it uses a table, which
>>> > increases the SPL binary by more than 2 KByte.
>>>
>>> Are you sure ? The uImage code also uses crc32, so I suspect
>>> that crc32
>>> stuff is already in SPL. And the bit operation can probably be
>>> easily
>>> done. I might be wrong ...
>>>
>>>
>>> I wrote that as a result of testing it. The binary grew by 2k+. I'll
>>> have to check the uimage crc.
>> That's probably a good idea.
>>
>>> Bit reversing can be done, yes. I tested that too. It's a rarther small
>>> function that could be added to some lib code (if it doesn't already
>>> exist, I haven't checked).
>> If we can reuse the CRC code, that'd be awesome.
>
> Ok, so I retested this and the result came as a bit of a shock to me.
> Binary size does increase by ~1.3kByte (not 2k+ as I wrote before) when
> using lib/crc32.c to do the CRC check (with private code for reversing
> bits that works). This is 1K for the CRC table plus some code. That's
> probably ok, but:
Thanks!
> The shock was that I thought lib/crc32.c is what is used to check uImage
> CRC and we shouldn't see any code size increasement. Turns out that none
> of the files in common/spl (core or loaders) check the CRC of a uImage!
> (Even with CONFIG_SPL_LOAD_FIT, the crc32 code isn't included.)
Uh, how does the signature verification work then ? I guess it at least
includes the SHA support ?
> Unless I'm mistaken, this means that SPL does not check the validity of
> a U-Boot image at all (unless using FIT and enabling
> CONFIG_SPL_FIT_SIGNATURE, but this does not fit into 64k for socfpga gen5).
Yikes
> Is this a known issue? Has it always been like this? Why do we have a 2
> CRCs in the U-Boot image then?
The bootm command should check it. I was not aware SPL doesn't check it
and I don't believe that was intended, but I might be wrong. Can you
investigate ? (I'm pushing more things unto you since I'm under a lot of
pressure recently, too much stuff to do, and I have quite a bit of
confidence in you, in that you can figure it out)
--
Best regards,
Marek Vasut
More information about the U-Boot
mailing list