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