Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .github/workflows/test-configs.yml
Original file line number Diff line number Diff line change
Expand Up @@ -624,6 +624,21 @@ jobs:
config-file: ./config/examples/polarfire_mpfs250_m.config
pre-build: sh tools/ci/gen_mpfs_libero_stub.sh tools/ci/mpfs_libero_stub
make-args: LIBERO_FPGA_CONFIG_DIR=tools/ci/mpfs_libero_stub
# The Icicle Kit System Controller probe (no DDR, no image source).
microchip_mpfs250_icicle_probe_test:
uses: ./.github/workflows/test-build-riscv.yml
with:
arch: riscv64
config-file: ./config/examples/polarfire_mpfs250_icicle.config
# The Icicle Kit variant: per-board BCLK phase, fabric SD/eMMC demux select
# and the signed FIT read from a file on the card's FAT32 partition.
microchip_mpfs250_icicle_m_test:
uses: ./.github/workflows/test-build-riscv.yml
with:
arch: riscv64
config-file: ./config/examples/polarfire_mpfs250_icicle_m.config
pre-build: sh tools/ci/gen_mpfs_libero_stub.sh tools/ci/mpfs_libero_stub
make-args: LIBERO_FPGA_CONFIG_DIR=tools/ci/mpfs_libero_stub
# The HSS replacement booting from the other two stores: eMMC (same SDHCI
# driver as SD, different pads) and QSPI into DDR (src/update_ram.c rather
# than src/update_disk.c).
Expand Down
74 changes: 74 additions & 0 deletions config/examples/polarfire_mpfs250_icicle.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
# PolarFire SoC MPFS250T Icicle Kit, M-mode System Controller probe
#
# The MPFS-ICICLE-KIT carries a non-secure die (MPFS250T_ES / MPFS250T) with
# no Athena/TeraFire user crypto co-processor, where the Video Kit configs in
# this directory assume an MPFS250TS secure die. This configuration exists to
# establish which System Controller services that die actually serves: the
# sNVM page survey, the device serial number, the SRAM-PUF and the TRNG.
#
# It carries no image source on purpose. wolfBoot runs hal_init(), which is
# where the survey happens, and then has nothing to boot - that is expected.
# MPFS_ATHENA is deliberately absent: there is no co-processor to drive.
#
# The service probe (MPFS_SC_PROBE: serial number, TRNG nonce, PUF emulation)
# is on by default in every M-mode build. The sNVM page survey is a make
# argument, not a config setting:
# cp config/examples/polarfire_mpfs250_icicle.config .config
# make CROSS_COMPILE=riscv64-unknown-elf- MPFS_SNVM_DUMP=1 \
# MPFS_SNVM_DUMP_FIRST=0 MPFS_SNVM_DUMP_COUNT=221
#
# Both need RISCV_MMODE=1 (options.mk): under HSS the System Controller
# mailbox belongs to HSS, so an S-mode build is refused.
#
# No DDR: LIBERO_FPGA_CONFIG_DIR is deliberately unset, so MPFS_DDR_INIT is
# off and hal/mpfs250_ddr.o is not linked. The Icicle's own Libero export is
# a later step; the System Controller does not need DDR.

ARCH?=RISCV64
TARGET?=mpfs250
SIGN?=ECC384
HASH?=SHA384
IMAGE_HEADER_SIZE=512
WOLFBOOT_VERSION?=1
ARMORED?=0
DEBUG?=0
DEBUG_SYMBOLS?=1
DEBUG_UART?=1
VTOR?=1
NO_XIP?=1
NVM_FLASH_WRITEONCE?=0
UART_FLASH?=0
V?=0
NO_MPU?=1
RAM_CODE?=0
SPMATH?=0
SPMATHALL?=1
DUALBANK_SWAP?=0
PKA?=0
ENCRYPT=0
WOLFTPM?=0
ELF?=1
STRIP_ELF?=1
OPTIMIZATION_LEVEL=1
RISCV_MMODE?=1
STACK_SIZE_PER_HART=0
NO_ASM?=1

