[Nouveau] [PATCH 7/8] secboot: add low-secure firmware hooks

Alexandre Courbot acourbot at nvidia.com
Tue Oct 11 06:45:52 UTC 2016


Secure firmwares provided by NVIDIA will follow the same overall
principle, but may slightly differ in format, or not use the same
bootloader descriptor even on the same chip. In order to handle
this as gracefully as possible, turn the LS firmware functions into
hooks that can be overloaded as needed.

The current hooks cover the external firmware loading as well as the
bootloader descriptor generation.

Signed-off-by: Alexandre Courbot <acourbot at nvidia.com>
---
 drm/nouveau/nvkm/subdev/secboot/acr_v1.c       | 243 ++++---------------------
 drm/nouveau/nvkm/subdev/secboot/acr_v1.h       | 210 +++++++++++++++++++++
 drm/nouveau/nvkm/subdev/secboot/acr_v1_gm20b.c |  31 +++-
 3 files changed, 279 insertions(+), 205 deletions(-)

diff --git a/drm/nouveau/nvkm/subdev/secboot/acr_v1.c b/drm/nouveau/nvkm/subdev/secboot/acr_v1.c
index db0fb3338398..68bb3113fd23 100644
--- a/drm/nouveau/nvkm/subdev/secboot/acr_v1.c
+++ b/drm/nouveau/nvkm/subdev/secboot/acr_v1.c
@@ -70,175 +70,6 @@ struct fw_bl_desc {
 };
 
 
