summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2017-01-26 16:12:10 +0900
committerBen Skeggs <bskeggs@redhat.com>2017-03-07 17:04:06 +1000
commit7716a5ceaff2bde17155960b2d4fb18d4e1cc232 (patch)
treee53cc9f3d0aaec35c389c8449adf75304249ad31
parentb78b9732bf9549de6efd755a83e793418ab77171 (diff)
downloadnouveau-7716a5ceaff2bde17155960b2d4fb18d4e1cc232.tar.gz
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 <acourbot@nvidia.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
-rw-r--r--drm/nouveau/nvkm/subdev/secboot/acr_r352.c60
1 files changed, 52 insertions, 8 deletions
diff --git a/drm/nouveau/nvkm/subdev/secboot/acr_r352.c b/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
index 77ed8f007..b4e0add13 100644
--- a/drm/nouveau/nvkm/subdev/secboot/acr_r352.c
+++ b/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;