nai_68int6: add wolfBoot target for the NAI 68INT6 (Intel Tiger Lake UP3) OpenVPX SBC

pull/933/head
David Garske 2026-10-07 14:21:43 -07:00
parent aa6fdb8fa9
commit 363483ed54
21 changed files with 1772 additions and 131 deletions

13
arch.mk
View File

@ -2207,13 +2207,13 @@ ifeq ($(USE_GCC),1)
endif
OUTPUT_FLAG?=-o
ifeq ($(filter $(TARGET),x86_fsp_qemu kontron_vx3060_s2),$(TARGET))
ifeq ($(filter $(TARGET),x86_fsp_qemu kontron_vx3060_s2 nai_68int6),$(TARGET))
FSP=1
CFLAGS+=-ffunction-sections -fdata-sections -ffreestanding -nostdlib -static
# some std libc have headers that bring in extra symbols used in
# FORTIFY_SOURCE realated checks. Use -U_FORTIFY_SOURCE to avoid that.
CFLAGS+=-U_FORTIFY_SOURCE
ifeq ($(TARGET), kontron_vx3060_s2)
ifeq ($(filter $(TARGET),kontron_vx3060_s2 nai_68int6),$(TARGET))
FSP_TGL=1
CFLAGS+=-DWOLFBOOT_TGL=1
endif
@ -2263,13 +2263,13 @@ ifeq ("${FSP}", "1")
OBJS += src/image.o
OBJS += src/keystore.o
OBJS += src/sig_wolfboot_raw.o
ifeq ($(TARGET), kontron_vx3060_s2)
OBJS += hal/kontron_vx3060_s2_loader.o
endif
OBJS += $(WOLFCRYPT_OBJS)
CFLAGS+=-DSTAGE1_AUTH
endif
# Generic stage1 loader HAL (stubs); shared by all x86 FSP targets.
OBJS += hal/stub_loader.o
CFLAGS += -fno-stack-protector -m32 -fno-PIC -fno-pie -mno-mmx -mno-sse -DDEBUG_UART
CFLAGS += -DFSP_M_BASE=$(FSP_M_BASE)
ifeq ($(FSP_TGL), 1)
@ -2277,9 +2277,6 @@ ifeq ("${FSP}", "1")
OBJS+=src/ucode0.o
CFLAGS += -DUCODE0_ADDRESS=$(UCODE0_BASE)
endif
ifeq ($(TARGET),x86_fsp_qemu)
OBJS += hal/x86_fsp_qemu_loader.o
endif
else
# building wolfBoot
ifeq ($(FSP_TGL), 1)

View File

@ -0,0 +1,96 @@
# NAI 68INT6 3U OpenVPX SBC (Tiger Lake UP3); needs the board's own FSP
# (nai_extract_fsp.sh). See the NAI 68INT6 section of docs/Targets.md.
ARCH=x86_64
TARGET=nai_68int6
WOLFBOOT_SMALL_STACK=0
# ECC P-384 signature, SHA-384 digest (measured boot uses SHA-256 on an
# SLB9670). See the integrity-algorithm table in docs/Targets.md.
SIGN=ECC384
HASH=SHA384
DEBUG=1
# FSP-M UPD dump on the console before FspMemInit (bring-up aid).
DUMP_FSP_UPD=0
SPMATH=1
ENCRYPTION=0
WOLFBOOT_NO_PARTITIONS=1
# Disk boot: signed kernels in GPT partitions 3/4, Ubuntu root in partition 2.
# The A/B boot-partition indices are set per target in src/update_disk.c.
WOLFBOOT_BOOT_DISK=0
FORCE_32BIT=1
########## Flash layout (measured from the factory descriptor, 32 MB) ##########
WOLFBOOT_PARTITION_BOOT_ADDRESS=0xff400000
WOLFBOOT_PARTITION_SWAP_ADDRESS=0x0
WOLFBOOT_PARTITION_UPDATE_ADDRESS=0x0
WOLFBOOT_LOAD_BASE=0x58000200
WOLFBOOT_SECTOR_SIZE?=0x1000
WOLFBOOT_DATA_ADDRESS=0x1000000
FSP_CONFIG_BASE=0xffe9f800
FSP_T_BASE=0xfff59000
FSP_M_BASE=0xfff60000
WOLFBOOT_ORIGIN=0xfff00000
BOOTLOADER_PARTITION_SIZE=0x600000
# Inert (the flash descriptor is used); kept for config parity.
BIOS_REGION_SIZE=0xc00000
UCODE0_BASE=0xffd90000
UCODE0_BIN=src/x86/ucode0.bin
FSP_T_BIN=./src/x86/fsp_t.bin
FSP_M_BIN=./src/x86/fsp_m.bin
FSP_S_BIN=./src/x86/fsp_s.bin
FSP_S_UPD_DATA_BIN=./src/x86/fsp_s_upd_data.bin
# Boot Guard is left to the board owner: supply an ACM and key here to build a
# Boot-Guard image. Unset, wolfBoot builds and boots without it.
ACM_BIN=
FSP_S_LOAD_BASE=0x0FED5F00
POLICY_BASE=0xffaa4000
KEYSTORE_OFFSET=0x3FE00
KEYSTORE_STAGE1_OFFSET=0x400
########## Console: LPSS UART2 (PCI 00:19.2), verified on hardware ##########
X86_UART_NUMBER=2
X86_UART_BASE=0xFE032000
X86_UART_REG_WIDTH=4
X86_UART_MMIO=1
########## PCH / PCI ##########
PCH_PCR_BASE=0xFD000000
PCI_ECAM_BASE=0xC0000000
PCI_USE_ECAM=1
PCH_HAS_PCR=1
# Generate ACPI tables so Linux gets the interrupt model and PCI routing.
ACPI=1
########## Payload: signed 64-bit Linux bzImage ##########
64BIT=1
ELF=1
DEBUG_ELF=0
MULTIBOOT2=1
LINUX_PAYLOAD=1
########## Security ##########
STAGE1_AUTH=1
WOLFTPM=1
MEASURED_BOOT=1
MEASURED_PCR_A=0
# Measure the verified OS image into PCR4, alongside the firmware in PCR0.
MEASURED_PCR_OS=4
WOLFBOOT_UNIVERSAL_KEYSTORE=1
WOLFBOOT_SKIP_AUTH_CHECK=0
ENABLE_DEBUG_CONSENT=0
# Deferred: TPM sealing and ATA disk lock/erase.
WOLFBOOT_TPM_SEAL=0
DISK_LOCK=0
DISK_ERASE=0
# Anti-rollback: persistent version floor + audit counters in TPM NV
# (trust-on-first-use; provision before first boot where that matters).
ANTI_ROLLBACK=1

View File

