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
......@@ -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;
......
......@@ -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;
......
......@@ -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;
}
......
......@@ -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,
......
......@@ -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)
{
......
......@@ -12,6 +12,7 @@ struct intel_uc_fw;
#include <linux/types.h>
int intel_huc_fw_load_and_auth_via_gsc(struct intel_huc *huc);
int intel_huc_fw_auth_via_gsccs(struct intel_huc *huc);
int intel_huc_fw_upload(struct intel_huc *huc);
int intel_huc_fw_get_binary_info(struct intel_uc_fw *huc_fw, const void *data, size_t size);
#endif
......@@ -538,7 +538,7 @@ static int __uc_init_hw(struct intel_uc *uc)
if (intel_huc_is_loaded_by_gsc(huc))
intel_huc_update_auth_status(huc);
else
intel_huc_auth(huc);
intel_huc_auth(huc, INTEL_HUC_AUTH_BY_GUC);
if (intel_uc_uses_guc_submission(uc)) {
ret = intel_guc_submission_enable(guc);
......
......@@ -11,19 +11,30 @@
/* PXP-Cmd-Op definitions */
#define PXP43_CMDID_START_HUC_AUTH 0x0000003A
#define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */
#define PXP43_CMDID_INIT_SESSION 0x00000036
/* PXP-Packet sizes for MTL's GSCCS-HECI instruction */
#define PXP43_MAX_HECI_INOUT_SIZE (SZ_32K)
/* PXP-Input-Packet: HUC-Authentication */
/* PXP-Packet size for MTL's NEW_HUC_AUTH instruction */
#define PXP43_HUC_AUTH_INOUT_SIZE (SZ_4K)
/* PXP-Input-Packet: HUC Load and Authentication */
struct pxp43_start_huc_auth_in {
struct pxp_cmd_header header;
__le64 huc_base_address;
} __packed;
/* PXP-Output-Packet: HUC-Authentication */
struct pxp43_start_huc_auth_out {
/* PXP-Input-Packet: HUC Auth-only */
struct pxp43_new_huc_auth_in {
struct pxp_cmd_header header;
u64 huc_base_address;
u32 huc_size;
} __packed;
/* PXP-Output-Packet: HUC Load and Authentication or Auth-only */
struct pxp43_huc_auth_out {
struct pxp_cmd_header header;
} __packed;
......
......@@ -19,7 +19,7 @@ int intel_pxp_huc_load_and_auth(struct intel_pxp *pxp)
struct intel_gt *gt;
struct intel_huc *huc;
struct pxp43_start_huc_auth_in huc_in = {0};
struct pxp43_start_huc_auth_out huc_out = {0};
struct pxp43_huc_auth_out huc_out = {0};
dma_addr_t huc_phys_addr;
u8 client_id = 0;
u8 fence_id = 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment