From c5e1fef4875b75df48a7e9828243062799e444dc Mon Sep 17 00:00:00 2001 From: Alexandre Courbot Date: Thu, 26 Jan 2017 16:12:10 +0900 Subject: [PATCH] drm/nouveau/secboot: support standard NVIDIA HS binaries I had the brilliant idea to "improve" the binary format by removing a useless indirection in the HS binary files. In the end it just makes things more complicated than they ought to be as NVIDIA-provided files need to be adapted. Since the format used can be identified by the header, support both. Signed-off-by: Alexandre Courbot Signed-off-by: Ben Skeggs --- .../gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c | 60 +++++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c index 77ed8f0..b4e0add13 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/acr_r352.c @@ -599,19 +599,35 @@ cleanup: /** - * acr_r352_hsf_patch_signature() - patch HS blob with correct signature + * acr_r352_hsf_patch_signature() - patch HS blob with correct signature for + * specified falcon. */ static void -acr_r352_hsf_patch_signature(struct nvkm_secboot *sb, void *acr_image) +acr_r352_hsf_patch_signature(const struct nvkm_falcon *falcon, void *acr_image, + bool new_format) { struct fw_bin_header *hsbin_hdr = acr_image; struct hsf_fw_header *fw_hdr = acr_image + hsbin_hdr->header_offset; void *hs_data = acr_image + hsbin_hdr->data_offset; void *sig; u32 sig_size; + u32 patch_loc, patch_sig; + + /* + * I had the brilliant idea to "improve" the binary format by + * removing this useless indirection. However to make NVIDIA files + * directly compatible, let's support both format. + */ + if (new_format) { + patch_loc = fw_hdr->patch_loc; + patch_sig = fw_hdr->patch_sig; + } else { + patch_loc = *(u32 *)(acr_image + fw_hdr->patch_loc); + patch_sig = *(u32 *)(acr_image + fw_hdr->patch_sig); + } /* Falcon in debug or production mode? */ - if (sb->boot_falcon->debug) { + if (falcon->debug) { sig = acr_image + fw_hdr->sig_dbg_offset; sig_size = fw_hdr->sig_dbg_size; } else { @@ -620,7 +636,7 @@ acr_r352_hsf_patch_signature(struct nvkm_secboot *sb, void *acr_image) } /* Patch signature */ - memcpy(hs_data + fw_hdr->patch_loc, sig + fw_hdr->patch_sig, sig_size); + memcpy(hs_data + patch_loc, sig + patch_sig, sig_size); } void @@ -670,6 +686,37 @@ acr_r352_generate_hs_bl_desc(const struct hsf_load_header *hdr, void *_bl_desc, bl_desc->data_size = hdr->data_size; } +void * +acr_r352_load_hs_blob(struct nvkm_secboot *sb, const struct nvkm_falcon *falcon, + const char *fw) +{ + struct nvkm_subdev *subdev = &sb->subdev; + void *acr_image; + bool new_format; + + acr_image = nvkm_acr_load_firmware(subdev, fw, 0); + if (IS_ERR(acr_image)) + return acr_image; + + /* detect the format to define how signature should be patched */ + switch (((u32 *)acr_image)[0]) { + case 0x3b1d14f0: + new_format = true; + break; + case 0x000010de: + new_format = false; + break; + default: + nvkm_error(subdev, "unknown header for HS blob %s\n", fw); + return ERR_PTR(-EINVAL); + } + + /* Patch signature */ + acr_r352_hsf_patch_signature(falcon, acr_image, new_format); + + return acr_image; +} + /** * acr_r352_prepare_hs_blob - load and prepare a HS blob and BL descriptor * @@ -692,7 +739,7 @@ acr_r352_prepare_hs_blob(struct acr_r352 *acr, struct nvkm_secboot *sb, void *acr_data; int ret; - acr_image = nvkm_acr_load_firmware(subdev, fw, 0); + acr_image = acr_r352_load_hs_blob(sb, sb->boot_falcon, fw); if (IS_ERR(acr_image)) return PTR_ERR(acr_image); @@ -701,9 +748,6 @@ acr_r352_prepare_hs_blob(struct acr_r352 *acr, struct nvkm_secboot *sb, load_hdr = acr_image + fw_hdr->hdr_offset; acr_data = acr_image + hsbin_hdr->data_offset; - /* Patch signature */ - acr_r352_hsf_patch_signature(sb, acr_image); - /* Patch descriptor with WPR information? */ if (patch) { struct hsflcn_acr_desc *desc; -- 2.7.4