Branch data Line data Source code
1 : : // SPDX-License-Identifier: MIT 2 : : /* 3 : : * Copyright © 2016-2019 Intel Corporation 4 : : */ 5 : : 6 : : #include <linux/types.h> 7 : : 8 : : #include "gt/intel_gt.h" 9 : : #include "intel_huc.h" 10 : : #include "i915_drv.h" 11 : : 12 : : /** 13 : : * DOC: HuC 14 : : * 15 : : * The HuC is a dedicated microcontroller for usage in media HEVC (High 16 : : * Efficiency Video Coding) operations. Userspace can directly use the firmware 17 : : * capabilities by adding HuC specific commands to batch buffers. 18 : : * 19 : : * The kernel driver is only responsible for loading the HuC firmware and 20 : : * triggering its security authentication, which is performed by the GuC. For 21 : : * The GuC to correctly perform the authentication, the HuC binary must be 22 : : * loaded before the GuC one. Loading the HuC is optional; however, not using 23 : : * the HuC might negatively impact power usage and/or performance of media 24 : : * workloads, depending on the use-cases. 25 : : * 26 : : * See https://github.com/intel/media-driver for the latest details on HuC 27 : : * functionality. 28 : : */ 29 : : 30 : : /** 31 : : * DOC: HuC Memory Management 32 : : * 33 : : * Similarly to the GuC, the HuC can't do any memory allocations on its own, 34 : : * with the difference being that the allocations for HuC usage are handled by 35 : : * the userspace driver instead of the kernel one. The HuC accesses the memory 36 : : * via the PPGTT belonging to the context loaded on the VCS executing the 37 : : * HuC-specific commands. 38 : : */ 39 : : 40 : 0 : void intel_huc_init_early(struct intel_huc *huc) 41 : : { 42 : 0 : struct drm_i915_private *i915 = huc_to_gt(huc)->i915; 43 : : 44 : 0 : intel_huc_fw_init_early(huc); 45 : : 46 [ # # ]: 0 : if (INTEL_GEN(i915) >= 11) { 47 : 0 : huc->status.reg = GEN11_HUC_KERNEL_LOAD_INFO; 48 : 0 : huc->status.mask = HUC_LOAD_SUCCESSFUL; 49 : 0 : huc->status.value = HUC_LOAD_SUCCESSFUL; 50 : : } else { 51 : 0 : huc->status.reg = HUC_STATUS2; 52 : 0 : huc->status.mask = HUC_FW_VERIFIED; 53 : 0 : huc->status.value = HUC_FW_VERIFIED; 54 : : } 55 : 0 : } 56 : : 57 : 0 : static int intel_huc_rsa_data_create(struct intel_huc *huc) 58 : : { 59 : 0 : struct intel_gt *gt = huc_to_gt(huc); 60 : 0 : struct intel_guc *guc = >->uc.guc; 61 : 0 : struct i915_vma *vma; 62 : 0 : size_t copied; 63 : 0 : void *vaddr; 64 : 0 : int err; 65 : : 66 : 0 : err = i915_inject_probe_error(gt->i915, -ENXIO); 67 : 0 : if (err) 68 : : return err; 69 : : 70 : : /* 71 : : * HuC firmware will sit above GUC_GGTT_TOP and will not map 72 : : * through GTT. Unfortunately, this means GuC cannot perform 73 : : * the HuC auth. as the rsa offset now falls within the GuC 74 : : * inaccessible range. We resort to perma-pinning an additional 75 : : * vma within the accessible range that only contains the rsa 76 : : * signature. The GuC can use this extra pinning to perform 77 : : * the authentication since its GGTT offset will be GuC 78 : : * accessible. 79 : : */ 80 : 0 : GEM_BUG_ON(huc->fw.rsa_size > PAGE_SIZE); 81 : 0 : vma = intel_guc_allocate_vma(guc, PAGE_SIZE); 82 [ # # ]: 0 : if (IS_ERR(vma)) 83 : 0 : return PTR_ERR(vma); 84 : : 85 : 0 : vaddr = i915_gem_object_pin_map(vma->obj, I915_MAP_WB); 86 [ # # ]: 0 : if (IS_ERR(vaddr)) { 87 : 0 : i915_vma_unpin_and_release(&vma, 0); 88 : 0 : return PTR_ERR(vaddr); 89 : : } 90 : : 91 : 0 : copied = intel_uc_fw_copy_rsa(&huc->fw, vaddr, vma->size); 92 : 0 : GEM_BUG_ON(copied < huc->fw.rsa_size); 93 : : 94 : 0 : i915_gem_object_unpin_map(vma->obj); 95 : : 96 : 0 : huc->rsa_data = vma; 97 : : 98 : 0 : return 0; 99 : : } 100 : : 101 : 0 : static void intel_huc_rsa_data_destroy(struct intel_huc *huc) 102 : : { 103 : 0 : i915_vma_unpin_and_release(&huc->rsa_data, 0); 104 : : } 105 : : 106 : 0 : int intel_huc_init(struct intel_huc *huc) 107 : : { 108 : 0 : struct drm_i915_private *i915 = huc_to_gt(huc)->i915; 109 : 0 : int err; 110 : : 111 : 0 : err = intel_uc_fw_init(&huc->fw); 112 [ # # ]: 0 : if (err) 113 : 0 : goto out; 114 : : 115 : : /* 116 : : * HuC firmware image is outside GuC accessible range. 117 : : * Copy the RSA signature out of the image into 118 : : * a perma-pinned region set aside for it 119 : : */ 120 : 0 : err = intel_huc_rsa_data_create(huc); 121 [ # # ]: 0 : if (err) 122 : 0 : goto out_fini; 123 : : 124 : : return 0; 125 : : 126 : : out_fini: 127 : 0 : intel_uc_fw_fini(&huc->fw); 128 : 0 : out: 129 : 0 : intel_uc_fw_cleanup_fetch(&huc->fw); 130 : 0 : DRM_DEV_DEBUG_DRIVER(i915->drm.dev, "failed with %d\n", err); 131 : 0 : return err; 132 : : } 133 : : 134 : 0 : void intel_huc_fini(struct intel_huc *huc) 135 : : { 136 [ # # ]: 0 : if (!intel_uc_fw_is_available(&huc->fw)) 137 : : return; 138 : : 139 : 0 : intel_huc_rsa_data_destroy(huc); 140 : 0 : intel_uc_fw_fini(&huc->fw); 141 : : } 142 : : 143 : : /** 144 : : * intel_huc_auth() - Authenticate HuC uCode 145 : : * @huc: intel_huc structure 146 : : * 147 : : * Called after HuC and GuC firmware loading during intel_uc_init_hw(). 148 : : * 149 : : * This function invokes the GuC action to authenticate the HuC firmware, 150 : : * passing the offset of the RSA signature to intel_guc_auth_huc(). It then 151 : : * waits for up to 50ms for firmware verification ACK. 152 : : */ 153 : 0 : int intel_huc_auth(struct intel_huc *huc) 154 : : { 155 [ # # ]: 0 : struct intel_gt *gt = huc_to_gt(huc); 156 : 0 : struct intel_guc *guc = >->uc.guc; 157 : 0 : int ret; 158 : : 159 : 0 : GEM_BUG_ON(intel_huc_is_authenticated(huc)); 160 : : 161 [ # # ]: 0 : if (!intel_uc_fw_is_loaded(&huc->fw)) 162 : : return -ENOEXEC; 163 : : 164 : 0 : ret = i915_inject_probe_error(gt->i915, -ENXIO); 165 : 0 : if (ret) 166 : : goto fail; 167 : : 168 : 0 : ret = intel_guc_auth_huc(guc, 169 : : intel_guc_ggtt_offset(guc, huc->rsa_data)); 170 [ # # ]: 0 : if (ret) { 171 : 0 : DRM_ERROR("HuC: GuC did not ack Auth request %d\n", ret); 172 : 0 : goto fail; 173 : : } 174 : : 175 : : /* Check authentication status, it should be done by now */ 176 : 0 : ret = __intel_wait_for_register(gt->uncore, 177 : : huc->status.reg, 178 : : huc->status.mask, 179 : : huc->status.value, 180 : : 2, 50, NULL); 181 [ # # ]: 0 : if (ret) { 182 : 0 : DRM_ERROR("HuC: Firmware not verified %d\n", ret); 183 : 0 : goto fail; 184 : : } 185 : : 186 : 0 : intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_RUNNING); 187 : 0 : return 0; 188 : : 189 : 0 : fail: 190 : 0 : i915_probe_error(gt->i915, "HuC: Authentication failed %d\n", ret); 191 : 0 : intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_FAIL); 192 : 0 : return ret; 193 : : } 194 : : 195 : : /** 196 : : * intel_huc_check_status() - check HuC status 197 : : * @huc: intel_huc structure 198 : : * 199 : : * This function reads status register to verify if HuC 200 : : * firmware was successfully loaded. 201 : : * 202 : : * Returns: 1 if HuC firmware is loaded and verified, 203 : : * 0 if HuC firmware is not loaded and -ENODEV if HuC 204 : : * is not present on this platform. 205 : : */ 206 : 0 : int intel_huc_check_status(struct intel_huc *huc) 207 : : { 208 [ # # ]: 0 : struct intel_gt *gt = huc_to_gt(huc); 209 : 0 : intel_wakeref_t wakeref; 210 : 0 : u32 status = 0; 211 : : 212 [ # # ]: 0 : if (!intel_huc_is_supported(huc)) 213 : : return -ENODEV; 214 : : 215 [ # # ]: 0 : with_intel_runtime_pm(gt->uncore->rpm, wakeref) 216 : 0 : status = intel_uncore_read(gt->uncore, huc->status.reg); 217 : : 218 : 0 : return (status & huc->status.mask) == huc->status.value; 219 : : }