@ -14,6 +14,7 @@ This README describes configuration of supported targets.
* [Infineon AURIX TC4xx](#infineon-aurix-tc4xx)
* [Intel x86-64 Intel FSP](#intel-x86_64-with-intel-fsp-support)
* [Kontron VX3060-S2](#kontron-vx3060-s2)
* [NAI 68INT6 (Intel Tiger Lake)](#nai-68int6-intel-tiger-lake)
* [Microchip PIC32CK](#microchip-pic32ck)
* [Microchip PIC32CZ](#microchip-pic32cz)
* [Microchip PolarFire SoC](#microchip-polarfire-soc)
@ -9609,6 +9610,74 @@ Attempting boot from partition A
```
At this point, the kernel image in partition "A" is verified and staged and you should be seeing the log messages of your OS booting.
## NAI 68INT6 (Intel Tiger Lake)
wolfBoot target `nai_68int6` for the North Atlantic Industries 68INT6, a 3U OpenVPX SOSA-aligned single board computer (Intel Core i7-1185GRE, Tiger Lake UP3). It uses the Intel FSP support described [above](#intel-x86_64-with-intel-fsp-support) and shares the Tiger Lake path with the Kontron target. wolfBoot boots a signed 64-bit Linux from the SATA disk with A/B update, measured boot and TPM anti-rollback, verified on a Rev D5 bench board. The public Tiger Lake FSP does not train this board's memory, so the FSP is extracted from a 68INT6 BIOS image.
| | |
|---|---|
| CPU | i7-1185GRE (`06-8C-01`), Tiger Lake UP3, PCH-LP |
| Memory | 2 x 32 GB DDR4-3200 SODIMM, non-ECC |
| BIOS flash | Rev C/D5: 2 x W25R256JV (32 MB), selected by JP36. Next revision: one 64 MB device |
| TPM | SLB9670 (SHA-1/256), or SLB9672, which adds a SHA-384 bank |
| Storage | Onboard SATA SSD, AHCI at `00:17.0` |
| Console | LPSS UART2, PCI `00:19.2`, RS-232; `X86_UART_NUMBER=2` |
### Building
```
cp config/examples/nai_68int6.config .config
./tools/scripts/x86_fsp/tgl/tgl_download_fsp.sh # FSP UPD headers, first time only
./tools/scripts/x86_fsp/tgl/nai_extract_fsp.sh <68INT6.bin> # board's own FSP blobs
./tools/scripts/x86_fsp/tgl/assemble_image.sh -k # generate signing keys
make
./tools/scripts/x86_fsp/tgl/assemble_image.sh -n <68INT6.bin>
```
`nai_extract_fsp.sh` takes FSP-T/M/S and the microcode from a 68INT6 BIOS image. Without it the build uses the public FSP, which compiles but does not train memory. The `-n` stitch replaces the top 6 MB (`BOOTLOADER_PARTITION_SIZE`) of the 12 MB BIOS region and keeps the descriptor and CSME byte for byte. The board has no recovery region (recovery is the second flash device), so use `-n`, not `-m`. The result is `final_image.bin`.
### Integrity algorithms
ECC P-384 and SHA-384 match what Intel Boot Guard uses for the Initial Boot Block.
| Layer | Algorithm |
|---|---|
| Image signature | ECC P-384 (`SIGN=ECC384`) |
| Image digest | SHA-384 (`HASH=SHA384`) |
| Measured boot PCR | SHA-256 (the SLB9670 has only SHA-1 and SHA-256 banks) |
`wolfBoot_image_measure()` re-hashes the authenticated digest with the PCR bank's algorithm, so one image serves either TPM. `MEASURED_PCR_ALG=SHA384` needs an SLB9672 with its SHA-384 bank allocated (`TPM2_PCR_Allocate` under platform auth, a provisioning step).
### Configuration
Notable options in [config/examples/nai_68int6.config](../config/examples/nai_68int6.config):
| Option | Meaning |
|---|---|
| `X86_UART_NUMBER=2` | LPSS UART2 for all three FSP phases (Kontron uses 0) |
| `ACPI=1` | Required. Generates ACPI tables (RSDP/XSDT/FADT/MADT/MCFG and a minimal DSDT); the board's PCI interrupt routing is only in the DSDT `_PRT`, since the MP table is the Kontron one |
| `ANTI_ROLLBACK=1` | Persistent version floor and boot audit counters in TPM NV |
| `MEASURED_BOOT=1`, `MEASURED_PCR_OS=4` | Firmware into PCR 0, the verified OS image into PCR 4 |
| `WOLFBOOT_BOOT_DISK=0` | Boot from GPT partitions; the A/B indices (sda3/sda4) are set in `src/update_disk.c` |
### BIOS region lock
Before handoff, `hal_flash_protect()` in the shared Tiger Lake HAL (`hal/x86_fsp_tgl.c`, as on Kontron) sets SPI Flash Protected Range 0 over the BIOS region with read and write protection, then FLOCKDN. Both hold until the next platform reset, so the booted OS cannot read or reprogram the BIOS region; update it with an external programmer.
### Anti-rollback
`ANTI_ROLLBACK=1` keeps a version floor and boot audit counters in a TPM NV index; the backend is `src/boot_state_tpm.c` and the policy is `src/boot_state.c`. The floor is the highest version ever booted, set trust-on-first-use. A validly signed older image still boots and records a rollback event. Only an untrustworthy reference halts the boot; `ANTI_ROLLBACK_HALT_ON_FAILURE=1` also halts when the TPM is unreachable, a write fails or the platform hierarchy cannot be disabled.
TPM NV is used instead of the partition state trailer because the floor must survive a full reimage of the disk or flash. `DISK_BOOT_CONFIRM` still handles per-slot confirmation, and the backend can move to a root-of-trust device later without changing the policy.
`ALLOW_DOWNGRADE` is left unset, the secure default: if the higher-versioned slot fails to verify, wolfBoot halts (`Rollback to lower version not allowed`) rather than boot the lower one. Building with `ALLOW_DOWNGRADE=1` allows that fall-back and leaves the TPM floor as the only rollback guard.
The booted OS cannot lower the floor. The index is platform-created and writable only under platform auth (`TPMA_NV_PPWRITE`), and on every boot wolfBoot disables the platform hierarchy (`TPM2_HierarchyControl`) until the next TPM reset, as in section 10 of the TCG PC Client Platform specification. The OS can then neither write nor undefine the index. An index with any other write attributes is treated as corrupt. Platform-auth provisioning, such as `TPM2_PCR_Allocate`, must be done before wolfBoot is installed.
### Boot, programming and recovery
wolfBoot boots the highest-versioned signed 64-bit `bzImage` that verifies from the two GPT boot partitions. It falls back to the other slot only if that is not a downgrade (see Anti-rollback), and halts if neither boots. Program the flash with a Dediprog SF100 on JP4 while the board is off; the BIOS region lock blocks `flashrom` from the booted OS. JP36 selects which bank boots and which one the programmer sees; move it only with the board off.
## Infineon PSOC Control C3
The [PSOC Control C3](https://www.infineon.com/products/microcontroller/32-bit-psoc-arm-cortex/32-bit-psoc-control-arm-cortex-m33-mcu/psoc-control-c3-main-line) family (PSC3, CAT1B) is an Arm Cortex-M33 motor-control MCU. wolfBoot runs as the first application the BootROM launches, verifies the signed firmware in the BOOT partition and jumps to it.

View File

@ -31,87 +31,6 @@
#ifdef __WOLFBOOT
#define SPI_PCI_DEV 31
#define SPI_PCI_FUN 5
#define SPI_BAR_OFF 0x10
/* Tiger Lake SPI controller register offsets, memory-mapped at the
* BAR0 base. FREG1 holds the BIOS flash region base/limit (region 0
* is the flash descriptor); FPR0 is the protected range register
* with the same base/limit layout. Offsets per the Intel PCH SPI
* register map (see drivers/spi/spi-intel.c in the Linux kernel):
* FDATA0-15 at 0x10-0x4C, FRACC at 0x50, FREG0-7 at 0x54-0x74,
* FPR0-4 at 0x84-0x9C. */
#define SPI_FREG1 0x58
#define SPI_FREG_BASE_MASK (0x7fffU << 0)
#define SPI_FREG_LIMIT_MASK (0x7fffU << 16)
#define SPI_FREG_LIMIT_SHIFT (16)
#define SPI_FREG_ADDR_SHIFT (12)
#define SPI_FPR0 (0x84)
#define SPI_FPR_WPE (1U << 31)
#define SPI_FPR_RPE (1U << 15)
#define SPI_BIOS_HSFSTS_CTL (0x4)
#define SPI_FLOCKDN (1U << 15)
int tgl_lock_bios_region()
{
uint32_t spi_bar, spi_cmd;
uint32_t reg;
int ret = 0;
#if defined(DEBUG)
uint32_t bios_reg_base, bios_reg_lim;
#endif
spi_bar = pci_config_read32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_BAR0_OFFSET);
spi_bar &= PCI_BAR_MASK;
spi_cmd =
pci_config_read32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET);
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET,
spi_cmd | PCI_COMMAND_MEM_SPACE);
/* The Flash Protected Range register has the same base/limit
* layout as the Flash Region register: take the BIOS region
* (FREG1, flash region 1) and enable read and write protection
* on it. The SPI registers live in the BAR's memory-mapped
* space, not in PCI configuration space. */
reg = mmio_read32(spi_bar + SPI_FREG1);
#if defined(DEBUG)
bios_reg_base = (reg & SPI_FREG_BASE_MASK) << SPI_FREG_ADDR_SHIFT;
bios_reg_lim = ((reg & SPI_FREG_LIMIT_MASK) >> SPI_FREG_LIMIT_SHIFT)
<< SPI_FREG_ADDR_SHIFT;
wolfBoot_printf("Bios reg base: 0x%x lim: 0x%x\r\n", bios_reg_base,
bios_reg_lim);
#endif
reg |= (SPI_FPR_RPE) | (SPI_FPR_WPE);
mmio_write32(spi_bar + SPI_FPR0, reg);
if ((mmio_read32(spi_bar + SPI_FPR0) &
(SPI_FPR_RPE | SPI_FPR_WPE)) != (SPI_FPR_RPE | SPI_FPR_WPE)) {
ret = -1;
}
/* lock down BIOS register configuration */
reg = mmio_read32(spi_bar + SPI_BIOS_HSFSTS_CTL);
reg |= SPI_FLOCKDN;
mmio_write32(spi_bar + SPI_BIOS_HSFSTS_CTL, reg);
if ((mmio_read32(spi_bar + SPI_BIOS_HSFSTS_CTL) & SPI_FLOCKDN) == 0) {
ret = -1;
}
/* restore original cmd */
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET, spi_cmd);
return ret;
}
int hal_flash_protect(haladdr_t address, int len)
{
(void)address;
(void)len;
/* The TGL BIOS region covers the bootloader partition, so the
* hook's address/len are the same range FREG1 describes. */
return tgl_lock_bios_region();
}
void hal_init(void)
{
gdt_setup_table();

View File

@ -1,4 +1,6 @@
/* kontron_vx3060_s2_loader.c
/* nai_68int6.c
*
* HAL for the NAI 68INT6 3U OpenVPX SBC (Intel Tiger Lake UP3).
*
* Copyright (C) 2026 wolfSSL Inc.
*
@ -6,7 +8,7 @@
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
@ -20,27 +22,41 @@
*/
#include <wolfboot/wolfboot.h>
#include <hal.h>
#include <stdint.h>
#include <string.h>
#include <uart_drv.h>
#include <printf.h>
#include <pci.h>
#include <x86/gdt.h>
#include <x86/fsp.h>
#include <x86/common.h>
#ifdef __WOLFBOOT
#include <printf.h>
static void panic(void);
void hal_init(void)
{
gdt_setup_table();
gdt_update_segments();
fsp_init_silicon();
}
void hal_prepare_boot(void)
{
}
#endif
#endif /* __WOLFBOOT */
int hal_flash_write(uint32_t address, const uint8_t *data, int len)
int hal_flash_write(uintptr_t address, const uint8_t *data, int len)
{
(void)address;
(void)data;
(void)len;
return 0;
}
int hal_flash_erase(uintptr_t address, int len)
{
(void)address;
(void)len;
return 0;
}
@ -52,15 +68,11 @@ void hal_flash_lock(void)
{
}
int hal_flash_erase(uint32_t address, int len)
{
return 0;
}
/* No automatic fallback: a verification failure is terminal on this
* target rather than silently reverting. */
int wolfBoot_fallback_is_possible(void)
{
return 0;
}
int wolfBoot_dualboot_candidate(void)
@ -75,7 +87,7 @@ void* hal_get_primary_address(void)
void* hal_get_update_address(void)
{
return (void*)0;
return (void*)0;
}
void *hal_get_dts_address(void)
@ -87,8 +99,3 @@ void *hal_get_dts_update_address(void)
{
return 0;
}
static void panic(void)
{
while(1) {}
}

View File

@ -1,4 +1,6 @@
/* x86_fsp_qemu_loader.c
/* stub_loader.c
*
* Generic stage1 loader HAL for x86 FSP targets.
*
* Copyright (C) 2026 wolfSSL Inc.
*
@ -6,7 +8,7 @@
*
* 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
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* wolfBoot is distributed in the hope that it will be useful,
@ -19,10 +21,14 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA
*/
/* x86 FSP stage1 runs XIP before memory init and only authenticates stage2,
* so every HAL entry point is a stub. */
#include <wolfboot/wolfboot.h>
#include <hal.h>
#include <uart_drv.h>
#include <stdint.h>
#include <string.h>
#include <uart_drv.h>
#ifdef __WOLFBOOT
#include <printf.h>
@ -34,10 +40,13 @@ void hal_init(void)
void hal_prepare_boot(void)
{
}
#endif
#endif /* __WOLFBOOT */
int hal_flash_write(uintptr_t address, const uint8_t *data, int len)
int hal_flash_write(haladdr_t address, const uint8_t *data, int len)
{
(void)address;
(void)data;
(void)len;
return 0;
}
@ -49,15 +58,16 @@ void hal_flash_lock(void)
{
}
int hal_flash_erase(uintptr_t address, int len)
int hal_flash_erase(haladdr_t address, int len)
{
(void)address;
(void)len;
return 0;
}
int wolfBoot_fallback_is_possible(void)
{
return 0;
}
int wolfBoot_dualboot_candidate(void)
@ -72,7 +82,7 @@ void* hal_get_primary_address(void)
void* hal_get_update_address(void)
{
return (void*)0;
return (void*)0;
}
void *hal_get_dts_address(void)
@ -84,4 +94,3 @@ void *hal_get_dts_update_address(void)
{
return 0;
}

View File

@ -27,6 +27,8 @@
#include "uart_drv.h"
#include "printf.h"
#include "loader.h"
#include "hal.h"
#include "pci.h"
#ifdef WOLFBOOT_FSP
#include "x86/ahci.h"
@ -35,7 +37,7 @@
#include "x86/tgl_fsp.h"
#endif
#if defined(TARGET_kontron_vx3060_s2)
#if defined(TARGET_kontron_vx3060_s2) || defined(TARGET_nai_68int6)
#define PCI_AHCI_BUS 0
#define PCI_AHCI_DEV 0x17
#define PCI_AHCI_FUN 0
@ -106,5 +108,88 @@ int x86_fsp_tgl_init_sata(uint32_t *bar)
*bar = sata_bar;
return 0;
}
#ifdef WOLFBOOT_TGL
#define SPI_PCI_DEV 31
#define SPI_PCI_FUN 5
#define SPI_BAR_OFF 0x10
/* Tiger Lake SPI controller register offsets, memory-mapped at the
* BAR0 base. FREG1 holds the BIOS flash region base/limit (region 0
* is the flash descriptor); FPR0 is the protected range register
* with the same base/limit layout. Offsets per the Intel PCH SPI
* register map (see drivers/spi/spi-intel.c in the Linux kernel):
* FDATA0-15 at 0x10-0x4C, FRACC at 0x50, FREG0-7 at 0x54-0x74,
* FPR0-4 at 0x84-0x9C. */
#define SPI_FREG1 0x58
#define SPI_FREG_BASE_MASK (0x7fffU << 0)
#define SPI_FREG_LIMIT_MASK (0x7fffU << 16)
#define SPI_FREG_LIMIT_SHIFT (16)
#define SPI_FREG_ADDR_SHIFT (12)
#define SPI_FPR0 (0x84)
#define SPI_FPR_WPE (1U << 31)
#define SPI_FPR_RPE (1U << 15)
#define SPI_BIOS_HSFSTS_CTL (0x4)
#define SPI_FLOCKDN (1U << 15)
int tgl_lock_bios_region(void)
{
uint32_t spi_bar, spi_cmd;
uint32_t reg;
int ret = 0;
#if defined(DEBUG)
uint32_t bios_reg_base, bios_reg_lim;
#endif
spi_bar = pci_config_read32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_BAR0_OFFSET);
spi_bar &= PCI_BAR_MASK;
spi_cmd =
pci_config_read32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET);
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET,
spi_cmd | PCI_COMMAND_MEM_SPACE);
/* The Flash Protected Range register has the same base/limit
* layout as the Flash Region register: take the BIOS region
* (FREG1, flash region 1) and enable read and write protection
* on it. The SPI registers live in the BAR's memory-mapped
* space, not in PCI configuration space. */
reg = mmio_read32(spi_bar + SPI_FREG1);
#if defined(DEBUG)
bios_reg_base = (reg & SPI_FREG_BASE_MASK) << SPI_FREG_ADDR_SHIFT;
bios_reg_lim = ((reg & SPI_FREG_LIMIT_MASK) >> SPI_FREG_LIMIT_SHIFT)
<< SPI_FREG_ADDR_SHIFT;
wolfBoot_printf("Bios reg base: 0x%x lim: 0x%x\r\n", bios_reg_base,
bios_reg_lim);
#endif
reg |= (SPI_FPR_RPE) | (SPI_FPR_WPE);
mmio_write32(spi_bar + SPI_FPR0, reg);
if ((mmio_read32(spi_bar + SPI_FPR0) &
(SPI_FPR_RPE | SPI_FPR_WPE)) != (SPI_FPR_RPE | SPI_FPR_WPE)) {
ret = -1;
}
/* lock down BIOS register configuration */
reg = mmio_read32(spi_bar + SPI_BIOS_HSFSTS_CTL);
reg |= SPI_FLOCKDN;
mmio_write32(spi_bar + SPI_BIOS_HSFSTS_CTL, reg);
if ((mmio_read32(spi_bar + SPI_BIOS_HSFSTS_CTL) & SPI_FLOCKDN) == 0) {
ret = -1;
}
/* restore original cmd */
pci_config_write32(0, SPI_PCI_DEV, SPI_PCI_FUN, PCI_COMMAND_OFFSET, spi_cmd);
return ret;
}
int hal_flash_protect(haladdr_t address, int len)
{
(void)address;
(void)len;
/* The TGL BIOS region covers the bootloader partition, so the
* hook's address/len are the same range FREG1 describes. */
return tgl_lock_bios_region();
}
#endif /* WOLFBOOT_TGL */
#endif

View File

@ -0,0 +1,44 @@
#ifndef FSP_CONFIG_H
#define FSP_CONFIG_H
#include <stdint.h>
#ifndef FSP_HYPERTHREADING
#define FSP_HYPERTHREADING 0
#endif
#if FSP_HYPERTHREADING
/* The MADT and MP table list four single-thread cores (APIC IDs 0/2/4/6). */
#error "FSP_HYPERTHREADING=1 needs sibling threads in the MADT and MP table"
#endif
#ifndef FSP_INTEL_SPEED_STEP
#define FSP_INTEL_SPEED_STEP 0
#endif
#ifndef FSP_INTEL_SPEED_SHIFT
#define FSP_INTEL_SPEED_SHIFT 0
#endif
#define FSP_BOOT_FREQ_MAX_NO_TURBO 0x1
#ifndef FSP_BOOT_PERFORMANCE_MODE
#define FSP_BOOT_PERFORMANCE_MODE FSP_BOOT_FREQ_MAX_NO_TURBO
#endif
#ifndef FSP_C_STATES
#define FSP_C_STATES 0
#endif
#ifndef FSP_TXT
#define FSP_TXT 0
#endif
#ifndef FSP_IN_BAND_ECC
#define FSP_IN_BAND_ECC 1
#endif
/* TM1/TM2 throttling at the thermal-control limit, the FSP default */
#ifndef FSP_THERMAL_THROTTLING
#define FSP_THERMAL_THROTTLING 1
#endif
#endif

File diff suppressed because it is too large Load Diff

View File

@ -150,7 +150,7 @@ enum mp_irq_source_types {
#define MP_CPU_NUM_ENTRY 1
#endif
#ifdef TARGET_kontron_vx3060_s2
#if defined(TARGET_kontron_vx3060_s2) || defined(TARGET_nai_68int6)
#define MP_IOAPIC_NUM_ENTRY 1
#define MP_INTSRC_NUM_ENTRY 17
#define MP_LINTSRC_NUM_ENTRY 0

View File

@ -24,5 +24,6 @@
#include <stdint.h>
int x86_fsp_tgl_init_sata(uint32_t *bar);
int tgl_lock_bios_region(void);
#endif /* TGL_FSP_H */

View File

@ -54,8 +54,16 @@ WOLFBOOT_TIME_TEST?=0
# Generate a minimal ACPI table set (RSDP/XSDT/FADT/MADT/MCFG + DSDT) for the
# x86 FSP Linux payload, so the OS gets the interrupt model and PCI routing.
ifeq ($(ACPI),1)
ifneq ($(TARGET),nai_68int6)
$(error ACPI=1 tables (CPU list, DSDT routing) are specific to nai_68int6)
endif
CFLAGS+=-D"WOLFBOOT_ACPI"
endif
ifeq ($(TARGET),nai_68int6)
ifneq ($(ACPI),1)
$(error nai_68int6 needs ACPI=1: its PCI interrupt routing is only in the DSDT)
endif
endif
# TPM NV version floor and boot audit counters (see docs/Targets.md).
# HALT_ON_FAILURE also halts when the TPM state cannot be read or locked.
@ -1601,6 +1609,7 @@ ifeq ($(FSP), 1)
X86_UART_BASE \
X86_UART_REG_WIDTH \
X86_UART_MMIO \
X86_UART_NUMBER \
PCH_HAS_PCR \
PCI_USE_ECAM \
PCH_PCR_BASE \

View File

@ -64,6 +64,15 @@ uint8_t mb2_boot_info[MAX_MB2_BOOT_INFO_SIZE];
#ifdef TARGET_kontron_vx3060_s2
static char *cmdline = "apic=verbose acpi=no pci=debug console=ttyS0,115200 debug";
#elif defined(TARGET_nai_68int6)
#define CMDLINE_STR_(x) #x
#define CMDLINE_STR(x) CMDLINE_STR_(x)
/* earlycon covers LPSS UART2 at its FSP-assigned base until the 8250 driver
* binds it as ttyS4 */
static char *cmdline =
"earlycon=uart8250,mmio32," CMDLINE_STR(X86_UART_BASE) ",115200n8 "
"console=ttyS4,115200 console=tty0 "
"root=/dev/sda2 rw rootwait";
#elif TARGET_x86_fsp_qemu
static char *cmdline = "console=ttyS0,115200 pci=earlydump debug";
#else

View File

@ -390,10 +390,18 @@ static int pci_pre_enum_cb(uint8_t bus, uint8_t dev, uint8_t fun)
#ifdef WOLFBOOT_TGL
if (bus != 0)
return 0;
/* don't change UART mapping */
if (dev == 0x1e && (fun == 0 || fun == 1)) {
/* Leave the console UART BAR at X86_UART_BASE. LPSS UART0/1 are
* 00:1e.0/1, UART2 is 00:19.2. */
#if defined(X86_UART_NUMBER) && (X86_UART_NUMBER == 2)
if (dev == 0x19 && fun == 2)
return 1;
}
#elif defined(X86_UART_NUMBER) && (X86_UART_NUMBER == 1)
if (dev == 0x1e && fun == 1)
return 1;
#else
if (dev == 0x1e && fun == 0)
return 1;
#endif
/* PMC BARs shouldn't be programmed as per FSP integration guide */
if (dev == 31 && fun == 2)
return 1;

View File

@ -477,7 +477,7 @@ int wolfBoot_tpm2_extend(uint8_t pcrIndex, uint8_t* hash, int line)
int rc;
#ifdef WOLFBOOT_DEBUG_TPM
uint8_t digest[WOLFBOOT_TPM_PCR_DIG_SZ];
int digestSz = 0;
int digestSz = (int)sizeof(digest);
#endif
/* clear auth session for PCR */
@ -502,7 +502,8 @@ int wolfBoot_tpm2_extend(uint8_t pcrIndex, uint8_t* hash, int line)
wolfBoot_printf("PCR %d: Res %d, Digest Sz %d\n",
pcrIndex, read_rc, digestSz);
wolfBoot_print_bin(digest, digestSz);
if (read_rc == 0)
wolfBoot_print_bin(digest, digestSz);
}
else {
wolfBoot_printf("Measure boot failed! Index %d, %x (%s)\n",

View File

@ -91,6 +91,11 @@ static uint8_t disk_encrypt_nonce[ENCRYPT_NONCE_SIZE];
#define BOOT_PART_A 5
#define BOOT_PART_B 6
#endif
#ifdef TARGET_nai_68int6
/* Signed kernels live in the 3rd and 4th GPT partitions (sda3/sda4). */
#define BOOT_PART_A 2
#define BOOT_PART_B 3
#endif
#endif /* WOLFBOOT_FSP */
/* Default values for BOOT_DISK, BOOT_PART_A and BOOT_PART_B */

View File

@ -27,7 +27,7 @@
#define LOCAL_APIC_ID 0xfee00020
#define LOCAL_APIC_VER 0xfee00030
#ifdef TARGET_kontron_vx3060_s2
#if defined(TARGET_kontron_vx3060_s2) || defined(TARGET_nai_68int6)
#define ISA_BUS 0x4
/* TGL mptable */
@ -518,7 +518,7 @@ void mptable_setup(void)
_mp->mpce_processor[0]._res[0] = _mp->mpce_processor[0]._res[1] = 0;
#ifdef TARGET_kontron_vx3060_s2
#if defined(TARGET_kontron_vx3060_s2) || defined(TARGET_nai_68int6)
{
int i;
for (i = 1; i < 4; ++i) {

View File

@ -47,6 +47,9 @@
#include <x86/fsp/FspsUpd.h>
#include <x86/ahci.h>
#include <stage2_params.h>
#ifdef TARGET_nai_68int6
#include <x86/fsp_config.h>
#endif
#define PCR_DMI_PORT_ID 0x88
#define PCR_DMI_LPCLGIR1 0x2730
@ -238,6 +241,9 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
FSP_M_CONFIG *mem_cfg;
mem_cfg = &udp->FspmConfig;
/* Kontron VX3060-S2 DQ maps and DDR tuning; other boards keep the FSP-M
* defaults. */
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->PlatformMemorySize = 93806592;
mem_cfg->DqMapCpu2DramMc0Ch0[0] = 13;
mem_cfg->DqMapCpu2DramMc0Ch0[1] = 12;
@ -367,6 +373,7 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
mem_cfg->DqMapCpu2DramMc1Ch3[13] = 9;
mem_cfg->DqMapCpu2DramMc1Ch3[14] = 8;
mem_cfg->DqMapCpu2DramMc1Ch3[15] = 13;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->TsegSize = 8388608;
mem_cfg->SpdAddressTable[0] = 160;
mem_cfg->SpdAddressTable[1] = 0;
@ -394,8 +401,10 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
mem_cfg->VtdBaseAddress[7] = 0;
mem_cfg->VtdBaseAddress[8] = 0;
mem_cfg->UserBd = 5;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->RMT = 1;
mem_cfg->NModeSupport = 2;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->PchHdaEnable = 0;
mem_cfg->GttMmAdr = 2147483648;
mem_cfg->DdiPort2Hpd = 1;
@ -404,14 +413,22 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
mem_cfg->DdiPort4Ddc = 1;
mem_cfg->EnableC6Dram = 0;
mem_cfg->HyperThreading = 0;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->CpuRatio = 0;
mem_cfg->FClkFrequency = 1;
#endif /* TARGET_kontron_vx3060_s2 */
#ifdef TARGET_nai_68int6
mem_cfg->VmxEnable = 1;
#else
mem_cfg->VmxEnable = 0;
#endif
mem_cfg->BiosGuard = 0;
mem_cfg->EnableSgx = 0;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->TxtDprMemorySize = 4194304;
mem_cfg->BiosAcmBase = 4285267968;
mem_cfg->ConfigTdpLevel = 2;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->PcieClkSrcUsage[0] = 128;
mem_cfg->PcieClkSrcUsage[1] = 128;
mem_cfg->PcieClkSrcUsage[2] = 128;
@ -434,7 +451,9 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
* set from X86_UART_NUMBER or the console changes between phases - output
* appears for part of the boot and then stops, reading as a hang. */
mem_cfg->SerialIoUartDebugControllerNumber = X86_UART_NUMBER;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->MrcSafeConfig = 1;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->TcssItbtPcie0En = 0;
mem_cfg->TcssItbtPcie1En = 0;
mem_cfg->TcssItbtPcie2En = 0;
@ -442,9 +461,12 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
mem_cfg->TcssXdciEn = 1;
mem_cfg->TcssDma0En = 0;
mem_cfg->TcssDma1En = 0;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->RMC = 0;
mem_cfg->EccSupport = 0;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->Ibecc = 1;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->IbeccParity = 1;
mem_cfg->RankInterleave = 0;
mem_cfg->EnhancedInterleave = 0;
@ -452,9 +474,12 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
mem_cfg->ChHashMask = 12492;
mem_cfg->PowerDownMode = 0;
mem_cfg->SafeMode = 1;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->UsbTcPortEnPreMem = 15;
mem_cfg->WrcFeatureEnable = 0;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->McParity = 1;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->PchHdaSdiEnable[0] = 1;
mem_cfg->PchHdaSdiEnable[1] = 1;
mem_cfg->PchHdaAudioLinkDmicEnable[0] = 0;
@ -470,7 +495,9 @@ static int fsp_set_memory_cfg(FSPM_UPD *udp)
mem_cfg->PchHdaAudioLinkSndwEnable[1] = 1;
mem_cfg->PchHdaAudioLinkSndwEnable[2] = 0;
mem_cfg->PchHdaAudioLinkSndwEnable[3] = 0;
#ifdef TARGET_kontron_vx3060_s2
mem_cfg->SkipCpuReplacementCheck = 1;
#endif /* TARGET_kontron_vx3060_s2 */
mem_cfg->SerialIoUartDebugMode = 4;
mem_cfg->PcieRefPllSsc = 0;
return 0;
@ -497,7 +524,9 @@ static void fsp_set_silicon_cfg(FSPS_UPD *fsps)
{
FSP_S_CONFIG *upd = &fsps->FspsConfig;
#ifdef TARGET_kontron_vx3060_s2
upd->GraphicsConfigPtr = 2024131364;
#endif /* TARGET_kontron_vx3060_s2 */
upd->SataPortsEnable[0] = 1;
upd->SataPortsEnable[1] = 1;
@ -661,18 +690,33 @@ static void fsp_set_silicon_cfg(FSPS_UPD *fsps)
upd->IomTypeCPortPadCfg[7] = 0;
upd->UsbTcPortEn = 15;
upd->AesEnable = 0;
#ifdef TARGET_kontron_vx3060_s2
upd->PchWriteProtectionEnable[0] = 1;
upd->PchWriteProtectionEnable[1] = 1;
#else
upd->PchWriteProtectionEnable[0] = 0;
upd->PchWriteProtectionEnable[1] = 0;
#endif /* TARGET_kontron_vx3060_s2 */
upd->PchWriteProtectionEnable[2] = 0;
upd->PchWriteProtectionEnable[3] = 0;
upd->PchWriteProtectionEnable[4] = 0;
#ifdef TARGET_kontron_vx3060_s2
upd->PchProtectedRangeLimit[0] = 13679;
upd->PchProtectedRangeLimit[1] = 16383;
#else
upd->PchProtectedRangeLimit[0] = 0;
upd->PchProtectedRangeLimit[1] = 0;
#endif /* TARGET_kontron_vx3060_s2 */
upd->PchProtectedRangeLimit[2] = 0;
upd->PchProtectedRangeLimit[3] = 0;
upd->PchProtectedRangeLimit[4] = 0;
#ifdef TARGET_kontron_vx3060_s2
upd->PchProtectedRangeBase[0] = 13312;
upd->PchProtectedRangeBase[1] = 13744;
#else
upd->PchProtectedRangeBase[0] = 0;
upd->PchProtectedRangeBase[1] = 0;
#endif /* TARGET_kontron_vx3060_s2 */
upd->PchProtectedRangeBase[2] = 0;
upd->PchProtectedRangeBase[3] = 0;
upd->PchProtectedRangeBase[4] = 0;
@ -953,9 +997,16 @@ int fsp_machine_update_s_parameters(uint8_t *default_s_params)
upd->MicrocodeRegionBase = 0x0;
upd->MicrocodeRegionSize = 0x0;
#ifdef TARGET_nai_68int6
/* No table: the FSP's built-in PCH interrupt routing matches the DSDT
* _PRT; a partial table leaves other devices' INTx unrouted. */
upd->DevIntConfigPtr = 0;
upd->NumOfDevIntConfig = 0;
#else
/* we can assume that is under 4gb */
upd->DevIntConfigPtr = (uint32_t)(uintptr_t)mPchHDevIntConfig;
upd->NumOfDevIntConfig = sizeof(mPchHDevIntConfig)/sizeof(mPchHDevIntConfig[0]);
#endif
upd->SataEnable = 1;
upd->SataMode = 0;
upd->SataSalpSupport = 0;
@ -978,6 +1029,13 @@ int fsp_machine_update_s_parameters(uint8_t *default_s_params)
memset(upd->PcieRpHotPlug, 0, sizeof(upd->PcieRpHotPlug));
memset(upd->CpuPcieRpHotPlug, 0, sizeof(upd->CpuPcieRpHotPlug));
#ifdef TARGET_nai_68int6
upd->Eist = FSP_INTEL_SPEED_STEP;
upd->Hwp = FSP_INTEL_SPEED_SHIFT;
upd->Cx = FSP_C_STATES;
upd->TxtEnable = FSP_TXT;
upd->ThermalMonitor = FSP_THERMAL_THROTTLING;
#endif
return 0;
}
/**
@ -1470,6 +1528,8 @@ static const struct tgl_gpio_conf gpio_table_presilicon[] = {
.gpio_term = GPIO_TERM_NONE},
};
#elif defined(TARGET_nai_68int6)
#include <x86/gpio_config.h>
#endif /* TARGET_kontron_vx3060_s2 */
/**
* @brief Configure GPIO settings for a specific device.
@ -1655,6 +1715,16 @@ int post_temp_ram_init_cb(void)
kontron_ask_for_recovery();
#elif defined(TARGET_nai_68int6)
unsigned int i;
unsigned int n;
/* No CPLD or SuperIO: the LTC2870 transceiver resets to RS-232, so only
* the console pads need setting up. */
n = sizeof(gpio_table_tempram)/sizeof(gpio_table_tempram[0]);
for (i = 0; i < n; i++) {
tgl_gpio_configure(&gpio_table_tempram[i]);
}
#else
(void)tgl_gpio_configure;
#endif /* TARGET_kontron_vx3060_s2 */
@ -1691,6 +1761,11 @@ int fsp_machine_update_m_parameters(uint8_t *default_m_params,
new_udp->FspmArchUpd.NvsBufferPtr = 0;
new_udp->FspmArchUpd.StackBase = mem_base;
new_udp->FspmArchUpd.StackSize = mem_size;
#ifdef TARGET_nai_68int6
new_udp->FspmConfig.HyperThreading = FSP_HYPERTHREADING;
new_udp->FspmConfig.BootFrequency = FSP_BOOT_PERFORMANCE_MODE;
new_udp->FspmConfig.Ibecc = FSP_IN_BAND_ECC;
#endif
return 0;
}
@ -1698,8 +1773,12 @@ int fsp_machine_update_m_parameters(uint8_t *default_m_params,
int fsp_pre_mem_init_cb(void)
{
unsigned int i;
unsigned int n;
for (i = 0; i < sizeof(gpio_table_premem)/sizeof(gpio_table_premem[0]); i++) {
/* via a variable: the table is empty on some targets, and comparing
* against the literal 0 that sizeof folds to trips -Wtype-limits. */
n = sizeof(gpio_table_premem)/sizeof(gpio_table_premem[0]);
for (i = 0; i < n; i++) {
tgl_gpio_configure(&gpio_table_premem[i]);
}

View File

@ -0,0 +1,109 @@
#!/bin/bash
#
# Switch the in-tree FSP set (UPD headers and FSP binaries) between QEMU,
# Tiger Lake and NAI; their generators all write the same paths.
#
# Usage:
# select_fsp.sh save {tgl|qemu|nai} snapshot the current in-tree set
# select_fsp.sh use {tgl|qemu|nai} restore a snapshotted set into the tree
# select_fsp.sh show report what is cached and what is in-tree
#
set -e
CACHE="${WOLFBOOT_FSP_CACHE:-$HOME/.cache/wolfboot-fsp}"
ROOT="$(cd "$(dirname "$0")/../../.." && pwd)"
HDRS="FspUpd.h FspmUpd.h FspsUpd.h FsptUpd.h"
# Headers only some generators emit; each set restores only its own, so one
# cannot leak into another.
HDRS_OPT_ALL="MemInfoHob.h"
HDRS_OPT_tgl="MemInfoHob.h"
HDRS_OPT_nai="MemInfoHob.h"
BINS="fsp_t.bin fsp_m.bin fsp_s.bin"
# ucode0.bin is only produced by the TGL flow
EXTRA_tgl="ucode0.bin"
# NAI: the TGL flow with NAI's own FSP and microcode (nai_extract_fsp.sh)
EXTRA_nai="ucode0.bin"
usage() { sed -n '3,9p' "$0" | sed 's/^# \{0,1\}//'; exit 1; }
check_set() {
case "$1" in
tgl|qemu|nai) ;;
*) echo "error: set must be 'tgl', 'qemu' or 'nai'" >&2; exit 1 ;;
esac
}
do_save() {
local s="$1" extra opt n=0
eval "extra=\${EXTRA_$s:-}"
eval "opt=\${HDRS_OPT_$s:-}"
mkdir -p "$CACHE/$s"
for f in $HDRS; do
[ -f "$ROOT/include/x86/fsp/$f" ] || { echo "error: missing include/x86/fsp/$f" >&2; exit 1; }
cp "$ROOT/include/x86/fsp/$f" "$CACHE/$s/"; n=$((n+1))
done
for f in $HDRS_OPT_ALL; do
rm -f "$CACHE/$s/$f"
done
for f in $opt; do
[ -f "$ROOT/include/x86/fsp/$f" ] && { cp "$ROOT/include/x86/fsp/$f" "$CACHE/$s/"; n=$((n+1)); }
done
for f in $BINS $extra; do
[ -f "$ROOT/src/x86/$f" ] || { echo "error: missing src/x86/$f" >&2; exit 1; }
cp "$ROOT/src/x86/$f" "$CACHE/$s/"; n=$((n+1))
done
echo "saved $n files to $CACHE/$s"
}
do_use() {
local s="$1" extra opt n=0
eval "extra=\${EXTRA_$s:-}"
eval "opt=\${HDRS_OPT_$s:-}"
[ -d "$CACHE/$s" ] || { echo "error: no snapshot for '$s'. Run the generator then 'select_fsp.sh save $s'." >&2; exit 1; }
# Check every required file before copying any, so a partial cache fails
# here rather than leaving a half-updated tree.
for f in $HDRS $BINS $extra; do
[ -f "$CACHE/$s/$f" ] || { echo "error: cached '$s' set is missing $f; re-run the generator then 'select_fsp.sh save $s'" >&2; exit 1; }
done
for f in $HDRS; do
cp "$CACHE/$s/$f" "$ROOT/include/x86/fsp/"; n=$((n+1))
done
for f in $HDRS_OPT_ALL; do
rm -f "$ROOT/include/x86/fsp/$f"
done
for f in $opt; do
[ -f "$CACHE/$s/$f" ] && { cp "$CACHE/$s/$f" "$ROOT/include/x86/fsp/"; n=$((n+1)); }
done
for f in $BINS $extra; do
cp "$CACHE/$s/$f" "$ROOT/src/x86/"; n=$((n+1))
done
echo "restored $n files of the '$s' FSP set"
}
do_show() {
echo "cache: $CACHE"
for s in tgl qemu nai; do
if [ -d "$CACHE/$s" ]; then
echo " $s: $(ls "$CACHE/$s" | wc -l) files"
else
echo " $s: (not snapshotted)"
fi
done
echo "in-tree include/x86/fsp/FspmUpd.h:"
if [ -f "$ROOT/include/x86/fsp/FspmUpd.h" ]; then
# the TGL header is thousands of lines; the QEMU one is a small stub
printf " %s lines -> looks like %s\n" \
"$(wc -l < "$ROOT/include/x86/fsp/FspmUpd.h")" \
"$([ "$(wc -l < "$ROOT/include/x86/fsp/FspmUpd.h")" -gt 1000 ] && echo TGL || echo QEMU)"
else
echo " (absent)"
fi
}
[ $# -ge 1 ] || usage
case "$1" in
save) [ $# -eq 2 ] || usage; check_set "$2"; do_save "$2" ;;
use) [ $# -eq 2 ] || usage; check_set "$2"; do_use "$2" ;;
show) do_show ;;
*) usage ;;
esac

View File

@ -0,0 +1,97 @@
#!/bin/bash
#
# Extract FSP-T/M/S and microcode from a 68INT6 BIOS image and rebase them
# to the .config addresses (the public TGL_IOT FSP does not train this board).
#
# Usage: tools/scripts/x86_fsp/tgl/nai_extract_fsp.sh <68INT6_bios_image.bin>
set -eu
IMG=${1:?usage: $0 <nai_bios_image.bin>}
WORK_DIR=/tmp/tgl_fsp
EDK2_COMMIT_ID=df25a5457f04ec465dce97428cfee96f462676e7
FSP_TOOL_URL=https://github.com/tianocore/edk2/raw/${EDK2_COMMIT_ID}/IntelFsp2Pkg/Tools/SplitFspBin.py
SCRIPT_DIR=$(readlink -f "$(dirname "$0")")
WOLFBOOT_DIR="${SCRIPT_DIR}/../../../.."
CFG="${WOLFBOOT_DIR}/.config"
[ -f "$IMG" ] || { echo "error: image not found: $IMG" >&2; exit 1; }
[ -f "$CFG" ] || { echo "error: no .config in ${WOLFBOOT_DIR}; copy config/examples/nai_68int6.config there first" >&2; exit 1; }
cfgval() { grep -E "^$1=" "$CFG" | tail -1 | cut -d= -f2 | tr -d ' '; }
FSP_T_BASE=$(cfgval FSP_T_BASE)
FSP_M_BASE=$(cfgval FSP_M_BASE)
FSP_S_LOAD_BASE=$(cfgval FSP_S_LOAD_BASE)
for v in FSP_T_BASE FSP_M_BASE FSP_S_LOAD_BASE; do
[ -n "${!v}" ] || { echo "error: $v not set in .config" >&2; exit 1; }
done
mkdir -p "$WORK_DIR"
if [ ! -f "$WORK_DIR/SplitFspBin.py" ]; then
echo "fetching SplitFspBin.py (edk2 ${EDK2_COMMIT_ID:0:12})"
curl -sL -o "$WORK_DIR/SplitFspBin.py" "$FSP_TOOL_URL"
fi
# Locate FSP-T/M/S by their FSP_INFO_HEADER (type = ComponentAttribute bits
# 15:12; the FV starts 0x94 before the header, inner FV for FSP-S).
python3 - "$IMG" "$WORK_DIR" <<'PY'
import struct, sys
img = open(sys.argv[1], 'rb').read()
work = sys.argv[2]
names = {1: 'T', 2: 'M', 3: 'S'}
found = {}
i = 0
while True:
i = img.find(b'FSPH', i)
if i < 0:
break
hlen = struct.unpack_from('<I', img, i + 4)[0]
if hlen in (0x48, 0x4C, 0x50):
imgrev, imgid, imgsize, imgbase, attr, cattr = struct.unpack_from('<I8sIIHH', img, i + 0x0C)
kind = names.get((cattr >> 12) & 0xF)
if kind and imgid.strip(b'\0') and 0 < imgsize < 0x200000:
fv = i - 0x94
found.setdefault(kind, (fv, imgsize, imgid, imgbase, imgrev))
i += 4
for k in 'TMS':
if k not in found:
print("error: FSP-%s not found in image" % k); sys.exit(1)
fv, size, imgid, base, rev = found[k]
open("%s/NAI_FSP_%s.fd" % (work, k), 'wb').write(img[fv:fv + size])
print(" FSP-%s %-9r rev %X.%X.%X.%X at 0x%08X size 0x%06X linked at 0x%08X"
% (k, imgid, (rev >> 24) & 0xFF, (rev >> 16) & 0xFF, (rev >> 8) & 0xFF, rev & 0xFF, fv, size, base))
# Newest microcode for this CPU from the same image.
best = None
for off in range(0, len(img) - 48, 16):
if struct.unpack_from('<I', img, off)[0] != 1:
continue
hv, urev, date, sig, cks, ldr, pf, dsz, tsz = struct.unpack_from('<9I', img, off)
if ldr != 1 or sig != 0x000806C1 or tsz == 0 or tsz > 0x40000 or off + tsz > len(img):
continue
blob = img[off:off + tsz]
if sum(struct.unpack_from('<%dI' % (tsz // 4), blob)) & 0xFFFFFFFF:
continue
if best is None or urev > best[0]:
best = (urev, date, blob)
if best is None:
print("error: no valid 06-8c-01 microcode found in image"); sys.exit(1)
urev, date, blob = best
open("%s/NAI_ucode0.bin" % work, 'wb').write(blob)
print(" ucode 06-8c-01 rev 0x%02X date %08X %d bytes" % (urev, date, len(blob)))
PY
rebase() {
local c=$1 base=$2
(cd "$WORK_DIR" && python3 SplitFspBin.py rebase -f "NAI_FSP_${c}.fd" -b "$base" \
-c "${c,,}" -o . -n "NAI_FSP_${c}_rebased.fd" >/dev/null)
cp "$WORK_DIR/NAI_FSP_${c}_rebased.fd" "${WOLFBOOT_DIR}/src/x86/fsp_${c,,}.bin"
echo " FSP-$c rebased to $base -> src/x86/fsp_${c,,}.bin"
}
rebase T "$FSP_T_BASE"
rebase M "$FSP_M_BASE"
rebase S "$FSP_S_LOAD_BASE"
cp "$WORK_DIR/NAI_ucode0.bin" "${WOLFBOOT_DIR}/src/x86/ucode0.bin"
echo " microcode -> src/x86/ucode0.bin"
echo
echo "Done. Snapshot it: tools/scripts/x86_fsp/select_fsp.sh save nai"

View File

@ -39,7 +39,7 @@ typedef uintptr_t haladdr_t;
#define MMIO_BASE 0xFED40000UL
/* SPI PCI device constants + register offsets from
* hal/kontron_vx3060_s2.c (extracted by the Makefile). */
* hal/x86_fsp_tgl.c (extracted by the Makefile). */
#include "kontron_spi_extract.h"
/* TGL register offsets used by the model. */
@ -122,7 +122,7 @@ static uint32_t mmio_read32(uintptr_t address)
}
/* The real tgl_lock_bios_region() + hal_flash_protect() from
* hal/kontron_vx3060_s2.c (extracted). */
* hal/x86_fsp_tgl.c (extracted). */
#include "kontron_spi_fn_extract.h"
/* The lock must land in the MMIO space: FPR0 carries the FREG1