Commit 08872cb1 authored by Daniele Ceraolo Spurio's avatar Daniele Ceraolo Spurio
Browse files

drm/i915/mtl/huc: auth HuC via GSC



The full authentication via the GSC requires an heci packet submission
to the GSC FW via the GSC CS. The GSC has new PXP command for this
(literally called NEW_HUC_AUTH).
The intel_huc_auth function is also updated to handle both authentication
types.

v2: check that the GuC auth for clear media has completed before
    proceding with the full auth

v3: use a define for the object size (Alan)

Signed-off-by: default avatarDaniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Alan Previn <alan.previn.teres.alexis@intel.com>
Reviewed-by: default avatarAlan Previn <alan.previn.teres.alexis@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20230531235415.1467475-6-daniele.ceraolospurio@intel.com
parent 98d2722a
Loading
Loading
Loading
Loading
+23 −4
Original line number Diff line number Diff line
@@ -29,13 +29,32 @@ static void gsc_work(struct work_struct *work)

	if (actions & GSC_ACTION_FW_LOAD) {
		ret = intel_gsc_uc_fw_upload(gsc);
		if (ret == -EEXIST) /* skip proxy if not a new load */
			actions &= ~GSC_ACTION_FW_LOAD;
		else if (ret)
		if (!ret)
			/* setup proxy on a new load */
			actions |= GSC_ACTION_SW_PROXY;
		else if (ret != -EEXIST)
			goto out_put;

		/*
		 * The HuC auth can be done both before or after the proxy init;
		 * if done after, a proxy request will be issued and must be
		 * serviced before the authentication can complete.
		 * Since this worker also handles proxy requests, we can't
		 * perform an action that requires the proxy from within it and
		 * then stall waiting for it, because we'd be blocking the
		 * service path. Therefore, it is easier for us to load HuC
		 * first and do proxy later. The GSC will ack the HuC auth and
		 * then send the HuC proxy request as part of the proxy init
		 * flow.
		 * Note that we can only do the GSC auth if the GuC auth was
		 * successful.
		 */
		if (intel_uc_uses_huc(&gt->uc) &&
		    intel_huc_is_authenticated(&gt->uc.huc, INTEL_HUC_AUTH_BY_GUC))
			intel_huc_auth(&gt->uc.huc, INTEL_HUC_AUTH_BY_GSC);
	}

	if (actions & (GSC_ACTION_FW_LOAD | GSC_ACTION_SW_PROXY)) {
	if (actions & GSC_ACTION_SW_PROXY) {
		if (!intel_gsc_uc_fw_init_done(gsc)) {
			gt_err(gt, "Proxy request received with GSC not loaded!\n");
			goto out_put;
+1 −1
Original line number Diff line number Diff line
@@ -99,7 +99,7 @@ void intel_gsc_uc_heci_cmd_emit_mtl_header(struct intel_gsc_mtl_header *header,
					   u64 host_session_id)
{
	host_session_id &= ~HOST_SESSION_MASK;
	if (heci_client_id == HECI_MEADDRESS_PXP)
	if (host_session_id && heci_client_id == HECI_MEADDRESS_PXP)
		host_session_id |= HOST_SESSION_PXP_SINGLE;

	header->validity_marker = GSC_HECI_VALIDITY_MARKER;
+42 −11
Original line number Diff line number Diff line
@@ -11,6 +11,7 @@
#include "intel_huc_print.h"
#include "i915_drv.h"
#include "i915_reg.h"
#include "pxp/intel_pxp_cmd_interface_43.h"

#include <linux/device/bus.h>
#include <linux/mei_aux.h>
@@ -371,20 +372,36 @@ static int check_huc_loading_mode(struct intel_huc *huc)

int intel_huc_init(struct intel_huc *huc)
{
	struct intel_gt *gt = huc_to_gt(huc);
	int err;

	err = check_huc_loading_mode(huc);
	if (err)
		goto out;

	if (HAS_ENGINE(gt, GSC0)) {
		struct i915_vma *vma;

		vma = intel_guc_allocate_vma(&gt->uc.guc, PXP43_HUC_AUTH_INOUT_SIZE * 2);
		if (IS_ERR(vma)) {
			huc_info(huc, "Failed to allocate heci pkt\n");
			goto out;
		}

		huc->heci_pkt = vma;
	}

	err = intel_uc_fw_init(&huc->fw);
	if (err)
		goto out;
		goto out_pkt;

	intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_LOADABLE);

	return 0;

out_pkt:
	if (huc->heci_pkt)
		i915_vma_unpin_and_release(&huc->heci_pkt, 0);
out:
	intel_uc_fw_change_status(&huc->fw, INTEL_UC_FIRMWARE_INIT_FAIL);
	huc_info(huc, "initialization failed %pe\n", ERR_PTR(err));
@@ -399,6 +416,9 @@ void intel_huc_fini(struct intel_huc *huc)
	 */
	delayed_huc_load_fini(huc);

	if (huc->heci_pkt)
		i915_vma_unpin_and_release(&huc->heci_pkt, 0);

	if (intel_uc_fw_is_loadable(&huc->fw))
		intel_uc_fw_fini(&huc->fw);
}
@@ -454,6 +474,7 @@ int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
/**
 * intel_huc_auth() - Authenticate HuC uCode
 * @huc: intel_huc structure
 * @type: authentication type (via GuC or via GSC)
 *
 * Called after HuC and GuC firmware loading during intel_uc_init_hw().
 *
@@ -461,7 +482,7 @@ int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
 * passing the offset of the RSA signature to intel_guc_auth_huc(). It then
 * waits for up to 50ms for firmware verification ACK.
 */
int intel_huc_auth(struct intel_huc *huc)
int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type type)
{
	struct intel_gt *gt = huc_to_gt(huc);
	struct intel_guc *guc = &gt->uc.guc;
@@ -470,31 +491,41 @@ int intel_huc_auth(struct intel_huc *huc)
	if (!intel_uc_fw_is_loaded(&huc->fw))
		return -ENOEXEC;

	/* GSC will do the auth */
	/* GSC will do the auth with the load */
	if (intel_huc_is_loaded_by_gsc(huc))
		return -ENODEV;

	if (intel_huc_is_authenticated(huc, type))
		return -EEXIST;

	ret = i915_inject_probe_error(gt->i915, -ENXIO);
	if (ret)
		goto fail;

	GEM_BUG_ON(intel_uc_fw_is_running(&huc->fw));

	switch (type) {
	case INTEL_HUC_AUTH_BY_GUC:
		ret = intel_guc_auth_huc(guc, intel_guc_ggtt_offset(guc, huc->fw.rsa_data));
	if (ret) {
		huc_err(huc, "authentication by GuC failed %pe\n", ERR_PTR(ret));
		goto fail;
		break;
	case INTEL_HUC_AUTH_BY_GSC:
		ret = intel_huc_fw_auth_via_gsccs(huc);
		break;
	default:
		MISSING_CASE(type);
		ret = -EINVAL;
	}
	if (ret)
		goto fail;

	/* Check authentication status, it should be done by now */
	ret = intel_huc_wait_for_auth_complete(huc, INTEL_HUC_AUTH_BY_GUC);
	ret = intel_huc_wait_for_auth_complete(huc, type);
	if (ret)
		goto fail;

	return 0;

fail:
	huc_probe_error(huc, "authentication failed %pe\n", ERR_PTR(ret));
	huc_probe_error(huc, "%s authentication failed %pe\n",
			auth_mode_string(huc, type), ERR_PTR(ret));
	return ret;
}

+5 −1
Original line number Diff line number Diff line
@@ -15,6 +15,7 @@
#include <linux/hrtimer.h>

struct bus_type;
struct i915_vma;

enum intel_huc_delayed_load_status {
	INTEL_HUC_WAITING_ON_GSC = 0,
@@ -46,6 +47,9 @@ struct intel_huc {
		enum intel_huc_delayed_load_status status;
	} delayed_load;

	/* for load via GSCCS */
	struct i915_vma *heci_pkt;

	bool loaded_via_gsc;
};

@@ -54,7 +58,7 @@ void intel_huc_init_early(struct intel_huc *huc);
int intel_huc_init(struct intel_huc *huc);
void intel_huc_fini(struct intel_huc *huc);
void intel_huc_suspend(struct intel_huc *huc);
int intel_huc_auth(struct intel_huc *huc);
int intel_huc_auth(struct intel_huc *huc, enum intel_huc_authentication_type type);
int intel_huc_wait_for_auth_complete(struct intel_huc *huc,
				     enum intel_huc_authentication_type type);
bool intel_huc_is_authenticated(struct intel_huc *huc,
+95 −0
Original line number Diff line number Diff line
@@ -6,11 +6,106 @@
#include "gt/intel_gsc.h"
#include "gt/intel_gt.h"
#include "intel_gsc_binary_headers.h"
#include "intel_gsc_uc_heci_cmd_submit.h"
#include "intel_huc.h"
#include "intel_huc_fw.h"
#include "intel_huc_print.h"
#include "i915_drv.h"
#include "pxp/intel_pxp_huc.h"
#include "pxp/intel_pxp_cmd_interface_43.h"

struct mtl_huc_auth_msg_in {
	struct intel_gsc_mtl_header header;
	struct pxp43_new_huc_auth_in huc_in;
} __packed;

struct mtl_huc_auth_msg_out {
	struct intel_gsc_mtl_header header;
	struct pxp43_huc_auth_out huc_out;
} __packed;

int intel_huc_fw_auth_via_gsccs(struct intel_huc *huc)
{
	struct intel_gt *gt = huc_to_gt(huc);
	struct drm_i915_private *i915 = gt->i915;
	struct drm_i915_gem_object *obj;
	struct mtl_huc_auth_msg_in *msg_in;
	struct mtl_huc_auth_msg_out *msg_out;
	void *pkt_vaddr;
	u64 pkt_offset;
	int retry = 5;
	int err = 0;

	if (!huc->heci_pkt)
		return -ENODEV;

	obj = huc->heci_pkt->obj;
	pkt_offset = i915_ggtt_offset(huc->heci_pkt);

	pkt_vaddr = i915_gem_object_pin_map_unlocked(obj,
						     i915_coherent_map_type(i915, obj, true));
	if (IS_ERR(pkt_vaddr))
		return PTR_ERR(pkt_vaddr);

	msg_in = pkt_vaddr;
	msg_out = pkt_vaddr + PXP43_HUC_AUTH_INOUT_SIZE;

	intel_gsc_uc_heci_cmd_emit_mtl_header(&msg_in->header,
					      HECI_MEADDRESS_PXP,
					      sizeof(*msg_in), 0);

	msg_in->huc_in.header.api_version = PXP_APIVER(4, 3);
	msg_in->huc_in.header.command_id = PXP43_CMDID_NEW_HUC_AUTH;
	msg_in->huc_in.header.status = 0;
	msg_in->huc_in.header.buffer_len = sizeof(msg_in->huc_in) -
					   sizeof(msg_in->huc_in.header);
	msg_in->huc_in.huc_base_address = huc->fw.vma_res.start;
	msg_in->huc_in.huc_size = huc->fw.obj->base.size;

	do {
		err = intel_gsc_uc_heci_cmd_submit_packet(&gt->uc.gsc,
							  pkt_offset, sizeof(*msg_in),
							  pkt_offset + PXP43_HUC_AUTH_INOUT_SIZE,
							  PXP43_HUC_AUTH_INOUT_SIZE);
		if (err) {
			huc_err(huc, "failed to submit GSC request to auth: %d\n", err);
			goto out_unpin;
		}

		if (msg_out->header.flags & GSC_OUTFLAG_MSG_PENDING) {
			msg_in->header.gsc_message_handle = msg_out->header.gsc_message_handle;
			err = -EBUSY;
			msleep(50);
		}
	} while (--retry && err == -EBUSY);

	if (err)
		goto out_unpin;

	if (msg_out->header.message_size != sizeof(*msg_out)) {
		huc_err(huc, "invalid GSC reply length %u [expected %zu]\n",
			msg_out->header.message_size, sizeof(*msg_out));
		err = -EPROTO;
		goto out_unpin;
	}

	/*
	 * The GSC will return PXP_STATUS_OP_NOT_PERMITTED if the HuC is already
	 * loaded. If the same error is ever returned with HuC not loaded we'll
	 * still catch it when we check the authentication bit later.
	 */
	if (msg_out->huc_out.header.status != PXP_STATUS_SUCCESS &&
	    msg_out->huc_out.header.status != PXP_STATUS_OP_NOT_PERMITTED) {
		huc_err(huc, "auth failed with GSC error = 0x%x\n",
			msg_out->huc_out.header.status);
		err = -EIO;
		goto out_unpin;
	}

out_unpin:
	i915_gem_object_unpin_map(obj);
	return err;
}

static void get_version_from_gsc_manifest(struct intel_uc_fw_ver *ver, const void *data)
{
Loading