# The Video Kit's flash hangs off the System Controller QSPI and its configs
# set EXT_FLASH=1 with -DMPFS_SC_SPI. The Icicle's is on the MSS QSPI
# controller instead, so neither applies here, and the probe needs no flash.
EXT_FLASH?=0
SPI_FLASH?=0
DISK_SDCARD?=0
DISK_EMMC?=0

# wolfBoot executes from the L2 scratchpad, as on the Video Kit: the four
# pinned scratchpad ways the startup in src/boot_riscv_start.S sets up.
WOLFBOOT_ORIGIN?=0x0A000000
WOLFBOOT_LOAD_ADDRESS?=0x0A020200
WOLFBOOT_SECTOR_SIZE?=0x10000
WOLFBOOT_PARTITION_SIZE?=0x1FE0000
WOLFBOOT_PARTITION_BOOT_ADDRESS?=0x20000
WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0x2000000
WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x4000000
CFLAGS_EXTRA+=-DWOLFBOOT_SHA_BLOCK_SIZE=4096
178 changes: 178 additions & 0 deletions config/examples/polarfire_mpfs250_icicle_m.config
Original file line number Diff line number Diff line change
@@ -0,0 +1,178 @@
# PolarFire SoC MPFS250T Icicle Kit, M-Mode (Machine Mode) with LPDDR4 + SD card
#
# The Icicle Kit variant of polarfire_mpfs250_m.config: the same standalone
# wolfBoot replacing HSS, with the three things that differ on this board:
# - the DDR PLL BCLK phase HSS measures on the Icicle is 4 (Video Kit: 3)
# - the SD/eMMC demux select is a fabric register at 0x4FFFFF00
# - the Libero design config must be an Icicle export (ICICLE_MSS), e.g.
# an HSS build/boards/mpfs-icicle-kit/fpga_design_config regenerated
# from the Icicle XML, not the Video Kit's
# The card keeps the stock HSS/U-Boot layout: a FAT32 first partition with
# the Yocto fitImage, so the signed image is read from a file on it rather
# than from the raw partition start.
#
# Flash via mpfsBootmodeProgrammer (bootmode 1):
# java -jar mpfsBootmodeProgrammer.jar --bootmode 1 --die MPFS250T \
# --package FCVG484 --workdir $PWD wolfboot.elf

ARCH?=RISCV64
TARGET?=mpfs250
SIGN?=ECC384
HASH?=SHA384
IMAGE_HEADER_SIZE=512
WOLFBOOT_VERSION?=1
ARMORED?=0
DEBUG?=0
DEBUG_SYMBOLS?=1
DEBUG_UART?=1
VTOR?=1
EXT_FLASH?=0
SPI_FLASH?=0
NO_XIP?=1
NVM_FLASH_WRITEONCE?=0
UART_FLASH?=0
V?=0
NO_MPU?=1
RAM_CODE?=0
SPMATH?=0
SPMATHALL?=1
DUALBANK_SWAP?=0
PKA?=0
ENCRYPT=0
WOLFTPM?=0
ELF?=1
#DEBUG_ELF?=1

OPTIMIZATION_LEVEL=1

# M-Mode configuration: runs on E51 from L2 SRAM
RISCV_MMODE?=1

# Stack size per hart (L2 SRAM constraints). Single source of truth: this
# Makefile var feeds both the startup asm (-DSTACK_SIZE_PER_HART) and the
# linker script (@STACK_SIZE_PER_HART@ in mpfs250-m.ld).
STACK_SIZE_PER_HART=4096

# E51 core lacks RISC-V crypto extensions (Zknh), use portable C
# RISC-V SHA256/384/512 assembly (wolfcrypt port/riscv) enabled by default.
# Verified on the MPFS250 E51 (rv64imac); requires wolfSSL with the RISC-V
# unaligned-access fix (PR #10530, present in the lib/wolfssl submodule).
# The E51 handles unaligned access so the default (faster) asm path is used;
# add -DWOLFSSL_RISCV_ASM_NO_UNALIGNED for RISC-V cores that trap on it.
NO_ASM?=0

# Enable LPDDR4 init in hal_init() by pointing at the Libero/HSS-generated
# fpga_design_config directory for this board. The directory must contain
# fpga_design_config.h and its sub-headers (memory_map/, ddr/, clocks/, ...).
# Typical sources:
# - HSS Icicle build:
# <hss>/build/boards/mpfs-icicle-kit/fpga_design_config
# (check fpga_design_config.h says ICICLE_MSS: the HSS generator only
# reruns when the XML changes, so a directory left from a Video Kit
# build keeps the Video Kit's SEG and IOMUX values)
# - Libero MSS Configurator export for the design.
# The -I path is added and -DMPFS_DDR_INIT is set automatically when this is
# non-empty (see arch.mk). Override on the command line for one-off builds:
# make LIBERO_FPGA_CONFIG_DIR=/path/to/fpga_design_config
LIBERO_FPGA_CONFIG_DIR?=

# DDR PLL BCLK/SCLK phase. HSS measures it with its software sweep; the
# Icicle Kit trains to 4, the Video Kit to 3 (the driver default). With the
# wrong value TIP training passes and no DRAM write ever completes.
MPFS_DDR_BCLK_PHASE=4

# SD/eMMC demux: on the Icicle Kit the select line is a register in the
# fabric (HSS CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS).
MPFS_SD_EMMC_DEMUX_ADDR=0x4FFFFF00

# Boot Linux: drop to S-mode after wolfBoot verifies kernel
CFLAGS_EXTRA+=-DWOLFBOOT_MMODE_SMODE_BOOT

# SD card storage for kernel image (no QSPI flash)
DISK_SDCARD?=1
DISK_EMMC?=0

# wolfBoot in L2 SRAM: all 4 scratchpad ways (0x0A000000 - 0x0A07FFFF)
WOLFBOOT_ORIGIN?=0x0A000000
WOLFBOOT_L2SCRATCH_SIZE?=512k

# Boot-hart stack, sized for ML-DSA-87 verify on top of the two
# IMAGE_HEADER_SIZE buffers update_disk.c puts on the stack. ECC384 needs less.
STACK_SIZE?=64k

# 4KB sector size (SD card flow is partition-based, not flash-erase-based)
WOLFBOOT_SECTOR_SIZE?=0x1000

# Scratch address where the signed FIT image is staged before signature
# verification + FIT parse. 0x82000000 is 32 MB into the cached DDR window
# at 0x80000000, which is 1 GB wide - 0xC0000000 up is the non-cached alias
# onto the same DDR, so staging must stay below it. It is clear of the
# kernel destination below and 128 MB below the DTB region, which is the
# headroom the staged-image bound further down depends on.
# After the FIT is parsed:
# kernel is copied to 0x80200000 (FIT-internal "load")
# DTB is copied to WOLFBOOT_LOAD_DTS_ADDRESS (0x8A000000)
# Layout:
# 0x80200000 - 0x814FFFFF : kernel (~19 MB after parse)
# 0x82000000 - 0x832FFFFF : FIT scratch (~19 MB - overwritten on next boot)
# 0x8A000000 - 0x8A004FFF : DTB
WOLFBOOT_LOAD_ADDRESS?=0x82000000

# DTB load address in DDR
WOLFBOOT_LOAD_DTS_ADDRESS?=0x8A000000

# Bound the UNAUTHENTICATED FIT image length before it drives the disk read
# into the DDR staging region (required by src/update_disk.c). The FIT is
# staged at WOLFBOOT_LOAD_ADDRESS (0x82000000); the DTB load region begins
# 128 MB above at 0x8A000000, so cap the staged image at 128 MB so an
# attacker-declared fw_size cannot overrun the DTB region before the
# signature check runs.
WOLFBOOT_RAMBOOT_MAX_SIZE=0x08000000

# The stock Icicle card (HSS/U-Boot layout): index 0 is the FAT32 BOOT
# partition carrying fitImage and boot.scr, index 1 the HSS payload, index 2
# the rootfs. The signed FIT is a file on the FAT32 partition, so HSS and
# U-Boot keep booting from the same card:
# ./tools/keytools/sign --ecc384 --sha384 fitImage \
# wolfboot_signing_private_key.der 1
# cp fitImage_v1_signed.bin <card>/wolfboot/
WOLFBOOT_NO_PARTITIONS=1
CFLAGS_EXTRA+=-DBOOT_PART_A=0
CFLAGS_EXTRA+=-DBOOT_PART_B=0
DISK_FS=fat32
CFLAGS_EXTRA+=-DBOOT_FILE_A='"/wolfboot/fitImage_v1_signed.bin"'
CFLAGS_EXTRA+=-DBOOT_FILE_B='"/wolfboot/fitImage_v1_signed.bin"'

# The Yocto fitImage carries a gzip-compressed kernel and an initramfs.
GZIP=1
FIT_RAMDISK=1

# The Icicle base design's CAN controller hangs the stock DTB's CAN driver.
CFLAGS_EXTRA+=-DLINUX_BOOTARGS='"earlycon=sbi initcall_blacklist=mpfs_can_driver_init"'

# Speed up disk partition read (512KB chunks - max DMA size)
CFLAGS_EXTRA+=-DDISK_BLOCK_SIZE=0x80000

# Card detect is not wired to the SDHCI controller's CI/CDPL inputs on the
# kits, so assume a card is present.
CFLAGS_EXTRA+=-DSDHCI_FORCE_CARD_DETECT

# Optional encryption (kernel signed+encrypted with AES-256)
#CUSTOM_ENCRYPT_KEY=1
#ENCRYPT=1
#ENCRYPT_WITH_AES256=1
#OBJS_EXTRA=src/my_custom_encrypt_key.o

# Used by test-application/ELF wrapper
WOLFBOOT_PARTITION_BOOT_ADDRESS=0x80200000
WOLFBOOT_PARTITION_SIZE=0x4000000