-/*
- *
- * LS blob structures
- *
- */
-
-/**
- * struct lsf_ucode_desc - LS falcon signatures
- * @prd_keys:		signature to use when the GPU is in production mode
- * @dgb_keys:		signature to use when the GPU is in debug mode
- * @b_prd_present:	whether the production key is present
- * @b_dgb_present:	whether the debug key is present
- * @falcon_id:		ID of the falcon the ucode applies to
- *
- * Directly loaded from a signature file.
- */
-struct lsf_ucode_desc {
-	u8  prd_keys[2][16];
-	u8  dbg_keys[2][16];
-	u32 b_prd_present;
-	u32 b_dbg_present;
-	u32 falcon_id;
-};
-
-/**
- * struct lsf_lsb_header - LS firmware header
- * @signature:		signature to verify the firmware against
- * @ucode_off:		offset of the ucode blob in the WPR region. The ucode
- *                      blob contains the bootloader, code and data of the
- *                      LS falcon
- * @ucode_size:		size of the ucode blob, including bootloader
- * @data_size:		size of the ucode blob data
- * @bl_code_size:	size of the bootloader code
- * @bl_imem_off:	offset in imem of the bootloader
- * @bl_data_off:	offset of the bootloader data in WPR region
- * @bl_data_size:	size of the bootloader data
- * @app_code_off:	offset of the app code relative to ucode_off
- * @app_code_size:	size of the app code
- * @app_data_off:	offset of the app data relative to ucode_off
- * @app_data_size:	size of the app data
- * @flags:		flags for the secure bootloader
- *
- * This structure is written into the WPR region for each managed falcon. Each
- * instance is referenced by the lsb_offset member of the corresponding
- * lsf_wpr_header.
- */
-struct lsf_lsb_header {
-	struct lsf_ucode_desc signature;
-	u32 ucode_off;
-	u32 ucode_size;
-	u32 data_size;
-	u32 bl_code_size;
-	u32 bl_imem_off;
-	u32 bl_data_off;
-	u32 bl_data_size;
-	u32 app_code_off;
-	u32 app_code_size;
-	u32 app_data_off;
-	u32 app_data_size;
-	u32 flags;
-#define LSF_FLAG_LOAD_CODE_AT_0		1
-#define LSF_FLAG_DMACTL_REQ_CTX		4
-#define LSF_FLAG_FORCE_PRIV_LOAD	8
-};
-
-/**
- * struct lsf_wpr_header - LS blob WPR Header
- * @falcon_id:		LS falcon ID
- * @lsb_offset:		offset of the lsb_lsf_header in the WPR region
- * @bootstrap_owner:	secure falcon reponsible for bootstrapping the LS falcon
- * @lazy_bootstrap:	skip bootstrapping by ACR
- * @status:		bootstrapping status
- *
- * An array of these is written at the beginning of the WPR region, one for
- * each managed falcon. The array is terminated by an instance which falcon_id
- * is LSF_FALCON_ID_INVALID.
- */
-struct lsf_wpr_header {
-	u32  falcon_id;
-	u32  lsb_offset;
-	u32  bootstrap_owner;
-	u32  lazy_bootstrap;
-	u32  status;
-#define LSF_IMAGE_STATUS_NONE				0
-#define LSF_IMAGE_STATUS_COPY				1
-#define LSF_IMAGE_STATUS_VALIDATION_CODE_FAILED		2
-#define LSF_IMAGE_STATUS_VALIDATION_DATA_FAILED		3
-#define LSF_IMAGE_STATUS_VALIDATION_DONE		4
-#define LSF_IMAGE_STATUS_VALIDATION_SKIPPED		5
-#define LSF_IMAGE_STATUS_BOOTSTRAP_READY		6
-};
-
-
-/**
- * struct ls_ucode_img_desc - descriptor of firmware image
- * @descriptor_size:		size of this descriptor
- * @image_size:			size of the whole image
- * @bootloader_start_offset:	start offset of the bootloader in ucode image
- * @bootloader_size:		size of the bootloader
- * @bootloader_imem_offset:	start off set of the bootloader in IMEM
- * @bootloader_entry_point:	entry point of the bootloader in IMEM
- * @app_start_offset:		start offset of the LS firmware
- * @app_size:			size of the LS firmware's code and data
- * @app_imem_offset:		offset of the app in IMEM
- * @app_imem_entry:		entry point of the app in IMEM
- * @app_dmem_offset:		offset of the data in DMEM
- * @app_resident_code_offset:	offset of app code from app_start_offset
- * @app_resident_code_size:	size of the code
- * @app_resident_data_offset:	offset of data from app_start_offset
- * @app_resident_data_size:	size of data
- *
- * A firmware image contains the code, data, and bootloader of a given LS
- * falcon in a single blob. This structure describes where everything is.
- *
- * This can be generated from a (bootloader, code, data) set if they have
- * been loaded separately, or come directly from a file.
- */
-struct ls_ucode_img_desc {
-	u32 descriptor_size;
-	u32 image_size;
-	u32 tools_version;
-	u32 app_version;
-	char date[64];
-	u32 bootloader_start_offset;
-	u32 bootloader_size;
-	u32 bootloader_imem_offset;
-	u32 bootloader_entry_point;
-	u32 app_start_offset;
-	u32 app_size;
-	u32 app_imem_offset;
-	u32 app_imem_entry;
-	u32 app_dmem_offset;
-	u32 app_resident_code_offset;
-	u32 app_resident_code_size;
-	u32 app_resident_data_offset;
-	u32 app_resident_data_size;
-	u32 nb_overlays;
-	struct {u32 start; u32 size; } load_ovl[64];
-	u32 compressed;
-};
-
-/**
- * struct ls_ucode_img - temporary storage for loaded LS firmwares
- * @node:		to link within lsf_ucode_mgr
- * @falcon_id:		ID of the falcon this LS firmware is for
- * @ucode_desc:		loaded or generated map of ucode_data
- * @ucode_header:	header of the firmware
- * @ucode_data:		firmware payload (code and data)
- * @ucode_size:		size in bytes of data in ucode_data
- * @wpr_header:		WPR header to be written to the LS blob
- * @lsb_header:		LSB header to be written to the LS blob
- *
- * Preparing the WPR LS blob requires information about all the LS firmwares
- * (size, etc) to be known. This structure contains all the data of one LS
- * firmware.
- */
-struct ls_ucode_img {
-	struct list_head node;
-	enum nvkm_falconidx falcon_id;
-
-	struct ls_ucode_img_desc ucode_desc;
-	u32 *ucode_header;
-	u8 *ucode_data;
-	u32 ucode_size;
-
-	struct lsf_wpr_header wpr_header;
-	struct lsf_lsb_header lsb_header;
-};
-
 /**
  * struct ls_ucode_mgr - manager for all LS falcon firmwares
  * @count:	number of managed LS falcons
@@ -340,12 +171,6 @@ struct hsflcn_acr_desc {
 	} vpr_desc;
 };
 
-
-static inline u64 flcn64_to_u64(const struct flcn_u64 f)
-{
-	return ((u64)f.hi) << 32 | f.lo;
-}
-
 /**
  * Convenience function to duplicate a firmware file in memory and check that
  * it has the required minimum size.
@@ -507,16 +332,14 @@ error:
 
 typedef int (*lsf_load_func)(const struct nvkm_subdev *, struct ls_ucode_img *);
 
-static int
-ls_ucode_img_load_fecs(const struct nvkm_subdev *subdev,
-		       struct ls_ucode_img *img)
+int
+acr_v1_ls_load_fecs(const struct nvkm_subdev *subdev, struct ls_ucode_img *img)
 {
 	return ls_ucode_img_load_generic(subdev, img, "fecs", NVKM_FALCON_FECS);
 }
 
-static int
-ls_ucode_img_load_gpccs(const struct nvkm_subdev *subdev,
-			struct ls_ucode_img *img)
+int
+acr_v1_ls_load_gpccs(const struct nvkm_subdev *subdev, struct ls_ucode_img *img)
 {
 	return ls_ucode_img_load_generic(subdev, img, "gpccs",
 					 NVKM_FALCON_GPCCS);
@@ -544,14 +367,8 @@ ls_ucode_img_load(const struct nvkm_subdev *subdev, lsf_load_func load_func)
 	return img;
 }
 
-static const lsf_load_func lsf_load_funcs[] = {
-	[NVKM_FALCON_END] = NULL, /* reserve enough space */
-	[NVKM_FALCON_FECS] = ls_ucode_img_load_fecs,
-	[NVKM_FALCON_GPCCS] = ls_ucode_img_load_gpccs,
-};
-
 /**
- * ls_ucode_img_populate_bl_desc() - populate a DMEM BL descriptor for LS image
+ * acr_v1_ls_generic_bl_desc() - populate a generic BL descriptor for LS image
  * @img:	ucode image to generate against
  * @desc:	descriptor to populate
  * @sb:		secure boot state to use for base addresses
@@ -561,10 +378,11 @@ static const lsf_load_func lsf_load_funcs[] = {
  *
  */
 static void
-ls_ucode_img_populate_bl_desc(struct ls_ucode_img *img, u64 wpr_addr,
-			      struct acr_v1_bl_desc *desc)
+acr_v1_ls_generic_bl_desc(const struct ls_ucode_img *img, u64 wpr_addr,
+			  void *_desc)
 {
-	struct ls_ucode_img_desc *pdesc = &img->ucode_desc;
+	struct acr_v1_bl_desc *desc = _desc;
+	const struct ls_ucode_img_desc *pdesc = &img->ucode_desc;
 	u64 addr_base;
 
 	addr_base = wpr_addr + img->lsb_header.ucode_off +
@@ -573,14 +391,14 @@ ls_ucode_img_populate_bl_desc(struct ls_ucode_img *img, u64 wpr_addr,
 	memset(desc, 0, sizeof(*desc));
 	desc->ctx_dma = FALCON_DMAIDX_UCODE;
 	desc->code_dma_base.lo = lower_32_bits(
-		(addr_base + pdesc->app_resident_code_offset));
+				 (addr_base + pdesc->app_resident_code_offset));
 	desc->code_dma_base.hi = upper_32_bits(
-		(addr_base + pdesc->app_resident_code_offset));
+				 (addr_base + pdesc->app_resident_code_offset));
 	desc->non_sec_code_size = pdesc->app_resident_code_size;
 	desc->data_dma_base.lo = lower_32_bits(
-		(addr_base + pdesc->app_resident_data_offset));
+				 (addr_base + pdesc->app_resident_data_offset));
 	desc->data_dma_base.hi = upper_32_bits(
-		(addr_base + pdesc->app_resident_data_offset));
+				 (addr_base + pdesc->app_resident_data_offset));
 	desc->data_size = pdesc->app_resident_data_size;
 	desc->code_entry_point = pdesc->app_imem_entry;
 }
@@ -609,6 +427,8 @@ ls_ucode_img_fill_headers(struct nvkm_acr_v1 *acr, struct ls_ucode_img *img,
 	struct lsf_wpr_header *whdr = &img->wpr_header;
 	struct lsf_lsb_header *lhdr = &img->lsb_header;
 	struct ls_ucode_img_desc *desc = &img->ucode_desc;
+	const struct nvkm_acr_v1_ls_single_func *func =
+						(*acr->ls_func)[img->falcon_id];
 
 	if (img->ucode_header) {
 		nvkm_fatal(acr->base.subdev,
@@ -669,9 +489,8 @@ ls_ucode_img_fill_headers(struct nvkm_acr_v1 *acr, struct ls_ucode_img *img,
 	if (img->falcon_id == NVKM_FALCON_GPCCS)
 		lhdr->flags |= LSF_FLAG_FORCE_PRIV_LOAD;
 
-	/* Align (size bloat) and save off BL descriptor size */
-	lhdr->bl_data_size = ALIGN(sizeof(struct acr_v1_bl_desc),
-				   LSF_BL_DATA_SIZE_ALIGN);
+	/* Align and save off BL descriptor size */
+	lhdr->bl_data_size = ALIGN(func->bl_desc_size, LSF_BL_DATA_SIZE_ALIGN);
 	/*
 	 * Align, save off, and include the additional BL data
 	 */
@@ -757,14 +576,14 @@ ls_ucode_mgr_write_wpr(struct nvkm_acr_v1 *acr, struct ls_ucode_mgr *mgr,
 
 		/* Generate and write BL descriptor */
 		if (!img->ucode_header) {
-			u8 desc[acr->func->bl_desc_size];
-			struct acr_v1_bl_desc gdesc;
+			const struct nvkm_acr_v1_ls_single_func *ls_func =
+				(*acr->ls_func)[img->falcon_id];
+			u8 gdesc[ls_func->bl_desc_size];
 
-			ls_ucode_img_populate_bl_desc(img, wpr_addr, &gdesc);
-			acr->func->generate_bl_desc(&gdesc, &desc);
+			ls_func->generate_bl_desc(img, wpr_addr, &gdesc);
 			nvkm_gpuobj_memcpy_to(wpr_blob,
 					      img->lsb_header.bl_data_off,
-					      &desc, acr->func->bl_desc_size);
+					      &gdesc, ls_func->bl_desc_size);
 		}
 
 		/* Copy ucode */
@@ -809,7 +628,8 @@ acr_v1_prepare_ls_blob(struct nvkm_acr_v1 *acr, u64 wpr_addr, u32 wpr_size)
 	for_each_set_bit(falcon_id, &managed_falcons, NVKM_FALCON_END) {
 		struct ls_ucode_img *img;
 
-		img = ls_ucode_img_load(subdev, lsf_load_funcs[falcon_id]);
+		img = ls_ucode_img_load(subdev,
+					(*acr->ls_func)[falcon_id]->load);
 		if (IS_ERR(img)) {
 			ret = PTR_ERR(img);
 			goto cleanup;
@@ -1265,6 +1085,20 @@ gm200_acr_v1_func = {
 	.generate_bl_desc = acr_v1_generate_bl_desc,
 };
 
+static const nvkm_acr_v1_ls_func
+acr_v1_ls_func = {
+	[NVKM_FALCON_FECS] = &(struct nvkm_acr_v1_ls_single_func) {
+		.load = acr_v1_ls_load_fecs,
+		.generate_bl_desc = acr_v1_ls_generic_bl_desc,
+		.bl_desc_size = sizeof(struct acr_v1_bl_desc),
+	},
+	[NVKM_FALCON_GPCCS] = &(struct nvkm_acr_v1_ls_single_func) {
+		.load = acr_v1_ls_load_gpccs,
+		.generate_bl_desc = acr_v1_ls_generic_bl_desc,
+		.bl_desc_size = sizeof(struct acr_v1_bl_desc),
+	},
+};
+
 static const struct nvkm_acr_func
 acr_v1_func = {
 	.managed_falcons = BIT(NVKM_FALCON_FECS) |
@@ -1288,6 +1122,7 @@ nvkm_acr_v1_new(void)
 
 	acr->base.func = &acr_v1_func;
 	acr->func = &gm200_acr_v1_func;
+	acr->ls_func = &acr_v1_ls_func;
 
 	return &acr->base;
 }
diff --git a/drm/nouveau/nvkm/subdev/secboot/acr_v1.h b/drm/nouveau/nvkm/subdev/secboot/acr_v1.h
index ac1273ce92f4..a3111c1ed9fb 100644
--- a/drm/nouveau/nvkm/subdev/secboot/acr_v1.h
+++ b/drm/nouveau/nvkm/subdev/secboot/acr_v1.h
@@ -25,11 +25,29 @@
 
 #include "acr.h"
 
+/**
+ * struct flcn_u64 - u64 ordered to be read by a falcon.
+ */
 struct flcn_u64 {
 	u32 lo;
 	u32 hi;
 };
 
+static inline u64 flcn64_to_u64(const struct flcn_u64 f)
+{
+	return ((u64)f.hi) << 32 | f.lo;
+}
+
+static inline struct flcn_u64 u64_to_flcn64(const u64 u)
+{
+	struct flcn_u64 ret = {
+		.hi = upper_32_bits(u),
+		.lo = lower_32_bits(u),
+	};
+
+	return ret;
+}
+
 /**
  * struct acr_v1_bl_desc - DMEM bootloader descriptor
  * @signature:		16B signature for secure code. 0s if no secure code
@@ -67,6 +85,174 @@ struct acr_v1_bl_desc {
 	u32 data_size;
 };
 
+/*
+ *
+ * LS blob structures
+ *
+ */
+
+/**
+ * struct lsf_ucode_desc - LS falcon signatures
+ * @prd_keys:		signature to use when the GPU is in production mode
+ * @dgb_keys:		signature to use when the GPU is in debug mode
+ * @b_prd_present:	whether the production key is present
+ * @b_dgb_present:	whether the debug key is present
+ * @falcon_id:		ID of the falcon the ucode applies to
+ *
+ * Directly loaded from a signature file.
+ */
+struct lsf_ucode_desc {
+	u8  prd_keys[2][16];
+	u8  dbg_keys[2][16];
+	u32 b_prd_present;
+	u32 b_dbg_present;
+	u32 falcon_id;
+};
+
+/**
+ * struct lsf_lsb_header - LS firmware header
+ * @signature:		signature to verify the firmware against
+ * @ucode_off:		offset of the ucode blob in the WPR region. The ucode
+ *                      blob contains the bootloader, code and data of the
+ *                      LS falcon
+ * @ucode_size:		size of the ucode blob, including bootloader
+ * @data_size:		size of the ucode blob data
+ * @bl_code_size:	size of the bootloader code
+ * @bl_imem_off:	offset in imem of the bootloader
+ * @bl_data_off:	offset of the bootloader data in WPR region
+ * @bl_data_size:	size of the bootloader data
+ * @app_code_off:	offset of the app code relative to ucode_off
+ * @app_code_size:	size of the app code
+ * @app_data_off:	offset of the app data relative to ucode_off
+ * @app_data_size:	size of the app data
+ * @flags:		flags for the secure bootloader
+ *
+ * This structure is written into the WPR region for each managed falcon. Each
+ * instance is referenced by the lsb_offset member of the corresponding
+ * lsf_wpr_header.
+ */
+struct lsf_lsb_header {
+	struct lsf_ucode_desc signature;
+	u32 ucode_off;
+	u32 ucode_size;
+	u32 data_size;
+	u32 bl_code_size;
+	u32 bl_imem_off;
+	u32 bl_data_off;
+	u32 bl_data_size;
+	u32 app_code_off;
+	u32 app_code_size;
+	u32 app_data_off;
+	u32 app_data_size;
+	u32 flags;
+#define LSF_FLAG_LOAD_CODE_AT_0		1
+#define LSF_FLAG_DMACTL_REQ_CTX		4
+#define LSF_FLAG_FORCE_PRIV_LOAD	8
+};
+
+/**
+ * struct lsf_wpr_header - LS blob WPR Header
+ * @falcon_id:		LS falcon ID
+ * @lsb_offset:		offset of the lsb_lsf_header in the WPR region
+ * @bootstrap_owner:	secure falcon reponsible for bootstrapping the LS falcon
+ * @lazy_bootstrap:	skip bootstrapping by ACR
+ * @status:		bootstrapping status
+ *
+ * An array of these is written at the beginning of the WPR region, one for
+ * each managed falcon. The array is terminated by an instance which falcon_id
+ * is LSF_FALCON_ID_INVALID.
+ */
+struct lsf_wpr_header {
+	u32  falcon_id;
+	u32  lsb_offset;
+	u32  bootstrap_owner;
+	u32  lazy_bootstrap;
+	u32  status;
+#define LSF_IMAGE_STATUS_NONE				0
+#define LSF_IMAGE_STATUS_COPY				1
+#define LSF_IMAGE_STATUS_VALIDATION_CODE_FAILED		2
+#define LSF_IMAGE_STATUS_VALIDATION_DATA_FAILED		3
+#define LSF_IMAGE_STATUS_VALIDATION_DONE		4
+#define LSF_IMAGE_STATUS_VALIDATION_SKIPPED		5
+#define LSF_IMAGE_STATUS_BOOTSTRAP_READY		6
+};
+
+
+/**
+ * struct ls_ucode_img_desc - descriptor of firmware image
+ * @descriptor_size:		size of this descriptor
+ * @image_size:			size of the whole image
+ * @bootloader_start_offset:	start offset of the bootloader in ucode image
+ * @bootloader_size:		size of the bootloader
+ * @bootloader_imem_offset:	start off set of the bootloader in IMEM
+ * @bootloader_entry_point:	entry point of the bootloader in IMEM
+ * @app_start_offset:		start offset of the LS firmware
+ * @app_size:			size of the LS firmware's code and data
+ * @app_imem_offset:		offset of the app in IMEM
+ * @app_imem_entry:		entry point of the app in IMEM
+ * @app_dmem_offset:		offset of the data in DMEM
+ * @app_resident_code_offset:	offset of app code from app_start_offset
+ * @app_resident_code_size:	size of the code
+ * @app_resident_data_offset:	offset of data from app_start_offset
+ * @app_resident_data_size:	size of data
+ *
+ * A firmware image contains the code, data, and bootloader of a given LS
+ * falcon in a single blob. This structure describes where everything is.
+ *
+ * This can be generated from a (bootloader, code, data) set if they have
+ * been loaded separately, or come directly from a file.
+ */
+struct ls_ucode_img_desc {
+	u32 descriptor_size;
+	u32 image_size;
+	u32 tools_version;
+	u32 app_version;
+	char date[64];
+	u32 bootloader_start_offset;
+	u32 bootloader_size;
+	u32 bootloader_imem_offset;
+	u32 bootloader_entry_point;
+	u32 app_start_offset;
+	u32 app_size;
+	u32 app_imem_offset;
+	u32 app_imem_entry;
+	u32 app_dmem_offset;
+	u32 app_resident_code_offset;
+	u32 app_resident_code_size;
+	u32 app_resident_data_offset;
+	u32 app_resident_data_size;
+	u32 nb_overlays;
+	struct {u32 start; u32 size; } load_ovl[64];
+	u32 compressed;
+};
+
+/**
+ * struct ls_ucode_img - temporary storage for loaded LS firmwares
+ * @node:		to link within lsf_ucode_mgr
+ * @falcon_id:		ID of the falcon this LS firmware is for
+ * @ucode_desc:		loaded or generated map of ucode_data
+ * @ucode_header:	header of the firmware
+ * @ucode_data:		firmware payload (code and data)
+ * @ucode_size:		size in bytes of data in ucode_data
+ * @wpr_header:		WPR header to be written to the LS blob
+ * @lsb_header:		LSB header to be written to the LS blob
+ *
+ * Preparing the WPR LS blob requires information about all the LS firmwares
+ * (size, etc) to be known. This structure contains all the data of one LS
+ * firmware.
+ */
+struct ls_ucode_img {
+	struct list_head node;
+	enum nvkm_falconidx falcon_id;
+
+	struct ls_ucode_img_desc ucode_desc;
+	u32 *ucode_header;
+	u8 *ucode_data;
+	u32 ucode_size;
+
+	struct lsf_wpr_header wpr_header;
+	struct lsf_lsb_header lsb_header;
+};
 
 /**
  * struct nvkm_acr_v1_func - manages nuances between ACR v1 instances
@@ -81,6 +267,29 @@ struct nvkm_acr_v1_func {
 };
 
 /**
+ * struct nvkm_acr_v1_ls_single_func - manages a single LS firmware
+ *
+ * @load:	load the external firmware into a ls_ucode_img
+ * @generate_bl_desc: function called on a block of bl_desc_size to generate the
+ *		   proper bootloader descriptor for this LS firmware
+ * @bl_desc_size: size of the bootloader descriptor
+ */
+struct nvkm_acr_v1_ls_single_func {
+	int (*load)(const struct nvkm_subdev *, struct ls_ucode_img *);
+	void (*generate_bl_desc)(const struct ls_ucode_img *, u64, void *);
+	u32 bl_desc_size;
+};
+
+/**
+ * typedef nvkm_acr_v1_ls_func - manages all the LS firmwares for this ACR
+ */
+typedef const struct nvkm_acr_v1_ls_single_func *
+nvkm_acr_v1_ls_func[NVKM_FALCON_END];
+
+int acr_v1_ls_load_fecs(const struct nvkm_subdev *, struct ls_ucode_img *);
+int acr_v1_ls_load_gpccs(const struct nvkm_subdev *, struct ls_ucode_img *);
+
+/**
  * struct nvkm_acr_v1 - version 1 of the ACR
  *
  * ACR v1 performs a very basic form of secure boot. It is only capable of
@@ -95,6 +304,7 @@ struct nvkm_acr_v1_func {
 struct nvkm_acr_v1 {
 	struct nvkm_acr base;
 	const struct nvkm_acr_v1_func *func;
+	const nvkm_acr_v1_ls_func *ls_func;
 
 	/*
 	 * HS FW - lock WPR region (dGPU only) and load LS FWs
diff --git a/drm/nouveau/nvkm/subdev/secboot/acr_v1_gm20b.c b/drm/nouveau/nvkm/subdev/secboot/acr_v1_gm20b.c
index fcf644b9656c..1062d4f6a1ff 100644
--- a/drm/nouveau/nvkm/subdev/secboot/acr_v1_gm20b.c
+++ b/drm/nouveau/nvkm/subdev/secboot/acr_v1_gm20b.c
@@ -26,7 +26,7 @@
 
 /*
  * The BL header format used by GM20B's firmware is slightly different
- * from the one of GM200. Fix the differences here.
+ * from the one of GM200. Handle the differences here.
  */
 struct acr_v1_gm20b_bl_desc {
 	u32 reserved[4];
@@ -73,6 +73,25 @@ gm20b_acr_v1_generate_bl_desc(const struct acr_v1_bl_desc *desc, void *ret)
 	gdesc->data_size = desc->data_size;
 }
 
+static void
+acr_v1_gm20b_ls_generic_bl_desc(const struct ls_ucode_img *img, u64 wpr_addr,
+				void *_desc)
+{
+	struct acr_v1_gm20b_bl_desc *desc = _desc;
+	const struct ls_ucode_img_desc *pdesc = &img->ucode_desc;
+	u64 base;
+
+	base = wpr_addr + img->lsb_header.ucode_off + pdesc->app_start_offset;
+
+	memset(desc, 0, sizeof(*desc));
+	desc->ctx_dma = FALCON_DMAIDX_UCODE;
+	desc->code_dma_base = (base + pdesc->app_resident_code_offset) >> 8;
+	desc->non_sec_code_size = pdesc->app_resident_code_size;
+	desc->data_dma_base = (base + pdesc->app_resident_data_offset) >> 8;
+	desc->data_size = pdesc->app_resident_data_size;
+	desc->code_entry_point = pdesc->app_imem_entry;
+}
+
 static const struct nvkm_acr_v1_func
 gm20b_acr_v1_func = {
 	.bl_desc_size = sizeof(struct acr_v1_gm20b_bl_desc),
@@ -90,6 +109,15 @@ gm20b_acr_func = {
 	.start = acr_v1_start,
 };
 
+static const nvkm_acr_v1_ls_func
+gm20b_acr_v1_ls_func = {
+	[NVKM_FALCON_FECS] = &(struct nvkm_acr_v1_ls_single_func) {
+		.load = acr_v1_ls_load_fecs,
+		.generate_bl_desc = acr_v1_gm20b_ls_generic_bl_desc,
+		.bl_desc_size = sizeof(struct acr_v1_gm20b_bl_desc),
+	},
+};
+
 struct nvkm_acr *
 nvkm_acr_v1_gm20b_new(void)
 {
@@ -101,6 +129,7 @@ nvkm_acr_v1_gm20b_new(void)
 
 	acr->base.func = &gm20b_acr_func;
 	acr->func = &gm20b_acr_v1_func;
+	acr->ls_func = &gm20b_acr_v1_ls_func;
 
 	return &acr->base;
 }
-- 
2.10.0



More information about the Nouveau mailing list