drm/i915/huc: Add fetch support for gsc-loaded HuC binary
On newer platforms (starting DG2 G10 B-step and G11 A-step), ownership of HuC loading has been moved from the GuC to the GSC. As part of the change, the header format of the HuC binary has been updated and does not match the GuC anymore. The GSC will perform all the required checks on the binary size, so we only need to check that the version matches. Note that since we still haven't added any gsc-loaded FWs, the loaded_via_gsc variable will always be kept to its initialization value of zero. v2: Add a note about loaded_via_gsc being zero (Alan) Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com> Reviewed-by: Alan Previn <alan.previn.teres.alexis@intel.com> Link: https://patchwork.freedesktop.org/patch/msgid/20220504204816.2082588-3-daniele.ceraolospurio@intel.com
This commit is contained in:
parent
315241d2d9
commit
a7b516bd98
3 changed files with 92 additions and 58 deletions
|
@ -301,6 +301,82 @@ static void __force_fw_fetch_failures(struct intel_uc_fw *uc_fw, int e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int check_gsc_manifest(const struct firmware *fw,
|
||||||
|
struct intel_uc_fw *uc_fw)
|
||||||
|
{
|
||||||
|
u32 *dw = (u32 *)fw->data;
|
||||||
|
u32 version = dw[HUC_GSC_VERSION_DW];
|
||||||
|
|
||||||
|
uc_fw->major_ver_found = FIELD_GET(HUC_GSC_MAJOR_VER_MASK, version);
|
||||||
|
uc_fw->minor_ver_found = FIELD_GET(HUC_GSC_MINOR_VER_MASK, version);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_ccs_header(struct drm_i915_private *i915,
|
||||||
|
const struct firmware *fw,
|
||||||
|
struct intel_uc_fw *uc_fw)
|
||||||
|
{
|
||||||
|
struct uc_css_header *css;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
/* Check the size of the blob before examining buffer contents */
|
||||||
|
if (unlikely(fw->size < sizeof(struct uc_css_header))) {
|
||||||
|
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
|
||||||
|
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
||||||
|
fw->size, sizeof(struct uc_css_header));
|
||||||
|
return -ENODATA;
|
||||||
|
}
|
||||||
|
|
||||||
|
css = (struct uc_css_header *)fw->data;
|
||||||
|
|
||||||
|
/* Check integrity of size values inside CSS header */
|
||||||
|
size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
|
||||||
|
css->exponent_size_dw) * sizeof(u32);
|
||||||
|
if (unlikely(size != sizeof(struct uc_css_header))) {
|
||||||
|
drm_warn(&i915->drm,
|
||||||
|
"%s firmware %s: unexpected header size: %zu != %zu\n",
|
||||||
|
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
||||||
|
fw->size, sizeof(struct uc_css_header));
|
||||||
|
return -EPROTO;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* uCode size must calculated from other sizes */
|
||||||
|
uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
|
||||||
|
|
||||||
|
/* now RSA */
|
||||||
|
uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
|
||||||
|
|
||||||
|
/* At least, it should have header, uCode and RSA. Size of all three. */
|
||||||
|
size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
|
||||||
|
if (unlikely(fw->size < size)) {
|
||||||
|
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
|
||||||
|
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
||||||
|
fw->size, size);
|
||||||
|
return -ENOEXEC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sanity check whether this fw is not larger than whole WOPCM memory */
|
||||||
|
size = __intel_uc_fw_get_upload_size(uc_fw);
|
||||||
|
if (unlikely(size >= i915->wopcm.size)) {
|
||||||
|
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",
|
||||||
|
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
||||||
|
size, (size_t)i915->wopcm.size);
|
||||||
|
return -E2BIG;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get version numbers from the CSS header */
|
||||||
|
uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
|
||||||
|
css->sw_version);
|
||||||
|
uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
|
||||||
|
css->sw_version);
|
||||||
|
|
||||||
|
if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
|
||||||
|
uc_fw->private_data_size = css->private_data_size;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* intel_uc_fw_fetch - fetch uC firmware
|
* intel_uc_fw_fetch - fetch uC firmware
|
||||||
* @uc_fw: uC firmware
|
* @uc_fw: uC firmware
|
||||||
|
@ -315,8 +391,6 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
|
||||||
struct device *dev = i915->drm.dev;
|
struct device *dev = i915->drm.dev;
|
||||||
struct drm_i915_gem_object *obj;
|
struct drm_i915_gem_object *obj;
|
||||||
const struct firmware *fw = NULL;
|
const struct firmware *fw = NULL;
|
||||||
struct uc_css_header *css;
|
|
||||||
size_t size;
|
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
GEM_BUG_ON(!i915->wopcm.size);
|
GEM_BUG_ON(!i915->wopcm.size);
|
||||||
|
@ -333,60 +407,12 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
|
||||||
if (err)
|
if (err)
|
||||||
goto fail;
|
goto fail;
|
||||||
|
|
||||||
/* Check the size of the blob before examining buffer contents */
|
if (uc_fw->loaded_via_gsc)
|
||||||
if (unlikely(fw->size < sizeof(struct uc_css_header))) {
|
err = check_gsc_manifest(fw, uc_fw);
|
||||||
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
|
else
|
||||||
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
err = check_ccs_header(i915, fw, uc_fw);
|
||||||
fw->size, sizeof(struct uc_css_header));
|
if (err)
|
||||||
err = -ENODATA;
|
|
||||||
goto fail;
|
goto fail;
|
||||||
}
|
|
||||||
|
|
||||||
css = (struct uc_css_header *)fw->data;
|
|
||||||
|
|
||||||
/* Check integrity of size values inside CSS header */
|
|
||||||
size = (css->header_size_dw - css->key_size_dw - css->modulus_size_dw -
|
|
||||||
css->exponent_size_dw) * sizeof(u32);
|
|
||||||
if (unlikely(size != sizeof(struct uc_css_header))) {
|
|
||||||
drm_warn(&i915->drm,
|
|
||||||
"%s firmware %s: unexpected header size: %zu != %zu\n",
|
|
||||||
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
|
||||||
fw->size, sizeof(struct uc_css_header));
|
|
||||||
err = -EPROTO;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* uCode size must calculated from other sizes */
|
|
||||||
uc_fw->ucode_size = (css->size_dw - css->header_size_dw) * sizeof(u32);
|
|
||||||
|
|
||||||
/* now RSA */
|
|
||||||
uc_fw->rsa_size = css->key_size_dw * sizeof(u32);
|
|
||||||
|
|
||||||
/* At least, it should have header, uCode and RSA. Size of all three. */
|
|
||||||
size = sizeof(struct uc_css_header) + uc_fw->ucode_size + uc_fw->rsa_size;
|
|
||||||
if (unlikely(fw->size < size)) {
|
|
||||||
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu < %zu\n",
|
|
||||||
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
|
||||||
fw->size, size);
|
|
||||||
err = -ENOEXEC;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Sanity check whether this fw is not larger than whole WOPCM memory */
|
|
||||||
size = __intel_uc_fw_get_upload_size(uc_fw);
|
|
||||||
if (unlikely(size >= i915->wopcm.size)) {
|
|
||||||
drm_warn(&i915->drm, "%s firmware %s: invalid size: %zu > %zu\n",
|
|
||||||
intel_uc_fw_type_repr(uc_fw->type), uc_fw->path,
|
|
||||||
size, (size_t)i915->wopcm.size);
|
|
||||||
err = -E2BIG;
|
|
||||||
goto fail;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get version numbers from the CSS header */
|
|
||||||
uc_fw->major_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MAJOR,
|
|
||||||
css->sw_version);
|
|
||||||
uc_fw->minor_ver_found = FIELD_GET(CSS_SW_VERSION_UC_MINOR,
|
|
||||||
css->sw_version);
|
|
||||||
|
|
||||||
if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
|
if (uc_fw->major_ver_found != uc_fw->major_ver_wanted ||
|
||||||
uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
|
uc_fw->minor_ver_found < uc_fw->minor_ver_wanted) {
|
||||||
|
@ -400,9 +426,6 @@ int intel_uc_fw_fetch(struct intel_uc_fw *uc_fw)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uc_fw->type == INTEL_UC_FW_TYPE_GUC)
|
|
||||||
uc_fw->private_data_size = css->private_data_size;
|
|
||||||
|
|
||||||
if (HAS_LMEM(i915)) {
|
if (HAS_LMEM(i915)) {
|
||||||
obj = i915_gem_object_create_lmem_from_data(i915, fw->data, fw->size);
|
obj = i915_gem_object_create_lmem_from_data(i915, fw->data, fw->size);
|
||||||
if (!IS_ERR(obj))
|
if (!IS_ERR(obj))
|
||||||
|
|
|
@ -102,6 +102,8 @@ struct intel_uc_fw {
|
||||||
u32 ucode_size;
|
u32 ucode_size;
|
||||||
|
|
||||||
u32 private_data_size;
|
u32 private_data_size;
|
||||||
|
|
||||||
|
bool loaded_via_gsc;
|
||||||
};
|
};
|
||||||
|
|
||||||
#ifdef CONFIG_DRM_I915_DEBUG_GUC
|
#ifdef CONFIG_DRM_I915_DEBUG_GUC
|
||||||
|
|
|
@ -39,6 +39,11 @@
|
||||||
* 3. Length info of each component can be found in header, in dwords.
|
* 3. Length info of each component can be found in header, in dwords.
|
||||||
* 4. Modulus and exponent key are not required by driver. They may not appear
|
* 4. Modulus and exponent key are not required by driver. They may not appear
|
||||||
* in fw. So driver will load a truncated firmware in this case.
|
* in fw. So driver will load a truncated firmware in this case.
|
||||||
|
*
|
||||||
|
* Starting from DG2, the HuC is loaded by the GSC instead of i915. The GSC
|
||||||
|
* firmware performs all the required integrity checks, we just need to check
|
||||||
|
* the version. Note that the header for GSC-managed blobs is different from the
|
||||||
|
* CSS used for dma-loaded firmwares.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
struct uc_css_header {
|
struct uc_css_header {
|
||||||
|
@ -78,4 +83,8 @@ struct uc_css_header {
|
||||||
} __packed;
|
} __packed;
|
||||||
static_assert(sizeof(struct uc_css_header) == 128);
|
static_assert(sizeof(struct uc_css_header) == 128);
|
||||||
|
|
||||||
|
#define HUC_GSC_VERSION_DW 44
|
||||||
|
#define HUC_GSC_MAJOR_VER_MASK (0xFF << 0)
|
||||||
|
#define HUC_GSC_MINOR_VER_MASK (0xFF << 16)
|
||||||
|
|
||||||
#endif /* _INTEL_UC_FW_ABI_H */
|
#endif /* _INTEL_UC_FW_ABI_H */
|
||||||
|
|
Loading…
Add table
Reference in a new issue