# Debug options (useful for initial M-mode + DDR bring-up)
CFLAGS_EXTRA+=-DDEBUG_BOOT
#CFLAGS_EXTRA+=-DDEBUG_SDHCI
#CFLAGS_EXTRA+=-DDEBUG_DISK
#CFLAGS_EXTRA+=-DDISK_TEST
# Verbose register-level DDR tracing, the post-training register dump and
# the DDR pattern test (development aids).
#CFLAGS_EXTRA+=-DDEBUG_DDR
#MPFS_DDR_MEMTEST=1
21 changes: 18 additions & 3 deletions docs/PolarFire.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ Path 1 needs no FPGA design files and never writes the device, so it is the righ
|---|---|
| RISC-V bare-metal toolchain | SoftConsole (`/opt/Microchip/SoftConsole-v2022.2-RISC-V-747/riscv-unknown-elf-gcc/bin`), or any `riscv64-unknown-elf-gcc` |
| `mpfsBootmodeProgrammer.jar` + a JRE | SoftConsole (`extras/mpfs/`, `eclipse/jre/bin/java`); paths 2 and 3 only |
| FlashPro programmer | on-board on the Video Kit, over the same USB cable as the consoles |
| FlashPro programmer | on-board on the Video Kit and the Icicle Kit (close J9 on the Icicle), over the same USB cable as the consoles |
| `dtc`, `mkimage` | `device-tree-compiler`, `u-boot-tools` |
| `hss-payload-generator` | `tools/hss-payload-generator` in the [hart-software-services](https://github.com/polarfire-soc/hart-software-services) tree; path 1 only |
| `fpga_design_config/` for the board | an HSS build (`build/boards/<board>/fpga_design_config`) or a Libero MSS Configurator export; paths 2 and 3 only |
Expand Down Expand Up @@ -145,7 +145,7 @@ $SC_INSTALL_DIR/eclipse/jre/bin/java -jar \
--bootmode 1 --die MPFS250T --package FCG1152 --workdir $PWD wolfboot.elf
```

`--bootmode 1` is non-secure boot from eNVM: the System Controller releases the harts at the eNVM reset vector. The die and package must match the part; `--die` defaults to `MPFS250T_ES` and `--package` to `FCVG484`, neither of which is the Video Kit.
`--bootmode 1` is non-secure boot from eNVM: the System Controller releases the harts at the eNVM reset vector. The die and package must match the part; `--die` defaults to `MPFS250T_ES` and `--package` to `FCVG484`, neither of which is the Video Kit (the Icicle Kit is `--die MPFS250T --package FCVG484`).

#### Boot

Expand Down Expand Up @@ -200,6 +200,9 @@ The programmer's `--die` list covers `MPFS025T` through `MPFS460T` and their `_E
| banner, then silence | the FIT loaded but Linux has no console: the dtb's own `/chosen/bootargs` wins unless `LINUX_BOOTARGS` is set at build time. See [bootargs](compile.md#linux-kernel-command-line-bootargs) |
| banner, then silence, and no `[SBI]` output at all | the image was built with `make CFLAGS_EXTRA=...`, which overrode the config's `-DWOLFBOOT_MMODE_SMODE_BOOT`. Check with `nm wolfboot.elf | grep sbi`; an M-mode build that boots an S-mode OS must have those symbols |
| DDR training stops or reports a failure | build with `CFLAGS_EXTRA+=-DDEBUG_DDR` and compare against the board's Libero settings |
| DDR trains but the OS misbehaves later | build with `MPFS_DDR_MEMTEST=1` for a CPU pattern test over the mapped DDR windows before the OS is loaded |
| TIP training passes (`train_stat=0x1F`) but `MTC WRCALIB TIMEOUT` on every retry, or a PDMA fill of DDR hangs | the DDR PLL BCLK/SCLK phase is another board's. Dump the PHY under HSS (tinyCLI `debug hexdump 0x20007000 0x1000`) and read `PLL_DIV_0_1_MAIN`/`PLL_DIV_2_3_MAIN` VCO phase selects, then set `MPFS_DDR_BCLK_PHASE` to match |
| Linux boots but userspace segfaults or the kernel reports an illegal instruction at valid code, more often with more CPUs | DRAM content corruption from a mode-register mismatch: the mode registers must be written masked so the controller supplies them from its CFG_* values (the driver does this now); check `MR13` data mask against `CFG_DATA_MASK` if it recurs |

### Next

Expand All @@ -219,7 +222,7 @@ The programmer's `--die` list covers `MPFS025T` through `MPFS460T` and their `_E

## Boot configurations

Nine ready-to-use config templates cover all supported boot mode / storage / memory combinations:
Ten ready-to-use config templates cover all supported boot mode / storage / memory combinations:

| Configuration | Config File | Boot Mode | Storage | Memory | HSS |
|---------------|-------------|-----------|---------|--------|-----|
Expand All @@ -231,6 +234,7 @@ Nine ready-to-use config templates cover all supported boot mode / storage / mem
| **M-Mode + DDR** | `polarfire_mpfs250_m.config` | M-mode (E51, no HSS) | SD Card | LPDDR4 (DDR) | No |
| **M-Mode + DDR, eMMC** | `polarfire_mpfs250_m_emmc.config` | M-mode (E51, no HSS) | eMMC | LPDDR4 (DDR) | No |
| **M-Mode + DDR, QSPI** | `polarfire_mpfs250_m_qspi_ddr.config` | M-mode (E51, no HSS) | SC QSPI | LPDDR4 (DDR) | No |
| **M-Mode + DDR, Icicle Kit** | `polarfire_mpfs250_icicle_m.config` | M-mode (E51, no HSS) | SD Card (FAT32 file) | LPDDR4 (DDR) | No |
| **Boot mode 2 UBL** | `polarfire_mpfs250_ubl.config` | System Controller -> sNVM stub | eNVM (verifies it) | L2-LIM | No |

The **M-Mode + DDR** configuration brings up the LPDDR4 controller from
Expand All @@ -252,6 +256,16 @@ still produces a working M-mode wolfBoot without DDR. Add
`-DDEBUG_DDR` to `CFLAGS_EXTRA` for verbose register-level traces
during bring-up.

The **Icicle Kit** variant (`polarfire_mpfs250_icicle_m.config`) is the same M-mode + DDR boot on the MPFS-ICICLE-KIT (MPFS250T, a non-secure die, package `FCVG484`). Three things are board-specific and are set in that config rather than detected:

- **DDR PLL BCLK/SCLK phase**, `MPFS_DDR_BCLK_PHASE`: HSS measures it per board with a software sweep; the Icicle trains at 4 where the Video Kit trains at 3. With the other board's value TIP training reports success and no DRAM write ever completes.
- **SD/eMMC demux select**, `MPFS_SD_EMMC_DEMUX_ADDR=0x4FFFFF00`: on the Icicle the demux is a fabric register (HSS's `CONFIG_SERVICE_MMC_FABRIC_SD_EMMC_DEMUX_SELECT_ADDRESS`), not the Video Kit's IOMUX override.
- **Libero design config**, `LIBERO_FPGA_CONFIG_DIR`: must be an Icicle export (`ICICLE_MSS`). An HSS `build/boards/mpfs-icicle-kit/fpga_design_config` is only regenerated when the XML changes, so one left behind by a Video Kit build silently carries the Video Kit's SEG and IOMUX values; the SEG difference leaves the 64-bit DDR windows unmapped and Linux dies at its first high-memory access.

The config reads the signed FIT from `/wolfboot/fitImage_v1_signed.bin` on the card's FAT32 partition (`DISK_FS=fat32`), so the stock HSS/U-Boot card layout stays usable, and sets `GZIP=1` and `FIT_RAMDISK=1` for the Yocto fitImage.

Validated on the Icicle: DDR training completes on every cold boot, and Linux 6.12 (4 CPUs) reaches login and survives a memory stress.

The eMMC and QSPI variants are the same configuration with a different
image store. One SDHCI controller reaches both the SD slot and the eMMC
through an external demux, so the SD and eMMC builds are mutually exclusive:
Expand Down Expand Up @@ -301,6 +315,7 @@ These flags apply to `polarfire_mpfs250_m_qspi.config` and are added via `CFLAGS
| `WATCHDOG` | undefined | Has no timeout to set on this target: the MSS watchdogs are armed by the bitstream and their window cannot be changed from software. See "Watchdog policy" below. wolfBoot refreshes all five in `hal_init()` and again in `hal_prepare_boot()` either way. |
| `MPFS_WDT_NODES_KEEP` (make variable, `=1`) | undefined | Linux boot only: keep the five MSS watchdog nodes enabled in the dtb and stop the parked E51 from refreshing them, so the OS owns the watchdogs. See "Watchdog policy" below. |
| `MPFS_QSPI_CLK_DIV` (make variable) | `QSPI_CLK_DIV_8` | QSPI SCK divider, a `QSPI_CLK_DIV_*` name from `hal/mpfs250.h`. See "PolarFire SoC QSPI". |
| `MPFS_SC_PROBE` (make variable) | `1` on M-mode builds | Read-only: at boot, report whether the System Controller serves the device serial number, the TRNG nonce and PUF emulation, with two stability checks (nonce differs across calls, PUF response repeats). No value is printed, only a checksum of the PUF response for comparing boots. `MPFS_SC_PROBE=0` disables it. M-mode only. |
| `MPFS_SNVM_DUMP` (make variable, `=1`) | undefined | Read-only: at boot, print the admin word, state and a checksum of `MPFS_SNVM_DUMP_COUNT` sNVM pages from `MPFS_SNVM_DUMP_FIRST` (defaults 2 from 200, the keystore and the wrapped image key). Page contents are never printed. M-mode only. |

### Stack overflow detection
Expand Down
Loading
Loading