From 801d2051e464dbda44af94ff60587f9101314a4d Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 1 Oct 2026 08:06:13 -0400 Subject: gsp-phys: fix booter-unload teardown (WPR meta/args) so WPR2 is cleared on release --- kernel/gsp_phys_fwsec.c | 65 +++++++++++++++++++++++++++++++++++++++++++++---- 1 file changed, 60 insertions(+), 5 deletions(-) (limited to 'kernel/gsp_phys_fwsec.c') diff --git a/kernel/gsp_phys_fwsec.c b/kernel/gsp_phys_fwsec.c index dc8c979..3c63a95 100644 --- a/kernel/gsp_phys_fwsec.c +++ b/kernel/gsp_phys_fwsec.c @@ -138,6 +138,19 @@ bool gsp_phys_fwsec_dryrun_enabled(void) #define GSP_PHYS_GFW_BOOT 0x118234 #define GSP_PHYS_GFW_BOOT_PROGRESS_MASK 0xff #define GSP_PHYS_GFW_BOOT_COMPLETED 0xff +/* + * VPR secure scratch 14. The Booter ucodes gate on the booter binary version + * (31:28) and on four sequence-handoff bits (27:24): Booter Load, AHESASC -> + * Booter Reload, Booter Reload -> ACR Unload and ACR Unload -> Booter Unload. + * Booter Unload requires all four DONE and the version field equal to its own + * build version (0 on TU102/TU104/TU106). + */ +#define GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14 0x001180f8 +#define GSP_PHYS_SCRATCH14_BOOTER_VERSION_MASK 0xf0000000u +#define GSP_PHYS_SCRATCH14_BOOTER_VERSION_SHIFT 28 +#define GSP_PHYS_SCRATCH14_HANDOFF_MASK 0x0f000000u +#define GSP_PHYS_SCRATCH14_HANDOFF_SHIFT 24 +#define GSP_PHYS_SCRATCH14_BOOTER_VERSION_TU10X 0u #define GSP_PHYS_GFW_PLM 0x118128 #define GSP_PHYS_GFW_PLM_LEVEL0 BIT(0) #define GSP_PHYS_RISCV_STATUS 0x111240 @@ -961,13 +974,48 @@ static void gsp_phys_fwsec_ucode_free(struct pci_dev *pdev, } /* - * Booter unload on SEC2: reset, load the unload image in direct mode and run - * it with mailbox0/1 = 0xff. Success leaves WPR2 down. + * Seed the VPR secure-scratch sequence state the Booter Unload ucode gates on + * at entry. In the reference lifecycle those bits are produced by Booter Load, + * AHESASC, Booter Reload and ACR Unload; a FWSEC-only WPR2 carve (stage 3c) + * never runs those ucodes, so the unload refuses with its sequence/handoff + * error (observed SEC2 M0=0x29) before it touches WPR2 and WPR2 stays up. + * Setting the four handoff bits DONE and the Booter binary version to the + * Turing build version (0) restores the state Booter Load would have left so + * the unload can run; the unload itself clears both fields on completion. + * The WPR meta is not consumed by the unload path at all (it only resets the + * GSP engine, invalidates the sub-WPRs and locks WPR2 down). + */ +static void gsp_phys_booter_seed_sequence_state(void __iomem *bar0) +{ + u32 before, after; + + before = readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14); + after = before & ~(GSP_PHYS_SCRATCH14_BOOTER_VERSION_MASK | + GSP_PHYS_SCRATCH14_HANDOFF_MASK); + after |= GSP_PHYS_SCRATCH14_BOOTER_VERSION_TU10X << + GSP_PHYS_SCRATCH14_BOOTER_VERSION_SHIFT; + after |= GSP_PHYS_SCRATCH14_HANDOFF_MASK; + writel(after, bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14); + + pr_info("gsp-phys-fwsec: booter sequence seed: scratch14 0x%08x -> 0x%08x (booterVersion=%u want %u, handoffs 0x%x)\n", + before, readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14), + (readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14) & + GSP_PHYS_SCRATCH14_BOOTER_VERSION_MASK) >> + GSP_PHYS_SCRATCH14_BOOTER_VERSION_SHIFT, + GSP_PHYS_SCRATCH14_BOOTER_VERSION_TU10X, + (readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14) & + GSP_PHYS_SCRATCH14_HANDOFF_MASK) >> + GSP_PHYS_SCRATCH14_HANDOFF_SHIFT); +} + +/* + * Booter unload on SEC2: seed the sequence state, reset, load the unload image + * in direct mode and run it with mailbox0/1 = 0xff. Success leaves WPR2 down. */ static int gsp_phys_booter_unload(void __iomem *bar0) { const u8 *img = gsp_phys_booter_unload_image; - u32 m0, m1; + u32 m0, m1, scratch; int ret; pr_info("gsp-phys-fwsec: booter unload: resetting SEC2 falcon\n"); @@ -977,6 +1025,7 @@ static int gsp_phys_booter_unload(void __iomem *bar0) gsp_phys_falcon_disable_ctx_req(bar0, GSP_PHYS_SEC2_BASE, GSP_PHYS_SEC2_FBIF_BASE); + gsp_phys_booter_seed_sequence_state(bar0); gsp_phys_falcon_imem_copy(bar0, GSP_PHYS_SEC2_BASE, GSP_PHYS_BOOTER_UNLOAD_NS_CODE_OFF, img + GSP_PHYS_BOOTER_UNLOAD_NS_CODE_OFF, @@ -1008,11 +1057,17 @@ static int gsp_phys_booter_unload(void __iomem *bar0) if (ret) return ret; + scratch = readl(bar0 + GSP_PHYS_BSI_VPR_SECURE_SCRATCH_14); m0 = readl(bar0 + GSP_PHYS_SEC2_BASE + GSP_PHYS_FALCON_MAILBOX0); m1 = readl(bar0 + GSP_PHYS_SEC2_BASE + GSP_PHYS_FALCON_MAILBOX1); - pr_info("gsp-phys-fwsec: booter unload done: SEC2 M0=0x%08x M1=0x%08x WPR2_LO=0x%08x WPR2_HI=0x%08x\n", + pr_info("gsp-phys-fwsec: booter unload done: SEC2 M0=0x%08x M1=0x%08x WPR2_LO=0x%08x WPR2_HI=0x%08x scratch14=0x%08x\n", m0, m1, readl(bar0 + GSP_PHYS_WPR2_ADDR_LO), - readl(bar0 + GSP_PHYS_WPR2_ADDR_HI)); + readl(bar0 + GSP_PHYS_WPR2_ADDR_HI), scratch); + pr_info("gsp-phys-fwsec: booter unload scratch14: booterVersion=%u handoffs=0x%x (unload clears both)\n", + (scratch & GSP_PHYS_SCRATCH14_BOOTER_VERSION_MASK) >> + GSP_PHYS_SCRATCH14_BOOTER_VERSION_SHIFT, + (scratch & GSP_PHYS_SCRATCH14_HANDOFF_MASK) >> + GSP_PHYS_SCRATCH14_HANDOFF_SHIFT); if (m0 != 0) { pr_err("gsp-phys-fwsec: booter unload reported error 0x%x\n", -- cgit v1.2.3