Skip to content

NAI 68INT6: board devices, ACPI tables, PCIe bring-up, Multiboot2 payloads, faster cold boot and an ATA write fix - #959

Open
dgarske wants to merge 15 commits into
wolfSSL:masterfrom
dgarske:nai_lpss_acpi
Open

dgarske wants to merge 15 commits into
wolfSSL:masterfrom
dgarske:nai_lpss_acpi

Conversation

@dgarske

@dgarske dgarske commented Oct 28, 2026 •

Copy link
Copy Markdown
Member

Description

Exposes the 68INT6 board devices on the LPSS I2C0 and GSPI0 controllers to Linux, the same way NAI's stock BIOS declares them, so NAI's Linux drivers (naigspi, plus at24 for the EEPROMs) bind under wolfBoot. It also lets one build boot either a Linux bzImage or a Multiboot2 ELF (an RTOS), chosen per image, cuts cold boot time by caching FSP-M's memory training data and removing a global reset on every cold boot, and brings up the PCIe switch the way the stock BIOS does. Linux also gets the TPM, VT-d, HPET and root port tables it gets from the stock BIOS, and every enabled CPU.

What it adds

  • src/x86/acpi_dsdt.asl, include/x86/acpi_dsdt.h - I2C0 (00:15.0) and SPI0 (00:1e.2) under the PCI root, with:
    • the PRC register controller on GSPI0 CS0 (15AC0001)
    • EEPROM (15AC0002, 0x56) and serial-number EEPROM (15AC0003, 0x5E)
    • RTC/watchdog (15AC0004, 0x68)
  • include/x86/gpio_config.h - GSPI0 (GPP_B15-B18) and I2C0 (GPP_C16/C17) pads in native mode, with the stock pad values; C15, E12, F9 and the USB power enables H7-H9 driven high, D2 held low for the OS; D0 and C22 as edge-triggered IOxAPIC inputs (C22 with its 20K pull-up) and H6 as a low output, as the stock BIOS sets them
  • include/x86/gpio_config.h, options.mk - the stock BIOS PCIe sequence: switch lane straps, NT mode and backplane clock before memory init (NAI_68INT6_PCIE_LANES, NAI_68INT6_PCIE_NT, NAI_68INT6_BACKPLANE_CLK), then the PCIE_RDY (GPP_C23) wait and GPP_B12 release before PCI enumeration, with the BIOS delays as options timed from the TSC rate in CPUID
  • src/x86/acpi_dsdt.asl, src/x86/acpi.c - TPM device (MSFT0101) with TPM2, HPET and DMAR tables; root ports PEG0, RP05, RP09 and RP10 with the stock INTx routing, 00:06.0 in the root _PRT, and _OSC on the PCI root
  • src/x86/common.c, src/x86/acpi.c, src/x86/mptable.c - MADT and MP table list the enabled logical processors (MSR_CORE_THREAD_COUNT, CPUID 0xB) instead of a fixed set, so FSP_HYPERTHREADING=1 is allowed; the MP table size is the build option MP_CPU_NUM_ENTRY
  • src/x86/tgl_fsp.c - on nai_68int6, SerialIoI2cMode[0] set to PCI mode (it was disabled), hot-plug on root ports 5, 9 and 10 so FSP-S keeps them when no link is up at boot, and CnviMode left on Auto: no CNVi module is fitted, and forcing Disable made FSP-S request a global reset on every cold boot
  • hal/nai_68int6.c - sets FULL_RST in the Reset Control register before handoff, as the stock BIOS does, so a later reset (SYS_RESET# from the IPMC) is a full reset
  • include/x86/fsp_config.h, options.mk - NAI_68INT6_DEBUG_CONSENT sets FSP-M PlatformDebugConsent: 0 (debug off) by default, 4 for an XDP/MIPI-60 JTAG probe
  • docs/Targets.md - notes the board devices in the DSDT, documents Multiboot2 ELF payloads and how their handoff differs from Linux, the training data cache and the PCIe options, and corrects the memory, build, measured boot and boot-confirmation notes
  • src/x86/fsp_nvs.c, include/x86/fsp_nvs.h - training data cache (FSP_NVS_CACHE=1, Tiger Lake only, enabled for nai_68int6 in a 128 KB area below the wolfBoot window). Stage 1 hands a valid saved record to FspMemInit; the record is keyed on a CRC of the FSP-M image and its UPDs, so a change to either falls back to full training. Stage 2 saves the FSP non-volatile storage HOB, only when it changed, after TempRamExit and before FSP-S and the BIOS region lock; the header is written last. Stage 1 sets a CMOS flag before FspMemInit runs with a saved record, an FSP-requested reset clears it, and stage 2 clears it once FspSiliconInit succeeds. If FspMemInit fails with the record, or a boot finds the flag still set because the previous boot crashed or hung with it, boots train from scratch until one gets through FspSiliconInit, and stage 2 replaces the record. assemble_image.sh -n blanks the cache area, so an image built from a board's flash dump does not carry that board's training data.
  • src/x86/fsp_nvs.c, src/loader.c, options.mk - optional FSP_NVS_TPM=1 (off by default, needs ANTI_ROLLBACK=1) authenticates the saved record, otherwise the only unauthenticated input FSP-M consumes. Stage 2 keeps a SHA-256 of the record in a TPM NV index that only the platform hierarchy can write. Stage 1 reads it before FspMemInit, with a small stack-only FIFO exchange since it has no writable data before memory is up, and trains from scratch unless the record in flash matches
  • options.mk - on nai_68int6 the PCI BAR window is split into two 512 MB pools, so a large BAR behind the PCIe switch leaves room for the devices enumerated after it
  • hal/x86_fsp_tgl.c - 4 KB erase and write through SPI hardware sequencing, BIOS region only, with the waits timed from the TSC
  • tools/unit-tests/unit-fsp-nvs.c, unit-fsp-nvs-save.c, unit-tgl-spi-hwseq.c, unit-x86-apic-ids.c, unit-x86-acpi.c, unit-boot-x86-fsp-payload.c, unit-boot-x86-fsp-measure.c, unit-ata-sector-io.c, unit-linux-loader-e820.c, unit-elf-mmu-fail.c - the cache record check, the retrain paths, the TPM reference hash and the save path, the SPI cycles against a modeled controller, the CPU list, the MADT, TPM2, HPET and DMAR builders, the ELF overlap check and payload choice, the PCR 0 re-hash, the ATA sector commands, the e820 entry types and the ELF segment size checks
    The serial-number EEPROM's read-only property is written as a name/value pair, as ACPI device properties require.

Touches shared code

  • src/boot_x86_fsp_payload.c - with both LINUX_PAYLOAD and ELF built in, do_boot() sends an image that starts with the ELF magic down the ELF/Multiboot2 path and boots anything else as Linux. Builds with only one payload type behave as before. The ELF parse is bounded by the verified payload size, and a segment whose physical or virtual range overlaps wolfBoot's own memory is rejected before it is copied.
  • src/update_disk.c, src/boot_x86_fsp_payload.c, include/stage2_params.h - a signed HDR_CMDLINE in the image replaces the built-in Linux command line; one outside the signed part of the header (after the digest TLV) is ignored (covered in unit-update-disk-fsp.c); the buffer size is WOLFBOOT_CMDLINE_MAX
  • src/elf.c - a segment whose p_filesz is larger than its p_memsz, or whose p_memsz does not fit the map callback's 32-bit size, is rejected
  • src/x86/linux_loader.c - only RAM and reserved memory go into the Linux e820 map. MMIO ranges were listed as reserved, which kept the kernel from assigning PCI BARs in the PCI window, and an I/O port range was listed as memory. With ACPI tables, the ECAM range is added as reserved so the kernel uses MMCONFIG
  • options.mk - WOLFTPM=0 together with an option that needs the TPM is a build error
  • src/x86/ata.c - sector writes use WRITE DMA EXT like reads do; the 28-bit WRITE DMA took LBA bits 27:24 from the fixed device register, so a write at or past 8 GiB landed at LBA & 0xFFFFFF. A failed read or write, including the write-back of a partial sector, now returns an error instead of the full byte count
  • src/boot_x86_fsp.c, tools/scripts/x86_fsp/compute_pcr.py - stage 1 re-hashes stage 2's digest with SHA-256 before extending PCR 0, as the OS measurement does, instead of truncating a SHA-384 digest; compute_pcr.py predicts the new value
  • src/boot_x86_fsp.c, src/x86/fsp.c, include/stage2_params.h - cache call sites and the record key passed from stage 1 to stage 2, all under FSP_NVS_CACHE
  • src/x86/tgl_fsp.c, src/x86/fsp.c - the Tiger Lake pad writer can set a pad's output level (GPIO_SET_TX), and a fsp_pre_pci_enum_cb() hook runs before PCI enumeration (a no-op on Kontron and QEMU)

Testing

Builds for nai_68int6 (both payloads, ELF only, Linux only, Hyper-Threading) and kontron_vx3060_s2. Tested on a 68INT6 Rev D5: one image boots a Multiboot2 RTOS test ELF and Ubuntu 22.04 (5.15). Under Linux the EEPROMs bind to at24, NAI's naigspi binds to the PRC, and rtc-ds1374 binds the RTC. The first boot after flashing saves the training data, later cold boots use it, a changed UPD set falls back to full training, a FspMemInit failure with the saved record retrains on the next boot and replaces it, a reset forced with the record in use does the same, and the per-boot global reset is gone. With FSP_NVS_TPM=1, a record rewritten in flash without the TPM hash is rejected and retrained. The PCIe switch enumerates as under the stock BIOS, the lane straps change its port layout, and the delays match wall-clock time. Linux finds /dev/tpm0, DMAR and HPET, 4 or 8 CPUs, root port 00:1d.1 with no card fitted, and uses the signed command line. Linux no longer clips the PCI window, assigns 00:1f.5 and the 00:1c.0 bridge window, uses MMCONFIG and enables AER on the root ports. The board used here has no XMC carrier, so the larger BAR pools were only checked for regressions. PCR 0 matches the compute_pcr.py prediction, Reset Control reads FULL_RST after handoff, the D0, C22 and H6 pad registers read back as under the stock BIOS, and an ELF with a segment over wolfBoot's memory is rejected. The warm reset FspMemInit requests on each power-on is not caused by any wolfBoot UPD and is left for follow-up with the FSP vendor. Linux still fails to assign some BARs behind the PCIe switch because wolfBoot's bridge windows are smaller than the stock BIOS's; populated devices work, and window sizing is a follow-up. The e820 change also applies to kontron_vx3060_s2 and QEMU, which build but were not run on hardware here.

@dgarske dgarske self-assigned this Oct 28, 2026
@dgarske dgarske changed the title NAI 68INT6: enable LPSS I2C0 and declare the board I2C0/GSPI0 devices in the DSDT NAI 68INT6: board I2C0/GSPI0 devices in the DSDT and Linux or Multiboot2 payload per image Oct 30, 2026
@dgarske
dgarske force-pushed the nai_lpss_acpi branch 2 times, most recently from 2b369ac to e7f091a Compare October 31, 2026 17:47
@dgarske dgarske changed the title NAI 68INT6: board I2C0/GSPI0 devices in the DSDT and Linux or Multiboot2 payload per image NAI 68INT6: board devices in the DSDT, Linux or Multiboot2 payload per image, and faster cold boot Oct 31, 2026
Copilot AI balanced review requested due to automatic review settings November 2, 2026 19:39

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🔵 Needs a closer look

Pre-FSP-S flash writes and persistent memory-training reuse require platform/FSP-owner review of flash ownership and reset or interrupted-write recovery guarantees not established by host models or reported board testing.

No open issues 🎉

What changed in this PR

Extends wolfBoot’s NAI 68INT6 support with Linux-visible board devices, per-image Linux or Multiboot2 payload selection, and faster cold boots through cached memory training data.

Changes:

  • Declares board I2C/SPI devices in ACPI and configures their native GPIO pads and controllers.
  • Selects the ELF or Linux boot path from the image format when both are enabled.
  • Adds FSP memory-training caching, Tiger Lake SPI erase/write support, and unit tests; adjusts NAI CNVi configuration to avoid recurring cold-boot global resets.
File Description
tools/​unit-tests/​unit-tgl-spi-hwseq.c Tests SPI address mapping, erase/write cycles, and failure handling.
tools/​unit-tests/​unit-fsp-nvs.c Tests cache validation and stage 1 handoff.
tools/​unit-tests/​unit-fsp-nvs-save.c Tests cache persistence using synthetic HOBs and flash.
tools/​unit-tests/​Makefile Registers and builds the three new test suites.
src/​x86/​tgl_fsp.c Enables NAI I2C0 and selects CNVi Auto mode.
src/​x86/​fsp.c Saves training data after TempRamExit, before FSP-S.
src/​x86/​fsp_nvs.c Implements cache validation, reuse, and persistence.
src/​x86/​acpi_dsdt.asl Declares EEPROMs, RTC/watchdog, and PRC devices.
src/​boot_x86_fsp.c Applies cached training data before memory initialization.
src/​boot_x86_fsp_payload.c Extracts ELF boot logic and adds per-image dispatch.
options.mk Validates cache configuration and supplies compiler defines.
include/​x86/​tgl_fsp.h Declares SPI flash erase/write interfaces.
include/​x86/​gpio_config.h Adds native-mode GSPI0 and I2C0 pad configuration.
include/​x86/​fsp_nvs.h Defines the cache record and public interfaces.
include/​x86/​acpi_dsdt.h Updates embedded AML for the board devices.
include/​stage2_params.h Carries the cache key between boot stages.
hal/​x86_fsp_tgl.c Implements BIOS-region SPI hardware-sequenced erase/write.
docs/​Targets.md Documents board devices, caching, and payload handoff differences.
config/​examples/​nai_68int6.config Enables a 128 KB training-data cache below wolfBoot.
arch.mk Includes cache implementation in both boot stages.
.gitignore Excludes new test binaries and the generated extraction header.

Review effort: Balanced

@dgarske
dgarske force-pushed the nai_lpss_acpi branch 4 times, most recently from e19e303 to 5cfba81 Compare November 3, 2026 23:30
@dgarske dgarske changed the title NAI 68INT6: board devices in the DSDT, Linux or Multiboot2 payload per image, and faster cold boot NAI 68INT6: board devices, ACPI tables, PCIe bring-up, Multiboot2 payloads, faster cold boot and an ATA write fix Nov 3, 2026
@dgarske
dgarske requested a balanced review from Copilot November 4, 2026 23:59

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

Critical issues permit unauthenticated Linux command-line injection, ELF loading over running stage 2, and firmware-overwriting flash writes when the reserved NVS cache size is zero.

4 open issues

Review effort: Balanced

Comment thread src/boot_x86_fsp_payload.c Resolved
Comment thread src/update_disk.c Resolved
Comment thread src/x86/fsp_nvs.c Resolved
Comment thread tools/unit-tests/unit-ata-sector-io.c Resolved
@dgarske
dgarske force-pushed the nai_lpss_acpi branch 3 times, most recently from d85c793 to 3853288 Compare November 5, 2026 20:04
@dgarske
dgarske requested review from wolfSSL-Fenrir-bot and a balanced review from Copilot November 5, 2026 22:31

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

ELF segment-size truncation and unchecked p_filesz > p_memsz allow writes beyond the validated memory range, potentially overwriting wolfBoot.

1 open issue
4 resolved since last review

Review effort: Balanced

Comment on lines +113 to +116
static int boot_elf_map_cb(uint64_t vaddr, uint64_t paddr, uint32_t size)
{
if (elf_reserved_overlap(paddr, size) ||
elf_reserved_overlap(vaddr, size)) {

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #959

Scan targets checked: wolfboot-src, wolfboot-bugs
Not reviewed (no scan target covers them): .gitignore, arch.mk, config/examples/nai_68int6.config, docs/Targets.md, options.mk, src/x86/acpi_dsdt.asl, tools/scripts/x86_fsp/compute_pcr.py, tools/scripts/x86_fsp/tgl/assemble_image.sh, tools/unit-tests/Makefile
Coverage: 20 of 31 in-scope changed file(s) opened by the reviewer; not opened: include/x86/acpi_dsdt.h, include/x86/common.h, include/x86/fsp_config.h, include/x86/fsp_nvs.h, tools/unit-tests/unit-boot-x86-fsp-measure.c, tools/unit-tests/unit-boot-x86-fsp-payload.c, tools/unit-tests/unit-fsp-nvs-save.c, tools/unit-tests/unit-fsp-nvs.c, tools/unit-tests/unit-tgl-spi-hwseq.c, tools/unit-tests/unit-x86-acpi.c and 1 more

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Max

@dgarske
dgarske force-pushed the nai_lpss_acpi branch 2 times, most recently from 9c186d3 to bb3f0ef Compare November 6, 2026 16:29
@dgarske dgarske removed their assignment Nov 6, 2026
@dgarske
dgarske requested a review from rizlik November 6, 2026 23:39
Comment thread src/x86/mptable.c Resolved
Comment thread src/update_disk.c Resolved
Comment thread src/update_disk.c Resolved
Comment thread include/x86/mptable.h Resolved

@rizlik rizlik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

first round of review:

  • NIT: the NAI strap levels belong more in the NAI section of gpio_config.h than in fsp_config.h
  • Instead of setting a sentinel on error when MemInit fails with the recorded value, set a "booting with cached value in progress" sentinel before MemInit and clear it afterwards (probably even better after the FSP-S callback). This way crashes and hangs will not loop into always trying to boot with the same value. The sentinel must be cleared before any FSP-requested reset, otherwise the cached value is never used.
  • Memory training values are not authenticated, so under an Intel Boot Guard enabled boot they will be the only unauthenticated data consumed by the board. Exploitability is highly hypothetical; consider whether adding the hash inside the TPM is worthwhile, even if using the TPM might not be feasible during stage 1, or add a warning if the risk is accepted.
  • The check that prints "GPP_B12 did not go high" doesn't really check the GPIO level, but whether setting the TX state was successful. Does the code match what we want to achieve?
  • Checking whether a header field is authenticated should be covered by a standard function in wolfBoot, probably in a follow-up PR.
  • DMAR_FLAGS 0x05 is commented as INTR_REMAP | X2APIC_OPT_OUT, which would be 0x03.

@rizlik rizlik assigned dgarske and unassigned rizlik Nov 11, 2026

@rizlik rizlik left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

great work! A last small fix and then it's good for me: avoid syncing the TPM hash if the nvs flash saving fails, otherwise the TPM might contain the hash of a stale record.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants