|
5 | 5 |
|
6 | 6 | #include "gt/intel_gsc.h" |
7 | 7 | #include "gt/intel_gt.h" |
| 8 | +#include "intel_gsc_binary_headers.h" |
8 | 9 | #include "intel_huc.h" |
9 | 10 | #include "intel_huc_fw.h" |
| 11 | +#include "intel_huc_print.h" |
10 | 12 | #include "i915_drv.h" |
11 | 13 | #include "pxp/intel_pxp_huc.h" |
12 | 14 |
|
| 15 | +static void get_version_from_gsc_manifest(struct intel_uc_fw_ver *ver, const void *data) |
| 16 | +{ |
| 17 | + const struct intel_gsc_manifest_header *manifest = data; |
| 18 | + |
| 19 | + ver->major = manifest->fw_version.major; |
| 20 | + ver->minor = manifest->fw_version.minor; |
| 21 | + ver->patch = manifest->fw_version.hotfix; |
| 22 | +} |
| 23 | + |
| 24 | +static bool css_valid(const void *data, size_t size) |
| 25 | +{ |
| 26 | + const struct uc_css_header *css = data; |
| 27 | + |
| 28 | + if (unlikely(size < sizeof(struct uc_css_header))) |
| 29 | + return false; |
| 30 | + |
| 31 | + if (css->module_type != 0x6) |
| 32 | + return false; |
| 33 | + |
| 34 | + if (css->module_vendor != PCI_VENDOR_ID_INTEL) |
| 35 | + return false; |
| 36 | + |
| 37 | + return true; |
| 38 | +} |
| 39 | + |
| 40 | +static inline u32 entry_offset(const struct intel_gsc_cpd_entry *entry) |
| 41 | +{ |
| 42 | + return entry->offset & INTEL_GSC_CPD_ENTRY_OFFSET_MASK; |
| 43 | +} |
| 44 | + |
| 45 | +int intel_huc_fw_get_binary_info(struct intel_uc_fw *huc_fw, const void *data, size_t size) |
| 46 | +{ |
| 47 | + struct intel_huc *huc = container_of(huc_fw, struct intel_huc, fw); |
| 48 | + const struct intel_gsc_cpd_header_v2 *header = data; |
| 49 | + const struct intel_gsc_cpd_entry *entry; |
| 50 | + size_t min_size = sizeof(*header); |
| 51 | + int i; |
| 52 | + |
| 53 | + if (!huc_fw->loaded_via_gsc) { |
| 54 | + huc_err(huc, "Invalid FW type for GSC header parsing!\n"); |
| 55 | + return -EINVAL; |
| 56 | + } |
| 57 | + |
| 58 | + if (size < sizeof(*header)) { |
| 59 | + huc_err(huc, "FW too small! %zu < %zu\n", size, min_size); |
| 60 | + return -ENODATA; |
| 61 | + } |
| 62 | + |
| 63 | + /* |
| 64 | + * The GSC-enabled HuC binary starts with a directory header, followed |
| 65 | + * by a series of entries. Each entry is identified by a name and |
| 66 | + * points to a specific section of the binary containing the relevant |
| 67 | + * data. The entries we're interested in are: |
| 68 | + * - "HUCP.man": points to the GSC manifest header for the HuC, which |
| 69 | + * contains the version info. |
| 70 | + * - "huc_fw": points to the legacy-style binary that can be used for |
| 71 | + * load via the DMA. This entry only contains a valid CSS |
| 72 | + * on binaries for platforms that support 2-step HuC load |
| 73 | + * via dma and auth via GSC (like MTL). |
| 74 | + * |
| 75 | + * -------------------------------------------------- |
| 76 | + * [ intel_gsc_cpd_header_v2 ] |
| 77 | + * -------------------------------------------------- |
| 78 | + * [ intel_gsc_cpd_entry[] ] |
| 79 | + * [ entry1 ] |
| 80 | + * [ ... ] |
| 81 | + * [ entryX ] |
| 82 | + * [ "HUCP.man" ] |
| 83 | + * [ ... ] |
| 84 | + * [ offset >----------------------------]------o |
| 85 | + * [ ... ] | |
| 86 | + * [ entryY ] | |
| 87 | + * [ "huc_fw" ] | |
| 88 | + * [ ... ] | |
| 89 | + * [ offset >----------------------------]----------o |
| 90 | + * -------------------------------------------------- | | |
| 91 | + * | | |
| 92 | + * -------------------------------------------------- | | |
| 93 | + * [ intel_gsc_manifest_header ]<-----o | |
| 94 | + * [ ... ] | |
| 95 | + * [ intel_gsc_version fw_version ] | |
| 96 | + * [ ... ] | |
| 97 | + * -------------------------------------------------- | |
| 98 | + * | |
| 99 | + * -------------------------------------------------- | |
| 100 | + * [ data[] ]<---------o |
| 101 | + * [ ... ] |
| 102 | + * [ ... ] |
| 103 | + * -------------------------------------------------- |
| 104 | + */ |
| 105 | + |
| 106 | + if (header->header_marker != INTEL_GSC_CPD_HEADER_MARKER) { |
| 107 | + huc_err(huc, "invalid marker for CPD header: 0x%08x!\n", |
| 108 | + header->header_marker); |
| 109 | + return -EINVAL; |
| 110 | + } |
| 111 | + |
| 112 | + /* we only have binaries with header v2 and entry v1 for now */ |
| 113 | + if (header->header_version != 2 || header->entry_version != 1) { |
| 114 | + huc_err(huc, "invalid CPD header/entry version %u:%u!\n", |
| 115 | + header->header_version, header->entry_version); |
| 116 | + return -EINVAL; |
| 117 | + } |
| 118 | + |
| 119 | + if (header->header_length < sizeof(struct intel_gsc_cpd_header_v2)) { |
| 120 | + huc_err(huc, "invalid CPD header length %u!\n", |
| 121 | + header->header_length); |
| 122 | + return -EINVAL; |
| 123 | + } |
| 124 | + |
| 125 | + min_size = header->header_length + sizeof(*entry) * header->num_of_entries; |
| 126 | + if (size < min_size) { |
| 127 | + huc_err(huc, "FW too small! %zu < %zu\n", size, min_size); |
| 128 | + return -ENODATA; |
| 129 | + } |
| 130 | + |
| 131 | + entry = data + header->header_length; |
| 132 | + |
| 133 | + for (i = 0; i < header->num_of_entries; i++, entry++) { |
| 134 | + if (strcmp(entry->name, "HUCP.man") == 0) |
| 135 | + get_version_from_gsc_manifest(&huc_fw->file_selected.ver, |
| 136 | + data + entry_offset(entry)); |
| 137 | + |
| 138 | + if (strcmp(entry->name, "huc_fw") == 0) { |
| 139 | + u32 offset = entry_offset(entry); |
| 140 | + |
| 141 | + if (offset < size && css_valid(data + offset, size - offset)) |
| 142 | + huc_fw->dma_start_offset = offset; |
| 143 | + } |
| 144 | + } |
| 145 | + |
| 146 | + return 0; |
| 147 | +} |
| 148 | + |
13 | 149 | int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc) |
14 | 150 | { |
15 | 151 | int ret; |
|
0 commit comments