First off, EIC7700 has several CPUs. MCPU (P550 cluster) + SCPU (E21) + LCPU (E21) + NPU and DSPs. The SCPU (Secure CPU) is used to run the Masked ROM after power on. The Masked ROM has the logic of loading different payloads from the selected boot source image and kickstarts other CPUs such as MCPU. Optionally it can also validate the cryptographic key/signature of the payload against OTP, thus implementing secure-boot. ESWIN calls the container of the payloads bootchain By default the boot source is QSPI boot flash. The bootchain is stored at the beginning of the flash (offset 0). The boot flash contains the following on my Hifive P550
- DDR init: Vendor binary blob to initialize DDR (closed source)
- "firmware": AFAIK, a very small piece of code that does little to nothing. Perhaps only to keep SCPU active.
- bootloader: The usual opensbi+u-boot stuff that runs on MCPU. (open source, ESWIN maintains the patched opensbi/u-boot)
As it's shown, the DDR init blob is supplied by vendor, and opensbi+u-boot is handed off to with DDR already initialized. Therefore, there's no u-boot SPL required
The bootchain follows the format defined by ESWIN. reference It looks something like this:
00000000 45 53 57 42 03 00 00 00 01 00 00 00 00 00 40 00 |ESWB..........@.| <--- bootchain header
00000010 00 00 00 00 4c 05 00 00 00 00 00 00 00 00 70 00 |....L.........p.|
00000020 00 00 00 00 00 00 00 00 00 00 00 00 01 00 00 00 |................|
00000030 00 00 10 00 00 00 00 00 20 d4 19 00 00 00 00 00 |........ .......|
00000040 00 00 10 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00000050 01 00 00 00 00 00 48 00 00 00 00 00 18 f7 3b 00 |......H.......;.|
00000060 00 00 00 00 00 00 30 01 00 00 00 00 00 00 00 00 |......0.........|
00000070 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
000000e0 ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
*
00100000 57 53 45 bb 00 00 00 00 00 00 00 00 00 00 00 00 |WSE.............| <--- paylodad header
00100010 60 0a 00 00 00 00 00 00 20 d4 19 00 00 00 00 00 |`....... .......|
00100020 00 00 00 59 00 00 00 00 00 00 00 59 00 00 00 00 |...Y.......Y....|
00100030 00 00 00 00 00 65 6e 67 00 00 00 00 00 00 00 00 |.....eng........|
00100040 10 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
00100050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00100100 b7 07 90 50 17 d7 19 00 23 2a f7 42 b7 07 81 51 |...P....#*.B...Q|
00100110 17 d7 19 00 23 22 f7 42 b7 87 82 51 17 d7 19 00 |....#".B...Q....|
...
00400000 57 53 45 bb 00 00 00 00 00 00 00 00 00 00 00 00 |WSE.............| <--- another payload header
00400010 00 02 00 00 00 00 00 00 4c 05 00 00 00 00 00 00 |........L.......|
00400020 00 00 00 59 00 00 00 00 00 00 00 59 00 00 00 00 |...Y.......Y....|
00400030 00 00 00 00 00 65 6e 67 00 00 00 00 00 00 00 00 |.....eng........|
00400040 70 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |p...............|
00400050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
*
00400100 41 11 22 c4 37 04 b4 21 06 c6 13 04 c4 03 00 40 |A.".7..!.......@|
00400110 0f 00 20 08 21 80 13 74 f4 0f 1d e8 b7 87 82 51 |.. .!..t.......Q|
The bootchain header is merely an array of pointers to different payload headers, and decoding the image gives:
Number of entries: 3
Entry 0: offset=0x400000 size=1356 (0x54c) payload_type=112 (FIRMWARE) last=0
payload_off=0x200 payload_size=1356 (0x54c) load_addr=0x59000000 entry_addr=0x59000000 boot=0 (SCPU)
Entry 1: offset=0x100000 size=1692704 (0x19d420) payload_type=16 (DDR) last=0
payload_off=0xa60 payload_size=1692704 (0x19d420) load_addr=0x59000000 entry_addr=0x59000000 boot=0 (SPCU)
Entry 2: offset=0x480000 size=3929880 (0x3bf718) payload_type=48 (BOOTLOADER) last=1
payload_off=0x19e1a0 payload_size=3929880 (0x3bf718) load_addr=0x80000000 entry_addr=0x80000000 boot=1 (MCPU)
This image is assembled by nsign with a config file that looks like this:
nsign.cfg
cmd=chief_sign
out=bootloader_ddr5_secboot.bin
{
in=second_boot_fw.bin
boot_flags=SCPU
payload_type=FIRMWARE
sign_algorithm=plaintext
keyid=00
version=00000001
link_addr=00000000
load_addr=59000000
entry_addr=59000000
payload_flags=plaintext
digest_mthd=SHA
encrypted_mthd=plaintext
devid=0000000000000000
vid=00
lang=656e67
mid=0000000000000000
params=00000000000000000000000000000000
dl_load_addr=00000000
dl_init_ofs=00000000
dl_destory_ofs=00000000
dl_ioctl_ofs=00000000
dl_load_flags=00000000
dl_irq_num=00000000
dl_irq_ofs=00000000
}
{
in=ddr_fw.bin
boot_flags=SCPU
payload_type=DDR
sign_algorithm=plaintext
keyid=00
version=00000001
link_addr=00000000
load_addr=59000000
entry_addr=59000000
payload_flags=plaintext
digest_mthd=SHA
encrypted_mthd=plaintext
devid=0000000000000000
vid=00
lang=656e67
mid=0000000000000000
params=00000000000000000000000000000000
dl_load_addr=00000000
dl_init_ofs=00000000
dl_destory_ofs=00000000
dl_ioctl_ofs=00000000
dl_load_flags=00000000
dl_irq_num=00000000
dl_irq_ofs=00000000
}
{
in=fw_payload.bin
boot_flags=MCPU
payload_type=BOOTLOADER
sign_algorithm=plaintext
keyid=00
version=00000001
link_addr=00000000
load_addr=80000000
entry_addr=80000000
payload_flags=plaintext
digest_mthd=SHA
encrypted_mthd=plaintext
devid=0000000000000000
vid=00
lang=656e67
mid=0000000000000000
params=00000000000000000000000000000000
dl_load_addr=00000000
dl_init_ofs=00000000
dl_destory_ofs=00000000
dl_ioctl_ofs=00000000
dl_load_flags=00000000
dl_irq_num=00000000
dl_irq_ofs=00000000
}
es_burn
command in the u-boot is the recommended way to update bootchain on the QSPI flash. It basically place the payloads at some predefined offsets and updates the bootchain header to point to the re-located payloads. Compared to the bootchain file you passed to es_burn
, the QSPI flash version basically got some holes added between the payloads, and the layloads can be aligned to block size of QSPI flash, making them easier to load for ROM.
Prepare the payloads. Either extract the payload from ESWIN published bootchain image, by using the dump
utilitiy from my forked nsign
repo, or you must find the correct payloads from different ESWIN/Sifive repos. The "official" way is to build it via https://github.com/sifive/meta-sifive/tree/rel/meta-sifive/hifive-premier-p550/recipes-bsp, but I prefer to do it manually.
- "firmware": https://github.com/sifive/hifive-premier-p550-tools/blob/master/second_boot_fw/second_boot_fw.bin
- DDR init: https://github.com/sifive/hifive-premier-p550-tools/blob/master/ddr-fw/ddr_fw.bin
- OpenSBI: https://github.com/riscv-software-src/opensbi/tree/v1.4 + patches from: https://github.com/sifive/meta-sifive/tree/rel/meta-sifive/hifive-premier-p550/recipes-bsp/opensbi/opensbi-sifive-hf-prem
- u-boot: https://github.com/eswincomputing/u-boot/tree/u-boot-2024.01-EIC7X + patches from: https://github.com/sifive/meta-sifive/tree/rel/meta-sifive/hifive-premier-p550/recipes-bsp/u-boot/u-boot-sifive-hf-prem
Prepare a nsign.cfg
file as described in previous section, and do nsign nsign.cfg
Disclaimer: the instructions are given by ESWIN. I have not tested it yet.
Prepare the payloads as the previous section. Change cmd=chief_sign
in nsign.cfg
to uart_sign
, and run nsign nsign.cfg
. There'll be a ihex file created for UART boot. Switch the bootsel DIP switch to UART mode, and then send the ihex file as is to UART port. The board should now boot from this bootchain image uploaded.