Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

drm/xe/huc: HuC authentication via GSC

HuC authentication via GSC is performed by submitting the appropriate
PXP packet to the GSC FW. This packet can trigger a "pending" reply from
the FW, so we need to handle that and resubmit. Note that the auth via
GSC can only be performed if the HuC has already been authenticated by
the GuC.

Signed-off-by: Daniele Ceraolo Spurio <daniele.ceraolospurio@intel.com>
Cc: Alan Previn <alan.previn.teres.alexis@intel.com>
Cc: John Harrison <John.C.Harrison@Intel.com>
Cc: Vivaik Balasubrawmanian <vivaik.balasubrawmanian@intel.com>
Reviewed-by: Vivaik Balasubrawmanian <vivaik.balasubrawmanian@intel.com>
Signed-off-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

authored by

Daniele Ceraolo Spurio and committed by
Rodrigo Vivi
d8b15713 7ce5716e

+218 -7
+59
drivers/gpu/drm/xe/abi/gsc_pxp_commands_abi.h
··· 1 + /* SPDX-License-Identifier: MIT */ 2 + /* 3 + * Copyright © 2023 Intel Corporation 4 + */ 5 + 6 + #ifndef _ABI_GSC_PXP_COMMANDS_ABI_H 7 + #define _ABI_GSC_PXP_COMMANDS_ABI_H 8 + 9 + #include <linux/types.h> 10 + 11 + /* Heci client ID for PXP commands */ 12 + #define HECI_MEADDRESS_PXP 17 13 + 14 + #define PXP_APIVER(x, y) (((x) & 0xFFFF) << 16 | ((y) & 0xFFFF)) 15 + 16 + /* 17 + * there are a lot of status codes for PXP, but we only define the cross-API 18 + * common ones that we actually can handle in the kernel driver. Other failure 19 + * codes should be printed to error msg for debug. 20 + */ 21 + enum pxp_status { 22 + PXP_STATUS_SUCCESS = 0x0, 23 + PXP_STATUS_ERROR_API_VERSION = 0x1002, 24 + PXP_STATUS_NOT_READY = 0x100e, 25 + PXP_STATUS_PLATFCONFIG_KF1_NOVERIF = 0x101a, 26 + PXP_STATUS_PLATFCONFIG_KF1_BAD = 0x101f, 27 + PXP_STATUS_OP_NOT_PERMITTED = 0x4013 28 + }; 29 + 30 + /* Common PXP FW message header */ 31 + struct pxp_cmd_header { 32 + u32 api_version; 33 + u32 command_id; 34 + union { 35 + u32 status; /* out */ 36 + u32 stream_id; /* in */ 37 + #define PXP_CMDHDR_EXTDATA_SESSION_VALID GENMASK(0, 0) 38 + #define PXP_CMDHDR_EXTDATA_APP_TYPE GENMASK(1, 1) 39 + #define PXP_CMDHDR_EXTDATA_SESSION_ID GENMASK(17, 2) 40 + }; 41 + /* Length of the message (excluding the header) */ 42 + u32 buffer_len; 43 + } __packed; 44 + 45 + #define PXP43_CMDID_NEW_HUC_AUTH 0x0000003F /* MTL+ */ 46 + 47 + /* PXP-Input-Packet: HUC Auth-only */ 48 + struct pxp43_new_huc_auth_in { 49 + struct pxp_cmd_header header; 50 + u64 huc_base_address; 51 + u32 huc_size; 52 + } __packed; 53 + 54 + /* PXP-Output-Packet: HUC Load and Authentication or Auth-only */ 55 + struct pxp43_huc_auth_out { 56 + struct pxp_cmd_header header; 57 + } __packed; 58 + 59 + #endif
+11 -3
drivers/gpu/drm/xe/xe_gsc.c
··· 16 16 #include "xe_gsc_submit.h" 17 17 #include "xe_gt.h" 18 18 #include "xe_gt_printk.h" 19 + #include "xe_huc.h" 19 20 #include "xe_map.h" 20 21 #include "xe_mmio.h" 21 22 #include "xe_sched_job.h" ··· 258 257 xe_force_wake_get(gt_to_fw(gt), XE_FW_GSC); 259 258 260 259 ret = gsc_upload(gsc); 261 - if (ret && ret != -EEXIST) 260 + if (ret && ret != -EEXIST) { 262 261 xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_LOAD_FAIL); 263 - else 264 - xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_TRANSFERRED); 262 + goto out; 263 + } 265 264 265 + xe_uc_fw_change_status(&gsc->fw, XE_UC_FIRMWARE_TRANSFERRED); 266 + 267 + /* HuC auth failure is not fatal */ 268 + if (xe_huc_is_authenticated(&gt->uc.huc, XE_HUC_AUTH_VIA_GUC)) 269 + xe_huc_auth(&gt->uc.huc, XE_HUC_AUTH_VIA_GSC); 270 + 271 + out: 266 272 xe_force_wake_put(gt_to_fw(gt), XE_FW_GSC); 267 273 xe_device_mem_access_put(xe); 268 274 }
+137 -4
drivers/gpu/drm/xe/xe_huc.c
··· 5 5 6 6 #include "xe_huc.h" 7 7 8 + #include <drm/drm_managed.h> 9 + 10 + #include "abi/gsc_pxp_commands_abi.h" 8 11 #include "regs/xe_gsc_regs.h" 9 12 #include "regs/xe_guc_regs.h" 10 13 #include "xe_assert.h" 11 14 #include "xe_bo.h" 12 15 #include "xe_device.h" 13 16 #include "xe_force_wake.h" 17 + #include "xe_gsc_submit.h" 14 18 #include "xe_gt.h" 15 19 #include "xe_guc.h" 20 + #include "xe_map.h" 16 21 #include "xe_mmio.h" 17 22 #include "xe_uc_fw.h" 18 23 ··· 37 32 huc_to_guc(struct xe_huc *huc) 38 33 { 39 34 return &container_of(huc, struct xe_uc, huc)->guc; 35 + } 36 + 37 + static void free_gsc_pkt(struct drm_device *drm, void *arg) 38 + { 39 + struct xe_huc *huc = arg; 40 + 41 + xe_bo_unpin_map_no_vm(huc->gsc_pkt); 42 + huc->gsc_pkt = NULL; 43 + } 44 + 45 + #define PXP43_HUC_AUTH_INOUT_SIZE SZ_4K 46 + static int huc_alloc_gsc_pkt(struct xe_huc *huc) 47 + { 48 + struct xe_gt *gt = huc_to_gt(huc); 49 + struct xe_device *xe = gt_to_xe(gt); 50 + struct xe_bo *bo; 51 + int err; 52 + 53 + /* we use a single object for both input and output */ 54 + bo = xe_bo_create_pin_map(xe, gt_to_tile(gt), NULL, 55 + PXP43_HUC_AUTH_INOUT_SIZE * 2, 56 + ttm_bo_type_kernel, 57 + XE_BO_CREATE_SYSTEM_BIT | 58 + XE_BO_CREATE_GGTT_BIT); 59 + if (IS_ERR(bo)) 60 + return PTR_ERR(bo); 61 + 62 + huc->gsc_pkt = bo; 63 + 64 + err = drmm_add_action_or_reset(&xe->drm, free_gsc_pkt, huc); 65 + if (err) { 66 + free_gsc_pkt(&xe->drm, huc); 67 + return err; 68 + } 69 + 70 + return 0; 40 71 } 41 72 42 73 int xe_huc_init(struct xe_huc *huc) ··· 97 56 if (!xe_uc_fw_is_enabled(&huc->fw)) 98 57 return 0; 99 58 59 + if (huc->fw.has_gsc_headers) { 60 + ret = huc_alloc_gsc_pkt(huc); 61 + if (ret) 62 + goto out; 63 + } 64 + 100 65 xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_LOADABLE); 101 66 102 67 return 0; ··· 119 72 return xe_uc_fw_upload(&huc->fw, 0, HUC_UKERNEL); 120 73 } 121 74 75 + #define huc_auth_msg_wr(xe_, map_, offset_, field_, val_) \ 76 + xe_map_wr_field(xe_, map_, offset_, struct pxp43_new_huc_auth_in, field_, val_) 77 + #define huc_auth_msg_rd(xe_, map_, offset_, field_) \ 78 + xe_map_rd_field(xe_, map_, offset_, struct pxp43_huc_auth_out, field_) 79 + 80 + static u32 huc_emit_pxp_auth_msg(struct xe_device *xe, struct iosys_map *map, 81 + u32 wr_offset, u32 huc_offset, u32 huc_size) 82 + { 83 + xe_map_memset(xe, map, wr_offset, 0, sizeof(struct pxp43_new_huc_auth_in)); 84 + 85 + huc_auth_msg_wr(xe, map, wr_offset, header.api_version, PXP_APIVER(4, 3)); 86 + huc_auth_msg_wr(xe, map, wr_offset, header.command_id, PXP43_CMDID_NEW_HUC_AUTH); 87 + huc_auth_msg_wr(xe, map, wr_offset, header.status, 0); 88 + huc_auth_msg_wr(xe, map, wr_offset, header.buffer_len, 89 + sizeof(struct pxp43_new_huc_auth_in) - sizeof(struct pxp_cmd_header)); 90 + huc_auth_msg_wr(xe, map, wr_offset, huc_base_address, huc_offset); 91 + huc_auth_msg_wr(xe, map, wr_offset, huc_size, huc_size); 92 + 93 + return wr_offset + sizeof(struct pxp43_new_huc_auth_in); 94 + } 95 + 96 + static int huc_auth_via_gsccs(struct xe_huc *huc) 97 + { 98 + struct xe_gt *gt = huc_to_gt(huc); 99 + struct xe_device *xe = gt_to_xe(gt); 100 + struct xe_bo *pkt = huc->gsc_pkt; 101 + u32 wr_offset; 102 + u32 rd_offset; 103 + u64 ggtt_offset; 104 + u32 out_status; 105 + int retry = 5; 106 + int err = 0; 107 + 108 + if (!pkt) 109 + return -ENODEV; 110 + 111 + ggtt_offset = xe_bo_ggtt_addr(pkt); 112 + 113 + wr_offset = xe_gsc_emit_header(xe, &pkt->vmap, 0, HECI_MEADDRESS_PXP, 0, 114 + sizeof(struct pxp43_new_huc_auth_in)); 115 + wr_offset = huc_emit_pxp_auth_msg(xe, &pkt->vmap, wr_offset, 116 + xe_bo_ggtt_addr(huc->fw.bo), 117 + huc->fw.bo->size); 118 + do { 119 + err = xe_gsc_pkt_submit_kernel(&gt->uc.gsc, ggtt_offset, wr_offset, 120 + ggtt_offset + PXP43_HUC_AUTH_INOUT_SIZE, 121 + PXP43_HUC_AUTH_INOUT_SIZE); 122 + if (err) 123 + break; 124 + 125 + if (xe_gsc_check_and_update_pending(xe, &pkt->vmap, 0, &pkt->vmap, 126 + PXP43_HUC_AUTH_INOUT_SIZE)) { 127 + err = -EBUSY; 128 + msleep(50); 129 + } 130 + } while (--retry && err == -EBUSY); 131 + 132 + if (err) { 133 + drm_err(&xe->drm, "failed to submit GSC request to auth: %d\n", err); 134 + return err; 135 + } 136 + 137 + err = xe_gsc_read_out_header(xe, &pkt->vmap, PXP43_HUC_AUTH_INOUT_SIZE, 138 + sizeof(struct pxp43_huc_auth_out), &rd_offset); 139 + if (err) { 140 + drm_err(&xe->drm, "HuC: invalid GSC reply for auth (err=%d)\n", err); 141 + return err; 142 + } 143 + 144 + /* 145 + * The GSC will return PXP_STATUS_OP_NOT_PERMITTED if the HuC is already 146 + * authenticated. If the same error is ever returned with HuC not loaded 147 + * we'll still catch it when we check the authentication bit later. 148 + */ 149 + out_status = huc_auth_msg_rd(xe, &pkt->vmap, rd_offset, header.status); 150 + if (out_status != PXP_STATUS_SUCCESS && out_status != PXP_STATUS_OP_NOT_PERMITTED) { 151 + drm_err(&xe->drm, "auth failed with GSC error = 0x%x\n", out_status); 152 + return -EIO; 153 + } 154 + 155 + return 0; 156 + } 157 + 122 158 static const struct { 123 159 const char *name; 124 160 struct xe_reg reg; ··· 215 85 HECI1_FWSTS5_HUC_AUTH_DONE }, 216 86 }; 217 87 218 - static bool huc_is_authenticated(struct xe_gt *gt, enum xe_huc_auth_types type) 88 + bool xe_huc_is_authenticated(struct xe_huc *huc, enum xe_huc_auth_types type) 219 89 { 90 + struct xe_gt *gt = huc_to_gt(huc); 91 + 220 92 return xe_mmio_read32(gt, huc_auth_modes[type].reg) & huc_auth_modes[type].val; 221 93 } 222 94 ··· 232 100 if (!xe_uc_fw_is_loadable(&huc->fw)) 233 101 return 0; 234 102 235 - xe_assert(xe, !xe_uc_fw_is_running(&huc->fw)); 236 - 237 103 /* On newer platforms the HuC survives reset, so no need to re-auth */ 238 - if (huc_is_authenticated(gt, type)) { 104 + if (xe_huc_is_authenticated(huc, type)) { 239 105 xe_uc_fw_change_status(&huc->fw, XE_UC_FIRMWARE_RUNNING); 240 106 return 0; 241 107 } ··· 245 115 case XE_HUC_AUTH_VIA_GUC: 246 116 ret = xe_guc_auth_huc(guc, xe_bo_ggtt_addr(huc->fw.bo) + 247 117 xe_uc_fw_rsa_offset(&huc->fw)); 118 + break; 119 + case XE_HUC_AUTH_VIA_GSC: 120 + ret = huc_auth_via_gsccs(huc); 248 121 break; 249 122 default: 250 123 XE_WARN_ON(type);
+1
drivers/gpu/drm/xe/xe_huc.h
··· 19 19 int xe_huc_init(struct xe_huc *huc); 20 20 int xe_huc_upload(struct xe_huc *huc); 21 21 int xe_huc_auth(struct xe_huc *huc, enum xe_huc_auth_types type); 22 + bool xe_huc_is_authenticated(struct xe_huc *huc, enum xe_huc_auth_types type); 22 23 void xe_huc_sanitize(struct xe_huc *huc); 23 24 void xe_huc_print_info(struct xe_huc *huc, struct drm_printer *p); 24 25
+5
drivers/gpu/drm/xe/xe_huc_types.h
··· 8 8 9 9 #include "xe_uc_fw_types.h" 10 10 11 + struct xe_bo; 12 + 11 13 /** 12 14 * struct xe_huc - HuC 13 15 */ 14 16 struct xe_huc { 15 17 /** @fw: Generic uC firmware management */ 16 18 struct xe_uc_fw fw; 19 + 20 + /** @gsc_pkt: bo to store the packet for auth via GSC */ 21 + struct xe_bo *gsc_pkt; 17 22 }; 18 23 19 24 #endif
+2
drivers/gpu/drm/xe/xe_uc_fw.c
··· 528 528 uc_fw->css_offset = offset; 529 529 } 530 530 531 + uc_fw->has_gsc_headers = true; 532 + 531 533 return 0; 532 534 } 533 535
+3
drivers/gpu/drm/xe/xe_uc_fw_types.h
··· 112 112 /** @bo: XE BO for uC firmware */ 113 113 struct xe_bo *bo; 114 114 115 + /** @has_gsc_headers: whether the FW image starts with GSC headers */ 116 + bool has_gsc_headers; 117 + 115 118 /* 116 119 * The firmware build process will generate a version header file with 117 120 * major and minor version defined. The versions are built into CSS