diff --git a/arch.mk b/arch.mk index a507f73226..c826730299 100644 --- a/arch.mk +++ b/arch.mk @@ -158,7 +158,11 @@ ifeq ($(ARCH),AARCH64) ifeq ($(TARGET),nxp_ls1028a) ARCH_FLAGS=-mcpu=cortex-a72+crypto -march=armv8-a+crypto -mtune=cortex-a72 CFLAGS+=$(ARCH_FLAGS) -DCORTEX_A72 - + # ZynqMP RVBAR (0xFD5C0040) does not exist on LS1028A -- the store faults + # pre-UART. Its reset vector comes from the boot ROM (DCFG BOOTLOCPTR). + CFLAGS+=-DSKIP_RVBAR=1 + # MMU on (boot_aarch64_start.S LS1028A table): DDR Normal cacheable -- required + # for coherency with the ENETC coherent DMA (SICAR=0x27276767); CCSR/BAR Device. CFLAGS +=-ffunction-sections -fdata-sections LDFLAGS+=-Wl,--gc-sections @@ -967,11 +971,16 @@ ifeq ($(ARCH),PPC) endif ifneq ($(NO_ASM),1) - # Use the SHA256 and SP math all assembly accelerations + # Use the SHA256/SHA512 and SP math assembly accelerations. + # (wolfSSL PR 10767 added the SHA-512 PPC32 asm transform referenced by + # sha512.c; --gc-sections prunes it when sha512.o is not linked, e.g. ED25519.) CFLAGS+=-DWOLFSSL_SP_PPC CFLAGS+=-DWOLFSSL_PPC32_ASM -DWOLFSSL_PPC32_ASM_INLINE #CFLAGS+=-DWOLFSSL_PPC32_ASM_SMALL MATH_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-sha256-asm_c.o + # Add the SHA-512 PPC32 asm object only if its source is present (wildcard): + # PR 10767 provides it; older checkouts fall back to C sha512. + MATH_OBJS+=$(patsubst %.c,%.o,$(wildcard $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-sha512-asm_c.c)) endif endif diff --git a/config/examples/nxp-ls1028a.config b/config/examples/nxp-ls1028a.config index 366b7dcee1..cb8a65ba2e 100644 --- a/config/examples/nxp-ls1028a.config +++ b/config/examples/nxp-ls1028a.config @@ -53,3 +53,31 @@ WOLFBOOT_PARTITION_SWAP_ADDRESS?=0x20080000 WOLFBOOT_LOAD_DTS_ADDRESS?=0x80000000 WOLFBOOT_DTS_BOOT_ADDRESS?=0x20F00000 WOLFBOOT_DTS_UPDATE_ADDRESS?=0x20F00000 + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles wolfIP + the NXP ENETC ethernet port into the test-app and runs a +# board-side network test (the Makefile auto-selects nxp_enetc for +# TARGET=nxp_ls1028a). ENETC is a PCIe integrated-endpoint MAC over ECAM +# (AArch64 LE, no byte-swap); runs MMU-on with cacheable DDR (required for +# coherent ENETC DMA), so the driver does explicit cache maintenance. +# +# wolfIP does not fit the default 256KB OCRAM load region: load the app into +# DDR and enlarge the boot partition (override the flash layout below). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +#WOLFBOOT_PARTITION_SIZE=0x100000 +#WOLFBOOT_PARTITION_BOOT_ADDRESS=0x20100000 +#WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x20300000 +#WOLFBOOT_PARTITION_SWAP_ADDRESS=0x20500000 +# Load (and run) the app from DDR rather than OCRAM: +#WOLFBOOT_LOAD_ADDRESS=0x80100000 +# PHY interface default is port0 SGMII (nxp_enetc_board.h); RGMII boards set 0: +#CFLAGS_EXTRA+=-DNXP_ENETC_IF_SGMII=0 +# Test mode (neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 diff --git a/config/examples/nxp-t1024.config b/config/examples/nxp-t1024.config index 8cbd033897..31f9576015 100644 --- a/config/examples/nxp-t1024.config +++ b/config/examples/nxp-t1024.config @@ -65,3 +65,26 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x7F100000 # Load to RAM before hash and verify CFLAGS_EXTRA+=-DWOLFBOOT_USE_RAMBOOT + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles wolfIP + the NXP QorIQ FMan ethernet port (mEMAC/MDIO, FM1@DTSEC1) +# into the test-app and runs a board-side network test. The T1024 (e5500) +# reuses the same nxp_fman driver as the T2080/T1040; default CCSRBAR is the +# reset value 0xFE000000 (no BOARD_CW_VPX3152 relocate). Build the app FLAT and +# 32-bit (ELF=0) at a low load address (the elf32 load path is unused). wolfIP +# objects are built -fno-plt -D_FORTIFY_SOURCE=0 (no PLT/GOT runtime fixup). +# Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout (or add it as lib/wolfip). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +#ELF=0 +#WOLFBOOT_LOAD_ADDRESS=0x100000 +# PHY interface default is FM1@DTSEC1 SGMII (nxp_fman_board.h); RGMII set 0: +#CFLAGS_EXTRA+=-DNXP_FMAN_IF_SGMII=0 +# Test mode (neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 diff --git a/config/examples/nxp-t1040.config b/config/examples/nxp-t1040.config index 317eb470ef..9d512cc832 100644 --- a/config/examples/nxp-t1040.config +++ b/config/examples/nxp-t1040.config @@ -65,3 +65,36 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x7F100000 # Load to RAM before hash and verify CFLAGS_EXTRA+=-DWOLFBOOT_USE_RAMBOOT + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles wolfIP + the NXP QorIQ FMan ethernet port (mEMAC/MDIO, FM1@DTSEC1) +# into the test-app and runs a board-side network test. The T1040 (e5500) +# reuses the same nxp_fman driver as the T2080; default CCSRBAR is the reset +# value 0xFE000000 (no BOARD_CW_VPX3152 relocate). Build the app FLAT and +# 32-bit (ELF=0) at a low load address (the elf32 load path is unused). wolfIP +# objects are built -fno-plt -D_FORTIFY_SOURCE=0 (no PLT/GOT runtime fixup). +# Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout (or add it as lib/wolfip). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +#ELF=0 +#WOLFBOOT_LOAD_ADDRESS=0x100000 +# PHY wiring. nxp_fman default is FM1@DTSEC1 SGMII, PHY probed at addr 0x2. +# On the T1040D4RDB the cabled front port "ETH0" is FM1@DTSEC4 (ethernet@e6000), +# RGMII, Realtek RTL8211 PHY (id 0x001CC915) at MDIO addr 4 -- hardware-verified +# (DHCP lease, WOLFIP_TEST: PASS). DTSEC1/2 are fixed-link to the on-board L2 +# switch (no PHY). Uncomment for the RDB ETH0 port: +#CFLAGS_EXTRA+=-DNXP_FMAN_MEMAC_IDX=4 +#CFLAGS_EXTRA+=-DNXP_FMAN_IF_SGMII=0 +#CFLAGS_EXTRA+=-DNXP_FMAN_PHY_ADDR=4 +# To find the cabled port on a different board, enable the MDIO bus scan: it +# prints ID1/ID2/BSR for every address after init; the one with link=UP (BSR +# bit 2) is the wired port. Diagnostic only. +#CFLAGS_EXTRA+=-DWOLFIP_PHY_SCAN +# Test mode (neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 diff --git a/config/examples/nxp-t2080.config b/config/examples/nxp-t2080.config index 39e11134fc..c3e32b0ac0 100644 --- a/config/examples/nxp-t2080.config +++ b/config/examples/nxp-t2080.config @@ -63,18 +63,22 @@ WOLFBOOT_ORIGIN?=0xEFFE0000 # wolfBoot partition size (custom) BOOTLOADER_PARTITION_SIZE=0x20000 +# The region [0xEFF00000, 0xEFFE0000) below wolfBoot is reserved for the FMan +# microcode (FMAN_FW_ADDR=0xEFF00000, the U-Boot-standard slot). The partitions +# below sit under it so a BOOT-partition erase/update never touches the ucode. + # Application Partition Size WOLFBOOT_PARTITION_SIZE?=0x100000 -# Location in Flash for Application Partition -WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xEFEE0000 +# Location in Flash for Application Partition (top = 0xEFF00000, below the ucode) +WOLFBOOT_PARTITION_BOOT_ADDRESS?=0xEFE00000 # Load Partition to RAM Address WOLFBOOT_LOAD_ADDRESS?=0x19000 # Location in Flash for Update Partition -WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0xEFDE0000 +WOLFBOOT_PARTITION_UPDATE_ADDRESS?=0xEFD00000 # Location of temporary sector used during updates -WOLFBOOT_PARTITION_SWAP_ADDRESS?=0xEFDD0000 +WOLFBOOT_PARTITION_SWAP_ADDRESS?=0xEFCF0000 # DTS (Device Tree) WOLFBOOT_DTS_BOOT_ADDRESS?=0xE8040000 @@ -124,3 +128,40 @@ WOLFBOOT_LOAD_DTS_ADDRESS?=0x200000 # wolfCrypt Test and Benchmark (requires larger partition size) #WOLFCRYPT_TEST?=1 #WOLFCRYPT_BENCHMARK?=1 + +# ----------------------------------------------------------------------------- +# wolfIP network test in the test-app (optional) +# ----------------------------------------------------------------------------- +# Compiles wolfIP + the NXP QorIQ FMan ethernet port (mEMAC/MDIO/SGMII, +# FM1@DTSEC1) into the test-app and runs a board-side network test. Build the +# app FLAT and 32-bit (ELF=0, OS_64BIT=0) at a low load address (the elf32 load +# path and 64-bit RTOS handoff are unused). wolfIP objects are built -fno-plt +# -D_FORTIFY_SOURCE=0 (no PLT/GOT runtime fixup). Point WOLFBOOT_LIB_WOLFIP at +# a wolfIP checkout (or add it as lib/wolfip). +#ENABLE_WOLFIP=1 +#WOLFBOOT_LIB_WOLFIP=../lib/wolfip +# Build FLAT + 32-bit at a low load address (as above; siblings t1040/t1024 too): +#ELF=0 +#OS_64BIT=0 +#WOLFBOOT_LOAD_ADDRESS=0x100000 +# Test mode (neither flag = acquire a DHCP lease and stop): +# WOLFBOOT_TEST_TFTP=1 RRQ a file from a host tftpd, report size+checksum +# (set CFLAGS_EXTRA TFTP_EXPECT_SIZE/TFTP_EXPECT_SUM to verify) +# WOLFIP_SPEED_TEST=1 TCP throughput server on port 9 (drive with nc/dd/pv) +#WOLFBOOT_TEST_TFTP=1 +#WOLFIP_SPEED_TEST=1 +# +# Per-board wolfIP ethernet wiring (defaults above are CW VPX3-152 / RDB = +# FM1@DTSEC1, SGMII, PHY probed at addr 0x2). Override per the board device +# tree if the wired port differs: +# +# NAII 68PPC2 (hardware-verified): PRIME port is FM1@DTSEC3 = RGMII, Marvell +# PHY at MDIO addr 0 (68ppc2.dts ethernet@e4000: "rgmii-id", ethernet-phy@0 +# reg <0>). The MDIO scan would otherwise grab DTSEC4's PHY at addr 1, so set +# the address explicitly: +#CFLAGS_EXTRA+=-DNXP_FMAN_MEMAC_IDX=3 +#CFLAGS_EXTRA+=-DNXP_FMAN_IF_SGMII=0 +#CFLAGS_EXTRA+=-DNXP_FMAN_PHY_ADDR=0 +# +# NAII NOR is dual-bank with only the top 128KB boot sector common to both +# banks; flash the ucode/app with the boot-bank select in its runtime state. diff --git a/docs/Targets.md b/docs/Targets.md index 35324a7163..35f11a1fab 100644 --- a/docs/Targets.md +++ b/docs/Targets.md @@ -5983,6 +5983,10 @@ variants are supported: Example configuration: [/config/examples/nxp-t2080.config](/config/examples/nxp-t2080.config). See [Board Selection](#board-selection) below for per-board setup. +> **FMan microcode (DPAA/wolfIP):** with DPAA/FMan enabled, wolfBoot uploads the FMan microcode from NOR at `FMAN_FW_ADDR` (`hal/nxp_t2080.c`), board-gated: the T2080 RDB and NAII 68PPC2 (128 MB NOR at `0xE8000000`) use `0xEFF00000` -- the U-Boot-standard slot (`CONFIG_SYS_FMAN_FW_ADDR` in `T208xRDB.h`) -- and CW VPX3-152 (256 MB NOR) uses `0xFFE60000`. The wolfBoot partitions sit below this reserved firmware region so a BOOT-partition erase/update never overwrites the ucode. The address is bounds-checked against the NOR window, so a wrong value fails gracefully instead of machine-checking. Flash the matching `fsl_fman_ucode_*` blob at that address. +> +> wolfIP-on-FMan is hardware-verified on the CW VPX3-152 (FM1@DTSEC1, SGMII), the NAII 68PPC2 (FM1@DTSEC3, RGMII, PHY @ addr 0 -- see the example config's wolfIP block), and the T1040D4RDB (e5500; FM1@DTSEC4, RGMII, RTL8211 @ addr 4). NAII NOR is dual-bank with only the top 128 KB boot sector common to both banks, so flash the ucode/app with the boot-bank select in its runtime state. + ### Design NXP T2080 PPC The QorIQ requires a Reset Configuration Word (RCW) to define the boot parameters, which resides at the start of the flash (`0xE8000000` for 128 MB boards, `0xF0000000` for the 256 MB CW VPX3-152). @@ -5995,202 +5999,29 @@ The flash boot entry point is the last 4 bytes of the NOR flash region (`0xEFFFF ``` CPU Core -> L1 (32KB I + 32KB D) -> L2 (2 MB, shared by the single 4-core cluster) - → CoreNet Fabric → CPC (2MB, SRAM or L3 cache) - → DDR Controller → DDR SDRAM - → IFC Controller → NOR Flash + -> CoreNet Fabric -> CPC (2MB, SRAM or L3 cache) + -> DDR Controller -> DDR SDRAM + -> IFC Controller -> NOR Flash ``` Each core begins execution at effective address `0x0_FFFF_FFFC` with a single 4KB MMU page (RM 4.3.3). The assembly startup (`boot_ppc_start.S`) configures TLBs, caches, and stack before jumping to C code. -**Cold Boot Stack (L1 Locked D-Cache)** - -CPC SRAM is unreliable for stores on cold power-on — L1 dirty-line evictions -through CoreNet to CPC cause bus errors (silent CPU checkstop with `MSR[ME]=0`). -The fix (matching U-Boot) uses L1 locked D-cache as the initial 16KB stack: -`dcbz` allocates cache lines without bus reads, `dcbtls` locks them so they -are never evicted. The locked lines at `L1_CACHE_ADDR` (`0xF8E00000`; `0xEE800000` on VPX3-152) are -entirely core-local. After DDR init in `hal_init()`, the stack relocates to -DDR and the CPC switches from SRAM to L3 cache mode. - -**Flash TLB and XIP** - -The flash TLB uses `MAS2_W | MAS2_G` (Write-Through + Guarded) during XIP -boot, allowing L1 I-cache to cache instruction fetches while preventing -speculative prefetch to the IFC. C code switches to `MAS2_I | MAS2_G` during -flash write/erase (command mode), then `MAS2_M` for full caching afterward. - -**CCSRBAR Relocation (CW VPX3-152 only)** - -The default CCSRBAR at `0xFE000000` (16 MB) falls within the VPX3-152's 256 MB -flash VA range (`0xF0000000`-`0xFFFFFFFF`). The startup assembly relocates -CCSRBAR to `0xEF000000` (just below flash). The CPC SRAM and L1 cache addresses -are also relocated to `0xEE900000`/`0xEE800000` to avoid overlap. - -**Boot ROM TLB invalidation (CW VPX3-152 only)** - -For VPX3-152, TLB1 Entry 2 maps the full 256 MB flash at `0xF0000000-0xFFFFFFFF` -with IPROT. This range overlaps with the boot ROM TLB (default 4 KB at -`0xFFFFF000`, resized to 256 KB at `0xFFFC0000` by `shrink_default_tlb1`). -Overlapping TLB1 entries cause an e6500 multi-hit machine check. After Entry 2 -is created, the boot ROM TLB is cleared via `tlbwe` with `V=0` and `IPROT=0`; -Entry 2 then serves all instruction fetches for the flash region including the -boot ROM range. For NAII 68PPC2 and T2080 RDB (128 MB flash at `0xE8000000`), -there is no overlap and the boot ROM TLB remains valid alongside Entry 2. - -**RAMFUNCTION Constraints** - -The NOR flash (two S29GL01GS x8 in parallel, 16-bit bus) enters -command mode bank-wide — instruction fetches during program/erase return status -data instead of code. All flash write/erase functions are marked `RAMFUNCTION`, -placed in `.ramcode`, copied to DDR, and remapped via TLB9. Key rules: - -- **No calls to flash-resident code.** The linker generates trampolines that - jump back to flash addresses. Any helper called from RAMFUNCTION code must - itself be RAMFUNCTION or fully inlined. Delay/clock helpers (for example, - `udelay` and associated clock accessors) are provided by `nxp_ppc.c` and - are marked `RAMFUNCTION` so they can be safely invoked without executing - from flash `.text`. -- **Inline TLB/cache ops.** `hal_flash_cache_disable/enable` use - `set_tlb()` / `write_tlb()` (inline `mtspr` helpers) and direct - L1CSR0/L1CSR1 manipulation. -- **WBP timing.** The write-buffer-program sequence (unlock → 0x25 → count → - data → 0x29) must execute without bus-stalling delays. UART output between - steps (~87us per character at 115200) triggers DQ1 abort. -- **WBP abort recovery.** Plain `AMD_CMD_RESET` (0xF0) is ignored in - WBP-abort state; the full unlock + 0xF0 sequence is required. - -**Multi-Core (ENABLE_MP)** - -The e6500 L2 cache is per-cluster (shared by all 4 cores). Secondary cores -must skip L2 flash-invalidate (L2FI) since the primary core already -initialized the shared L2; they only set L1 stash ID via L1CSR2. - -**e6500 64-bit GPR** - -The e6500 has 64-bit GPRs even in 32-bit mode. `lis` sign-extends to 64 bits, -producing incorrect values for addresses >= 0x80000000 (e.g., `lis r3, 0xEFFE` -→ `0xFFFFFFFF_EFFE0000`), causing TLB misses on `blr`. The `LOAD_ADDR32` -macro (`li reg, 0` + `oris` + `ori`) avoids this for all address loads. - -**MSR Configuration** - -After the stack is established: `MSR[CE|ME|DE|RI]` — critical interrupt, -machine check (exceptions instead of checkstop), debug, and recoverable -interrupt enable. Branch prediction (BUCSR) is deferred to `hal_init()` after -DDR stack relocation. - -**e6500 Cluster L2 ECC bring-up** - -The e6500 cluster L2 (memory-mapped `L2CSR0`) must be enabled in a specific -order or its ECC array is left uninitialized for ranges the OS later fetches, -producing an uncorrectable multi-bit ECC machine check (`MCSR[IF]`, -`L2ERRDET` MBECC). `boot_ppc_start.S` follows the CW U-Boot / SDK2.0 sequence: -(1) `L2FI | L2LFC` (flash-invalidate + lock-flash-clear), polling until clear; -(2) `L2PE` (ECC enable) in its own write, polling until it reads back set, -BEFORE the cache is enabled; (3) `L2E | L2PE | L2REP_MODE` to enable the cache -with ECC. Writing a bare `L2E` without first polling `L2PE` set is the -misordering that machine-checks VxWorks. - -#### VxWorks 7 64-bit Boot Support (ENABLE_OS64BIT) - -When `ENABLE_OS64BIT` is set, `do_boot()` performs the additional handoff -work needed to launch a VxWorks 7 64-bit kernel (Curtiss-Wright `ossel=ostype2` -mode) or a 64-bit Linux kernel via the ePAPR convention. - -**ePAPR handoff:** wolfBoot passes the FDT pointer in `r3`, the IMA size in -`r7`, and `0x45504150` (`'EPAP'`) in `r6`. Other GPRs are zero. MSR is -`0x00002200` (`FP|DE`); the OS sets `MSR[CM]=1` itself within its first ~30 -instructions. - -**Final 64-bit memory map (FUM Table 2.5).** `hal_os64bit_map_transition()` -in `src/boot_ppc.c` performs the board-agnostic DDR-to-slot-0 remap and -delegates the board-specific peripheral LAW/ATMU programming to -`hal_cw_vpx3152_os64_periph()`, which builds the 36-bit-aliased peripheral -map VxWorks 7 expects on CW VPX3-152: - -| Effective Address | Physical Address | Region | -|---|---|---| -| `0xF000_0000` | `0xF_F000_0000` | Flash (256 MB) | -| `0xEF00_0000` | `0xF_EF00_0000` | CCSR (16 MB) | -| `0xEE40_0000` | `0xF_EE40_0000` | FPGA / NVRAM (4 MB span) | -| `0xEE00_0000` | `0xF_EE00_0000` | DCSR (4 MB) | -| `0xEC00_0000` | `0xF_EC00_0000` | QMan portals (32 MB) | -| `0xEA00_0000` | `0xF_EA00_0000` | BMan portals (32 MB) | -| `0xE000_0000` | `0xD_0000_0000` | PCIe1 (XMC) memory (2 GB) | -| `0xC000_0000` | `0xC_0000_0000` | PCIe4 (Switch) memory (2 GB) | -| `0x0000_0000` | `0x0_0000_0000` | DDR identity (2 GB, slot 0) | - -**DDR at TLB1 slot 0.** VxWorks 7's early entry stub iterates TLB1 from -slot 1 upward invalidating each entry, then reads slot 0 expecting it to -contain the DDR mapping. wolfBoot pins DDR at slot 12 by default; the -OS-handoff transition invalidates slot 12 and writes DDR identity (2 GB, -`MAS3_SX|SW|SR`, `MAS2_M`, IPROT) at slot 0. - -**Spin-table.** `hal_mp_init()` places the secondary-core spin-table at -`bootpg - BOOT_ROM_SIZE`. For VxWorks 7 the bootpg is anchored just below -the FUM `/memory` hole at `0x7E40_0000` so `cpu-release-addr` lands inside -declared memory. `hal_mp_up()` releases all secondaries into the spin loop -via `DCFG_BRR` regardless of `ENABLE_OS64BIT` (the earlier theory that CW -U-Boot holds the secondaries in reset for `ossel=ostype2` was disproven -- -U-Boot also releases CPU0/2/4/6 into the spin loop first). The OS then -brings up each released core via the standard ePAPR spin-table protocol -(`cpu-release-addr` in the FDT). - -**FDT fixups.** `hal_dts_fixup()` populates `cpus/cpu@N/cpu-release-addr` -and `enable-method = "spin-table"` for every core, and marks every core -`status = "okay"` (marking the secondaries `"disabled"` made VxWorks skip -them and stall on the first spin-table release). The -DTB's existing `/memory.reg` is left untouched if already populated -(matching production U-Boot's `fdt_fixup_memory` which only writes when -the node is missing). The DTB's bootargs is replaced with the -`WOLFBOOT_BOOTARGS` value from `.config` if defined. - -**RAMFUNCTION OS-jump trampoline.** wolfBoot is XIP from flash by default; -`wolfBoot_os64bit_jump()` is a `RAMFUNCTION` (lives in `.ramcode` / -DDR). Steps it performs in order: - -1. Copy the exception handler (`isr_empty`, ~208 bytes) from flash - `0xFFFE_0000` to DDR at `0x0080_0000` (4 KB-aligned), then re-point - `IVPR` to the DDR copy. Without this, the next step (switching - flash to cache-inhibit + guarded) would break the e6500 fetcher's - ability to service handler instructions, causing any subsequent - exception to silent-hang. Production U-Boot's `IVPR` likewise - targets its DDR-relocated code, not flash. -2. Call `hal_flash_cache_disable_pre_os()` (also `RAMFUNCTION`) which - switches the flash TLB to `MAS2_I|MAS2_G`, asserts DUART1 MCR=3 - (DTR+RTS, matching production U-Boot's pre-bootm value), and zeros - `TCR` to disable any leftover watchdog reset arming. -3. `sync; isync` to drain the pipeline. -4. Indirect-jump to the OS entry through `bctrl`. The bctrl is fetched - from DDR (the trampoline itself), matching the production U-Boot - pattern of running its final pre-OS instructions out of DDR. - -**Other VxWorks-driven adjustments:** - -- `CORES_PER_CLUSTER = 4` for T2080: the four e6500 cores share a single - cluster (2 MB L2), so the MP secondary path's linear core-ID is - `(PIR>>5)*4 + ((PIR>>3) & 0x3)`. The cluster term is 0 on this one-cluster - part; an earlier value of 2 (a mistaken "2 clusters of 2" reading) was - masked by that and only worked by accident. -- T2080 rev-1 e6500 errata block at primary core reset and the - secondary boot path. Erratum A003999 (HDBCR1 |= 0x0100_0000) is - intentionally NOT applied because production CW U-Boot does not - apply it to T2080. -- Secondary L2 init is gated on cluster ID > 0; T2080's four cores are all - in cluster 0, so every secondary skips it and shares the boot core's L2. -- IFC chip-selects on CW VPX3-152: AMASK + `MSEL=GPCM` aligned with CW - U-Boot's CSPR programming. CSOR is left alone while wolfBoot is still - XIP from flash (writing CSOR would alter the GPCM timing of the very - flash we are fetching from). - -**Early-boot UART debug (`WOLFBOOT_EARLY_UART`).** Defining this -preprocessor flag compiles in the e6500 early-boot (pre-C) UART debug -helper macros in `src/boot_ppc_start.S` (DUART1 at `CCSR + 0x11C500`). -They emit single-character breadcrumbs from the assembly startup when -bringing up a new board or OS, before the C `wolfBoot_printf` path is -available. Off by default. +The HAL handles several QorIQ boot constraints; the rationale is documented in `src/boot_ppc_start.S` and `hal/nxp_t2080.c`: + +- **Cold-boot stack.** CPC SRAM is unreliable for stores on cold power-on, so the initial 16KB stack uses locked L1 D-cache and relocates to DDR after `hal_init()`. +- **XIP flash access.** wolfBoot executes in place from NOR. Because program/erase puts the NOR into command mode bank-wide, all flash write/erase routines are `RAMFUNCTION` (copied to DDR) and must not call flash-resident code; the flash TLB switches cache attributes around program/erase. +- **Multi-core (`ENABLE_MP`).** The e6500 L2 is shared by all four cores in the single cluster, so secondaries skip L2 re-init and share the boot core's L2. +- **CW VPX3-152 (256 MB NOR) only.** The larger flash VA range forces CCSRBAR to relocate from `0xFE000000` to `0xEF000000` (CPC/L1 addresses move to `0xEE900000`/`0xEE800000`), and the boot-ROM TLB is invalidated to avoid an e6500 multi-hit machine check. The 128 MB RDB and NAII boards need neither adjustment. + +#### VxWorks 7 / 64-bit OS Boot Support (ENABLE_OS64BIT) + +With `ENABLE_OS64BIT`, `do_boot()` performs the extra handoff needed to launch a 64-bit kernel -- a VxWorks 7 kernel (Curtiss-Wright `ossel=ostype2` mode) or a 64-bit Linux kernel via the ePAPR convention. This path is hardware-verified on the CW VPX3-152 booting VxWorks 7 and Green Hills INTEGRITY-178 tuMP. + +wolfBoot hands off per ePAPR: FDT pointer in `r3`, `'EPAP'` in `r6`, IMA size in `r7`, remaining GPRs zero, with the OS switching itself to 64-bit mode. Before the jump wolfBoot builds the final 64-bit memory map (DDR identity-mapped at TLB1 slot 0, plus the board's peripheral and PCIe windows), fixes up the FDT (`cpu-release-addr`, `enable-method`, per-core `status`, and the `WOLFBOOT_BOOTARGS` bootargs), releases the secondary cores into the ePAPR spin-table, and jumps to the OS entry from a `RAMFUNCTION` trampoline running out of DDR. The board-specific peripheral map is supplied by the board HAL (for the VPX3-152, `hal_cw_vpx3152_os64_periph()`). + +Set `WOLFBOOT_EARLY_UART` to compile in pre-C single-character UART breadcrumbs (DUART1) emitted from the assembly startup, useful when bringing up a new board or OS. Off by default. ### Building wolfBoot for NXP T2080 PPC @@ -6261,8 +6092,8 @@ Flash Layout (T2080 RDB / NAII 68PPC2, 128 MB flash): | Description | File | Address | | ----------- | ---- | ------- | | Reset Configuration Word (RCW) | _(board-specific)_ | `0xE8000000` | -| Frame Manager Microcode | `fsl_fman_ucode_t2080_r1.0.bin` | `0xE8020000` | -| Signed Application | `test-app/image_v1_signed.bin` | `0xE8080000` | +| Signed Application | `test-app/image_v1_signed.bin` | `0xEFE00000` | +| Frame Manager Microcode | `fsl_fman_ucode_t2080_r1.0.bin` | `0xEFF00000` | | wolfBoot | `wolfboot.bin` | `0xEFFE0000` | | Boot Entry Point (offset jump to init code) | | `0xEFFFFFFC` | @@ -6271,8 +6102,8 @@ Flash Layout (CW VPX3-152, 256 MB flash): | Description | File | Address | | ----------- | ---- | ------- | | Reset Configuration Word (RCW) | _(board-specific)_ | `0xF0000000` | -| Frame Manager Microcode | `fsl_fman_ucode_t2080_r1.0.bin` | `0xF0020000` | -| Signed Application | `test-app/image_v1_signed.bin` | `0xF0080000` | +| Frame Manager Microcode | `fsl_fman_ucode_t2080_r1.0.bin` | `0xFFE60000` | +| Signed Application | `test-app/image_v1_signed.bin` | `0xFF000000` | | wolfBoot | `wolfboot.bin` | `0xFFFE0000` | | Boot Entry Point (offset jump to init code) | | `0xFFFFFFFC` | diff --git a/hal/nxp_ls1028a.c b/hal/nxp_ls1028a.c index c603adaed7..cd326d70d5 100644 --- a/hal/nxp_ls1028a.c +++ b/hal/nxp_ls1028a.c @@ -41,8 +41,6 @@ void hal_flash_init(void); -void switch_el3_to_el2(void); -extern void mmu_enable(void); #ifdef DEBUG_UART void uart_init(void) @@ -272,11 +270,6 @@ void* hal_get_dts_update_address(void) return (void*)NULL; } -void erratum_err050568(void) -{ - /* Use IP bus only if systembus PLL is 300MHz (Dont use 300MHz) */ -} - /* Application on Serial NOR Flash device 18.6.3 */ void xspi_init(void) { @@ -698,10 +691,6 @@ int ext_flash_erase(uintptr_t address, int len) void hal_prepare_boot(void) { - #if 0 - /* TODO: EL2 */ - switch_el3_to_el2(); - #endif } #ifdef TEST_HW_DDR @@ -814,30 +803,130 @@ static int test_flash(void) } #endif /* TEST_EXT_FLASH */ -/* Function to set MMU MAIR memory attributes base on index */ -void set_memory_attribute(uint32_t attr_idx, uint64_t mair_value) -{ - uint64_t mair = 0; - - asm volatile("mrs %0, mair_el3" : "=r"(mair)); - mair &= ~(0xffUL << (attr_idx * 8)); - mair |= (mair_value << (attr_idx * 8)); - asm volatile("msr mair_el3, %0" : : "r"(mair)); -} - void hal_init_tzpc(void) { TZDECPROT0_SET = 0xff; //0x86; TZDECPROT1_SET = 0xff; //0x00; TZPCR0SIZE = 0x00; //0x200; - /* Enable TZASC to allow secure read/write access to the DDR */ - /* Really, we are allowing the full Region 0 to be R/W in secure world */ + /* 0x110 gates only SECURE R/W; NS access is REGION_ID_ACCESS_0 (0x114). + * Open NS R/W too, or the non-secure ENETC bus-master DMA faults + * (SIUSBEDR[V]/TBSR[SBE]). TF-A programs both. */ TZASC_ACTION = TZASC_ACTION_ENABLE_DECERR; TZASC_REGION_ATTRIBUTES_0 = TZASC_REGION_ATTRIBUTES_ALLOW_SECRW; + TZASC_REGION_ID_ACCESS_0 = TZASC_REGION_ID_ACCESS_ALL_NS; TZASC_GATE_KEEPER = TZASC_GATE_KEEPER_REQUEST_OPEN; } +/* Boot ROM can leave a Cortex-A72 SP805 watchdog armed; unserviced it resets + * the SoC mid-boot. Log the reset cause + core0 WDT state, then disable both. */ +#define LS1028A_RST_BASE 0x01E60000UL +#define LS1028A_RSTRQSR1 (LS1028A_RST_BASE + 0x18UL) /* reset request status */ +#define LS1028A_RSTRQSR2 (LS1028A_RST_BASE + 0x1CUL) +#define LS1028A_RSTRQWDTSRL (LS1028A_RST_BASE + 0x30UL) /* WDT reset status lo */ +#define LS1028A_RSTRQWDTSRU (LS1028A_RST_BASE + 0x34UL) /* WDT reset status hi */ +#define LS1028A_WDOG0_BASE 0x0C000000UL /* cluster1 core0 SP805 */ +#define LS1028A_WDOG1_BASE 0x0C010000UL /* cluster1 core1 SP805 */ +#define SP805_WDOGVALUE 0x004UL /* current count (RO) */ +#define SP805_WDOGCONTROL 0x008UL /* bit0 INTEN, bit1 RESEN */ +#define SP805_WDOGLOCK 0xC00UL +#define SP805_WDOG_UNLOCK 0x1ACCE551UL + +static void ls1028a_wdt_disable(uint32_t base) +{ + *(volatile uint32_t *)(base + SP805_WDOGLOCK) = SP805_WDOG_UNLOCK; + *(volatile uint32_t *)(base + SP805_WDOGCONTROL) = 0x0UL; + *(volatile uint32_t *)(base + SP805_WDOGLOCK) = 0x0UL; /* re-lock */ +} + +static void ls1028a_reset_diag(void) +{ +#if defined(DEBUG_UART) + /* Reset-cause / watchdog status readout; diagnostic only. */ + uint32_t rstcause, wctrl, wval; + + rstcause = *(volatile uint32_t *)LS1028A_RSTRQSR1; + wctrl = *(volatile uint32_t *)(LS1028A_WDOG0_BASE + SP805_WDOGCONTROL); + wval = *(volatile uint32_t *)(LS1028A_WDOG0_BASE + SP805_WDOGVALUE); + wolfBoot_printf("RST: RSTRQSR1=0x%x WDOG0 ctrl=0x%x val=0x%x\n", + rstcause, wctrl, wval); + wolfBoot_printf("RST: RSTRQSR2=0x%x WDTSRL=0x%x WDTSRU=0x%x\n", + *(volatile uint32_t *)LS1028A_RSTRQSR2, + *(volatile uint32_t *)LS1028A_RSTRQWDTSRL, + *(volatile uint32_t *)LS1028A_RSTRQWDTSRU); +#endif + + ls1028a_wdt_disable(LS1028A_WDOG0_BASE); + ls1028a_wdt_disable(LS1028A_WDOG1_BASE); +} + +/* Bypass the SMMU-500 (TF-A's job): without it the non-secure ENETC DMA is + * faulted on its BD prefetch (SIUSBEDR[V]/TBSR[SBE]). Set CLIENTPD + clear + * USFCFG in the secure SCR0 and the non-secure NSCR0. */ +#define LS1028A_SMMU_BASE 0x05000000UL +#define SMMU_SCR0 0x000UL +#define SMMU_NSCR0 0x400UL +#define SMMU_SCR0_CLIENTPD 0x00000001UL +#define SMMU_SCR0_USFCFG 0x00000400UL + +static void ls1028a_smmu_bypass(void) +{ + volatile uint32_t *scr0 = (volatile uint32_t *)(LS1028A_SMMU_BASE + SMMU_SCR0); + volatile uint32_t *nscr0 = (volatile uint32_t *)(LS1028A_SMMU_BASE + SMMU_NSCR0); + + *scr0 = (*scr0 | SMMU_SCR0_CLIENTPD) & ~SMMU_SCR0_USFCFG; + *nscr0 = (*nscr0 | SMMU_SCR0_CLIENTPD) & ~SMMU_SCR0_USFCFG; +} + +/* Enable CCI-400 snoop+DVM for the A72 cluster (slave iface 4); TF-A's job. + * Without it the coherent ENETC DMA (SICAR=0x27276767) cannot snoop the caches + * and takes a bus error (TBSR[SBE]). */ +#define LS1028A_CCI_BASE 0x04090000UL +#define CCI_SLAVE_IFACE4 0x5000UL /* A72 cluster 0 */ +#define CCI_SNOOP_CTRL 0x000UL +#define CCI_SNOOP_EN 0x00000001UL +#define CCI_DVM_EN 0x00000002UL +#define CCI_STATUS 0x00CUL +#define CCI_STATUS_CHANGE_PEND 0x00000001UL + +static void ls1028a_cci_enable_coherency(void) +{ + volatile uint32_t *snoop = (volatile uint32_t *) + (LS1028A_CCI_BASE + CCI_SLAVE_IFACE4 + CCI_SNOOP_CTRL); + volatile uint32_t *status = (volatile uint32_t *) + (LS1028A_CCI_BASE + CCI_STATUS); + uint32_t timeout = 1000000U; + + *snoop = *snoop | CCI_SNOOP_EN | CCI_DVM_EN; + while ((*status & CCI_STATUS_CHANGE_PEND) != 0U && --timeout) { + } + if (timeout == 0U) { + /* Best-effort: coherency backs up the TZASC fix and driver cache + * maintenance, so warn and continue. */ + wolfBoot_printf("CCI: snoop-enable did not commit; continuing\n"); + } +} + +/* Enable the ARMv8 system counter (TF-A's job): route to the A72 (CLTBENR b0) + * and start it (CNTCR.EN), or CNTPCT stays frozen and DHCP never retries. + * CNTFRQ_EL0 is published from CNTFID0 in boot_aarch64_start.S. */ +#define LS1028A_PMU_BASE 0x01E30000UL +#define PMU_CLTBENR 0x18A0UL /* cluster timer base enable */ +#define LS1028A_SYSCNT_BASE 0x023E0000UL +#define SYSCNT_CNTCR 0x000UL +#define SYSCNT_CNTCR_EN 0x00000001UL + +static void ls1028a_enable_syscounter(void) +{ + volatile uint32_t *cltbenr = (volatile uint32_t *) + (LS1028A_PMU_BASE + PMU_CLTBENR); + volatile uint32_t *cntcr = (volatile uint32_t *) + (LS1028A_SYSCNT_BASE + SYSCNT_CNTCR); + + *cltbenr = *cltbenr | 0x1U; /* cluster 0 timer base */ + *cntcr = *cntcr | SYSCNT_CNTCR_EN; /* start the system counter */ +} + void hal_init(void) { volatile uint32_t counter=0xFFFFul; /* used for delay */ @@ -846,6 +935,11 @@ void hal_init(void) wolfBoot_printf("wolfBoot Init\n"); #endif + ls1028a_reset_diag(); + ls1028a_smmu_bypass(); + ls1028a_cci_enable_coherency(); + ls1028a_enable_syscounter(); + hal_init_tzpc(); hal_flash_init(); @@ -878,12 +972,6 @@ void hal_init(void) wolfBoot_printf("DDR R/W test passed\n"); } #endif - -#if 0 - /* TODO: MMU enable? */ - mmu_enable(); - wolfBoot_printf("MMU init done\n"); -#endif } #endif /* TARGET_nxp_ls1028a */ diff --git a/hal/nxp_ls1028a.h b/hal/nxp_ls1028a.h index b7af78dea1..c461ad3439 100644 --- a/hal/nxp_ls1028a.h +++ b/hal/nxp_ls1028a.h @@ -268,7 +268,12 @@ #define TZASC_REGION_ATTRIBUTES_0 *((volatile uint32_t*)(TZASC_BASE + 0x110)) #define TZASC_ACTION_ENABLE_DECERR 0x1 /* RM 32.4.3 */ #define TZASC_GATE_KEEPER_REQUEST_OPEN 0x1 /* RM 32.4.3 */ -#define TZASC_REGION_ATTRIBUTES_ALLOW_SECRW 0xC0000001 /* RM 32.4.15 */ +#define TZASC_REGION_ATTRIBUTES_ALLOW_SECRW 0xC0000001 /* RM 32.4.15 (secure R/W only) */ +/* TZC-400 Region 0 ID-access register (non-secure permissions; 0x110 gates + * only SECURE). bits[15:0]=per-NSAID read en, bits[31:16]=per-NSAID write en; + * 0xFFFFFFFF = NS read+write for all NSAIDs, needed for ENETC bus-master DMA. */ +#define TZASC_REGION_ID_ACCESS_0 *((volatile uint32_t*)(TZASC_BASE + 0x114)) +#define TZASC_REGION_ID_ACCESS_ALL_NS 0xFFFFFFFF /* TZPC Trust Zone Protection Controller for OCRAM RM 32.6 */ #define TZPC_OCRAM (0x2200000) diff --git a/hal/nxp_ls1028a.ld b/hal/nxp_ls1028a.ld index 87ca474dbf..cba029bdf9 100644 --- a/hal/nxp_ls1028a.ld +++ b/hal/nxp_ls1028a.ld @@ -77,6 +77,28 @@ SECTIONS _rodata_end = .; } > FLASH + /* AArch64 MMU translation tables, each 4KB-aligned (satisfies L0/L1/L2) in + * NOR (XIP: the table walk reads them from flash). Without these explicit + * sections they land in .rodata at 8-byte align -> bad walk, hang at MMU + * enable. */ + .mmu_tbl0 (ALIGN(4096)) : { + __mmu_tbl0_start = .; + *(.mmu_tbl0) + __mmu_tbl0_end = .; + } > FLASH + + .mmu_tbl1 (ALIGN(4096)) : { + __mmu_tbl1_start = .; + *(.mmu_tbl1) + __mmu_tbl1_end = .; + } > FLASH + + .mmu_tbl2 (ALIGN(4096)) : { + __mmu_tbl2_start = .; + *(.mmu_tbl2) + __mmu_tbl2_end = .; + } > FLASH + PROVIDE(_stored_data = .); .data : diff --git a/hal/nxp_t10xx.c b/hal/nxp_t10xx.c index 973dcffe46..c263c5177a 100644 --- a/hal/nxp_t10xx.c +++ b/hal/nxp_t10xx.c @@ -3293,9 +3293,9 @@ int hal_flash_write(uint32_t address, const uint8_t *data, int len) for (i=0; iheader; unsigned int i; + /* Guard: FMAN_FW_ADDR must lie in the NOR window, else the magic read + * below machine-checks. Compare via offset-from-base (not base+size) so the + * bound does not overflow uintptr_t when a 256MB NOR sits at the top of the + * 32-bit space (CW VPX3-152: 0xF0000000 + 256MB wraps to 0); the first + * clause ensures addr >= base, so the subtraction is safe. */ + if ((uintptr_t)FMAN_FW_ADDR < (uintptr_t)FLASH_BASE_ADDR || + ((uintptr_t)FMAN_FW_ADDR - (uintptr_t)FLASH_BASE_ADDR) >= + (uintptr_t)FLASH_BANK_SIZE) { + wolfBoot_printf("FMAN: fw addr 0x%x outside NOR, skipping\n", + (unsigned)FMAN_FW_ADDR); + return -1; + } + /* Check firmware magic */ if (hdr->magic[0] != 'Q' || hdr->magic[1] != 'E' || hdr->magic[2] != 'F') { - wolfBoot_printf("FMAN: no firmware at 0x%x\n", FMAN_FW_ADDR); + wolfBoot_printf("FMAN: no firmware at 0x%x\n", (unsigned)FMAN_FW_ADDR); return -1; } diff --git a/include/user_settings.h b/include/user_settings.h index 5c59ae3ed1..2cfe52d592 100644 --- a/include/user_settings.h +++ b/include/user_settings.h @@ -217,8 +217,12 @@ extern int tolower(int c); #if !defined(PKCS11_SMALL) && !defined(WOLFCRYPT_TEST) && !defined(WOLFCRYPT_BENCHMARK) # define HAVE_ECC_CDH #endif + /* Don't force SP_MATH when a config selects SP_MATH_ALL (SPMATHALL=1, + * e.g. T1024/T1040); the two SP math backends are mutually exclusive. */ +# if !defined(WOLFSSL_SP_MATH_ALL) # define WOLFSSL_SP_MATH # define WOLFSSL_SP_SMALL +# endif # define WOLFSSL_HAVE_SP_ECC # define WOLFSSL_KEY_GEN # define HAVE_ECC_KEY_EXPORT @@ -622,6 +626,15 @@ extern int tolower(int c); #define CUSTOM_RAND_GENERATE_SEED my_rng_seed_gen #define CUSTOM_RAND_GENERATE_BLOCK my_rng_seed_gen extern int my_rng_seed_gen(unsigned char* output, unsigned int sz); + + /* Full test/benchmark algo set: AES ECB/CBC/CTR/GCM/XTS, + * SHA-256/384/512, SHA-3. (AES-CBC/GCM added below; SHA-384/512 + * from HASH=SHA384.) */ + #define WOLFSSL_AES_COUNTER + #define HAVE_AES_ECB + #define WOLFSSL_AES_XTS + #define WOLFSSL_AES_DIRECT + #define WOLFSSL_SHA3 #endif #define HAVE_AESGCM diff --git a/src/boot_aarch64.c b/src/boot_aarch64.c index 7605b78143..6cf3a2ac0c 100644 --- a/src/boot_aarch64.c +++ b/src/boot_aarch64.c @@ -61,6 +61,11 @@ extern void gicv2_init_secure(void); extern void el2_flush_and_disable_mmu(void); #endif +/* Clean & invalidate the data cache over [start,end) (in boot_aarch64_start.S). + * Used before jumping to a freshly-loaded image with MMU/caches still on, so the + * code reaches memory and the I-cache refills from it, not from stale lines. */ +extern void flush_dcache_range(unsigned long start, unsigned long end); + /* SKIP_GIC_INIT - Skip GIC initialization before booting app * This is needed for: * - Versal: Uses GICv3, not GICv2. BL31 handles GIC setup. @@ -198,6 +203,33 @@ void RAMFUNCTION do_boot(const uint32_t *app_offset) /* Non-Linux EL2 and EL3 path: legacy direct br x4 */ +#if defined(TARGET_nxp_ls1028a) && defined(MMU) && \ + (!defined(EL2_HYPERVISOR) || EL2_HYPERVISOR == 0) + /* LS1028A EL3 path keeps MMU/caches ON (its ENETC needs coherent cacheable + * DMA). Scoped here because other MMU AArch64 parts (e.g. raspi3) tear the + * MMU down for Linux and do not define WOLFBOOT_PARTITION_SIZE. Clean the + * image + DTB from D-cache and invalidate I-cache before the jump, or the + * core fetches stale DRAM. Bound the app clean by WOLFBOOT_PARTITION_SIZE + * (over-cleaning is harmless; under-cleaning is the defect). */ + #ifndef WOLFBOOT_MMU_FLUSH_APP_SIZE + #define WOLFBOOT_MMU_FLUSH_APP_SIZE WOLFBOOT_PARTITION_SIZE + #endif + #ifndef WOLFBOOT_MMU_FLUSH_DTS_SIZE + #define WOLFBOOT_MMU_FLUSH_DTS_SIZE 0x100000UL + #endif + flush_dcache_range((unsigned long)(uintptr_t)app_offset, + (unsigned long)(uintptr_t)app_offset + + (unsigned long)WOLFBOOT_MMU_FLUSH_APP_SIZE); + if ((uintptr_t)dts_offset != 0) { + flush_dcache_range((unsigned long)(uintptr_t)dts_offset, + (unsigned long)(uintptr_t)dts_offset + + (unsigned long)WOLFBOOT_MMU_FLUSH_DTS_SIZE); + } + asm volatile("ic iallu"); + asm volatile("dsb ish"); + asm volatile("isb"); +#endif + /* Set application address via x4 */ asm volatile("mov x4, %0" : : "r"(app_offset)); @@ -302,6 +334,37 @@ void IRQInterrupt(void) { hardfault_halt("IRQ"); } void FIQInterrupt(void) { hardfault_halt("FIQ"); } void SErrorInterrupt(void) { hardfault_halt("SERROR"); } +#elif defined(DEBUG_UART) && (!defined(EL2_HYPERVISOR) || EL2_HYPERVISOR == 0) +/* EL3 exception diagnostic: print the syndrome then halt -- catches a faulting + * datapath (ENETC DMA abort/SError) over UART before a watchdog reset masks it. */ +#ifndef READ_SYSREG +#define READ_SYSREG(_out, _reg) __asm__ volatile("mrs %0, " #_reg : "=r"(_out)) +#endif +static void el3_fault_halt(const char *type) +{ + uint64_t esr = 0, elr = 0, far = 0; + unsigned int el = current_el(); + + /* ESR_EL3/ELR_EL3/FAR_EL3 are only legal at EL3; guard on the runtime EL so + * a non-EL3 AArch64 target built with DEBUG_UART does not nested-trap. */ + if (el == 3) { + READ_SYSREG(esr, ESR_EL3); + READ_SYSREG(elr, ELR_EL3); + READ_SYSREG(far, FAR_EL3); + wolfBoot_printf("\n*** %s EXCEPTION (EL3) ***\n", type); + wolfBoot_printf("ESR_EL3: 0x%08x%08x\n", (uint32_t)(esr >> 32), (uint32_t)esr); + wolfBoot_printf("ELR_EL3: 0x%08x%08x\n", (uint32_t)(elr >> 32), (uint32_t)elr); + wolfBoot_printf("FAR_EL3: 0x%08x%08x\n", (uint32_t)(far >> 32), (uint32_t)far); + } + else { + wolfBoot_printf("\n*** %s EXCEPTION (EL%d) ***\n", type, el); + } + while (1) { __asm__ volatile("wfi"); } +} +void SynchronousInterrupt(void) { el3_fault_halt("SYNCHRONOUS"); } +void IRQInterrupt(void) { el3_fault_halt("IRQ"); } +void FIQInterrupt(void) { el3_fault_halt("FIQ"); } +void SErrorInterrupt(void) { el3_fault_halt("SERROR"); } #else /* Simple stubs when debug not enabled */ void SynchronousInterrupt(void) { while (1) { __asm__ volatile("wfi"); } } diff --git a/src/boot_aarch64_start.S b/src/boot_aarch64_start.S index 58066d1424..e3ddb9259e 100644 --- a/src/boot_aarch64_start.S +++ b/src/boot_aarch64_start.S @@ -219,7 +219,15 @@ InitEL3: * accurate psu_init DDR-training delays. Hardcoding 100MHz here is wrong * when the counter runs at the BootROM (undivided) rate. */ #ifndef WOLFBOOT_ZYNQMP_FSBL +#ifdef TARGET_nxp_ls1028a + /* Read the true base frequency from the system counter (CNTFID0 @ SYSCNT + * base+0x20 = SYS_REF_CLK/4); the counterfreq constant is the undivided + * clock and would make CNTPCT time run ~4x fast. */ + ldr x1, =0x023E0020 + ldr w0, [x1] +#else ldr x0,=counterfreq +#endif msr CNTFRQ_EL0, x0 #endif @@ -575,6 +583,12 @@ invalidatecaches_end: .set Memory, 0x405 | (3 << 8) | (0x0) /* normal writeback write allocate inner shared read write */ #endif .set Device, 0x409 | (1 << 53) | (1 << 54) | (0x0) /* strongly ordered read write non executable*/ +/* Outer-shareable Normal WB. A coherent DMA master behind the CCI (LS1028A + * ENETC) needs Outer-Shareable to snoop the A72 caches; Inner-Shareable only + * covers the CPU cluster. */ +.set MemoryOSH, 0x405 | (2 << 8) | (0x0) + +#ifndef TARGET_nxp_ls1028a .section .mmu_tbl0,"a" MMUTableL0: @@ -748,6 +762,64 @@ converted to 62MB */ .set SECT, SECT+0x200000 /* 0xFFE0_0000 - 0xFFFF_FFFF*/ .8byte SECT + Memory /* 2MB OCM/TCM */ +#else /* TARGET_nxp_ls1028a */ +/* ============================================================================ + * LS1028A translation tables (4KB granule, 40-bit VA/PA, T0SZ=24). + * Memory map: + * 0x00000000-0x17FFFFFF Device (CCSR: DCFG 0x1E00000, RST 0x1E60000, + * SP805 0xC000000, FlexSPI ctrl 0x20C0000, ...) + * 0x18000000-0x181FFFFF Normal (OCRAM: wolfBoot .data/.bss/stack) + * 0x18200000-0x1FFFFFFF Device + * 0x20000000-0x3FFFFFFF Normal (FlexSPI NOR: wolfBoot XIP code, executable) + * 0x40000000-0x7FFFFFFF Device + * 0x80000000-0xFFFFFFFF Normal (DDR, 2GB) Outer-Shareable Cacheable + * 0x100000000-0x7FFFFFFFF Device (incl. ENETC ECAM 0x1F0000000 + BAR + * 0x1F8000000 at the 7-8GB block) + * DDR is Normal Outer-Shareable Cacheable (MemoryOSH) for coherency with the + * ENETC coherent bus-master DMA (SICAR=0x27276767), which snoops from outside + * the CPU cluster. NOR/OCRAM are Normal for XIP execution and cacheable data. + * ========================================================================== */ +.section .mmu_tbl0,"a" +MMUTableL0: +.set SECT, MMUTableL1 +.8byte SECT + 0x3 /* 0x00_0000_0000 - 0x7F_FFFF_FFFF -> L1 */ +.8byte 0x0 /* 0x80_0000_0000 - 0xFF_FFFF_FFFF -> invalid */ + +.section .mmu_tbl1,"a" +MMUTableL1: +.set SECT, MMUTableL2 +.8byte SECT + 0x3 /* 0x0000_0000 - 0x3FFF_FFFF -> L2 (mixed) */ +.set SECT, 0x40000000 +.8byte SECT + Device /* 0x4000_0000 - 0x7FFF_FFFF 1GB Device */ +.set SECT, 0x80000000 +.8byte SECT + MemoryOSH /* 0x8000_0000 - 0xBFFF_FFFF 1GB DDR (OSH for DMA) */ +.set SECT, 0xC0000000 +.8byte SECT + MemoryOSH /* 0xC000_0000 - 0xFFFF_FFFF 1GB DDR (OSH for DMA) */ +.set SECT, 0x100000000 +.rept 0x1FC /* 0x1_0000_0000 - 0x7F_FFFF_FFFF Device (508GB) */ +.8byte SECT + Device /* incl. ENETC ECAM/BAR at the 7-8GB block */ +.set SECT, SECT + 0x40000000 +.endr + +.section .mmu_tbl2,"a" +MMUTableL2: +.set SECT, 0x0 +.rept 0xC0 /* 0x0000_0000 - 0x17FF_FFFF Device (384MB CCSR) */ +.8byte SECT + Device +.set SECT, SECT + 0x200000 +.endr +.8byte SECT + Memory /* 0x1800_0000 - 0x181F_FFFF OCRAM */ +.set SECT, SECT + 0x200000 +.rept 0x3F /* 0x1820_0000 - 0x1FFF_FFFF Device */ +.8byte SECT + Device +.set SECT, SECT + 0x200000 +.endr +.rept 0x100 /* 0x2000_0000 - 0x3FFF_FFFF NOR (512MB, exec) */ +.8byte SECT + Memory +.set SECT, SECT + 0x200000 +.endr +#endif /* TARGET_nxp_ls1028a */ + /* * FPUContextSize is the size of the array where floating point registers are diff --git a/test-app/Makefile b/test-app/Makefile index c8c6fed54e..3ab831ab25 100644 --- a/test-app/Makefile +++ b/test-app/Makefile @@ -6,19 +6,32 @@ WOLFBOOT_LIB_WOLFSSL?=../lib/wolfssl WOLFBOOT_LIB_WOLFTPM?=../lib/wolfTPM WOLFBOOT_LIB_WOLFHSM?=../lib/wolfHSM +WOLFBOOT_LIB_WOLFIP?=../lib/wolfip WOLFSSL_LOCAL_OBJDIR?=wolfssl_obj WOLFTPM_LOCAL_OBJDIR?=wolftpm_obj WOLFHSM_LOCAL_OBJDIR?=wolfhsm_obj +WOLFIP_LOCAL_OBJDIR?=wolfip_obj vpath %.c $(WOLFBOOT_LIB_WOLFSSL) vpath %.S $(WOLFBOOT_LIB_WOLFSSL) vpath %.c $(WOLFBOOT_LIB_WOLFTPM) vpath %.S $(WOLFBOOT_LIB_WOLFTPM) vpath %.c $(WOLFBOOT_LIB_WOLFHSM) vpath %.S $(WOLFBOOT_LIB_WOLFHSM) +vpath %.c $(WOLFBOOT_LIB_WOLFIP) WOLFBOOT_ROOT?=.. TARGET?=none ARCH?=ARM + +# PPC64 (e5500/e6500) vs 32-bit (e500/e500mc), set early so the wolfCrypt asm +# wiring below sees it; per-TARGET blocks later re-assert the same value. +ifeq ($(ARCH),PPC) + ifneq ($(filter nxp_t2080 nxp_t1024 nxp_t1040,$(TARGET)),) + PPC64=1 + else + PPC64=0 + endif +endif MCUXPRESSO_CMSIS?=$(MCUXPRESSO)/CMSIS ifneq (,$(filter $(TARGET),mcxa mcxw mcxn)) ifneq ($(WOLFCRYPT_TZ_PSA),1) @@ -181,6 +194,7 @@ ifeq ($(WOLFCRYPT_SUPPORT),1) # Add SHA implementations (needed for test/benchmark) APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha256.o APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha512.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sha3.o APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/hmac.o # Add RNG support (needed for ECC signing and tests) @@ -219,32 +233,70 @@ ifeq ($(WOLFCRYPT_SUPPORT),1) endif endif - # Power PC + # Power PC (wolfSSL PRs 10740 + 10767: AES/SHA-2/SHA-3 PPC asm) ifeq ($(ARCH),PPC) - # SP mp int PowerPC ASM + # SP big-number math stays on the 32-bit PPC asm path (matches the + # bootloader and the SP_WORD_SIZE=32 user_settings.h forces for PPC); the + # AES/SHA asm under test is independent of SP math. + CFLAGS+=-DWOLFSSL_SP_PPC + # PPC_ASM=0 builds wolfCrypt pure-C (no PPC64/PPC32 AES/SHA asm) for the + # C-vs-asm benchmark baseline. Default on. + PPC_ASM?=1 + ifeq ($(PPC_ASM),1) ifeq ($(PPC64),1) - CFLAGS+=-DWOLFSSL_SP_PPC64 - else - CFLAGS+=-DWOLFSSL_SP_PPC - endif - - # SHA256 - APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-sha256-asm_c.o - CFLAGS+=-DWOLFSSL_PPC32_ASM - CFLAGS+=-DWOLFSSL_PPC32_ASM_INLINE - CFLAGS+=-DWOLFSSL_PPC32_ASM_SMALL - - ifeq ($(PPC64),1) # requires wolfssl PR 9852 - # AES - APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc64/ppc64-aes-asm_c.o + # e5500/e6500: PPC64 base-scalar ASM (AES T-table, SHA-2/SHA-3 via + # 64-bit GPR ops). These are NOT POWER8 -- no VSX/vector-crypto -- so + # WOLFSSL_PPC64_ASM_CRYPTO / _POWER8 must NOT be set (they emit + # vcipher/vshasigma and would trap). CFLAGS+=-DWOLFSSL_PPC64_ASM CFLAGS+=-DWOLFSSL_PPC64_ASM_INLINE CFLAGS+=-DWOLFSSL_PPC64_ASM_SMALL CFLAGS+=-DWOLFSSL_PPC64_ASM_AES_NO_HARDEN + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc64/ppc64-aes-asm_c.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc64/ppc64-sha256-asm_c.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc64/ppc64-sha512-asm_c.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc64/ppc64-sha3-asm_c.o + else + # e500mc: PPC32 base-scalar ASM, condition-register variant (PR 10740). + # INLINE_REG selects the *_cr.c files and needs the assembler to accept + # symbolic register names (-Wa,-mregnames). + CFLAGS+=-DWOLFSSL_PPC32_ASM + CFLAGS+=-DWOLFSSL_PPC32_ASM_INLINE + CFLAGS+=-DWOLFSSL_PPC32_ASM_INLINE_REG -Wa,-mregnames + CFLAGS+=-DWOLFSSL_PPC32_ASM_SMALL + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-aes-asm_cr.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-sha256-asm_cr.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-sha512-asm_cr.o + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/ppc32/ppc32-sha3-asm_cr.o endif + endif # PPC_ASM CFLAGS+=-fomit-frame-pointer endif + + # AArch64 (ARMv8): armv8 asm + SP arm64 objects (as arch.mk links for the + # bootloader). The test-app is a separate link with full AES/SHA/ECC under + # WOLFSSL_ARMASM (and the __aarch64__ SP asm in user_settings.h). + ifeq ($(ARCH),AARCH64) + ifneq ($(NO_ARM_ASM),1) + ifeq ($(SPMATH),1) + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/sp_arm64.o + endif + APP_OBJS+=$(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/cpuid.o \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-aes-asm_c.o \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-sha256-asm_c.o \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-sha512-asm_c.o \ + $(WOLFBOOT_LIB_WOLFSSL)/wolfcrypt/src/port/arm/armv8-sha3-asm_c.o + # armv8 asm uses crypto mnemonics (aese/sha256h); arch.mk's +crypto is + # lost to a later -mstrict-align, so restore it here for the asm. + CFLAGS+=-march=armv8-a+crypto + # libgcc for SP math 128-bit helpers (__udivti3); link is -nodefaultlibs. + LIBS+=-lgcc + # syscalls.c _sbrk references _Min_Heap_Size; no heap, so anchor it at + # zero (ARM does the same). + LDFLAGS+=-Wl,--defsym=_Min_Heap_Size=0 + endif + endif endif CFLAGS+=-DWOLFSSL_USER_SETTINGS @@ -631,8 +683,6 @@ ifeq ($(TARGET),nxp_t2080) ifneq ($(SIGN),NONE) APP_OBJS+=../src/keystore.o endif - CFLAGS+=-ffunction-sections -fdata-sections - # PowerPC e6500 PPC64=1 endif @@ -1128,11 +1178,69 @@ ifeq ($(TARGET),aurix_tc3xx) endif endif +# On PPC64 (e5500/e6500) arch.mk turns on PPC32 SHA asm for the bootloader's +# image-verify link; strip it from the test-app's wolfCrypt so PPC_ASM alone +# controls the app's AES/SHA asm. +ifeq ($(PPC64),1) + CFLAGS:=$(filter-out -DWOLFSSL_PPC32_ASM -DWOLFSSL_PPC32_ASM_INLINE,$(CFLAGS)) +endif + # Capture final flags for locally built wolfSSL objects. WOLFSSL_CFLAGS:=$(CFLAGS) WOLFTPM_CFLAGS:=$(CFLAGS) WOLFHSM_CFLAGS:=$(CFLAGS) +# Optional wolfIP network stack in the test-app. +# ENABLE_WOLFIP=1 wolfIP ethernet port (nxp_fman, or nxp_enetc on +# LS1028A) + a link/PHY smoke test. +# WOLFBOOT_TEST_TFTP=1 additionally pull in wolfIP core + TFTP client for +# the full network TFTP-fetch test. +# Point WOLFBOOT_LIB_WOLFIP at a wolfIP checkout, e.g. +# make WOLFBOOT_LIB_WOLFIP=/path/to/wolfip ENABLE_WOLFIP=1 ... +ifeq ($(ENABLE_WOLFIP),1) + # Fail early with a clear message if the wolfIP checkout is missing. + ifeq ($(wildcard $(WOLFBOOT_LIB_WOLFIP)/src/wolfip.c),) + $(error ENABLE_WOLFIP=1 but no wolfIP sources found at WOLFBOOT_LIB_WOLFIP=$(WOLFBOOT_LIB_WOLFIP). Set WOLFBOOT_LIB_WOLFIP to a wolfIP checkout, e.g. make WOLFBOOT_LIB_WOLFIP=/path/to/wolfip ENABLE_WOLFIP=1 ...) + endif + # Port by target: LS1028A (AArch64) uses ENETC; QorIQ PowerPC uses FMan. + ifeq ($(TARGET),nxp_ls1028a) + WOLFIP_PORT:=nxp_enetc + WOLFIP_PORT_OBJ:=nxp_enetc.o + CFLAGS+=-DWOLFIP_PORT_ENETC + else + WOLFIP_PORT:=nxp_fman + WOLFIP_PORT_OBJ:=nxp_fman.o + # The PPC test-app's _app_entry does no BSS-PLT fixup, so -mbss-plt + # (arch.mk) would route cross-module libc calls (e.g. variable-size memcpy + # in the wolfIP driver) through an uninitialized PLT stub branching to 0; + # and default _FORTIFY_SOURCE rewrites memcpy/memmove into the _chk glibc + # symbols (absent here -> R_PPC_JMP_SLOT imports, zero GOT slots). -fno-plt + # + fortify-off keep those calls direct and unfortified. Scoped to the + # wolfIP build so default builds are unchanged. + CFLAGS+=-ffunction-sections -fdata-sections + CFLAGS+=-fno-plt -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=0 + endif + WOLFIP_PORTDIR:=$(WOLFBOOT_LIB_WOLFIP)/src/port/$(WOLFIP_PORT) + CFLAGS+=-DENABLE_WOLFIP + # wolfIP core (wolfip.c) provides the stack incl. DHCP/ICMP/TCP/UDP. + WOLFIP_OBJS:=$(WOLFIP_PORTDIR)/$(WOLFIP_PORT_OBJ) \ + $(WOLFBOOT_LIB_WOLFIP)/src/wolfip.o + ifeq ($(WOLFBOOT_TEST_TFTP),1) + CFLAGS+=-DWOLFBOOT_TEST_TFTP + WOLFIP_OBJS+=$(WOLFBOOT_LIB_WOLFIP)/src/tftp/wolftftp.o + endif + ifeq ($(WOLFIP_SPEED_TEST),1) + CFLAGS+=-DWOLFIP_SPEED_TEST + endif + APP_OBJS+=$(WOLFIP_OBJS) wolfip_tftp_test.o + # wolfIP TUs need the port headers first (so config.h resolves to the + # port copy) and tolerate wolfIP's own style; drop -Werror/-Wstack-usage. + WOLFIP_CFLAGS:=-I"$(WOLFIP_PORTDIR)" -I"$(WOLFBOOT_LIB_WOLFIP)" \ + $(filter-out -Werror -Wstack-usage=$(STACK_USAGE_LIMIT),$(CFLAGS)) \ + -DWOLFIP_ENABLE_TFTP=$(if $(filter 1,$(WOLFBOOT_TEST_TFTP)),1,0) \ + -Wno-unused -Wno-sign-compare -Wno-missing-field-initializers +endif + ifeq ($(WOLFHSM_CLIENT),1) CFLAGS += -DSTRING_USER -I"$(WOLFBOOT_LIB_WOLFSSL)" APP_OBJS += $(WOLFHSM_OBJS) @@ -1167,6 +1275,9 @@ image.srec: image.elf APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFSSL)/%, \ $(WOLFSSL_LOCAL_OBJDIR)/%, $(APP_OBJS)) +APP_OBJS := $(patsubst $(WOLFBOOT_LIB_WOLFIP)/%, \ + $(WOLFIP_LOCAL_OBJDIR)/%, $(APP_OBJS)) + ifeq ($(ELF_FLASH_SCATTER),1) # When ELF_FLASH_SCATTER=1, preprocess the ELF file with the squashelf tool SQUASHELF_TOOL = ../tools/squashelf/squashelf @@ -1243,10 +1354,22 @@ $(WOLFHSM_LOCAL_OBJDIR)/%.o: %.S $(Q)mkdir -p $(dir $@) $(Q)$(CC) $(WOLFHSM_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + +$(WOLFIP_LOCAL_OBJDIR)/%.o: %.c + @echo "\t[CC-$(ARCH)] $@" + $(Q)mkdir -p $(dir $@) + $(Q)$(CC) $(WOLFIP_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + +# Local test-app wolfIP glue, built with the wolfIP include/flag set. +wolfip_tftp_test.o: wolfip_tftp_test.c + @echo "\t[CC-$(ARCH)] $@" + $(Q)$(CC) $(WOLFIP_CFLAGS) -c $(OUTPUT_FLAG) $@ $< + + clean: $(Q)rm -f *.bin *.elf tags *.o $(LSCRIPT) $(APP_OBJS) wcs/*.o $(Q)rm -rf $(WOLFSSL_LOCAL_OBJDIR) $(WOLFTPM_LOCAL_OBJDIR) \ - $(WOLFHSM_LOCAL_OBJDIR) + $(WOLFHSM_LOCAL_OBJDIR) $(WOLFIP_LOCAL_OBJDIR) $(LSCRIPT): $(LSCRIPT_TEMPLATE) FORCE $(Q)printf "%d" $(WOLFBOOT_PARTITION_BOOT_ADDRESS) > .wolfboot-offset diff --git a/test-app/app_nxp_ls1028a.c b/test-app/app_nxp_ls1028a.c index fb0f6af527..3f391e998f 100644 --- a/test-app/app_nxp_ls1028a.c +++ b/test-app/app_nxp_ls1028a.c @@ -21,96 +21,58 @@ #include #include "wolfboot/wolfboot.h" - -/* P1021 */ -#define CCSRBAR (0x1000000) -#define SYS_CLK (400000000) - -/* P1021 PC16552D Dual UART */ -#define BAUD_RATE 115200 -#define UART_SEL 0 /* select UART 0 or 1 */ - -#define UART_BASE(n) (0x21C0500 + (n * 100)) - -#define UART_RBR(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* receiver buffer register */ -#define UART_THR(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* transmitter holding register */ -#define UART_IER(n) *((volatile uint8_t*)(UART_BASE(n) + 1)) /* interrupt enable register */ -#define UART_FCR(n) *((volatile uint8_t*)(UART_BASE(n) + 2)) /* FIFO control register */ -#define UART_IIR(n) *((volatile uint8_t*)(UART_BASE(n) + 2)) /* interrupt ID register */ -#define UART_LCR(n) *((volatile uint8_t*)(UART_BASE(n) + 3)) /* line control register */ -#define UART_LSR(n) *((volatile uint8_t*)(UART_BASE(n) + 5)) /* line status register */ -#define UART_SCR(n) *((volatile uint8_t*)(UART_BASE(n) + 7)) /* scratch register */ - -/* enabled when UART_LCR_DLAB set */ -#define UART_DLB(n) *((volatile uint8_t*)(UART_BASE(n) + 0)) /* divisor least significant byte register */ -#define UART_DMB(n) *((volatile uint8_t*)(UART_BASE(n) + 1)) /* divisor most significant byte register */ - -#define UART_FCR_TFR (0x04) /* Transmitter FIFO reset */ -#define UART_FCR_RFR (0x02) /* Receiver FIFO reset */ -#define UART_FCR_FEN (0x01) /* FIFO enable */ -#define UART_LCR_DLAB (0x80) /* Divisor latch access bit */ -#define UART_LCR_WLS (0x03) /* Word length select: 8-bits */ -#define UART_LSR_TEMT (0x40) /* Transmitter empty */ -#define UART_LSR_THRE (0x20) /* Transmitter holding register empty */ - -static void uart_init(void) -{ - /* calc divisor for UART - * example config values: - * clock_div, baud, base_clk 163 115200 300000000 - * +0.5 to round up - */ - uint32_t div = (((SYS_CLK / 2.0) / (16 * BAUD_RATE)) + 0.5); - - while (!(UART_LSR(UART_SEL) & UART_LSR_TEMT)) - ; - - /* set ier, fcr, mcr */ - UART_IER(UART_SEL) = 0; - UART_FCR(UART_SEL) = (UART_FCR_TFR | UART_FCR_RFR | UART_FCR_FEN); - - /* enable baud rate access (DLAB=1) - divisor latch access bit*/ - UART_LCR(UART_SEL) = (UART_LCR_DLAB | UART_LCR_WLS); - /* set divisor */ - UART_DLB(UART_SEL) = (div & 0xff); - UART_DMB(UART_SEL) = ((div >> 8) & 0xff); - /* disable rate access (DLAB=0) */ - UART_LCR(UART_SEL) = (UART_LCR_WLS); -} - -static void uart_write(const char* buf, uint32_t sz) -{ - uint32_t pos = 0; - while (sz-- > 0) { - while (!(UART_LSR(UART_SEL) & UART_LSR_THRE)) - ; - UART_THR(UART_SEL) = buf[pos++]; - } -} - -static const char* hex_lut = "0123456789abcdef"; - +#include "printf.h" + +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + +#if defined(WOLFCRYPT_TEST) || defined(WOLFCRYPT_BENCHMARK) +#include +#endif +#ifdef WOLFCRYPT_TEST +#include +int wolfcrypt_test(void *args); +#endif +#ifdef WOLFCRYPT_BENCHMARK +#include +int benchmark_test(void *args); +#endif + +/* UART is up from wolfBoot hal_init; wolfBoot_printf() routes to it (no-op + * when DEBUG_UART=0). */ __attribute__((section(".boot"))) void main(void) { - int i = 0; - int j = 0; - int k = 0; - char snum[8]; - uint32_t bootver; - uint32_t updv; - - uart_write("Test App\n", 9); - - /* Wait for reboot */ - while(1) { - for (j=0; j<1000000; j++); - i++; - - uart_write("\r\n0x", 4); - for (k=0; k<8; k++) { - snum[7 - k] = hex_lut[(i >> 4*k) & 0xf]; - } - uart_write(snum, 8); - } + /* App BSS lives in uninitialized DDR (no crt0 startup), so zero it. */ + extern char _start_bss[], _end_bss[]; + char *p; + + for (p = _start_bss; p < _end_bss; p++) + *p = 0; + + wolfBoot_printf("Test App\r\n"); + +#if defined(WOLFCRYPT_TEST) || defined(WOLFCRYPT_BENCHMARK) + wolfCrypt_Init(); +#ifdef WOLFCRYPT_TEST + wolfBoot_printf("\r\nRunning wolfCrypt tests...\r\n"); + wolfcrypt_test(NULL); + wolfBoot_printf("Tests complete.\r\n"); +#endif +#ifdef WOLFCRYPT_BENCHMARK + wolfBoot_printf("\r\nRunning wolfCrypt benchmarks...\r\n"); + benchmark_test(NULL); + wolfBoot_printf("Benchmarks complete.\r\n"); +#endif + wolfCrypt_Cleanup(); +#endif + +#ifdef ENABLE_WOLFIP + wolfip_tftp_test_report(); +#endif + + wolfBoot_printf("Test App: idle\r\n"); + while (1) + ; } diff --git a/test-app/app_nxp_t1024.c b/test-app/app_nxp_t1024.c index 8e511b5af8..dc8058750d 100644 --- a/test-app/app_nxp_t1024.c +++ b/test-app/app_nxp_t1024.c @@ -47,12 +47,9 @@ __asm__ ( " blr\n" ); -/* Assembly entry point: set stack pointer, enable FPU, and call main. - * The linker script defines _stack_top at the end of the stack region. - * PPC ABI: r1 = stack pointer, 16-byte aligned, back-chain to 0. - * FPU must be enabled because GCC's variadic function ABI (used by - * uart_printf/wolfBoot_printf) saves FP registers via stfd instructions. - * Without MSR[FP], this causes a Floating-Point Unavailable exception. */ +/* Assembly entry: set SP (_stack_top, PPC ABI: 16-byte aligned, back-chain 0), + * enable the FPU (MSR[FP]) -- the variadic printf ABI saves FP regs via stfd + * and would otherwise fault -- then branch to main. */ __asm__ ( ".section .text._app_entry\n" ".global _app_entry\n" @@ -73,6 +70,10 @@ __asm__ ( #include "../hal/nxp_ppc.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + static uint8_t boot_part_state = IMG_STATE_NEW; static uint8_t update_part_state = IMG_STATE_NEW; @@ -174,6 +175,10 @@ void main(void) wolfBoot_success(); wolfBoot_printf("\r\nBoot partition marked successful\r\n"); +#ifdef ENABLE_WOLFIP + wolfip_tftp_test_report(); +#endif + wolfBoot_printf("Test App: idle loop\r\n"); while(1) { /* Idle */ diff --git a/test-app/app_nxp_t1040.c b/test-app/app_nxp_t1040.c index c58e586416..19548afbee 100644 --- a/test-app/app_nxp_t1040.c +++ b/test-app/app_nxp_t1040.c @@ -47,12 +47,9 @@ __asm__ ( " blr\n" ); -/* Assembly entry point: set stack pointer, enable FPU, and call main. - * The linker script defines _stack_top at the end of the stack region. - * PPC ABI: r1 = stack pointer, 16-byte aligned, back-chain to 0. - * FPU must be enabled because GCC's variadic function ABI (used by - * uart_printf/wolfBoot_printf) saves FP registers via stfd instructions. - * Without MSR[FP], this causes a Floating-Point Unavailable exception. */ +/* Assembly entry: set SP (_stack_top, PPC ABI: 16-byte aligned, back-chain 0), + * enable the FPU (MSR[FP]) -- the variadic printf ABI saves FP regs via stfd + * and would otherwise fault -- then branch to main. */ __asm__ ( ".section .text._app_entry\n" ".global _app_entry\n" @@ -73,6 +70,10 @@ __asm__ ( #include "../hal/nxp_ppc.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + static uint8_t boot_part_state = IMG_STATE_NEW; static uint8_t update_part_state = IMG_STATE_NEW; @@ -174,6 +175,10 @@ void main(void) wolfBoot_success(); wolfBoot_printf("\r\nBoot partition marked successful\r\n"); +#ifdef ENABLE_WOLFIP + wolfip_tftp_test_report(); +#endif + wolfBoot_printf("Test App: idle loop\r\n"); while(1) { /* Idle */ diff --git a/test-app/app_nxp_t2080.c b/test-app/app_nxp_t2080.c index 7167cc70b4..fd2e1cd1b4 100644 --- a/test-app/app_nxp_t2080.c +++ b/test-app/app_nxp_t2080.c @@ -51,6 +51,10 @@ void __attribute__((naked, section(".text._app_entry"))) _app_entry(void) #include "../hal/nxp_ppc.h" +#ifdef ENABLE_WOLFIP +#include "wolfip_tftp_test.h" +#endif + /* wolfCrypt test/benchmark support */ #ifdef WOLFCRYPT_TEST #include @@ -139,9 +143,8 @@ static int print_info(void) void main(void) { - /* Zero BSS - required for bare-metal since there's no crt0 startup. - * Without this, static variables (gTestMemory, HEAP_HINT, etc.) - * contain DDR garbage, causing crashes in wc_LoadStaticMemory. */ + /* Zero BSS (no crt0 on bare metal): the wolfCrypt static-memory pools + * (gTestMemory/HEAP_HINT) must start zeroed or wc_LoadStaticMemory crashes. */ extern char _start_bss[], _end_bss[]; { char *p = _start_bss; @@ -177,6 +180,10 @@ void main(void) wolfCrypt_Cleanup(); #endif +#ifdef ENABLE_WOLFIP + wolfip_tftp_test_report(); +#endif + wolfBoot_printf("Test App: idle loop\r\n"); while(1) { /* Idle */ diff --git a/test-app/boot_arm64_start.S b/test-app/boot_arm64_start.S index d370552c1c..2fd37d2c4d 100644 --- a/test-app/boot_arm64_start.S +++ b/test-app/boot_arm64_start.S @@ -66,9 +66,10 @@ _start: .size _start, . - _start -/* Provide _exit stub for bare-metal builds (required by some standard library code) */ +/* _exit stub for bare-metal builds (some libc code needs it). Weak so + * syscalls.c (wolfCrypt test/benchmark) can supply the strong _exit. */ .section .text, "ax" -.global _exit +.weak _exit .type _exit, @function _exit: diff --git a/test-app/wolfcrypt_support.c b/test-app/wolfcrypt_support.c index b4f2447126..13d7fba22c 100644 --- a/test-app/wolfcrypt_support.c +++ b/test-app/wolfcrypt_support.c @@ -45,8 +45,7 @@ #elif defined(TARGET_lpc55s69) extern volatile uint64_t SysTick_time_ms; #elif defined(TARGET_nxp_t2080) || defined(TARGET_nxp_t1024) - /* PPC timebase register for accurate timing. - * Timebase frequency = platform_clock / 16. */ + /* PPC time base register for accurate timing (e6500). */ static uint32_t ppc_tb_hz = 0; static unsigned long long ppc_start_ticks = 0; @@ -66,18 +65,44 @@ static uint32_t ppc_get_timebase_hz(void) { - /* Read Platform PLL ratio from CLOCKING_PLLPGSR register. - * CCSRBAR=0xFE000000, CLOCKING_BASE=CCSRBAR+0xE1000, - * PLLPGSR=CLOCKING_BASE+0xC00 */ - volatile uint32_t *pllpgsr = - (volatile uint32_t *)(0xFE000000UL + 0xE1C00UL); - uint32_t plat_ratio = ((*pllpgsr) >> 1) & 0x1F; + /* CoreNet (e6500): platform PLL ratio in RCWSR0 (DCFG/GUTS + 0x100), + * bits (RCWSR0 >> 25) & 0x1f (U-Boot mpc85xx/speed.c). Platform clock = + * SYSCLK * ratio; time base = platform_clock / 16 (TBCLK_DIV = 16). + * CCSRBAR is board-relocated: CW VPX3-152 uses 0xEF000000; reading the + * RDB default 0xFE000000 there is unmapped (0xFFFFFFFF -> ratio 31). */ + #ifdef BOARD_CW_VPX3152 + uintptr_t ccsr = 0xEF000000UL; + #else + uintptr_t ccsr = 0xFE000000UL; + #endif + volatile uint32_t *rcwsr0 = (volatile uint32_t *)(ccsr + 0xE0100UL); + uint32_t plat_ratio = ((*rcwsr0) >> 25) & 0x1FU; #if defined(BOARD_NAII_68PPC2) || defined(TARGET_nxp_t1024) uint32_t sys_clk = 100000000; /* 100 MHz */ #else - uint32_t sys_clk = 66666667; /* 66.66 MHz (T2080 RDB) */ + uint32_t sys_clk = 66666667; /* 66.66 MHz */ #endif - return (sys_clk * plat_ratio) / 16; + return (sys_clk * plat_ratio) / 16U; + } +#elif defined(TARGET_nxp_ls1028a) + /* ARMv8 generic system counter (enabled by the wolfBoot HAL). */ + static unsigned long long a64_tb_hz = 0; + static unsigned long long a64_start_ticks = 0; + + static unsigned long long a64_get_ticks(void) + { + unsigned long long v; + __asm__ volatile ("mrs %0, cntpct_el0" : "=r"(v)); + return v; + } + + static unsigned long long a64_get_hz(void) + { + unsigned long long v; + __asm__ volatile ("mrs %0, cntfrq_el0" : "=r"(v)); + /* wolfBoot programs CNTFRQ_EL0 from CNTFID0; fall back to the 25 MHz + * LS1028A default if it reads zero (matches now_ms). */ + return v ? v : 25000000ULL; } #else /* Simple tick counter fallback */ @@ -110,6 +135,14 @@ unsigned long my_time(unsigned long* timer) if (timer) *timer = t; return t; } +#elif defined(TARGET_nxp_ls1028a) + if (a64_tb_hz == 0) + a64_tb_hz = a64_get_hz(); + { + unsigned long t = (unsigned long)(a64_get_ticks() / a64_tb_hz); + if (timer) *timer = t; + return t; + } #else /* Simple incrementing counter */ tick_counter++; @@ -140,6 +173,12 @@ double current_time(int reset) if (reset) ppc_start_ticks = ppc_get_ticks(); return (double)(ppc_get_ticks() - ppc_start_ticks) / (double)ppc_tb_hz; +#elif defined(TARGET_nxp_ls1028a) + if (a64_tb_hz == 0) + a64_tb_hz = a64_get_hz(); + if (reset) + a64_start_ticks = a64_get_ticks(); + return (double)(a64_get_ticks() - a64_start_ticks) / (double)a64_tb_hz; #else /* Simple counter-based timing */ if (reset) diff --git a/test-app/wolfip_tftp_test.c b/test-app/wolfip_tftp_test.c new file mode 100644 index 0000000000..96b1e8b4f7 --- /dev/null +++ b/test-app/wolfip_tftp_test.c @@ -0,0 +1,544 @@ +/* wolfip_tftp_test.c + * + * Optional wolfIP network test for the wolfBoot test-app. Ethernet port and ms + * timebase are compile-time selected: NXP QorIQ FMan (T2080/T1024/T1040, + * big-endian PowerPC) or NXP Layerscape ENETC (LS1028A, AArch64). Modes: + * default DHCP lease only + * WOLFBOOT_TEST_TFTP + TFTP RRQ fetch into RAM, report size+checksum + * (optionally verify them via TFTP_EXPECT_SIZE/SUM) + * WOLFIP_SPEED_TEST + TCP throughput server on port 9 (benchmark) + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ + +#include +#include + +#include "printf.h" +#include "wolfip.h" +#ifdef WOLFBOOT_TEST_TFTP +#include "src/tftp/wolftftp.h" +#endif + +/* Port selection: WOLFIP_PORT_ENETC -> LS1028A ENETC, else QorIQ FMan. Driver + * entry points are wrapped so the bring-up code below is port-agnostic. */ +#if defined(WOLFIP_PORT_ENETC) +#include "nxp_enetc.h" +#define WOLFIP_NETDEV_INIT nxp_enetc_init +#define WOLFIP_NETDEV_PHY_ADDR nxp_enetc_phy_addr +#define WOLFIP_NETDEV_PHY_READ nxp_enetc_phy_read +#define WOLFIP_NETDEV_LINK_UP nxp_enetc_link_up +#define WOLFIP_NETDEV_SET_LOG nxp_enetc_set_log +#define WOLFIP_NETDEV_NAME "ENETC" +#else +#include "nxp_fman.h" +#define WOLFIP_NETDEV_INIT nxp_fman_init +#define WOLFIP_NETDEV_PHY_ADDR nxp_fman_phy_addr +#define WOLFIP_NETDEV_PHY_READ nxp_fman_phy_read +#define WOLFIP_NETDEV_PHY_READ_AT nxp_fman_phy_read_at +#define WOLFIP_NETDEV_LINK_UP nxp_fman_link_up +#define WOLFIP_NETDEV_NAME "FMan mEMAC" +#endif + +/* Host running in.tftpd / the throughput peer (same subnet as the DHCP lease). + * Override from the build config, e.g. + * CFLAGS_EXTRA+=-DHOST_IP_STR='"192.168.1.5"' -DTFTP_FILENAME='"img.bin"'. */ +#ifndef HOST_IP_STR +#define HOST_IP_STR "10.0.4.24" +#endif +#ifndef TFTP_FILENAME +#define TFTP_FILENAME "wolfip_test.bin" +#endif +/* Optional integrity check: when non-zero, the fetched byte count and/or + * additive 32-bit checksum must match or the test FAILS; 0 (default) just + * reports the measured values. E.g. CFLAGS_EXTRA+=-DTFTP_EXPECT_SIZE=8192 + * -DTFTP_EXPECT_SUM=0xFF000. */ +#ifndef TFTP_EXPECT_SIZE +#define TFTP_EXPECT_SIZE 0U +#endif +#ifndef TFTP_EXPECT_SUM +#define TFTP_EXPECT_SUM 0U +#endif + +/* Millisecond clock from a free-running counter, self-contained (no bootloader + * symbol). wolfIP timers are coarse so exactness is moot. */ +#if defined(__aarch64__) +/* ARMv8 generic timer: CNTPCT_EL0 counts at CNTFRQ_EL0 Hz. */ +static uint64_t read_tb(void) +{ + uint64_t v; + __asm__ __volatile__("isb; mrs %0, cntpct_el0" : "=r"(v)); + return v; +} +static uint64_t tb_hz(void) +{ + static uint64_t cached = 0; /* CNTFRQ is a boot constant; read once */ + uint64_t f; + if (cached != 0) + return cached; + __asm__ __volatile__("mrs %0, cntfrq_el0" : "=r"(f)); + cached = f ? f : 25000000ULL; /* LS1028A SYSCLK-derived default */ + return cached; +} +static uint64_t now_ms(void) +{ + return read_tb() / (tb_hz() / 1000ULL); +} +#else +/* PowerPC e5500/e6500 Time Base via SPRs (TBL=268, TBU=269) = platform clock + * / 16; default is the VPX3-152 value (600 MHz -> 37.5 MHz). Other platform + * clocks MUST override this -- it scales the wolfIP TCP/DHCP timers fed by + * now_ms, not just harness timeouts -- e.g. -DTIMEBASE_HZ=50000000ULL. */ +#ifndef TIMEBASE_HZ +#define TIMEBASE_HZ 37500000ULL +#endif + +static uint64_t read_tb(void) +{ + uint32_t hi, lo, hi2; + do { + __asm__ __volatile__("mfspr %0, 269" : "=r"(hi)); + __asm__ __volatile__("mfspr %0, 268" : "=r"(lo)); + __asm__ __volatile__("mfspr %0, 269" : "=r"(hi2)); + } while (hi != hi2); + return ((uint64_t)hi << 32) | lo; +} + +static uint64_t now_ms(void) +{ + return (uint64_t)(read_tb() / (TIMEBASE_HZ / 1000ULL)); +} +#endif + +/* wolfIP needs an RNG (TCP ISN, DHCP xid, ephemeral ports). LFSR seeded + * from the free-running timebase. NOT cryptographic. */ +uint32_t wolfIP_getrandom(void) +{ + static uint32_t lfsr; + if (lfsr == 0) + lfsr = (uint32_t)read_tb() | 1U; + lfsr ^= (uint32_t)read_tb(); + lfsr ^= lfsr << 13; + lfsr ^= lfsr >> 17; + lfsr ^= lfsr << 5; + return lfsr; +} + +#define DHCP_TIMEOUT_MS 30000ULL + +#if defined(WOLFIP_NETDEV_SET_LOG) && defined(WOLFIP_DRIVER_LOG) +/* Driver bring-up stage logger (opt-in via -DWOLFIP_DRIVER_LOG). */ +static void wolfip_driver_log(const char *msg) +{ + wolfBoot_printf(" drv: %s\r\n", msg); +} +#endif + +/* Bring up the driver + wolfIP + DHCP. Returns the stack on a bound lease, + * NULL on failure. Prints PHY/link and the lease. */ +static struct wolfIP *wolfip_bringup(void) +{ + struct wolfIP *s = NULL; + struct wolfIP_ll_dev *ll; + uint64_t start, now; + ip4 ip = 0, nm = 0, gw = 0; + int rc, addr; + uint16_t id1, bsr; + + wolfIP_init_static(&s); + ll = wolfIP_getdev(s); + + wolfBoot_printf("wolfIP: bringing up %s\r\n", WOLFIP_NETDEV_NAME); +#if defined(WOLFIP_NETDEV_SET_LOG) && defined(WOLFIP_DRIVER_LOG) + /* Print each bring-up stage so a hang/fault is localized by the last + * marker (enable with -DWOLFIP_DRIVER_LOG). */ + WOLFIP_NETDEV_SET_LOG(wolfip_driver_log); +#endif + rc = WOLFIP_NETDEV_INIT(ll, NULL); + if (rc < 0) { + wolfBoot_printf("wolfIP: netdev init failed rc=%d\r\n", rc); + return NULL; + } + addr = WOLFIP_NETDEV_PHY_ADDR(); + id1 = WOLFIP_NETDEV_PHY_READ(0x02); + bsr = WOLFIP_NETDEV_PHY_READ(0x01); + wolfBoot_printf("wolfIP: PHY addr=%d ID1=0x%x BSR=0x%x link=%s\r\n", + addr, id1, bsr, WOLFIP_NETDEV_LINK_UP() ? "UP" : "down"); + +#if defined(WOLFIP_PHY_SCAN) && defined(WOLFIP_NETDEV_PHY_READ_AT) + /* MDIO bus scan: print ID1/ID2/BSR for every clause-22 address to identify + * the cabled port (BSR bit 2 = link up). Diagnostic; -DWOLFIP_PHY_SCAN. */ + { + int a; + uint16_t i1, i2, bs; + wolfBoot_printf("wolfIP: MDIO scan (addr: ID1 ID2 BSR link)\r\n"); + for (a = 0; a < 32; a++) { + i1 = WOLFIP_NETDEV_PHY_READ_AT((uint8_t)a, 0x02); + if (i1 == 0xFFFFU || i1 == 0x0000U) + continue; /* no PHY at this address */ + i2 = WOLFIP_NETDEV_PHY_READ_AT((uint8_t)a, 0x03); + bs = WOLFIP_NETDEV_PHY_READ_AT((uint8_t)a, 0x01); + wolfBoot_printf(" %d: 0x%x 0x%x 0x%x %s\r\n", + a, i1, i2, bs, (bs & 0x0004U) ? "UP" : "down"); + } + } +#endif + + (void)wolfIP_poll(s, now_ms()); + wolfBoot_printf("wolfIP: starting DHCP...\r\n"); + (void)dhcp_client_init(s); + + start = now_ms(); + for (;;) { + now = now_ms(); + (void)wolfIP_poll(s, now); + if (dhcp_bound(s)) { + wolfIP_ipconfig_get(s, &ip, &nm, &gw); + wolfBoot_printf("wolfIP: DHCP bound ip=%u.%u.%u.%u gw=%u.%u.%u.%u\r\n", + (unsigned)((ip >> 24) & 0xFF), (unsigned)((ip >> 16) & 0xFF), + (unsigned)((ip >> 8) & 0xFF), (unsigned)(ip & 0xFF), + (unsigned)((gw >> 24) & 0xFF), (unsigned)((gw >> 16) & 0xFF), + (unsigned)((gw >> 8) & 0xFF), (unsigned)(gw & 0xFF)); + return s; + } + if ((now - start) > DHCP_TIMEOUT_MS) { + wolfBoot_printf("wolfIP: DHCP timed out\r\n"); + return NULL; + } + } +} + +#ifdef WOLFBOOT_TEST_TFTP +/* ---- TFTP RRQ fetch into a RAM buffer + integrity check ------------- */ +#define TFTP_RAM_MAX (128U * 1024U) +#define TFTP_LOCAL_PORT 6900U + +struct tftp_ram_ctx { + uint8_t buf[TFTP_RAM_MAX]; + uint32_t len; /* highest offset+len written */ + uint32_t sum; /* additive 32-bit checksum of all bytes */ + int overflow; +}; +static struct tftp_ram_ctx g_tftp; + +struct tftp_glue { struct wolfIP *s; int sock; }; + +/* Zero a local struct without pulling in a libc memset (freestanding app). */ +static void zmem(void *p, unsigned int n) +{ + unsigned int i; + for (i = 0; i < n; i++) + ((uint8_t *)p)[i] = 0; +} + +static int tftp_io_open(void *arg, const char *name, int is_write, + uint32_t *size_hint, void **handle) +{ + (void)name; (void)is_write; (void)size_hint; + g_tftp.len = 0; + g_tftp.sum = 0; + g_tftp.overflow = 0; + *handle = &g_tftp; + return 0; +} + +static int tftp_io_write(void *arg, void *handle, uint32_t offset, + const uint8_t *buf, uint16_t len) +{ + struct tftp_ram_ctx *c = (struct tftp_ram_ctx *)handle; + uint16_t i; + (void)arg; + /* Overflow-safe bounds check: never compute offset+len (could wrap a + * 32-bit offset). Compare against the remaining space instead. */ + if (offset > TFTP_RAM_MAX || len > TFTP_RAM_MAX - offset) { + c->overflow = 1; + return -1; + } + for (i = 0; i < len; i++) { + c->buf[offset + i] = buf[i]; + c->sum += buf[i]; + } + if (offset + len > c->len) + c->len = offset + len; + return 0; +} + +static int tftp_send(void *arg, uint16_t local_port, + const struct wolftftp_endpoint *remote, const uint8_t *buf, uint16_t len) +{ + struct tftp_glue *g = (struct tftp_glue *)arg; + struct wolfIP_sockaddr_in dst; + int ret; + (void)local_port; + zmem(&dst, sizeof(dst)); + dst.sin_family = AF_INET; + dst.sin_port = ee16(remote->port); + dst.sin_addr.s_addr = ee32(remote->ip); + ret = wolfIP_sock_sendto(g->s, g->sock, buf, len, 0, + (struct wolfIP_sockaddr *)&dst, sizeof(dst)); + return (ret == (int)len) ? 0 : (ret < 0 ? ret : -1); +} + +static int run_tftp_fetch(struct wolfIP *s) +{ + struct tftp_glue glue; + struct wolftftp_transport_ops transport; + struct wolftftp_io_ops io; + struct wolftftp_transfer_cfg cfg; + struct wolftftp_client client; + struct wolftftp_endpoint srv; + struct wolfIP_sockaddr_in bind_addr; + uint8_t pkt[1500]; + int sock, ret = -1; + uint64_t deadline, now; + + sock = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_DGRAM, 0); + if (sock < 0) { + wolfBoot_printf("TFTP: udp socket failed\r\n"); + return -1; + } + zmem(&bind_addr, sizeof(bind_addr)); + bind_addr.sin_family = AF_INET; + bind_addr.sin_port = ee16(TFTP_LOCAL_PORT); + if (wolfIP_sock_bind(s, sock, (struct wolfIP_sockaddr *)&bind_addr, + sizeof(bind_addr)) < 0) { + wolfBoot_printf("TFTP: bind to local port %u failed\r\n", + TFTP_LOCAL_PORT); + goto out; + } + + glue.s = s; glue.sock = sock; + zmem(&transport, sizeof(transport)); + transport.send = tftp_send; + transport.arg = &glue; + zmem(&io, sizeof(io)); + io.open = tftp_io_open; + io.write = tftp_io_write; + io.arg = &g_tftp; + zmem(&cfg, sizeof(cfg)); + cfg.local_port = TFTP_LOCAL_PORT; + cfg.blksize = WOLFTFTP_DEFAULT_BLKSIZE; + cfg.timeout_s = WOLFTFTP_DEFAULT_TIMEOUT_S; + cfg.windowsize = 1; + cfg.max_retries = 5; + + wolftftp_client_init(&client, &transport, &io, &cfg); + zmem(&srv, sizeof(srv)); + srv.ip = atoip4(HOST_IP_STR); + srv.port = 69; + + wolfBoot_printf("TFTP: RRQ %s from %s\r\n", TFTP_FILENAME, HOST_IP_STR); + if (wolftftp_client_start_rrq(&client, &srv, TFTP_FILENAME) != 0) { + wolfBoot_printf("TFTP: start_rrq failed\r\n"); + goto out; + } + + now = now_ms(); + deadline = now + 20000ULL; + while (client.state != WOLFTFTP_CLIENT_COMPLETE && + client.state != WOLFTFTP_CLIENT_ERROR && + now < deadline) { + struct wolfIP_sockaddr_in rem; + uint32_t rlen; + int n; + (void)wolfIP_poll(s, now); + for (;;) { + rlen = sizeof(rem); + n = wolfIP_sock_recvfrom(s, sock, pkt, sizeof(pkt), 0, + (struct wolfIP_sockaddr *)&rem, &rlen); + if (n <= 0) + break; + { + struct wolftftp_endpoint rep; + rep.ip = ee32(rem.sin_addr.s_addr); + rep.port = ee16(rem.sin_port); + (void)wolftftp_client_receive(&client, TFTP_LOCAL_PORT, + &rep, pkt, (uint16_t)n); + } + } + (void)wolftftp_client_poll(&client, (uint32_t)now); + now = now_ms(); + } + + if (client.state != WOLFTFTP_CLIENT_COMPLETE) { + wolfBoot_printf("TFTP: FAILED (state=%d status=%d)\r\n", + client.state, client.last_status); + goto out; + } + if (g_tftp.overflow) { + wolfBoot_printf("TFTP: file exceeds %u byte RAM buffer\r\n", TFTP_RAM_MAX); + goto out; + } + wolfBoot_printf("TFTP: got %u bytes, checksum 0x%x\r\n", + (unsigned)g_tftp.len, (unsigned)g_tftp.sum); +#if (TFTP_EXPECT_SIZE != 0U) + if (g_tftp.len != (uint32_t)TFTP_EXPECT_SIZE) { + wolfBoot_printf("TFTP: size mismatch (expected %u)\r\n", + (unsigned)TFTP_EXPECT_SIZE); + goto out; + } +#endif +#if (TFTP_EXPECT_SUM != 0U) + if (g_tftp.sum != (uint32_t)TFTP_EXPECT_SUM) { + wolfBoot_printf("TFTP: checksum mismatch (expected 0x%x)\r\n", + (unsigned)TFTP_EXPECT_SUM); + goto out; + } +#endif + ret = 0; + +out: + (void)wolfIP_sock_close(s, sock); + return ret; +} +#endif /* WOLFBOOT_TEST_TFTP */ + +#ifdef WOLFIP_SPEED_TEST +/* ---- Benchmark: one-connection TCP throughput server on port 9 ------- * + * RX sinks everything the peer sends; TX pushes a chargen buffer whenever + * writable. Prints B/s on close. + * RX (board sinks): dd if=/dev/zero bs=1460 count=N | nc 9 + * TX (board sources): nc 9 /dev/null */ +#define SPEED_PORT 9 +static int speed_listen_fd = -1; +static int speed_client_fd = -1; +static uint64_t speed_rx_bytes, speed_tx_bytes, speed_start_ms; +static uint8_t speed_buf[1460]; + +static void speed_print(void) +{ + uint64_t ms = now_ms() - speed_start_ms; + if (ms == 0) ms = 1; + wolfBoot_printf("SPEED done %ums RX %u B (~%u B/s) TX %u B (~%u B/s)\r\n", + (unsigned)ms, (unsigned)speed_rx_bytes, + (unsigned)((speed_rx_bytes * 1000ULL) / ms), + (unsigned)speed_tx_bytes, + (unsigned)((speed_tx_bytes * 1000ULL) / ms)); +} + +static void speed_cb(int fd, uint16_t event, void *arg) +{ + struct wolfIP *s = (struct wolfIP *)arg; + int n, k; + + if (fd == speed_listen_fd) { + if (event & CB_EVENT_READABLE) { + int c = wolfIP_sock_accept(s, speed_listen_fd, NULL, NULL); + if (c >= 0) { + if (speed_client_fd >= 0) { + (void)wolfIP_sock_close(s, c); + } else { + speed_client_fd = c; + speed_rx_bytes = 0; speed_tx_bytes = 0; + speed_start_ms = now_ms(); + wolfIP_register_callback(s, c, speed_cb, s); + wolfBoot_printf("SPEED client connected\r\n"); + } + } + } + return; + } + if (fd != speed_client_fd) + return; + + if (event & CB_EVENT_READABLE) { + k = 0; + do { + n = wolfIP_sock_recvfrom(s, fd, speed_buf, sizeof(speed_buf), 0, + NULL, NULL); + if (n > 0) + speed_rx_bytes += (uint64_t)n; + } while (n > 0 && ++k < 32); + } + if (event & CB_EVENT_WRITABLE) { + k = 0; + do { + n = wolfIP_sock_send(s, fd, speed_buf, sizeof(speed_buf), 0); + if (n > 0) + speed_tx_bytes += (uint64_t)n; + } while (n > 0 && ++k < 32); + } + if (event & CB_EVENT_CLOSED) { + speed_print(); + (void)wolfIP_sock_close(s, fd); + speed_client_fd = -1; + } +} + +static int run_speed_server(struct wolfIP *s) +{ + struct wolfIP_sockaddr_in addr; + + speed_listen_fd = wolfIP_sock_socket(s, AF_INET, IPSTACK_SOCK_STREAM, 0); + if (speed_listen_fd < 0) { + wolfBoot_printf("SPEED: socket failed\r\n"); + return -1; + } + wolfIP_register_callback(s, speed_listen_fd, speed_cb, s); + zmem(&addr, sizeof(addr)); + addr.sin_family = AF_INET; + addr.sin_port = ee16(SPEED_PORT); + if (wolfIP_sock_bind(s, speed_listen_fd, + (struct wolfIP_sockaddr *)&addr, sizeof(addr)) < 0) { + wolfBoot_printf("SPEED: bind to port %d failed\r\n", SPEED_PORT); + (void)wolfIP_sock_close(s, speed_listen_fd); + speed_listen_fd = -1; + return -1; + } + if (wolfIP_sock_listen(s, speed_listen_fd, 1) < 0) { + wolfBoot_printf("SPEED: listen on port %d failed\r\n", SPEED_PORT); + (void)wolfIP_sock_close(s, speed_listen_fd); + speed_listen_fd = -1; + return -1; + } + + wolfBoot_printf("SPEED: TCP throughput server on port %d. Drive from host:\r\n", + SPEED_PORT); + wolfBoot_printf(" RX: dd if=/dev/zero bs=1460 count=20000 | nc %d\r\n", + SPEED_PORT); + wolfBoot_printf(" TX: nc %d /dev/null\r\n", + SPEED_PORT); + for (;;) + (void)wolfIP_poll(s, now_ms()); + /* not reached */ +} +#endif /* WOLFIP_SPEED_TEST */ + +int wolfip_tftp_test_run(void) +{ + struct wolfIP *s = wolfip_bringup(); + if (s == NULL) + return -1; +#if defined(WOLFBOOT_TEST_TFTP) + return run_tftp_fetch(s); +#elif defined(WOLFIP_SPEED_TEST) + return run_speed_server(s); /* loops forever */ +#else + return 0; /* DHCP lease only, no transfer */ +#endif +} + +void wolfip_tftp_test_report(void) +{ + wolfBoot_printf("\r\nStarting wolfIP network test...\r\n"); + if (wolfip_tftp_test_run() == 0) + wolfBoot_printf("WOLFIP_TEST: PASS\r\n"); + else + wolfBoot_printf("WOLFIP_TEST: FAIL\r\n"); +} diff --git a/test-app/wolfip_tftp_test.h b/test-app/wolfip_tftp_test.h new file mode 100644 index 0000000000..25b24a985a --- /dev/null +++ b/test-app/wolfip_tftp_test.h @@ -0,0 +1,35 @@ +/* wolfip_tftp_test.h + * + * Optional wolfIP network test entry for the wolfBoot test-app. + * + * Copyright (C) 2026 wolfSSL Inc. + * + * This file is part of wolfBoot. + * + * wolfBoot is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * wolfBoot is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA + */ +#ifndef WOLFIP_TFTP_TEST_H +#define WOLFIP_TFTP_TEST_H + +/* Run the wolfIP network test. Returns 0 on success, negative on failure. + * Without WOLFBOOT_TEST_TFTP this is a link/PHY bring-up smoke test; + * with WOLFBOOT_TEST_TFTP it performs a full TFTP fetch and verify. */ +int wolfip_tftp_test_run(void); + +/* Run the test and print the "Starting..." banner and PASS/FAIL result. + * Convenience wrapper so each target app's main() is a single call. */ +void wolfip_tftp_test_report(void); + +#endif /* WOLFIP_TFTP_TEST_H */ diff --git a/tools/scripts/nxp_t1040/t1040_flash.cmm b/tools/scripts/nxp_t1040/t1040_flash.cmm index cac80d7e3f..3d837be526 100644 --- a/tools/scripts/nxp_t1040/t1040_flash.cmm +++ b/tools/scripts/nxp_t1040/t1040_flash.cmm @@ -59,36 +59,24 @@ SYStem.DETECT CPU CORE.ASSIGN 1. SYStem.Option.FREEZE OFF -; Use RCW override to prevent flash RCW from running before we are ready. -; This keeps the system halted for configuration. -PRINT "Initializing with temporary RCW override..." -SYStem.Mode.Prepare - -SYStem.Option.HRCWOVerRide ON - -; Load RCW (T1040D4RDB values extracted from factory flash) -Data.Set DBG:0x01000000 0x0c18000e -Data.Set DBG:0x01000001 0x0e000000 -Data.Set DBG:0x01000002 0x00000000 -Data.Set DBG:0x01000003 0x00000000 -Data.Set DBG:0x01000004 0x66000002 -Data.Set DBG:0x01000005 0x40000002 -Data.Set DBG:0x01000006 0xec027000 -Data.Set DBG:0x01000007 0x01000000 -Data.Set DBG:0x01000008 0x00000000 -Data.Set DBG:0x01000009 0x00000000 -Data.Set DBG:0x0100000A 0x00000000 -Data.Set DBG:0x0100000B 0x00030810 -Data.Set DBG:0x0100000C 0x00000000 -Data.Set DBG:0x0100000D 0x0342580f -Data.Set DBG:0x0100000E 0x00000000 -Data.Set DBG:0x0100000F 0x00000000 - +; RCW handling. On a BARE board with no valid RCW, a hard RCW override holds +; the core in a clean pre-boot state. But a board that already has a valid RCW +; in NOR (this T1040D4RDB boots) rejects the hard override -- it fails with +; "RCW override finished without success ... debug port fail". For that case +; use a plain SYStem.Up: the NOR RCW runs (clocks/DDR come up) and TRACE32 +; halts the core at the reset vector. The flash algorithm runs from CPC-SRAM, +; so erasing/reprogramming NOR with the core halted is safe. +; (For a BARE board with no valid RCW, restore a hard RCW override here: +; SYStem.Mode.Prepare ; SYStem.Option.HRCWOVerRide ON +; write the 16 RCW words to DBG:0x01000000..0x0100000F ; SYStem.Up +; SYStem.Option.HRCWOVerRide OFF +; The T1040D4RDB RCW words are preserved in this file's git history. The hard +; override FAILS on a board that already has a valid NOR RCW -- "RCW override +; finished without success ... debug port fail" -- so this board uses a plain +; SYStem.Up instead.) +PRINT "Attaching to running target (using the valid NOR RCW)..." SYStem.Up - -SYStem.Option.HRCWOVerRide OFF - -PRINT "System initialized (halted state with temporary RCW)" +PRINT "System halted for flashing (NOR RCW applied)" ; Set CCSRBAR to 0x40000000 Data.Set ANC:IOBASE()+0x00004 %Long 0x40000000