From d72fb36c45698b9f49a1159eb1a3eb46235d3586 Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Tue, 13 Dec 2016 17:11:27 +0900 Subject: [PATCH] drm/nouveau/secboot: use falcon library Use the falcon library functions in secure boot. This removes a lot of code and makes the secure boot flow easier to understand as no register is directly accessed. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/include/nvkm/subdev/secboot.h | 4 +- drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c | 146 ++------------------- .../gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c | 125 ++++++------------ drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h | 2 - 4 files changed, 51 insertions(+), 226 deletions(-) diff --git a/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h b/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h index 781586b..2a2f651 100644 --- a/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h +++ b/drivers/gpu/drm/nouveau/include/nvkm/subdev/secboot.h @@ -42,9 +42,7 @@ enum nvkm_secboot_falcon { struct nvkm_secboot { const struct nvkm_secboot_func *func; struct nvkm_subdev subdev; - - enum nvkm_devidx devidx; - u32 base; + struct nvkm_falcon *boot_falcon; }; #define nvkm_secboot(p) container_of((p), struct nvkm_secboot, subdev) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c index 6ee140e..a6e18ef 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/base.c @@ -23,6 +23,7 @@ #include #include +#include static const char * managed_falcons_names[] = { @@ -32,130 +33,6 @@ managed_falcons_names[] = { [NVKM_SECBOOT_FALCON_GPCCS] = "GPCCS", [NVKM_SECBOOT_FALCON_END] = "", }; - -/* - * Helper falcon functions - */ - -static int -falcon_clear_halt_interrupt(struct nvkm_device *device, u32 base) -{ - int ret; - - /* clear halt interrupt */ - nvkm_mask(device, base + 0x004, 0x10, 0x10); - /* wait until halt interrupt is cleared */ - ret = nvkm_wait_msec(device, 10, base + 0x008, 0x10, 0x0); - if (ret < 0) - return ret; - - return 0; -} - -static int -falcon_wait_idle(struct nvkm_device *device, u32 base) -{ - int ret; - - ret = nvkm_wait_msec(device, 10, base + 0x04c, 0xffff, 0x0); - if (ret < 0) - return ret; - - return 0; -} - -static int -nvkm_secboot_falcon_enable(struct nvkm_secboot *sb) -{ - struct nvkm_device *device = sb->subdev.device; - int ret; - - /* enable engine */ - nvkm_mc_enable(device, sb->devidx); - ret = nvkm_wait_msec(device, 10, sb->base + 0x10c, 0x6, 0x0); - if (ret < 0) { - nvkm_error(&sb->subdev, "Falcon mem scrubbing timeout\n"); - nvkm_mc_disable(device, sb->devidx); - return ret; - } - - ret = falcon_wait_idle(device, sb->base); - if (ret) - return ret; - - /* enable IRQs */ - nvkm_wr32(device, sb->base + 0x010, 0xff); - nvkm_mc_intr_mask(device, sb->devidx, true); - - return 0; -} - -static int -nvkm_secboot_falcon_disable(struct nvkm_secboot *sb) -{ - struct nvkm_device *device = sb->subdev.device; - - /* disable IRQs and wait for any previous code to complete */ - nvkm_mc_intr_mask(device, sb->devidx, false); - nvkm_wr32(device, sb->base + 0x014, 0xff); - - falcon_wait_idle(device, sb->base); - - /* disable engine */ - nvkm_mc_disable(device, sb->devidx); - - return 0; -} - -int -nvkm_secboot_falcon_reset(struct nvkm_secboot *sb) -{ - int ret; - - ret = nvkm_secboot_falcon_disable(sb); - if (ret) - return ret; - - ret = nvkm_secboot_falcon_enable(sb); - if (ret) - return ret; - - return 0; -} - -/** - * nvkm_secboot_falcon_run - run the falcon that will perform secure boot - * - * This function is to be called after all chip-specific preparations have - * been completed. It will start the falcon to perform secure boot, wait for - * it to halt, and report if an error occurred. - */ -int -nvkm_secboot_falcon_run(struct nvkm_secboot *sb) -{ - struct nvkm_device *device = sb->subdev.device; - int ret; - - /* Start falcon */ - nvkm_wr32(device, sb->base + 0x100, 0x2); - - /* Wait for falcon halt */ - ret = nvkm_wait_msec(device, 100, sb->base + 0x100, 0x10, 0x10); - if (ret < 0) - return ret; - - /* If mailbox register contains an error code, then ACR has failed */ - ret = nvkm_rd32(device, sb->base + 0x040); - if (ret) { - nvkm_error(&sb->subdev, "ACR boot failed, ret 0x%08x", ret); - falcon_clear_halt_interrupt(device, sb->base); - return -EINVAL; - } - - return 0; -} - - /** * nvkm_secboot_reset() - reset specified falcon */ @@ -205,6 +82,16 @@ nvkm_secboot_oneinit(struct nvkm_subdev *subdev) struct nvkm_secboot *sb = nvkm_secboot(subdev); int ret = 0; + switch (sb->func->boot_falcon) { + case NVKM_SECBOOT_FALCON_PMU: + sb->boot_falcon = subdev->device->pmu->falcon; + break; + default: + nvkm_error(subdev, "Unmanaged boot falcon %s!\n", + managed_falcons_names[sb->func->boot_falcon]); + return -EINVAL; + } + /* Call chip-specific init function */ if (sb->func->init) ret = sb->func->init(sb); @@ -258,17 +145,6 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func, nvkm_subdev_ctor(&nvkm_secboot, device, index, &sb->subdev); sb->func = func; - /* setup the performing falcon's base address and masks */ - switch (func->boot_falcon) { - case NVKM_SECBOOT_FALCON_PMU: - sb->devidx = NVKM_SUBDEV_PMU; - sb->base = 0x10a000; - break; - default: - nvkm_error(&sb->subdev, "invalid secure boot falcon\n"); - return -EINVAL; - }; - nvkm_debug(&sb->subdev, "securely managed falcons:\n"); for_each_set_bit(fid, &sb->func->managed_falcons, NVKM_SECBOOT_FALCON_END) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index ec48e4a..a2a33f1 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c @@ -86,14 +86,7 @@ #include #include #include - -enum { - FALCON_DMAIDX_UCODE = 0, - FALCON_DMAIDX_VIRT = 1, - FALCON_DMAIDX_PHYS_VID = 2, - FALCON_DMAIDX_PHYS_SYS_COH = 3, - FALCON_DMAIDX_PHYS_SYS_NCOH = 4, -}; +#include /** * struct fw_bin_header - header of firmware files @@ -887,7 +880,7 @@ gm200_secboot_hsf_patch_signature(struct gm200_secboot *gsb, void *acr_image) u32 sig_size; /* Falcon in debug or production mode? */ - if ((nvkm_rd32(sb->subdev.device, sb->base + 0xc08) >> 20) & 0x1) { + if (sb->boot_falcon->debug) { sig = acr_image + fw_hdr->sig_dbg_offset; sig_size = fw_hdr->sig_dbg_size; } else { @@ -1101,96 +1094,33 @@ gm200_secboot_blobs_ready(struct gm200_secboot *gsb) * gm200_secboot_load_hs_bl() - load HS bootloader into DMEM and IMEM */ static void -gm200_secboot_load_hs_bl(struct gm200_secboot *gsb, void *data, u32 data_size) +gm200_secboot_load_hs_bl(struct gm200_secboot *gsb, struct nvkm_falcon *falcon, + void *data, u32 data_size) { - struct nvkm_device *device = gsb->base.subdev.device; struct fw_bin_header *hdr = gsb->hsbl_blob; struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset; void *blob_data = gsb->hsbl_blob + hdr->data_offset; void *hsbl_code = blob_data + hsbl_desc->code_off; void *hsbl_data = blob_data + hsbl_desc->data_off; u32 code_size = ALIGN(hsbl_desc->code_size, 256); - const u32 base = gsb->base.base; - u32 blk; u32 tag; - int i; /* * Copy HS bootloader data */ - nvkm_wr32(device, base + 0x1c0, (0x00000000 | (0x1 << 24))); - for (i = 0; i < hsbl_desc->data_size / 4; i++) - nvkm_wr32(device, base + 0x1c4, ((u32 *)hsbl_data)[i]); + nvkm_falcon_load_dmem(falcon, hsbl_data, 0x0, hsbl_desc->data_size, 0); /* * Copy HS bootloader interface structure where the HS descriptor * expects it to be */ - nvkm_wr32(device, base + 0x1c0, - (hsbl_desc->dmem_load_off | (0x1 << 24))); - for (i = 0; i < data_size / 4; i++) - nvkm_wr32(device, base + 0x1c4, ((u32 *)data)[i]); + nvkm_falcon_load_dmem(falcon, data, hsbl_desc->dmem_load_off, data_size, + 0); /* Copy HS bootloader code to end of IMEM */ - blk = (nvkm_rd32(device, base + 0x108) & 0x1ff) - (code_size >> 8); tag = hsbl_desc->start_tag; - nvkm_wr32(device, base + 0x180, ((blk & 0xff) << 8) | (0x1 << 24)); - for (i = 0; i < code_size / 4; i++) { - /* write new tag every 256B */ - if ((i & 0x3f) == 0) { - nvkm_wr32(device, base + 0x188, tag & 0xffff); - tag++; - } - nvkm_wr32(device, base + 0x184, ((u32 *)hsbl_code)[i]); - } - nvkm_wr32(device, base + 0x188, 0); -} - -/** - * gm200_secboot_setup_falcon() - set up the secure falcon for secure boot - */ -static int -gm200_secboot_setup_falcon(struct gm200_secboot *gsb) -{ - struct nvkm_device *device = gsb->base.subdev.device; - struct fw_bin_header *hdr = gsb->hsbl_blob; - struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset; - /* virtual start address for boot vector */ - u32 virt_addr = hsbl_desc->start_tag << 8; - const u32 base = gsb->base.base; - const u32 reg_base = base + 0xe00; - u32 inst_loc; - int ret; - - ret = nvkm_secboot_falcon_reset(&gsb->base); - if (ret) - return ret; - - /* setup apertures - virtual */ - nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_UCODE), 0x4); - nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_VIRT), 0x0); - /* setup apertures - physical */ - nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_VID), 0x4); - nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_SYS_COH), - 0x4 | 0x1); - nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_SYS_NCOH), - 0x4 | 0x2); - - /* Set context */ - if (nvkm_memory_target(gsb->inst->memory) == NVKM_MEM_TARGET_VRAM) - inst_loc = 0x0; /* FB */ - else - inst_loc = 0x3; /* Non-coherent sysmem */ - - nvkm_mask(device, base + 0x048, 0x1, 0x1); - nvkm_wr32(device, base + 0x480, - ((gsb->inst->addr >> 12) & 0xfffffff) | - (inst_loc << 28) | (1 << 30)); - - /* Set boot vector to code's starting virtual address */ - nvkm_wr32(device, base + 0x104, virt_addr); - - return 0; + nvkm_falcon_load_imem(falcon, hsbl_code, falcon->code.limit - code_size, + code_size, tag, 0, false); } /** @@ -1200,16 +1130,27 @@ static int gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob, struct gm200_flcn_bl_desc *desc) { - struct nvkm_vma vma; - u64 vma_addr; + struct nvkm_subdev *subdev = &gsb->base.subdev; + struct fw_bin_header *hdr = gsb->hsbl_blob; + struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset; + struct nvkm_falcon *falcon = gsb->base.boot_falcon; + const u32 virt_addr = hsbl_desc->start_tag << 8; const u32 bl_desc_size = gsb->func->bl_desc_size; u8 bl_desc[bl_desc_size]; + struct nvkm_vma vma; + u64 vma_addr; int ret; + ret = nvkm_falcon_get(falcon, subdev); + if (ret) + return ret; + /* Map the HS firmware so the HS bootloader can see it */ ret = nvkm_gpuobj_map(blob, gsb->vm, NV_MEM_ACCESS_RW, &vma); - if (ret) + if (ret) { + nvkm_falcon_put(falcon, subdev); return ret; + } /* Add the mapping address to the DMA bases */ vma_addr = flcn64_to_u64(desc->code_dma_base) + vma.offset; @@ -1222,19 +1163,30 @@ gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob, /* Fixup the BL header */ gsb->func->fixup_bl_desc(desc, &bl_desc); - /* Reset the falcon and make it ready to run the HS bootloader */ - ret = gm200_secboot_setup_falcon(gsb); + /* Reset and set the falcon up */ + ret = nvkm_falcon_reset(falcon); if (ret) goto done; + nvkm_falcon_bind_context(falcon, gsb->inst); /* Load the HS bootloader into the falcon's IMEM/DMEM */ - gm200_secboot_load_hs_bl(gsb, &bl_desc, bl_desc_size); + gm200_secboot_load_hs_bl(gsb, falcon, &bl_desc, bl_desc_size); /* Start the HS bootloader */ - ret = nvkm_secboot_falcon_run(&gsb->base); + nvkm_falcon_set_start_addr(falcon, virt_addr); + nvkm_falcon_start(falcon); + ret = nvkm_falcon_wait_for_halt(falcon, 100); if (ret) goto done; + /* If mailbox register contains an error code, then ACR has failed */ + ret = nvkm_falcon_rd32(falcon, 0x040); + if (ret) { + nvkm_error(subdev, "ACR boot failed, ret 0x%08x", ret); + ret = -EINVAL; + goto done; + } + done: /* Restore the original DMA addresses */ vma_addr = flcn64_to_u64(desc->code_dma_base) - vma.offset; @@ -1246,6 +1198,7 @@ done: /* We don't need the ACR firmware anymore */ nvkm_gpuobj_unmap(&vma); + nvkm_falcon_put(falcon, subdev); return ret; } diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h index 2ad6d62..4b090d2 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/priv.h @@ -41,8 +41,6 @@ struct nvkm_secboot_func { int nvkm_secboot_ctor(const struct nvkm_secboot_func *, struct nvkm_device *, int index, struct nvkm_secboot *); -int nvkm_secboot_falcon_reset(struct nvkm_secboot *); -int nvkm_secboot_falcon_run(struct nvkm_secboot *); struct flcn_u64 { u32 lo; -- 2.7.4