diff options
Diffstat (limited to 'kernel/gsp_phys_fwsec.c')
| -rw-r--r-- | kernel/gsp_phys_fwsec.c | 378 |
1 files changed, 344 insertions, 34 deletions
diff --git a/kernel/gsp_phys_fwsec.c b/kernel/gsp_phys_fwsec.c index a6f81e2..bf422df 100644 --- a/kernel/gsp_phys_fwsec.c +++ b/kernel/gsp_phys_fwsec.c @@ -27,6 +27,7 @@ #include <linux/slab.h> #include <linux/string.h> #include <linux/jiffies.h> +#include <linux/crc32.h> #include <asm/unaligned.h> #include "gsp_phys_fwsec.h" @@ -39,11 +40,22 @@ module_param_named(gsp_phys_fwsec, gsp_phys_fwsec_param, bool, 0644); MODULE_PARM_DESC(gsp_phys_fwsec, "Run the stage-3c FWSEC/FRTS verification on the claimed GPU after the boot layout succeeds (default 0; device writes)"); +static bool gsp_phys_fwsec_dryrun_param; +module_param_named(gsp_phys_fwsec_dryrun, gsp_phys_fwsec_dryrun_param, bool, + 0644); +MODULE_PARM_DESC(gsp_phys_fwsec_dryrun, + "Read-only validation of the stage-3c VBIOS/BIT/FWSEC parse and the staging/placement math on the claimed GPU after the boot layout succeeds (default 0; no device writes)"); + bool gsp_phys_fwsec_enabled(void) { return gsp_phys_fwsec_param; } +bool gsp_phys_fwsec_dryrun_enabled(void) +{ + return gsp_phys_fwsec_dryrun_param; +} + /* Falcon engine bases (BAR0 absolute). */ #define GSP_PHYS_GSP_BASE 0x00110000 #define GSP_PHYS_GSP_FBIF_BASE 0x00110600 @@ -79,6 +91,13 @@ bool gsp_phys_fwsec_enabled(void) #define GSP_PHYS_DMACTL_DMEM_SCRUBBING BIT(1) #define GSP_PHYS_DMACTL_IMEM_SCRUBBING BIT(2) #define GSP_PHYS_HWCFG_IMEM_SIZE 0x1ff +/* + * SEC2 falcon HWCFG DMEM capacity: bits 17:9 in 256-byte blocks (the v04 + * falcon reports IMEM at 8:0 and DMEM at 17:9). Used to check the Booter + * Unload DMEM data section against the engine's real capacity. + */ +#define GSP_PHYS_HWCFG_DMEM_SIZE 0x0003fe00 +#define GSP_PHYS_HWCFG_DMEM_SIZE_SHIFT 9 /* FBIF CTL / TRANSCFG fields. */ #define GSP_PHYS_FBIF_CTL_ALLOW_PHYS_NO_CTX BIT(7) @@ -460,10 +479,12 @@ static void gsp_phys_read_vbios_desc_init(struct gsp_phys_fwsec_read_vbios_desc * Patch the FWSEC interface in the staged DMEM copy for one command: walk * the application-interface header to the DMEM mapper entry, program * init_cmd and copy the command payload into the mapper's input buffer. + * When cmd_offset is non-NULL it receives the input-buffer offset (used by + * the read-only dry-run to dump the exact command bytes). */ static int gsp_phys_fwsec_patch_interface(struct gsp_phys_fwsec_ucode *u, u32 cmd, const void *cmd_buf, - u32 cmd_size) + u32 cmd_size, u32 *cmd_offset) { struct gsp_phys_fwsec_intf_header *hdr; struct gsp_phys_fwsec_dmem_mapper *mapper = NULL; @@ -522,6 +543,8 @@ static int gsp_phys_fwsec_patch_interface(struct gsp_phys_fwsec_ucode *u, } memcpy(data + mapper->cmd_in_buffer_offset, cmd_buf, cmd_size); + if (cmd_offset) + *cmd_offset = mapper->cmd_in_buffer_offset; pr_info("gsp-phys-fwsec: interface patched: mapper@0x%x init_cmd=0x%x cmd@0x%x (0x%x bytes), out buffer 0x%x/0x%x\n", (u32)((u8 *)mapper - data), cmd, mapper->cmd_in_buffer_offset, cmd_size, @@ -530,19 +553,16 @@ static int gsp_phys_fwsec_patch_interface(struct gsp_phys_fwsec_ucode *u, } /* - * Prepare and run one FWSEC command on the GSP falcon through the generic - * SEC2 boot-loader: patch the interface, reset the falcon, then load the - * boot-loader at the top of IMEM with the FWSEC code/data descriptors. + * Compute the 84-byte boot-loader DMEM descriptor for the staged FWSEC + * image. Pure host-memory math with the same bounds checks the real run + * applies; the read-only dry-run calls this to log the exact plan. */ -static int gsp_phys_fwsec_exec_with_loader(void __iomem *bar0, - struct gsp_phys_fwsec_ucode *u) +static int gsp_phys_fwsec_bl_desc_fill(const struct gsp_phys_fwsec_ucode *u, + struct gsp_phys_fwsec_bl_dmem_desc *bl) { - struct gsp_phys_fwsec_bl_dmem_desc bl; const struct gsp_phys_fwsec_desc *d = &u->desc; s64 secure_off64; - u32 secure_off, secure_size, block_count, bl_dst; - u32 transcfg, cpuctl; - int ret; + u32 secure_off, secure_size; secure_off64 = (s64)d->imem_sec_base - d->imem_virt_base + d->imem_phys_base; @@ -563,6 +583,38 @@ static int gsp_phys_fwsec_exec_with_loader(void __iomem *bar0, return -EINVAL; } + memset(bl, 0, sizeof(*bl)); + bl->ctx_dma = 4; /* physical system memory DMA context */ + bl->code_dma_lo = lower_32_bits(u->code_dma); + bl->code_dma_hi = upper_32_bits(u->code_dma); + bl->non_secure_code_off = d->imem_phys_base; + bl->non_secure_code_size = d->imem_load_size - d->imem_sec_size; + bl->secure_code_off = secure_off; + bl->secure_code_size = secure_size; + bl->code_entry_point = 0; + bl->data_dma_lo = lower_32_bits(u->data_dma); + bl->data_dma_hi = upper_32_bits(u->data_dma); + bl->data_size = d->dmem_load_size; + return 0; +} + +/* + * Prepare and run one FWSEC command on the GSP falcon through the generic + * SEC2 boot-loader: patch the interface, reset the falcon, then load the + * boot-loader at the top of IMEM with the FWSEC code/data descriptors. + */ +static int gsp_phys_fwsec_exec_with_loader(void __iomem *bar0, + struct gsp_phys_fwsec_ucode *u) +{ + struct gsp_phys_fwsec_bl_dmem_desc bl; + u32 block_count, bl_dst; + u32 transcfg, cpuctl; + int ret; + + ret = gsp_phys_fwsec_bl_desc_fill(u, &bl); + if (ret) + return ret; + gsp_phys_falcon_disable_ctx_req(bar0, GSP_PHYS_GSP_BASE, GSP_PHYS_GSP_FBIF_BASE); @@ -579,19 +631,6 @@ static int gsp_phys_fwsec_exec_with_loader(void __iomem *bar0, readl(bar0 + GSP_PHYS_GSP_FBIF_BASE + GSP_PHYS_FBIF_TRANSCFG(4))); - memset(&bl, 0, sizeof(bl)); - bl.ctx_dma = 4; /* physical system memory DMA context */ - bl.code_dma_lo = lower_32_bits(u->code_dma); - bl.code_dma_hi = upper_32_bits(u->code_dma); - bl.non_secure_code_off = d->imem_phys_base; - bl.non_secure_code_size = d->imem_load_size - d->imem_sec_size; - bl.secure_code_off = secure_off; - bl.secure_code_size = secure_size; - bl.code_entry_point = 0; - bl.data_dma_lo = lower_32_bits(u->data_dma); - bl.data_dma_hi = upper_32_bits(u->data_dma); - bl.data_size = d->dmem_load_size; - gsp_phys_falcon_dmem_copy(bar0, GSP_PHYS_GSP_BASE, 0, (const u8 *)&bl, sizeof(bl)); pr_info("gsp-phys-fwsec: BL descriptor at DMEM0: ctxDma=%u codeDma=0x%llx nsOff/Size=0x%x/0x%x secOff/Size=0x%x/0x%x dataDma=0x%llx dataSize=0x%x\n", @@ -636,7 +675,7 @@ static int gsp_phys_fwsec_exec_cmd(void __iomem *bar0, { int ret; - ret = gsp_phys_fwsec_patch_interface(u, cmd, cmd_buf, cmd_size); + ret = gsp_phys_fwsec_patch_interface(u, cmd, cmd_buf, cmd_size, NULL); if (ret) return ret; @@ -647,7 +686,8 @@ static int gsp_phys_fwsec_exec_cmd(void __iomem *bar0, return gsp_phys_fwsec_exec_with_loader(bar0, u); } -static void gsp_phys_fwsec_ucode_free(struct pci_dev *pdev); +static void gsp_phys_fwsec_ucode_free(struct pci_dev *pdev, + struct gsp_phys_fwsec_ucode *u); /* * Stage the FWSEC code/data images into device-visible coherent memory. The @@ -656,9 +696,9 @@ static void gsp_phys_fwsec_ucode_free(struct pci_dev *pdev); */ static int gsp_phys_fwsec_ucode_stage(struct pci_dev *pdev, const struct gsp_phys_vbios *vbios, - const struct gsp_phys_fwsec_desc *desc) + const struct gsp_phys_fwsec_desc *desc, + struct gsp_phys_fwsec_ucode *u) { - struct gsp_phys_fwsec_ucode *u = &fwsec.ucode; u32 image_start = desc->desc_offset + desc->desc_size; u32 code_alloc, data_alloc, secure_off, secure_size; s64 secure_off64; @@ -713,7 +753,7 @@ static int gsp_phys_fwsec_ucode_stage(struct pci_dev *pdev, if (!u->data_va) { pr_err("gsp-phys-fwsec: FWSEC data allocation (0x%x) failed\n", data_alloc); - gsp_phys_fwsec_ucode_free(pdev); + gsp_phys_fwsec_ucode_free(pdev, u); return -ENOMEM; } @@ -732,10 +772,9 @@ static int gsp_phys_fwsec_ucode_stage(struct pci_dev *pdev, return 0; } -static void gsp_phys_fwsec_ucode_free(struct pci_dev *pdev) +static void gsp_phys_fwsec_ucode_free(struct pci_dev *pdev, + struct gsp_phys_fwsec_ucode *u) { - struct gsp_phys_fwsec_ucode *u = &fwsec.ucode; - if (u->code_va) dma_free_coherent(&pdev->dev, u->code_size, u->code_va, u->code_dma); @@ -938,7 +977,7 @@ int gsp_phys_fwsec_run(struct gsp_phys_boot *boot, struct pci_dev *pdev, return ret; } - ret = gsp_phys_fwsec_ucode_stage(pdev, &vbios, &desc); + ret = gsp_phys_fwsec_ucode_stage(pdev, &vbios, &desc, &fwsec.ucode); gsp_phys_vbios_free(&vbios); if (ret) return ret; @@ -1000,6 +1039,277 @@ recover: return ret; } +/* + * Read-only dry-run of stage 3c: locate and parse the VBIOS FWSEC image, + * read the ucode head/tail and CRC, read the capacity registers the staging + * math depends on, stage into host DMA memory and compute the complete + * placement plan - without a single BAR0 write, falcon reset or DMA kick. + * readl() of state registers is the only device interaction. Any failed + * read-only precondition is logged under the dry-run prefix and returned so + * the cycle is visibly red. + */ +int gsp_phys_fwsec_dryrun_run(struct gsp_phys_boot *boot, struct pci_dev *pdev, + void __iomem *bar0) +{ + struct gsp_phys_vbios vbios = { }; + struct gsp_phys_fwsec_desc desc; + struct gsp_phys_fwsec_frts_cmd frts; + struct gsp_phys_fwsec_ucode u = { }; + struct gsp_phys_fwsec_bl_dmem_desc bl; + u32 wpr2_hi, wpr2_lo, hwcfg2, fuse; + u32 gsp_hwcfg, sec2_hwcfg, imem_blocks, bl_blocks, dmem_blocks; + u32 cmd_off = 0, image_start, data_start; + const u8 *code; + u32 code_crc, data_crc; + bool use_debug_app, is_fallback, uload_ok; + int ret; + + if (!boot || !pdev || !bar0) + return -EINVAL; + + if (gsp_phys_fwsec_param) { + pr_err("gsp-phys-fwsec-dryrun: gsp_phys_fwsec=1 is also set; the device-writing FWSEC run and this read-only dry-run are mutually exclusive - refusing both\n"); + return -EINVAL; + } + if (!boot->initialized) { + pr_err("gsp-phys-fwsec-dryrun: boot layout not initialised; refusing dry-run\n"); + return -EINVAL; + } + if (boot->frts_size != ((u64)GSP_PHYS_FRTS_REGION_SIZE_4K << 12)) { + pr_err("gsp-phys-fwsec-dryrun: FRTS region size mismatch: boot layout 0x%llx, FWSEC constant 0x%llx; refusing dry-run\n", + boot->frts_size, + (u64)GSP_PHYS_FRTS_REGION_SIZE_4K << 12); + return -EINVAL; + } + + pr_info("gsp-phys-fwsec-dryrun: READ-ONLY stage 3c validation on %s: frtsOffset=0x%llx frtsSize=0x%llx (no BAR0 writes, no falcon reset, no DMA kick)\n", + pci_name(pdev), boot->frts_offset, boot->frts_size); + + /* Read-only preconditions, each pass/fail. */ + wpr2_lo = gsp_phys_fwsec_wpr2_lo_val(bar0); + wpr2_hi = gsp_phys_fwsec_wpr2_hi_val(bar0); + pr_info("gsp-phys-fwsec-dryrun: precondition WPR2 down: LO raw=0x%08x VAL=0x%x HI raw=0x%08x VAL=0x%x -> %s\n", + readl(bar0 + GSP_PHYS_WPR2_ADDR_LO), wpr2_lo, + readl(bar0 + GSP_PHYS_WPR2_ADDR_HI), wpr2_hi, + wpr2_hi == 0 ? "PASS" : "FAIL"); + if (wpr2_hi != 0) { + pr_err("gsp-phys-fwsec-dryrun: WPR2 already up; a real stage 3c would refuse, dry-run stops here\n"); + return -EBUSY; + } + + ret = gsp_phys_fwsec_wait_gfw_boot(bar0); + pr_info("gsp-phys-fwsec-dryrun: precondition GFW boot complete (halted + PLM level0 + progress 0xff) -> %s\n", + ret ? "FAIL" : "PASS"); + if (ret) + return ret; + + hwcfg2 = readl(bar0 + GSP_PHYS_GSP_BASE + GSP_PHYS_FALCON_HWCFG2); + pr_info("gsp-phys-fwsec-dryrun: precondition RISC-V core enabled (HWCFG2[10]): HWCFG2=0x%08x -> %s\n", + hwcfg2, (hwcfg2 & BIT(10)) ? "PASS" : "FAIL"); + if (!(hwcfg2 & BIT(10))) + return -ENODEV; + + pr_info("gsp-phys-fwsec-dryrun: precondition falcon state (read-only): GSP_CPUCTL=0x%08x SEC2_CPUCTL=0x%08x\n", + readl(bar0 + GSP_PHYS_GSP_BASE + GSP_PHYS_FALCON_CPUCTL), + readl(bar0 + GSP_PHYS_SEC2_BASE + GSP_PHYS_FALCON_CPUCTL)); + + /* VBIOS PROM read + IFR/expansion-ROM/BIT/FWSEC parse (real code). */ + ret = gsp_phys_vbios_read(&vbios, pdev, bar0); + if (ret) + return ret; + + fuse = readl(bar0 + GSP_PHYS_FUSE_SECURE_GSP_DEBUG_DIS); + use_debug_app = !(fuse & GSP_PHYS_FUSE_SECURE_GSP_DEBUG_DIS_FIELD); + + ret = gsp_phys_vbios_parse_fwsec(&vbios, use_debug_app, &desc); + if (ret) { + pr_err("gsp-phys-fwsec-dryrun: FWSEC parse from VBIOS failed: %d\n", + ret); + gsp_phys_vbios_free(&vbios); + return ret; + } + + is_fallback = desc.app_id == GSP_PHYS_FWSEC_APPID_FIRMWARE_SEC_LIC; + image_start = desc.desc_offset + desc.desc_size; + data_start = image_start + desc.dmem_offset; + + pr_info("gsp-phys-fwsec-dryrun: VBIOS summary: ROM size=0x%zx pciOffset=0x%x expansionRomOffset=0x%x IFRversion=%u VBIOSversion=0x%llx\n", + vbios.size, vbios.pci_offset, vbios.expansion_rom_offset, + vbios.ifr_version, vbios.version); + pr_info("gsp-phys-fwsec-dryrun: BIT summary: header@0x%x tokenType=%u-byte (%s) tokens=%u; selected entry appId=0x%x targetId=%u (%s, fuse SECURE_GSP_DEBUG_DIS=0x%08x)\n", + vbios.bit_addr, vbios.bit_token_size, + vbios.bit_token_size >= GSP_PHYS_BIT_TOKEN_SIZE_8 ? + "2b1w1d u32 DataPtr" : "2b2w u16 DataPtr", + vbios.bit_token_entries, desc.app_id, desc.target_id, + is_fallback ? "fallback FIRMWARE_SEC_LIC 0x05" : + (use_debug_app ? "debug 0x45" : "production 0x85"), fuse); + pr_info("gsp-phys-fwsec-dryrun: FWSEC descriptor type=V%u size=%u at 0x%x; ucode code at 0x%x size=0x%x, data at 0x%x size=0x%x, interfaceOff=0x%x entry=0x%x\n", + desc.desc_version, desc.desc_size, desc.desc_offset, + image_start, desc.imem_load_size, data_start, + desc.dmem_load_size, desc.interface_offset, + desc.virtual_entry); + + /* First/last 4 words + CRC over the extracted image (bounds-checked). */ + if (image_start > vbios.size || + desc.imem_load_size > vbios.size - image_start || + desc.imem_load_size < 16 || + data_start > vbios.size || + desc.dmem_load_size > vbios.size - data_start) { + pr_err("gsp-phys-fwsec-dryrun: FWSEC image outside the ROM copy (image=0x%x imem=0x%x data=0x%x dmem=0x%x rom=0x%zx); refusing\n", + image_start, desc.imem_load_size, data_start, + desc.dmem_load_size, vbios.size); + gsp_phys_vbios_free(&vbios); + return -EINVAL; + } + + code = vbios.data + image_start; + code_crc = crc32_le(0, code, desc.imem_load_size); + data_crc = crc32_le(0, vbios.data + data_start, desc.dmem_load_size); + pr_info("gsp-phys-fwsec-dryrun: ucode first 4 words: %08x %08x %08x %08x\n", + get_unaligned_le32(code), get_unaligned_le32(code + 4), + get_unaligned_le32(code + 8), get_unaligned_le32(code + 12)); + pr_info("gsp-phys-fwsec-dryrun: ucode last 4 words: %08x %08x %08x %08x\n", + get_unaligned_le32(code + desc.imem_load_size - 16), + get_unaligned_le32(code + desc.imem_load_size - 12), + get_unaligned_le32(code + desc.imem_load_size - 8), + get_unaligned_le32(code + desc.imem_load_size - 4)); + pr_info("gsp-phys-fwsec-dryrun: CRC32 code(0x%x bytes)=0x%08x data(0x%x bytes)=0x%08x\n", + desc.imem_load_size, code_crc, desc.dmem_load_size, data_crc); + + /* Capacity registers the staging/placement math depends on. */ + gsp_hwcfg = readl(bar0 + GSP_PHYS_GSP_BASE + GSP_PHYS_FALCON_HWCFG); + imem_blocks = gsp_hwcfg & GSP_PHYS_HWCFG_IMEM_SIZE; + bl_blocks = imem_blocks >= GSP_PHYS_SEC2_BL_CODE_SIZE / 256 ? + imem_blocks - GSP_PHYS_SEC2_BL_CODE_SIZE / 256 : 0; + pr_info("gsp-phys-fwsec-dryrun: GSP falcon HWCFG=0x%08x IMEM_SIZE=%u blocks (256 B) -> generic BL at block %u (IMEM addr 0x%x), tag 0x%x, fits=%s\n", + gsp_hwcfg, imem_blocks, bl_blocks, bl_blocks << 8, + GSP_PHYS_SEC2_BL_START_TAG, + imem_blocks * 256 >= GSP_PHYS_SEC2_BL_CODE_SIZE ? "yes" : + "no"); + if (imem_blocks * 256 < GSP_PHYS_SEC2_BL_CODE_SIZE) { + pr_err("gsp-phys-fwsec-dryrun: GSP IMEM too small for the generic boot-loader (%u blocks); refusing\n", + imem_blocks); + gsp_phys_vbios_free(&vbios); + return -EINVAL; + } + + sec2_hwcfg = readl(bar0 + GSP_PHYS_SEC2_BASE + GSP_PHYS_FALCON_HWCFG); + dmem_blocks = (sec2_hwcfg & GSP_PHYS_HWCFG_DMEM_SIZE) >> + GSP_PHYS_HWCFG_DMEM_SIZE_SHIFT; + pr_info("gsp-phys-fwsec-dryrun: SEC2 falcon HWCFG=0x%08x IMEM_SIZE=%u blocks DMEM_SIZE=%u blocks (0x%x bytes) vs booter-unload DMEM data 0x%x -> %s\n", + sec2_hwcfg, sec2_hwcfg & GSP_PHYS_HWCFG_IMEM_SIZE, + dmem_blocks, dmem_blocks * 256, + GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE, + dmem_blocks * 256 >= GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE ? + "PASS" : "FAIL"); + if (dmem_blocks == 0) { + pr_err("gsp-phys-fwsec-dryrun: SEC2 HWCFG DMEM_SIZE (bits 17:9) decodes to zero - the capacity is not readable/reporting on this part; refusing\n"); + gsp_phys_vbios_free(&vbios); + return -ENODEV; + } + if (dmem_blocks * 256 < GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE) { + pr_err("gsp-phys-fwsec-dryrun: Booter-Unload DMEM data 0x%x does not fit SEC2 DMEM 0x%x; the unload split would not load; refusing\n", + GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE, dmem_blocks * 256); + gsp_phys_vbios_free(&vbios); + return -ENOSPC; + } + + /* Stage into host DMA memory (no device access) and patch the cmd. */ + ret = gsp_phys_fwsec_ucode_stage(pdev, &vbios, &desc, &u); + gsp_phys_vbios_free(&vbios); + if (ret) + return ret; + + gsp_phys_read_vbios_desc_init(&frts.read_vbios_desc); + frts.frts_region_desc.version = 1; + frts.frts_region_desc.size = sizeof(frts.frts_region_desc); + frts.frts_region_desc.frts_region_offset4k = + (u32)(boot->frts_offset >> 12); + frts.frts_region_desc.frts_region_size = GSP_PHYS_FRTS_REGION_SIZE_4K; + frts.frts_region_desc.frts_region_media_type = + GSP_PHYS_FRTS_REGION_MEDIA_FB; + + ret = gsp_phys_fwsec_patch_interface(&u, GSP_PHYS_FWSEC_CMD_FRTS, &frts, + sizeof(frts), &cmd_off); + if (ret) + goto out_free; + + ret = gsp_phys_fwsec_bl_desc_fill(&u, &bl); + if (ret) + goto out_free; + + pr_info("gsp-phys-fwsec-dryrun: staging plan (host DMA only): code alloc=0x%zx dma=0x%llx (imemLoad=0x%x secOff/Size=0x%x/0x%x), data alloc=0x%zx dma=0x%llx (dmemLoad=0x%x)\n", + u.code_size, (u64)u.code_dma, u.desc.imem_load_size, + bl.secure_code_off, bl.secure_code_size, u.data_size, + (u64)u.data_dma, u.desc.dmem_load_size); + pr_info("gsp-phys-fwsec-dryrun: 84-byte BL descriptor: reserved[4]=0 signature[4]=0 ctxDma=%u codeDma=0x%llx nsOff/Size=0x%x/0x%x secOff/Size=0x%x/0x%x entry=0x%x dataDma=0x%llx dataSize=0x%x argc=%u argv=%u\n", + bl.ctx_dma, + ((u64)bl.code_dma_hi << 32) | bl.code_dma_lo, + bl.non_secure_code_off, bl.non_secure_code_size, + bl.secure_code_off, bl.secure_code_size, + bl.code_entry_point, + ((u64)bl.data_dma_hi << 32) | bl.data_dma_lo, + bl.data_size, bl.argc, bl.argv); + pr_info("gsp-phys-fwsec-dryrun: generic-BL placement from real HWCFG: block %u IMEM addr 0x%x BOOTVEC=0x%x code 0x%x bytes tag 0x%x\n", + bl_blocks, bl_blocks << 8, GSP_PHYS_SEC2_BL_START_TAG << 8, + GSP_PHYS_SEC2_BL_CODE_SIZE, GSP_PHYS_SEC2_BL_START_TAG); + pr_info("gsp-phys-fwsec-dryrun: FRTS region: frtsOffset>>12=0x%x size4K=0x%x media=FB(%u); readVbiosDesc{version=%u size=%u flags=%u}\n", + frts.frts_region_desc.frts_region_offset4k, + frts.frts_region_desc.frts_region_size, + frts.frts_region_desc.frts_region_media_type, + frts.read_vbios_desc.version, frts.read_vbios_desc.size, + frts.read_vbios_desc.flags); + pr_info("gsp-phys-fwsec-dryrun: 44-byte interface-patch block at DMEM 0x%x: %*ph\n", + cmd_off, (int)sizeof(frts), (const u8 *)u.data_va + cmd_off); + pr_info("gsp-phys-fwsec-dryrun: expected WPR2 after a real run: HI VAL nonzero; LO VAL=0x%x raw encoding=0x%08x\n", + (u32)(boot->frts_offset >> 12), + (u32)((boot->frts_offset >> 12) << 4)); + + /* Bindata header/size/tag verification (compile-time vs image). */ + pr_info("gsp-phys-fwsec-dryrun: generic SEC2 BL bindata: image=0x%zx code=0x%x at 0 data=0x100 at 0x200 blStartTag=0x%x blDmemDescLoadOff=0 -> %s\n", + sizeof(gsp_phys_sec2_bl_image), GSP_PHYS_SEC2_BL_CODE_SIZE, + GSP_PHYS_SEC2_BL_START_TAG, + sizeof(gsp_phys_sec2_bl_image) == 0x300 && + GSP_PHYS_SEC2_BL_CODE_SIZE + 0x100 == + sizeof(gsp_phys_sec2_bl_image) ? "PASS" : "FAIL"); + + uload_ok = sizeof(gsp_phys_booter_unload_image) == + GSP_PHYS_BOOTER_UNLOAD_IMAGE_SIZE && + GSP_PHYS_BOOTER_UNLOAD_NS_CODE_OFF == 0 && + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_OFF == + GSP_PHYS_BOOTER_UNLOAD_NS_CODE_OFF + + GSP_PHYS_BOOTER_UNLOAD_NS_CODE_SIZE && + GSP_PHYS_BOOTER_UNLOAD_DATA_OFF == + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_OFF + + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_SIZE && + GSP_PHYS_BOOTER_UNLOAD_DATA_OFF + + GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE == + GSP_PHYS_BOOTER_UNLOAD_IMAGE_SIZE; + pr_info("gsp-phys-fwsec-dryrun: Booter-Unload bindata: image=0x%zx nsCode=0x%x@0x%x secCode=0x%x@0x%x codeEnd=0x%x data=0x%x@0x%x dataEnd=0x%x mailboxTag=0x%x/0x%x sig@0x4e00=%08x -> %s\n", + sizeof(gsp_phys_booter_unload_image), + GSP_PHYS_BOOTER_UNLOAD_NS_CODE_SIZE, + GSP_PHYS_BOOTER_UNLOAD_NS_CODE_OFF, + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_SIZE, + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_OFF, + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_OFF + + GSP_PHYS_BOOTER_UNLOAD_SEC_CODE_SIZE, + GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE, + GSP_PHYS_BOOTER_UNLOAD_DATA_OFF, + GSP_PHYS_BOOTER_UNLOAD_DATA_OFF + + GSP_PHYS_BOOTER_UNLOAD_DATA_SIZE, + GSP_PHYS_BOOTER_UNLOAD_MBOX, GSP_PHYS_BOOTER_UNLOAD_MBOX, + get_unaligned_le32(gsp_phys_booter_unload_image + 0x4e00), + uload_ok ? "PASS" : "FAIL"); + + gsp_phys_fwsec_ucode_free(pdev, &u); + pr_info("gsp-phys-fwsec-dryrun: stage 3c dry-run complete: VBIOS/BIT/FWSEC parse, capacity registers, staging and placement plan validated; no device writes (WPR2 stays down, no falcon reset, no DMA kick)\n"); + return 0; + +out_free: + gsp_phys_fwsec_ucode_free(pdev, &u); + return ret; +} + int gsp_phys_fwsec_release(struct gsp_phys_boot *boot, struct pci_dev *pdev, void __iomem *bar0) { @@ -1012,14 +1322,14 @@ int gsp_phys_fwsec_release(struct gsp_phys_boot *boot, struct pci_dev *pdev, if (!gsp_phys_fwsec_wpr2_up(bar0)) { pr_info("gsp-phys-fwsec: release: WPR2 already down; freeing FWSEC staging and handing back\n"); - gsp_phys_fwsec_ucode_free(pdev); + gsp_phys_fwsec_ucode_free(pdev, &fwsec.ucode); fwsec.touched = false; return 0; } pr_info("gsp-phys-fwsec: release: WPR2 is up; tearing down before hand-back\n"); ret = gsp_phys_fwsec_teardown(bar0); - gsp_phys_fwsec_ucode_free(pdev); + gsp_phys_fwsec_ucode_free(pdev, &fwsec.ucode); if (ret || gsp_phys_fwsec_wpr2_up(bar0)) { pr_err("gsp-phys-fwsec: release: WPR2 still up after teardown (HI=0x%08x); refusing the hand-back to the distribution driver\n", |
