int intel_gsc_uc_fw_proxy_get_status(struct intel_gsc_uc *gsc)
{ if (!(IS_ENABLED(CONFIG_INTEL_MEI_GSC_PROXY))) return -ENODEV; if (!intel_uc_fw_is_loadable(&gsc->fw)) return -ENODEV; if (__intel_uc_fw_status(&gsc->fw) == INTEL_UC_FIRMWARE_LOAD_FAIL) return -ENOLINK; if (!intel_gsc_uc_fw_proxy_init_done(gsc, true)) return -EAGAIN;
if (size < min_size) {
gt_err(gt, "GSC FW too small! %zu < %zu\n", size, min_size); return -ENODATA;
}
/* * The GSC binary starts with the pointer layout, which contains the * locations of the various partitions of the binary. The one we're * interested in to get the version is the boot1 partition, where we can * find a BPDT header followed by entries, one of which points to the * RBE sub-section of the partition. From here, we can parse the CPD * header and the following entries to find the manifest location * (entry identified by the "RBEP.man" name), from which we can finally * extract the version. * * -------------------------------------------------- * [ intel_gsc_layout_pointers ] * [ ... ] * [ boot1.offset >---------------------------]------o * [ ... ] | * -------------------------------------------------- | * | * -------------------------------------------------- | * [ intel_gsc_bpdt_header ]<-----o * -------------------------------------------------- * [ intel_gsc_bpdt_entry[] ] * [ entry1 ] * [ ... ] * [ entryX ] * [ type == GSC_RBE ] * [ offset >-----------------------------]------o * [ ... ] | * -------------------------------------------------- | * | * -------------------------------------------------- | * [ intel_gsc_cpd_header_v2 ]<-----o * -------------------------------------------------- * [ intel_gsc_cpd_entry[] ] * [ entry1 ] * [ ... ] * [ entryX ] * [ "RBEP.man" ] * [ ... ] * [ offset >----------------------------]------o * [ ... ] | * -------------------------------------------------- | * | * -------------------------------------------------- | * [ intel_gsc_manifest_header ]<-----o * [ ... ] * [ intel_gsc_version fw_version ] * [ ... ] * --------------------------------------------------
*/
min_size = layout->boot1.offset + layout->boot1.size; if (size < min_size) {
gt_err(gt, "GSC FW too small for boot section! %zu < %zu\n",
size, min_size); return -ENODATA;
}
min_size = sizeof(*bpdt_header); if (layout->boot1.size < min_size) {
gt_err(gt, "GSC FW boot section too small for BPDT header: %u < %zu\n",
layout->boot1.size, min_size); return -ENODATA;
}
bpdt_header = data + layout->boot1.offset; if (bpdt_header->signature != INTEL_GSC_BPDT_HEADER_SIGNATURE) {
gt_err(gt, "invalid signature for BPDT header: 0x%08x!\n",
bpdt_header->signature); return -EINVAL;
}
min_size += sizeof(*bpdt_entry) * bpdt_header->descriptor_count; if (layout->boot1.size < min_size) {
gt_err(gt, "GSC FW boot section too small for BPDT entries: %u < %zu\n",
layout->boot1.size, min_size); return -ENODATA;
}
bpdt_entry = (void *)bpdt_header + sizeof(*bpdt_header); for (i = 0; i < bpdt_header->descriptor_count; i++, bpdt_entry++) { if ((bpdt_entry->type & INTEL_GSC_BPDT_ENTRY_TYPE_MASK) !=
INTEL_GSC_BPDT_ENTRY_TYPE_GSC_RBE) continue;
if (!cpd_header) {
gt_err(gt, "couldn't find CPD header in GSC binary!\n"); return -ENODATA;
}
if (layout->boot1.size < min_size) {
gt_err(gt, "GSC FW boot section too small for CPD header: %u < %zu\n",
layout->boot1.size, min_size); return -ENODATA;
}
if (cpd_header->header_marker != INTEL_GSC_CPD_HEADER_MARKER) {
gt_err(gt, "invalid marker for CPD header in GSC bin: 0x%08x!\n",
cpd_header->header_marker); return -EINVAL;
}
min_size += sizeof(*cpd_entry) * cpd_header->num_of_entries; if (layout->boot1.size < min_size) {
gt_err(gt, "GSC FW boot section too small for CPD entries: %u < %zu\n",
layout->boot1.size, min_size); return -ENODATA;
}
cpd_entry = (void *)cpd_header + cpd_header->header_length; for (i = 0; i < cpd_header->num_of_entries; i++, cpd_entry++) { if (strcmp(cpd_entry->name, "RBEP.man") == 0) {
manifest = (void *)cpd_header + cpd_entry_offset(cpd_entry);
intel_uc_fw_version_from_gsc_manifest(&gsc->release,
manifest);
gsc->security_version = manifest->security_version; break;
}
}
/* * ARL SKUs require newer firmwares, but the blob is actually common * across all MTL and ARL SKUs, so we need to do an explicit version check * here rather than using a separate table entry. If a too old version * is found, then just don't use GSC rather than aborting the driver load. * Note that the major number in the GSC FW version is used to indicate * the platform, so we expect it to always be 102 for MTL/ARL binaries.
*/ if (IS_ARROWLAKE_S(gt->i915))
min_ver = (struct intel_uc_fw_ver){ 102, 0, 10, 1878 }; elseif (IS_ARROWLAKE_H(gt->i915) || IS_ARROWLAKE_U(gt->i915))
min_ver = (struct intel_uc_fw_ver){ 102, 1, 15, 1926 };
if (IS_METEORLAKE(gt->i915) && gsc->release.major != 102) {
gt_info(gt, "Invalid GSC firmware for MTL/ARL, got %d.%d.%d.%d but need 102.x.x.x",
gsc->release.major, gsc->release.minor,
gsc->release.patch, gsc->release.build); return -EINVAL;
}
if (too_old) {
gt_info(gt, "GSC firmware too old for ARL, got %d.%d.%d.%d but need at least %d.%d.%d.%d",
gsc->release.major, gsc->release.minor,
gsc->release.patch, gsc->release.build,
min_ver.major, min_ver.minor,
min_ver.patch, min_ver.build); return -EINVAL;
}
}
int intel_gsc_uc_fw_upload(struct intel_gsc_uc *gsc)
{ struct intel_gt *gt = gsc_uc_to_gt(gsc); struct intel_uc_fw *gsc_fw = &gsc->fw; int err;
/* check current fw status */ if (intel_gsc_uc_fw_init_done(gsc)) { if (GEM_WARN_ON(!intel_uc_fw_is_loaded(gsc_fw)))
intel_uc_fw_change_status(gsc_fw, INTEL_UC_FIRMWARE_TRANSFERRED); return -EEXIST;
}
if (!intel_uc_fw_is_loadable(gsc_fw)) return -ENOEXEC;
/* FW blob is ok, so clean the status */
intel_uc_fw_sanitize(&gsc->fw);
if (!gsc_is_in_reset(gt->uncore)) return -EIO;
err = gsc_fw_load_prepare(gsc); if (err) goto fail;
/* * GSC is only killed by an FLR, so we need to trigger one on unload to * make sure we stop it. This is because we assign a chunk of memory to * the GSC as part of the FW load , so we need to make sure it stops * using it when we release it to the system on driver unload. Note that * this is not a problem of the unload per-se, because the GSC will not * touch that memory unless there are requests for it coming from the * driver; therefore, no accesses will happen while i915 is not loaded, * but if we re-load the driver then the GSC might wake up and try to * access that old memory location again. * Given that an FLR is a very disruptive action (see the FLR function * for details), we want to do it as the last action before releasing * the access to the MMIO bar, which means we need to do it as part of * the primary uncore cleanup. * An alternative approach to the FLR would be to use a memory location * that survives driver unload, like e.g. stolen memory, and keep the * GSC loaded across reloads. However, this requires us to make sure we * preserve that memory location on unload and then determine and * reserve its offset on each subsequent load, which is not trivial, so * it is easier to just kill everything and start fresh.
*/
intel_uncore_set_flr_on_fini(>->i915->uncore);
err = gsc_fw_load(gsc); if (err) goto fail;
err = gsc_fw_wait(gt); if (err) goto fail;
err = gsc_fw_query_compatibility_version(gsc); if (err) goto fail;
/* we only support compatibility version 1.0 at the moment */
err = intel_uc_check_file_version(gsc_fw, NULL); if (err) goto fail;
/* FW is not fully operational until we enable SW proxy */
intel_uc_fw_change_status(gsc_fw, INTEL_UC_FIRMWARE_TRANSFERRED);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.