u32 hdr_size;
};
+
/**
- * struct hsf_load_header - HS firmware load header
+ * struct gm200_flcn_bl_desc - DMEM bootloader descriptor
+ * @signature: 16B signature for secure code. 0s if no secure code
+ * @ctx_dma: DMA context to be used by BL while loading code/data
+ * @code_dma_base: 256B-aligned Physical FB Address where code is located
+ * (falcon's $xcbase register)
+ * @non_sec_code_off: offset from code_dma_base where the non-secure code is
+ * located. The offset must be multiple of 256 to help perf
+ * @non_sec_code_size: the size of the nonSecure code part.
+ * @sec_code_off: offset from code_dma_base where the secure code is
+ * located. The offset must be multiple of 256 to help perf
+ * @sec_code_size: offset from code_dma_base where the secure code is
+ * located. The offset must be multiple of 256 to help perf
+ * @code_entry_point: code entry point which will be invoked by BL after
+ * code is loaded.
+ * @data_dma_base: 256B aligned Physical FB Address where data is located.
+ * (falcon's $xdbase register)
+ * @data_size: size of data block. Should be multiple of 256B
+ *
+ * Structure used by the bootloader to load the rest of the code. This has
+ * to be filled by host and copied into DMEM at offset provided in the
+ * hsflcn_bl_desc.bl_desc_dmem_load_off.
*/
-struct hsf_load_header {
+struct gm200_flcn_bl_desc {
+ u32 reserved[4];
+ u32 signature[4];
+ u32 ctx_dma;
+ struct flcn_u64 code_dma_base;
u32 non_sec_code_off;
u32 non_sec_code_size;
- u32 data_dma_base;
+ u32 sec_code_off;
+ u32 sec_code_size;
+ u32 code_entry_point;
+ struct flcn_u64 data_dma_base;
u32 data_size;
- u32 num_apps;
- struct {
- u32 sec_code_off;
- u32 sec_code_size;
- } app[0];
};
+
/**
* Convenience function to duplicate a firmware file in memory and check that
* it has the required minimum size.
}
/**
- * gm200_secboot_populate_hsf_bl_desc() - populate BL descriptor for HS image
- */
-static void
-gm200_secboot_populate_hsf_bl_desc(void *acr_image,
- struct gm200_flcn_bl_desc *bl_desc)
-{
- struct fw_bin_header *hsbin_hdr = acr_image;
- struct hsf_fw_header *fw_hdr = acr_image + hsbin_hdr->header_offset;
- struct hsf_load_header *load_hdr = acr_image + fw_hdr->hdr_offset;
-
- /*
- * Descriptor for the bootloader that will load the ACR image into
- * IMEM/DMEM memory.
- */
- fw_hdr = acr_image + hsbin_hdr->header_offset;
- load_hdr = acr_image + fw_hdr->hdr_offset;
- memset(bl_desc, 0, sizeof(*bl_desc));
- bl_desc->ctx_dma = FALCON_DMAIDX_VIRT;
- bl_desc->non_sec_code_off = load_hdr->non_sec_code_off;
- bl_desc->non_sec_code_size = load_hdr->non_sec_code_size;
- bl_desc->sec_code_off = load_hdr->app[0].sec_code_off;
- bl_desc->sec_code_size = load_hdr->app[0].sec_code_size;
- bl_desc->code_entry_point = 0;
- /*
- * We need to set code_dma_base to the virtual address of the acr_blob,
- * and add this address to data_dma_base before writing it into DMEM
- */
- bl_desc->code_dma_base.lo = 0;
- bl_desc->data_dma_base.lo = load_hdr->data_dma_base;
- bl_desc->data_size = load_hdr->data_size;
-}
-
-/**
* struct hsflcn_acr_desc - data section of the HS firmware
*
* This header is to be copied at the beginning of DMEM by the HS bootloader.
static int
gm200_secboot_prepare_hs_blob(struct gm200_secboot *gsb, const char *fw,
struct nvkm_gpuobj **blob,
- struct gm200_flcn_bl_desc *bl_desc, bool patch)
+ struct hsf_load_header *load_header, bool patch)
{
struct nvkm_subdev *subdev = &gsb->base.subdev;
void *acr_image;
struct fw_bin_header *hsbin_hdr;
struct hsf_fw_header *fw_hdr;
- void *acr_data;
struct hsf_load_header *load_hdr;
- struct hsflcn_acr_desc *desc;
+ void *acr_data;
int ret;
acr_image = gm200_secboot_load_firmware(subdev, fw, 0);
if (IS_ERR(acr_image))
return PTR_ERR(acr_image);
+
hsbin_hdr = acr_image;
+ fw_hdr = acr_image + hsbin_hdr->header_offset;
+ load_hdr = acr_image + fw_hdr->hdr_offset;
+ acr_data = acr_image + hsbin_hdr->data_offset;
/* Patch signature */
gm200_secboot_hsf_patch_signature(gsb, acr_image);
- acr_data = acr_image + hsbin_hdr->data_offset;
-
/* Patch descriptor with WPR information? */
if (patch) {
- fw_hdr = acr_image + hsbin_hdr->header_offset;
- load_hdr = acr_image + fw_hdr->hdr_offset;
+ struct hsflcn_acr_desc *desc;
+
desc = acr_data + load_hdr->data_dma_base;
gm200_secboot_fixup_hs_desc(gsb, desc);
}
- /* Generate HS BL descriptor */
- gm200_secboot_populate_hsf_bl_desc(acr_image, bl_desc);
+ if (load_hdr->num_apps > GM200_ACR_MAX_APPS) {
+ nvkm_error(subdev, "more apps (%d) than supported (%d)!",
+ load_hdr->num_apps, GM200_ACR_MAX_APPS);
+ ret = -EINVAL;
+ goto cleanup;
+ }
+ memcpy(load_header, load_hdr, sizeof(*load_header) +
+ (sizeof(load_hdr->app[0]) * load_hdr->num_apps));
/* Create ACR blob and copy HS data to it */
ret = nvkm_gpuobj_new(subdev->device, ALIGN(hsbin_hdr->data_size, 256),
if (!gsb->acr_load_blob) {
ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_load",
&gsb->acr_load_blob,
- &gsb->acr_load_bl_desc, true);
+ &gsb->load_bl_header, true);
if (ret)
return ret;
}
if (!gsb->acr_unload_blob) {
ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_unload",
&gsb->acr_unload_blob,
- &gsb->acr_unload_bl_desc, false);
+ &gsb->unload_bl_header, false);
if (ret)
return ret;
}
* gm200_secboot_run_hs_blob() - run the given high-secure blob
*/
static int
-gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob,
- struct gm200_flcn_bl_desc *desc)
+gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob)
{
struct nvkm_subdev *subdev = &gsb->base.subdev;
struct fw_bin_header *hdr = gsb->hsbl_blob;
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;
+ const struct hsf_load_header *load_hdr;
u8 bl_desc[bl_desc_size];
struct nvkm_vma vma;
- u64 vma_addr;
int ret;
+ /* Find the bootloader descriptor for our blob and copy it */
+ if (blob == gsb->acr_load_blob) {
+ load_hdr = &gsb->load_bl_header;
+
+ } else if (blob == gsb->acr_unload_blob) {
+ load_hdr = &gsb->unload_bl_header;
+ } else {
+ nvkm_error(&gsb->base.subdev, "invalid secure boot blob!\n");
+ return -EINVAL;
+ }
+
ret = nvkm_falcon_get(falcon, subdev);
if (ret)
return ret;
return ret;
}
- /* Add the mapping address to the DMA bases */
- vma_addr = flcn64_to_u64(desc->code_dma_base) + vma.offset;
- desc->code_dma_base.lo = lower_32_bits(vma_addr);
- desc->code_dma_base.hi = upper_32_bits(vma_addr);
- vma_addr = flcn64_to_u64(desc->data_dma_base) + vma.offset;
- desc->data_dma_base.lo = lower_32_bits(vma_addr);
- desc->data_dma_base.hi = upper_32_bits(vma_addr);
-
- /* Fixup the BL header */
- gsb->func->fixup_bl_desc(desc, &bl_desc);
+ /* Generate the BL header */
+ gsb->func->generate_bl_desc(load_hdr, bl_desc, vma.offset);
/* Reset and set the falcon up */
ret = nvkm_falcon_reset(falcon);
if (ret)
- goto done;
+ goto end;
nvkm_falcon_bind_context(falcon, gsb->inst);
/* Load the HS bootloader into the falcon's IMEM/DMEM */
nvkm_falcon_start(falcon);
ret = nvkm_falcon_wait_for_halt(falcon, 100);
if (ret)
- goto done;
+ goto end;
/* 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;
+ goto end;
}
-done:
- /* Restore the original DMA addresses */
- vma_addr = flcn64_to_u64(desc->code_dma_base) - vma.offset;
- desc->code_dma_base.lo = lower_32_bits(vma_addr);
- desc->code_dma_base.hi = upper_32_bits(vma_addr);
- vma_addr = flcn64_to_u64(desc->data_dma_base) - vma.offset;
- desc->data_dma_base.lo = lower_32_bits(vma_addr);
- desc->data_dma_base.hi = upper_32_bits(vma_addr);
-
+end:
/* We don't need the ACR firmware anymore */
nvkm_gpuobj_unmap(&vma);
nvkm_falcon_put(falcon, subdev);
/* If WPR is set and we have an unload blob, run it to unlock WPR */
if (gsb->acr_unload_blob &&
gsb->falcon_state[NVKM_SECBOOT_FALCON_FECS] != NON_SECURE) {
- ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_unload_blob,
- &gsb->acr_unload_bl_desc);
+ ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_unload_blob);
if (ret)
return ret;
}
/* Reload all managed falcons */
- ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_load_blob,
- &gsb->acr_load_bl_desc);
+ ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_load_blob);
if (ret)
return ret;
/* Run the unload blob to unprotect the WPR region */
if (gsb->acr_unload_blob &&
gsb->falcon_state[NVKM_SECBOOT_FALCON_FECS] != NON_SECURE)
- ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_unload_blob,
- &gsb->acr_unload_bl_desc);
+ ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_unload_blob);
for (i = 0; i < NVKM_SECBOOT_FALCON_END; i++)
gsb->falcon_state[i] = NON_SECURE;
.boot_falcon = NVKM_SECBOOT_FALCON_PMU,
};
-/**
- * gm200_fixup_bl_desc - just copy the BL descriptor
- *
- * Use the GM200 descriptor format by default.
- */
static void
-gm200_secboot_fixup_bl_desc(const struct gm200_flcn_bl_desc *desc, void *ret)
+gm200_secboot_generate_bl_desc(const struct hsf_load_header *hdr,
+ void *_bl_desc, u64 offset)
{
- memcpy(ret, desc, sizeof(*desc));
+ struct gm200_flcn_bl_desc *bl_desc = _bl_desc;
+
+ memset(bl_desc, 0, sizeof(*bl_desc));
+ bl_desc->ctx_dma = FALCON_DMAIDX_VIRT;
+ bl_desc->non_sec_code_off = hdr->non_sec_code_off;
+ bl_desc->non_sec_code_size = hdr->non_sec_code_size;
+ bl_desc->sec_code_off = hdr->app[0].sec_code_off;
+ bl_desc->sec_code_size = hdr->app[0].sec_code_size;
+ bl_desc->code_entry_point = 0;
+
+ bl_desc->code_dma_base = u64_to_flcn64(offset);
+ bl_desc->data_dma_base = u64_to_flcn64(offset + hdr->data_dma_base);
+ bl_desc->data_size = hdr->data_size;
}
static const struct gm200_secboot_func
gm200_secboot_func = {
.bl_desc_size = sizeof(struct gm200_flcn_bl_desc),
- .fixup_bl_desc = gm200_secboot_fixup_bl_desc,
+ .generate_bl_desc = gm200_secboot_generate_bl_desc,
.prepare_blobs = gm200_secboot_prepare_blobs,
};
return 0;
}
-/**
- * gm20b_secboot_fixup_bl_desc - adapt BL descriptor to format used by GM20B FW
- *
- * There is only a slight format difference (DMA addresses being 32-bits and
- * 256B-aligned) to address.
- */
static void
-gm20b_secboot_fixup_bl_desc(const struct gm200_flcn_bl_desc *desc, void *ret)
+gm20b_secboot_generate_bl_desc(const struct hsf_load_header *load_hdr,
+ void *_bl_desc, u64 offset)
{
- struct gm20b_flcn_bl_desc *gdesc = ret;
- u64 addr;
-
- memcpy(gdesc->reserved, desc->reserved, sizeof(gdesc->reserved));
- memcpy(gdesc->signature, desc->signature, sizeof(gdesc->signature));
- gdesc->ctx_dma = desc->ctx_dma;
- addr = desc->code_dma_base.hi;
- addr <<= 32;
- addr |= desc->code_dma_base.lo;
- gdesc->code_dma_base = lower_32_bits(addr >> 8);
- gdesc->non_sec_code_off = desc->non_sec_code_off;
- gdesc->non_sec_code_size = desc->non_sec_code_size;
- gdesc->sec_code_off = desc->sec_code_off;
- gdesc->sec_code_size = desc->sec_code_size;
- gdesc->code_entry_point = desc->code_entry_point;
- addr = desc->data_dma_base.hi;
- addr <<= 32;
- addr |= desc->data_dma_base.lo;
- gdesc->data_dma_base = lower_32_bits(addr >> 8);
- gdesc->data_size = desc->data_size;
+ struct gm20b_flcn_bl_desc *bl_desc = _bl_desc;
+
+ memset(bl_desc, 0, sizeof(*bl_desc));
+ bl_desc->ctx_dma = FALCON_DMAIDX_VIRT;
+ bl_desc->non_sec_code_off = load_hdr->non_sec_code_off;
+ bl_desc->non_sec_code_size = load_hdr->non_sec_code_size;
+ bl_desc->sec_code_off = load_hdr->app[0].sec_code_off;
+ bl_desc->sec_code_size = load_hdr->app[0].sec_code_size;
+ bl_desc->code_entry_point = 0;
+ bl_desc->code_dma_base = offset >> 8;
+ bl_desc->data_dma_base = (offset + load_hdr->data_dma_base) >> 8;
+ bl_desc->data_size = load_hdr->data_size;
}
static const struct gm200_secboot_func
gm20b_secboot_func = {
.bl_desc_size = sizeof(struct gm20b_flcn_bl_desc),
- .fixup_bl_desc = gm20b_secboot_fixup_bl_desc,
+ .generate_bl_desc = gm20b_secboot_generate_bl_desc,
.prepare_blobs = gm20b_secboot_prepare_blobs,
};
u32 lo;
u32 hi;
};
+
static inline u64 flcn64_to_u64(const struct flcn_u64 f)
{
return ((u64)f.hi) << 32 | f.lo;
}
+static inline struct flcn_u64 u64_to_flcn64(u64 u)
+{
+ struct flcn_u64 ret;
+
+ ret.hi = upper_32_bits(u);
+ ret.lo = lower_32_bits(u);
+
+ return ret;
+}
+
+#define GM200_ACR_MAX_APPS 8
+
+struct hsf_load_header_app {
+ u32 sec_code_off;
+ u32 sec_code_size;
+};
+
/**
- * struct gm200_flcn_bl_desc - DMEM bootloader descriptor
- * @signature: 16B signature for secure code. 0s if no secure code
- * @ctx_dma: DMA context to be used by BL while loading code/data
- * @code_dma_base: 256B-aligned Physical FB Address where code is located
- * (falcon's $xcbase register)
- * @non_sec_code_off: offset from code_dma_base where the non-secure code is
- * located. The offset must be multiple of 256 to help perf
- * @non_sec_code_size: the size of the nonSecure code part.
- * @sec_code_off: offset from code_dma_base where the secure code is
- * located. The offset must be multiple of 256 to help perf
- * @sec_code_size: offset from code_dma_base where the secure code is
- * located. The offset must be multiple of 256 to help perf
- * @code_entry_point: code entry point which will be invoked by BL after
- * code is loaded.
- * @data_dma_base: 256B aligned Physical FB Address where data is located.
- * (falcon's $xdbase register)
- * @data_size: size of data block. Should be multiple of 256B
- *
- * Structure used by the bootloader to load the rest of the code. This has
- * to be filled by host and copied into DMEM at offset provided in the
- * hsflcn_bl_desc.bl_desc_dmem_load_off.
+ * struct hsf_load_header - HS firmware load header
*/
-struct gm200_flcn_bl_desc {
- u32 reserved[4];
- u32 signature[4];
- u32 ctx_dma;
- struct flcn_u64 code_dma_base;
+struct hsf_load_header {
u32 non_sec_code_off;
u32 non_sec_code_size;
- u32 sec_code_off;
- u32 sec_code_size;
- u32 code_entry_point;
- struct flcn_u64 data_dma_base;
+ u32 data_dma_base;
u32 data_size;
+ u32 num_apps;
+ struct hsf_load_header_app app[0];
};
/**
* on Tegra the HS FW copies the LS blob into the fixed WPR instead
*/
struct nvkm_gpuobj *acr_load_blob;
- struct gm200_flcn_bl_desc acr_load_bl_desc;
+ struct {
+ struct hsf_load_header load_bl_header;
+ struct hsf_load_header_app __load_apps[GM200_ACR_MAX_APPS];
+ };
/* HS FW - unlock WPR region (dGPU only) */
struct nvkm_gpuobj *acr_unload_blob;
- struct gm200_flcn_bl_desc acr_unload_bl_desc;
+ struct {
+ struct hsf_load_header unload_bl_header;
+ struct hsf_load_header_app __unload_apps[GM200_ACR_MAX_APPS];
+ };
/* HS bootloader */
void *hsbl_blob;
/**
* Contains functions we wish to abstract between GM200-like implementations
* @bl_desc_size: size of the BL descriptor used by this chip.
- * @fixup_bl_desc: hook that generates the proper BL descriptor format from
- * the generic GM200 format into a data array of size
- * bl_desc_size
+ * @generate_bl_desc: hook that generates the proper BL descriptor format from
+ * the hsf_load_header format into a preallocated array of
+ * size bl_desc_size
* @prepare_blobs: prepares the various blobs needed for secure booting
*/
struct gm200_secboot_func {
* callback is called on it
*/
u32 bl_desc_size;
- void (*fixup_bl_desc)(const struct gm200_flcn_bl_desc *, void *);
+ void (*generate_bl_desc)(const struct hsf_load_header *, void *, u64);
int (*prepare_blobs)(struct gm200_secboot *);
};