From 0055d732c38518bae3a0a58e8d4a6e427317ad8c Mon Sep 17 00:00:00 2001 From: Arthur Hanson Rasmusson Date: Thu, 1 Oct 2026 01:21:50 -0400 Subject: gsp-phys: fix the WPR2-up release hand-back and tighten FWSEC/VBIOS checks --- kernel/gsp_phys_fwsec.c | 30 ++++++++++++++++++++++-------- kernel/gsp_phys_vbios.c | 30 +++++++++++++++++++----------- 2 files changed, 41 insertions(+), 19 deletions(-) (limited to 'kernel') diff --git a/kernel/gsp_phys_fwsec.c b/kernel/gsp_phys_fwsec.c index 93a4208..a6f81e2 100644 --- a/kernel/gsp_phys_fwsec.c +++ b/kernel/gsp_phys_fwsec.c @@ -413,22 +413,29 @@ static int gsp_phys_falcon_wait_halt(void __iomem *bar0, u32 base, } } -/* Wait for GFW boot completion: falcon halted and progress 0xff. */ +/* Wait for GFW boot completion: falcon halted, PLM lowered and progress 0xff. */ static int gsp_phys_fwsec_wait_gfw_boot(void __iomem *bar0) { unsigned long deadline = jiffies + msecs_to_jiffies(GSP_PHYS_GFW_BOOT_TIMEOUT_MS); - u32 cpuctl = 0, progress = 0; + u32 cpuctl = 0, progress = 0, plm = 0; for (;;) { cpuctl = readl(bar0 + GSP_PHYS_GSP_BASE + GSP_PHYS_FALCON_CPUCTL); + plm = readl(bar0 + GSP_PHYS_GFW_PLM); progress = readl(bar0 + GSP_PHYS_GFW_BOOT) & GSP_PHYS_GFW_BOOT_PROGRESS_MASK; + /* + * FWSEC lowers its read-protection level before GFW posts + * progress; level0 must be readable for the progress to be + * meaningful. + */ if ((cpuctl & GSP_PHYS_CPUCTL_HALTED) && + (plm & GSP_PHYS_GFW_PLM_LEVEL0) && progress == GSP_PHYS_GFW_BOOT_COMPLETED) { - pr_info("gsp-phys-fwsec: GFW boot complete: CPUCTL=0x%08x (halted) progress=0xff\n", - cpuctl); + pr_info("gsp-phys-fwsec: GFW boot complete: CPUCTL=0x%08x (halted) PLM=0x%08x progress=0xff\n", + cpuctl, plm); return 0; } if (time_after_eq(jiffies, deadline)) @@ -436,8 +443,8 @@ static int gsp_phys_fwsec_wait_gfw_boot(void __iomem *bar0) msleep(1); } - pr_err("gsp-phys-fwsec: GFW boot not complete (CPUCTL=0x%08x progress=0x%x, timeout %ums); not resetting or kicking the falcon\n", - cpuctl, progress, GSP_PHYS_GFW_BOOT_TIMEOUT_MS); + pr_err("gsp-phys-fwsec: GFW boot not complete (CPUCTL=0x%08x PLM=0x%08x progress=0x%x, timeout %ums); not resetting or kicking the falcon\n", + cpuctl, plm, progress, GSP_PHYS_GFW_BOOT_TIMEOUT_MS); return -ETIMEDOUT; } @@ -876,6 +883,13 @@ int gsp_phys_fwsec_run(struct gsp_phys_boot *boot, struct pci_dev *pdev, return -EINVAL; } + if (boot->frts_size != ((u64)GSP_PHYS_FRTS_REGION_SIZE_4K << 12)) { + pr_err("gsp-phys-fwsec: FRTS region size mismatch: boot layout 0x%llx, FWSEC constant 0x%llx; refusing stage 3c\n", + boot->frts_size, + (u64)GSP_PHYS_FRTS_REGION_SIZE_4K << 12); + return -EINVAL; + } + pr_info("gsp-phys-fwsec: stage 3c FWSEC/FRTS on %s: frtsOffset=0x%llx frtsSize=0x%llx\n", pci_name(pdev), boot->frts_offset, boot->frts_size); @@ -991,10 +1005,10 @@ int gsp_phys_fwsec_release(struct gsp_phys_boot *boot, struct pci_dev *pdev, { int ret; - if (!fwsec.touched) - return 0; if (!pdev || !bar0) return -EIO; + if (!fwsec.touched && !gsp_phys_fwsec_wpr2_up(bar0)) + return 0; if (!gsp_phys_fwsec_wpr2_up(bar0)) { pr_info("gsp-phys-fwsec: release: WPR2 already down; freeing FWSEC staging and handing back\n"); diff --git a/kernel/gsp_phys_vbios.c b/kernel/gsp_phys_vbios.c index 4c35636..fa7849d 100644 --- a/kernel/gsp_phys_vbios.c +++ b/kernel/gsp_phys_vbios.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include @@ -210,6 +211,12 @@ static int gsp_phys_vbios_find_pci_header(void __iomem *bar0, u32 *pci_offset) return -EINVAL; } + if (image_offset & 0x3) { + pr_err("gsp-phys-vbios: IFR image offset 0x%x is not 4-byte aligned\n", + image_offset); + return -EINVAL; + } + if (image_offset > GSP_PHYS_VBIOS_MAX_SIZE - sizeof(u32)) { pr_err("gsp-phys-vbios: IFR image offset 0x%x out of range\n", image_offset); @@ -400,7 +407,7 @@ int gsp_phys_vbios_read(struct gsp_phys_vbios *img, struct pci_dev *pdev, void __iomem *bar0) { u32 pci_offset = 0, bios_size = 0, expansion_rom_offset = 0; - u32 rom_sig; + u32 rom_sig, rom_end; int ret; if (!img || !bar0) @@ -438,9 +445,10 @@ int gsp_phys_vbios_read(struct gsp_phys_vbios *img, struct pci_dev *pdev, pr_err("gsp-phys-vbios: expansion ROM walk failed: %d\n", ret); return ret; } - if (bios_size > GSP_PHYS_VBIOS_MAX_SIZE) { - pr_err("gsp-phys-vbios: expansion ROM size 0x%x exceeds the window\n", - bios_size); + if (check_add_overflow(pci_offset, bios_size, &rom_end) || + rom_end > GSP_PHYS_VBIOS_MAX_SIZE) { + pr_err("gsp-phys-vbios: expansion ROM span 0x%x+0x%x exceeds the window\n", + pci_offset, bios_size); return -EINVAL; } @@ -677,9 +685,7 @@ int gsp_phys_vbios_parse_fwsec(const struct gsp_phys_vbios *img, &data_ptr)) continue; } else { - if (!gsp_phys_img_read(img, token_offset + 4, 2, - &data_ptr)) - continue; + data_ptr = 0; } if (token_id == GSP_PHYS_BIT_TOKEN_BIOSDATA && @@ -703,10 +709,12 @@ int gsp_phys_vbios_parse_fwsec(const struct gsp_phys_vbios *img, continue; { - u32 table_offset = img->expansion_rom_offset + - table_ptr; - u32 table_version, table_hdr_size, entry_size; - u32 entry_count, j; + u32 table_offset, table_version, table_hdr_size; + u32 entry_size, entry_count, j; + + if (check_add_overflow(img->expansion_rom_offset, + table_ptr, &table_offset)) + continue; if (!gsp_phys_img_read(img, table_offset, 1, &table_version) || -- cgit v1.2.3