drm/nouveau/secboot: abstract LS firmware loading functions
The WPR and LSB headers, used to generate the LS blob, may have a different layout and sizes depending on the driver version they come from. Abstract them and confine their use to driver-specific code. Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Signed-off-by: Ben Skeggs <bskeggs@redhat.com>
This commit is contained in:
parent
9839307cfe
commit
9d896f3e41
@ -21,7 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "acr_r352.h"
|
#include "acr_r352.h"
|
||||||
#include "ls_ucode.h"
|
|
||||||
|
|
||||||
#include <core/gpuobj.h>
|
#include <core/gpuobj.h>
|
||||||
#include <core/firmware.h>
|
#include <core/firmware.h>
|
||||||
@ -94,11 +93,12 @@ struct acr_r352_flcn_bl_desc {
|
|||||||
*/
|
*/
|
||||||
static void
|
static void
|
||||||
acr_r352_generate_flcn_bl_desc(const struct nvkm_acr *acr,
|
acr_r352_generate_flcn_bl_desc(const struct nvkm_acr *acr,
|
||||||
const struct ls_ucode_img *img, u64 wpr_addr,
|
const struct ls_ucode_img *_img, u64 wpr_addr,
|
||||||
void *_desc)
|
void *_desc)
|
||||||
{
|
{
|
||||||
|
struct ls_ucode_img_r352 *img = ls_ucode_img_r352(_img);
|
||||||
struct acr_r352_flcn_bl_desc *desc = _desc;
|
struct acr_r352_flcn_bl_desc *desc = _desc;
|
||||||
const struct ls_ucode_img_desc *pdesc = &img->ucode_desc;
|
const struct ls_ucode_img_desc *pdesc = &_img->ucode_desc;
|
||||||
u64 base, addr_code, addr_data;
|
u64 base, addr_code, addr_data;
|
||||||
|
|
||||||
base = wpr_addr + img->lsb_header.ucode_off + pdesc->app_start_offset;
|
base = wpr_addr + img->lsb_header.ucode_off + pdesc->app_start_offset;
|
||||||
@ -163,29 +163,46 @@ struct hsflcn_acr_desc {
|
|||||||
* Low-secure blob creation
|
* Low-secure blob creation
|
||||||
*/
|
*/
|
||||||
|
|
||||||
typedef int (*lsf_load_func)(const struct nvkm_subdev *, struct ls_ucode_img *);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ls_ucode_img_load() - create a lsf_ucode_img and load it
|
* ls_ucode_img_load() - create a lsf_ucode_img and load it
|
||||||
*/
|
*/
|
||||||
static struct ls_ucode_img *
|
struct ls_ucode_img *
|
||||||
ls_ucode_img_load(const struct nvkm_subdev *subdev, lsf_load_func load_func)
|
acr_r352_ls_ucode_img_load(const struct acr_r352 *acr,
|
||||||
|
enum nvkm_secboot_falcon falcon_id)
|
||||||
{
|
{
|
||||||
struct ls_ucode_img *img;
|
const struct nvkm_subdev *subdev = acr->base.subdev;
|
||||||
|
struct ls_ucode_img_r352 *img;
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
img = kzalloc(sizeof(*img), GFP_KERNEL);
|
img = kzalloc(sizeof(*img), GFP_KERNEL);
|
||||||
if (!img)
|
if (!img)
|
||||||
return ERR_PTR(-ENOMEM);
|
return ERR_PTR(-ENOMEM);
|
||||||
|
|
||||||
ret = load_func(subdev, img);
|
img->base.falcon_id = falcon_id;
|
||||||
|
|
||||||
|
ret = acr->func->ls_func[falcon_id]->load(subdev, &img->base);
|
||||||
|
|
||||||
if (ret) {
|
if (ret) {
|
||||||
|
kfree(img->base.ucode_data);
|
||||||
|
kfree(img->base.sig);
|
||||||
kfree(img);
|
kfree(img);
|
||||||
return ERR_PTR(ret);
|
return ERR_PTR(ret);
|
||||||
}
|
}
|
||||||
|
|
||||||
return img;
|
/* Check that the signature size matches our expectations... */
|
||||||
|
if (img->base.sig_size != sizeof(img->lsb_header.signature)) {
|
||||||
|
nvkm_error(subdev, "invalid signature size for %s falcon!\n",
|
||||||
|
nvkm_secboot_falcon_name[falcon_id]);
|
||||||
|
return ERR_PTR(-EINVAL);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Copy signature to the right place */
|
||||||
|
memcpy(&img->lsb_header.signature, img->base.sig, img->base.sig_size);
|
||||||
|
|
||||||
|
/* not needed? the signature should already have the right value */
|
||||||
|
img->lsb_header.signature.falcon_id = falcon_id;
|
||||||
|
|
||||||
|
return &img->base;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define LSF_LSB_HEADER_ALIGN 256
|
#define LSF_LSB_HEADER_ALIGN 256
|
||||||
@ -195,7 +212,7 @@ ls_ucode_img_load(const struct nvkm_subdev *subdev, lsf_load_func load_func)
|
|||||||
#define LSF_UCODE_DATA_ALIGN 4096
|
#define LSF_UCODE_DATA_ALIGN 4096
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ls_ucode_img_fill_headers - fill the WPR and LSB headers of an image
|
* acr_r352_ls_img_fill_headers - fill the WPR and LSB headers of an image
|
||||||
* @acr: ACR to use
|
* @acr: ACR to use
|
||||||
* @img: image to generate for
|
* @img: image to generate for
|
||||||
* @offset: offset in the WPR region where this image starts
|
* @offset: offset in the WPR region where this image starts
|
||||||
@ -206,24 +223,25 @@ ls_ucode_img_load(const struct nvkm_subdev *subdev, lsf_load_func load_func)
|
|||||||
* Return: offset at the end of this image.
|
* Return: offset at the end of this image.
|
||||||
*/
|
*/
|
||||||
static u32
|
static u32
|
||||||
ls_ucode_img_fill_headers(struct acr_r352 *acr, struct ls_ucode_img *img,
|
acr_r352_ls_img_fill_headers(struct acr_r352 *acr,
|
||||||
u32 offset)
|
struct ls_ucode_img_r352 *img, u32 offset)
|
||||||
{
|
{
|
||||||
struct lsf_wpr_header *whdr = &img->wpr_header;
|
struct ls_ucode_img *_img = &img->base;
|
||||||
struct lsf_lsb_header *lhdr = &img->lsb_header;
|
struct acr_r352_lsf_wpr_header *whdr = &img->wpr_header;
|
||||||
struct ls_ucode_img_desc *desc = &img->ucode_desc;
|
struct acr_r352_lsf_lsb_header *lhdr = &img->lsb_header;
|
||||||
|
struct ls_ucode_img_desc *desc = &_img->ucode_desc;
|
||||||
const struct acr_r352_ls_func *func =
|
const struct acr_r352_ls_func *func =
|
||||||
acr->func->ls_func[img->falcon_id];
|
acr->func->ls_func[_img->falcon_id];
|
||||||
|
|
||||||
/* Fill WPR header */
|
/* Fill WPR header */
|
||||||
whdr->falcon_id = img->falcon_id;
|
whdr->falcon_id = _img->falcon_id;
|
||||||
whdr->bootstrap_owner = acr->base.boot_falcon;
|
whdr->bootstrap_owner = acr->base.boot_falcon;
|
||||||
whdr->status = LSF_IMAGE_STATUS_COPY;
|
whdr->status = LSF_IMAGE_STATUS_COPY;
|
||||||
|
|
||||||
/* Align, save off, and include an LSB header size */
|
/* Align, save off, and include an LSB header size */
|
||||||
offset = ALIGN(offset, LSF_LSB_HEADER_ALIGN);
|
offset = ALIGN(offset, LSF_LSB_HEADER_ALIGN);
|
||||||
whdr->lsb_offset = offset;
|
whdr->lsb_offset = offset;
|
||||||
offset += sizeof(struct lsf_lsb_header);
|
offset += sizeof(*lhdr);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Align, save off, and include the original (static) ucode
|
* Align, save off, and include the original (static) ucode
|
||||||
@ -231,7 +249,7 @@ ls_ucode_img_fill_headers(struct acr_r352 *acr, struct ls_ucode_img *img,
|
|||||||
*/
|
*/
|
||||||
offset = ALIGN(offset, LSF_UCODE_DATA_ALIGN);
|
offset = ALIGN(offset, LSF_UCODE_DATA_ALIGN);
|
||||||
lhdr->ucode_off = offset;
|
lhdr->ucode_off = offset;
|
||||||
offset += img->ucode_size;
|
offset += _img->ucode_size;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* For falcons that use a boot loader (BL), we append a loader
|
* For falcons that use a boot loader (BL), we append a loader
|
||||||
@ -261,7 +279,7 @@ ls_ucode_img_fill_headers(struct acr_r352 *acr, struct ls_ucode_img *img,
|
|||||||
lhdr->app_data_size = desc->app_resident_data_size;
|
lhdr->app_data_size = desc->app_resident_data_size;
|
||||||
|
|
||||||
lhdr->flags = func->lhdr_flags;
|
lhdr->flags = func->lhdr_flags;
|
||||||
if (img->falcon_id == acr->base.boot_falcon)
|
if (_img->falcon_id == acr->base.boot_falcon)
|
||||||
lhdr->flags |= LSF_FLAG_DMACTL_REQ_CTX;
|
lhdr->flags |= LSF_FLAG_DMACTL_REQ_CTX;
|
||||||
|
|
||||||
/* Align and save off BL descriptor size */
|
/* Align and save off BL descriptor size */
|
||||||
@ -280,10 +298,10 @@ ls_ucode_img_fill_headers(struct acr_r352 *acr, struct ls_ucode_img *img,
|
|||||||
/**
|
/**
|
||||||
* acr_r352_ls_fill_headers - fill WPR and LSB headers of all managed images
|
* acr_r352_ls_fill_headers - fill WPR and LSB headers of all managed images
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
acr_r352_ls_fill_headers(struct acr_r352 *acr, struct list_head *imgs)
|
acr_r352_ls_fill_headers(struct acr_r352 *acr, struct list_head *imgs)
|
||||||
{
|
{
|
||||||
struct ls_ucode_img *img;
|
struct ls_ucode_img_r352 *img;
|
||||||
struct list_head *l;
|
struct list_head *l;
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
u32 offset;
|
u32 offset;
|
||||||
@ -298,34 +316,35 @@ acr_r352_ls_fill_headers(struct acr_r352 *acr, struct list_head *imgs)
|
|||||||
* read of this array and cache it internally so it's ok to pack these.
|
* read of this array and cache it internally so it's ok to pack these.
|
||||||
* Also, we add 1 to the falcon count to indicate the end of the array.
|
* Also, we add 1 to the falcon count to indicate the end of the array.
|
||||||
*/
|
*/
|
||||||
offset = sizeof(struct lsf_wpr_header) * (count + 1);
|
offset = sizeof(img->wpr_header) * (count + 1);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Walk the managed falcons, accounting for the LSB structs
|
* Walk the managed falcons, accounting for the LSB structs
|
||||||
* as well as the ucode images.
|
* as well as the ucode images.
|
||||||
*/
|
*/
|
||||||
list_for_each_entry(img, imgs, node) {
|
list_for_each_entry(img, imgs, base.node) {
|
||||||
offset = ls_ucode_img_fill_headers(acr, img, offset);
|
offset = acr_r352_ls_img_fill_headers(acr, img, offset);
|
||||||
}
|
}
|
||||||
|
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ls_ucode_mgr_write_wpr - write the WPR blob contents
|
* acr_r352_ls_write_wpr - write the WPR blob contents
|
||||||
*/
|
*/
|
||||||
static int
|
int
|
||||||
ls_ucode_mgr_write_wpr(struct acr_r352 *acr, struct list_head *imgs,
|
acr_r352_ls_write_wpr(struct acr_r352 *acr, struct list_head *imgs,
|
||||||
struct nvkm_gpuobj *wpr_blob, u32 wpr_addr)
|
struct nvkm_gpuobj *wpr_blob, u32 wpr_addr)
|
||||||
{
|
{
|
||||||
struct ls_ucode_img *img;
|
struct ls_ucode_img *_img;
|
||||||
u32 pos = 0;
|
u32 pos = 0;
|
||||||
|
|
||||||
nvkm_kmap(wpr_blob);
|
nvkm_kmap(wpr_blob);
|
||||||
|
|
||||||
list_for_each_entry(img, imgs, node) {
|
list_for_each_entry(_img, imgs, node) {
|
||||||
|
struct ls_ucode_img_r352 *img = ls_ucode_img_r352(_img);
|
||||||
const struct acr_r352_ls_func *ls_func =
|
const struct acr_r352_ls_func *ls_func =
|
||||||
acr->func->ls_func[img->falcon_id];
|
acr->func->ls_func[_img->falcon_id];
|
||||||
u8 gdesc[ls_func->bl_desc_size];
|
u8 gdesc[ls_func->bl_desc_size];
|
||||||
|
|
||||||
nvkm_gpuobj_memcpy_to(wpr_blob, pos, &img->wpr_header,
|
nvkm_gpuobj_memcpy_to(wpr_blob, pos, &img->wpr_header,
|
||||||
@ -335,14 +354,14 @@ ls_ucode_mgr_write_wpr(struct acr_r352 *acr, struct list_head *imgs,
|
|||||||
&img->lsb_header, sizeof(img->lsb_header));
|
&img->lsb_header, sizeof(img->lsb_header));
|
||||||
|
|
||||||
/* Generate and write BL descriptor */
|
/* Generate and write BL descriptor */
|
||||||
ls_func->generate_bl_desc(&acr->base, img, wpr_addr, gdesc);
|
ls_func->generate_bl_desc(&acr->base, _img, wpr_addr, gdesc);
|
||||||
|
|
||||||
nvkm_gpuobj_memcpy_to(wpr_blob, img->lsb_header.bl_data_off,
|
nvkm_gpuobj_memcpy_to(wpr_blob, img->lsb_header.bl_data_off,
|
||||||
gdesc, ls_func->bl_desc_size);
|
gdesc, ls_func->bl_desc_size);
|
||||||
|
|
||||||
/* Copy ucode */
|
/* Copy ucode */
|
||||||
nvkm_gpuobj_memcpy_to(wpr_blob, img->lsb_header.ucode_off,
|
nvkm_gpuobj_memcpy_to(wpr_blob, img->lsb_header.ucode_off,
|
||||||
img->ucode_data, img->ucode_size);
|
_img->ucode_data, _img->ucode_size);
|
||||||
|
|
||||||
pos += sizeof(img->wpr_header);
|
pos += sizeof(img->wpr_header);
|
||||||
}
|
}
|
||||||
@ -382,13 +401,12 @@ acr_r352_prepare_ls_blob(struct acr_r352 *acr, u64 wpr_addr, u32 wpr_size)
|
|||||||
for_each_set_bit(falcon_id, &managed_falcons, NVKM_SECBOOT_FALCON_END) {
|
for_each_set_bit(falcon_id, &managed_falcons, NVKM_SECBOOT_FALCON_END) {
|
||||||
struct ls_ucode_img *img;
|
struct ls_ucode_img *img;
|
||||||
|
|
||||||
img = ls_ucode_img_load(subdev,
|
img = acr->func->ls_ucode_img_load(acr, falcon_id);
|
||||||
acr->func->ls_func[falcon_id]->load);
|
|
||||||
|
|
||||||
if (IS_ERR(img)) {
|
if (IS_ERR(img)) {
|
||||||
ret = PTR_ERR(img);
|
ret = PTR_ERR(img);
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
list_add_tail(&img->node, &imgs);
|
list_add_tail(&img->node, &imgs);
|
||||||
managed_count++;
|
managed_count++;
|
||||||
}
|
}
|
||||||
@ -397,7 +415,7 @@ acr_r352_prepare_ls_blob(struct acr_r352 *acr, u64 wpr_addr, u32 wpr_size)
|
|||||||
* Fill the WPR and LSF headers with the right offsets and compute
|
* Fill the WPR and LSF headers with the right offsets and compute
|
||||||
* required WPR size
|
* required WPR size
|
||||||
*/
|
*/
|
||||||
image_wpr_size = acr_r352_ls_fill_headers(acr, &imgs);
|
image_wpr_size = acr->func->ls_fill_headers(acr, &imgs);
|
||||||
image_wpr_size = ALIGN(image_wpr_size, WPR_ALIGNMENT);
|
image_wpr_size = ALIGN(image_wpr_size, WPR_ALIGNMENT);
|
||||||
|
|
||||||
/* Allocate GPU object that will contain the WPR region */
|
/* Allocate GPU object that will contain the WPR region */
|
||||||
@ -426,13 +444,14 @@ acr_r352_prepare_ls_blob(struct acr_r352 *acr, u64 wpr_addr, u32 wpr_size)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Write LS blob */
|
/* Write LS blob */
|
||||||
ret = ls_ucode_mgr_write_wpr(acr, &imgs, acr->ls_blob, wpr_addr);
|
ret = acr->func->ls_write_wpr(acr, &imgs, acr->ls_blob, wpr_addr);
|
||||||
if (ret)
|
if (ret)
|
||||||
nvkm_gpuobj_del(&acr->ls_blob);
|
nvkm_gpuobj_del(&acr->ls_blob);
|
||||||
|
|
||||||
cleanup:
|
cleanup:
|
||||||
list_for_each_entry_safe(img, t, &imgs, node) {
|
list_for_each_entry_safe(img, t, &imgs, node) {
|
||||||
kfree(img->ucode_data);
|
kfree(img->ucode_data);
|
||||||
|
kfree(img->sig);
|
||||||
kfree(img);
|
kfree(img);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -859,6 +878,9 @@ const struct acr_r352_func
|
|||||||
acr_r352_func = {
|
acr_r352_func = {
|
||||||
.generate_hs_bl_desc = acr_r352_generate_hs_bl_desc,
|
.generate_hs_bl_desc = acr_r352_generate_hs_bl_desc,
|
||||||
.hs_bl_desc_size = sizeof(struct acr_r352_flcn_bl_desc),
|
.hs_bl_desc_size = sizeof(struct acr_r352_flcn_bl_desc),
|
||||||
|
.ls_ucode_img_load = acr_r352_ls_ucode_img_load,
|
||||||
|
.ls_fill_headers = acr_r352_ls_fill_headers,
|
||||||
|
.ls_write_wpr = acr_r352_ls_write_wpr,
|
||||||
.ls_func = {
|
.ls_func = {
|
||||||
[NVKM_SECBOOT_FALCON_FECS] = &acr_r352_ls_fecs_func,
|
[NVKM_SECBOOT_FALCON_FECS] = &acr_r352_ls_fecs_func,
|
||||||
[NVKM_SECBOOT_FALCON_GPCCS] = &acr_r352_ls_gpccs_func,
|
[NVKM_SECBOOT_FALCON_GPCCS] = &acr_r352_ls_gpccs_func,
|
||||||
|
@ -23,11 +23,116 @@
|
|||||||
#define __NVKM_SECBOOT_ACR_R352_H__
|
#define __NVKM_SECBOOT_ACR_R352_H__
|
||||||
|
|
||||||
#include "acr.h"
|
#include "acr.h"
|
||||||
|
#include "ls_ucode.h"
|
||||||
|
|
||||||
struct ls_ucode_img;
|
struct ls_ucode_img;
|
||||||
|
|
||||||
#define ACR_R352_MAX_APPS 8
|
#define ACR_R352_MAX_APPS 8
|
||||||
|
|
||||||
|
/*
|
||||||
|
*
|
||||||
|
* LS blob structures
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* struct acr_r352_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 acr_r352_lsf_lsb_header {
|
||||||
|
/**
|
||||||
|
* LS falcon signatures
|
||||||
|
* @prd_keys: signature to use in production mode
|
||||||
|
* @dgb_keys: signature to use 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
|
||||||
|
*/
|
||||||
|
struct {
|
||||||
|
u8 prd_keys[2][16];
|
||||||
|
u8 dbg_keys[2][16];
|
||||||
|
u32 b_prd_present;
|
||||||
|
u32 b_dbg_present;
|
||||||
|
u32 falcon_id;
|
||||||
|
} 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 acr_r352_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 acr_r352_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_r352 - ucode image augmented with r352 headers
|
||||||
|
*/
|
||||||
|
struct ls_ucode_img_r352 {
|
||||||
|
struct ls_ucode_img base;
|
||||||
|
|
||||||
|
struct acr_r352_lsf_wpr_header wpr_header;
|
||||||
|
struct acr_r352_lsf_lsb_header lsb_header;
|
||||||
|
};
|
||||||
|
#define ls_ucode_img_r352(i) container_of(i, struct ls_ucode_img_r352, base)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
* HS blob structures
|
||||||
|
*/
|
||||||
|
|
||||||
struct hsf_load_header_app {
|
struct hsf_load_header_app {
|
||||||
u32 sec_code_off;
|
u32 sec_code_off;
|
||||||
u32 sec_code_size;
|
u32 sec_code_size;
|
||||||
@ -62,6 +167,8 @@ struct acr_r352_ls_func {
|
|||||||
u32 lhdr_flags;
|
u32 lhdr_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct acr_r352;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* struct acr_r352_func - manages nuances between ACR versions
|
* struct acr_r352_func - manages nuances between ACR versions
|
||||||
*
|
*
|
||||||
@ -74,6 +181,12 @@ struct acr_r352_func {
|
|||||||
u64);
|
u64);
|
||||||
u32 hs_bl_desc_size;
|
u32 hs_bl_desc_size;
|
||||||
|
|
||||||
|
struct ls_ucode_img *(*ls_ucode_img_load)(const struct acr_r352 *,
|
||||||
|
enum nvkm_secboot_falcon);
|
||||||
|
int (*ls_fill_headers)(struct acr_r352 *, struct list_head *);
|
||||||
|
int (*ls_write_wpr)(struct acr_r352 *, struct list_head *,
|
||||||
|
struct nvkm_gpuobj *, u32);
|
||||||
|
|
||||||
const struct acr_r352_ls_func *ls_func[NVKM_SECBOOT_FALCON_END];
|
const struct acr_r352_ls_func *ls_func[NVKM_SECBOOT_FALCON_END];
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -125,4 +238,10 @@ struct acr_r352 {
|
|||||||
struct nvkm_acr *acr_r352_new_(const struct acr_r352_func *,
|
struct nvkm_acr *acr_r352_new_(const struct acr_r352_func *,
|
||||||
enum nvkm_secboot_falcon, unsigned long);
|
enum nvkm_secboot_falcon, unsigned long);
|
||||||
|
|
||||||
|
struct ls_ucode_img *acr_r352_ls_ucode_img_load(const struct acr_r352 *,
|
||||||
|
enum nvkm_secboot_falcon);
|
||||||
|
int acr_r352_ls_fill_headers(struct acr_r352 *, struct list_head *);
|
||||||
|
int acr_r352_ls_write_wpr(struct acr_r352 *, struct list_head *,
|
||||||
|
struct nvkm_gpuobj *, u32);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -21,7 +21,6 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
#include "acr_r352.h"
|
#include "acr_r352.h"
|
||||||
#include "ls_ucode.h"
|
|
||||||
|
|
||||||
#include <engine/falcon.h>
|
#include <engine/falcon.h>
|
||||||
|
|
||||||
@ -64,11 +63,12 @@ struct acr_r361_flcn_bl_desc {
|
|||||||
|
|
||||||
static void
|
static void
|
||||||
acr_r361_generate_flcn_bl_desc(const struct nvkm_acr *acr,
|
acr_r361_generate_flcn_bl_desc(const struct nvkm_acr *acr,
|
||||||
const struct ls_ucode_img *img, u64 wpr_addr,
|
const struct ls_ucode_img *_img, u64 wpr_addr,
|
||||||
void *_desc)
|
void *_desc)
|
||||||
{
|
{
|
||||||
|
struct ls_ucode_img_r352 *img = ls_ucode_img_r352(_img);
|
||||||
struct acr_r361_flcn_bl_desc *desc = _desc;
|
struct acr_r361_flcn_bl_desc *desc = _desc;
|
||||||
const struct ls_ucode_img_desc *pdesc = &img->ucode_desc;
|
const struct ls_ucode_img_desc *pdesc = &img->base.ucode_desc;
|
||||||
u64 base, addr_code, addr_data;
|
u64 base, addr_code, addr_data;
|
||||||
|
|
||||||
base = wpr_addr + img->lsb_header.ucode_off + pdesc->app_start_offset;
|
base = wpr_addr + img->lsb_header.ucode_off + pdesc->app_start_offset;
|
||||||
@ -123,6 +123,9 @@ const struct acr_r352_func
|
|||||||
acr_r361_func = {
|
acr_r361_func = {
|
||||||
.generate_hs_bl_desc = acr_r361_generate_hs_bl_desc,
|
.generate_hs_bl_desc = acr_r361_generate_hs_bl_desc,
|
||||||
.hs_bl_desc_size = sizeof(struct acr_r361_flcn_bl_desc),
|
.hs_bl_desc_size = sizeof(struct acr_r361_flcn_bl_desc),
|
||||||
|
.ls_ucode_img_load = acr_r352_ls_ucode_img_load,
|
||||||
|
.ls_fill_headers = acr_r352_ls_fill_headers,
|
||||||
|
.ls_write_wpr = acr_r352_ls_write_wpr,
|
||||||
.ls_func = {
|
.ls_func = {
|
||||||
[NVKM_SECBOOT_FALCON_FECS] = &acr_r361_ls_fecs_func,
|
[NVKM_SECBOOT_FALCON_FECS] = &acr_r361_ls_fecs_func,
|
||||||
[NVKM_SECBOOT_FALCON_GPCCS] = &acr_r361_ls_gpccs_func,
|
[NVKM_SECBOOT_FALCON_GPCCS] = &acr_r361_ls_gpccs_func,
|
||||||
|
@ -88,8 +88,8 @@
|
|||||||
#include <subdev/timer.h>
|
#include <subdev/timer.h>
|
||||||
#include <subdev/pmu.h>
|
#include <subdev/pmu.h>
|
||||||
|
|
||||||
static const char *
|
const char *
|
||||||
managed_falcons_names[] = {
|
nvkm_secboot_falcon_name[] = {
|
||||||
[NVKM_SECBOOT_FALCON_PMU] = "PMU",
|
[NVKM_SECBOOT_FALCON_PMU] = "PMU",
|
||||||
[NVKM_SECBOOT_FALCON_RESERVED] = "<reserved>",
|
[NVKM_SECBOOT_FALCON_RESERVED] = "<reserved>",
|
||||||
[NVKM_SECBOOT_FALCON_FECS] = "FECS",
|
[NVKM_SECBOOT_FALCON_FECS] = "FECS",
|
||||||
@ -135,7 +135,7 @@ nvkm_secboot_oneinit(struct nvkm_subdev *subdev)
|
|||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
nvkm_error(subdev, "Unmanaged boot falcon %s!\n",
|
nvkm_error(subdev, "Unmanaged boot falcon %s!\n",
|
||||||
managed_falcons_names[sb->acr->boot_falcon]);
|
nvkm_secboot_falcon_name[sb->acr->boot_falcon]);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -197,7 +197,8 @@ nvkm_secboot_ctor(const struct nvkm_secboot_func *func, struct nvkm_acr *acr,
|
|||||||
nvkm_debug(&sb->subdev, "securely managed falcons:\n");
|
nvkm_debug(&sb->subdev, "securely managed falcons:\n");
|
||||||
for_each_set_bit(fid, &sb->acr->managed_falcons,
|
for_each_set_bit(fid, &sb->acr->managed_falcons,
|
||||||
NVKM_SECBOOT_FALCON_END)
|
NVKM_SECBOOT_FALCON_END)
|
||||||
nvkm_debug(&sb->subdev, "- %s\n", managed_falcons_names[fid]);
|
nvkm_debug(&sb->subdev, "- %s\n",
|
||||||
|
nvkm_secboot_falcon_name[fid]);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
@ -27,98 +27,6 @@
|
|||||||
#include <core/subdev.h>
|
#include <core/subdev.h>
|
||||||
#include <subdev/secboot.h>
|
#include <subdev/secboot.h>
|
||||||
|
|
||||||
/*
|
|
||||||
*
|
|
||||||
* 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
|
* struct ls_ucode_img_desc - descriptor of firmware image
|
||||||
@ -175,8 +83,8 @@ struct ls_ucode_img_desc {
|
|||||||
* @ucode_desc: loaded or generated map of ucode_data
|
* @ucode_desc: loaded or generated map of ucode_data
|
||||||
* @ucode_data: firmware payload (code and data)
|
* @ucode_data: firmware payload (code and data)
|
||||||
* @ucode_size: size in bytes of data in ucode_data
|
* @ucode_size: size in bytes of data in ucode_data
|
||||||
* @wpr_header: WPR header to be written to the LS blob
|
* @sig: signature for this firmware
|
||||||
* @lsb_header: LSB header to be written to the LS blob
|
* @sig:size: size of the signature in bytes
|
||||||
*
|
*
|
||||||
* Preparing the WPR LS blob requires information about all the LS firmwares
|
* 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
|
* (size, etc) to be known. This structure contains all the data of one LS
|
||||||
@ -190,8 +98,8 @@ struct ls_ucode_img {
|
|||||||
u8 *ucode_data;
|
u8 *ucode_data;
|
||||||
u32 ucode_size;
|
u32 ucode_size;
|
||||||
|
|
||||||
struct lsf_wpr_header wpr_header;
|
u8 *sig;
|
||||||
struct lsf_lsb_header lsb_header;
|
u32 sig_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -91,10 +91,9 @@ ls_ucode_img_build(const struct firmware *bl, const struct firmware *code,
|
|||||||
*/
|
*/
|
||||||
static int
|
static int
|
||||||
ls_ucode_img_load_gr(const struct nvkm_subdev *subdev, struct ls_ucode_img *img,
|
ls_ucode_img_load_gr(const struct nvkm_subdev *subdev, struct ls_ucode_img *img,
|
||||||
const char *falcon_name, const u32 falcon_id)
|
const char *falcon_name)
|
||||||
{
|
{
|
||||||
const struct firmware *bl, *code, *data;
|
const struct firmware *bl, *code, *data, *sig;
|
||||||
struct lsf_ucode_desc *lsf_desc;
|
|
||||||
char f[64];
|
char f[64];
|
||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
@ -113,6 +112,17 @@ ls_ucode_img_load_gr(const struct nvkm_subdev *subdev, struct ls_ucode_img *img,
|
|||||||
if (ret)
|
if (ret)
|
||||||
goto free_inst;
|
goto free_inst;
|
||||||
|
|
||||||
|
snprintf(f, sizeof(f), "gr/%s_sig", falcon_name);
|
||||||
|
ret = nvkm_firmware_get(subdev->device, f, &sig);
|
||||||
|
if (ret)
|
||||||
|
goto free_data;
|
||||||
|
img->sig = kmemdup(sig->data, sig->size, GFP_KERNEL);
|
||||||
|
if (!img->sig) {
|
||||||
|
ret = -ENOMEM;
|
||||||
|
goto free_sig;
|
||||||
|
}
|
||||||
|
img->sig_size = sig->size;
|
||||||
|
|
||||||
img->ucode_data = ls_ucode_img_build(bl, code, data,
|
img->ucode_data = ls_ucode_img_build(bl, code, data,
|
||||||
&img->ucode_desc);
|
&img->ucode_desc);
|
||||||
if (IS_ERR(img->ucode_data)) {
|
if (IS_ERR(img->ucode_data)) {
|
||||||
@ -121,23 +131,8 @@ ls_ucode_img_load_gr(const struct nvkm_subdev *subdev, struct ls_ucode_img *img,
|
|||||||
}
|
}
|
||||||
img->ucode_size = img->ucode_desc.image_size;
|
img->ucode_size = img->ucode_desc.image_size;
|
||||||
|
|
||||||
snprintf(f, sizeof(f), "gr/%s_sig", falcon_name);
|
free_sig:
|
||||||
lsf_desc = nvkm_acr_load_firmware(subdev, f, sizeof(*lsf_desc));
|
nvkm_firmware_put(sig);
|
||||||
if (IS_ERR(lsf_desc)) {
|
|
||||||
ret = PTR_ERR(lsf_desc);
|
|
||||||
goto free_image;
|
|
||||||
}
|
|
||||||
/* not needed? the signature should already have the right value */
|
|
||||||
lsf_desc->falcon_id = falcon_id;
|
|
||||||
memcpy(&img->lsb_header.signature, lsf_desc, sizeof(*lsf_desc));
|
|
||||||
img->falcon_id = lsf_desc->falcon_id;
|
|
||||||
kfree(lsf_desc);
|
|
||||||
|
|
||||||
/* success path - only free requested firmware files */
|
|
||||||
goto free_data;
|
|
||||||
|
|
||||||
free_image:
|
|
||||||
kfree(img->ucode_data);
|
|
||||||
free_data:
|
free_data:
|
||||||
nvkm_firmware_put(data);
|
nvkm_firmware_put(data);
|
||||||
free_inst:
|
free_inst:
|
||||||
@ -152,14 +147,12 @@ int
|
|||||||
acr_ls_ucode_load_fecs(const struct nvkm_subdev *subdev,
|
acr_ls_ucode_load_fecs(const struct nvkm_subdev *subdev,
|
||||||
struct ls_ucode_img *img)
|
struct ls_ucode_img *img)
|
||||||
{
|
{
|
||||||
return ls_ucode_img_load_gr(subdev, img, "fecs",
|
return ls_ucode_img_load_gr(subdev, img, "fecs");
|
||||||
NVKM_SECBOOT_FALCON_FECS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
acr_ls_ucode_load_gpccs(const struct nvkm_subdev *subdev,
|
acr_ls_ucode_load_gpccs(const struct nvkm_subdev *subdev,
|
||||||
struct ls_ucode_img *img)
|
struct ls_ucode_img *img)
|
||||||
{
|
{
|
||||||
return ls_ucode_img_load_gr(subdev, img, "gpccs",
|
return ls_ucode_img_load_gr(subdev, img, "gpccs");
|
||||||
NVKM_SECBOOT_FALCON_GPCCS);
|
|
||||||
}
|
}
|
||||||
|
@ -33,6 +33,8 @@ struct nvkm_secboot_func {
|
|||||||
int (*run_blob)(struct nvkm_secboot *, struct nvkm_gpuobj *);
|
int (*run_blob)(struct nvkm_secboot *, struct nvkm_gpuobj *);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
extern const char *nvkm_secboot_falcon_name[];
|
||||||
|
|
||||||
int nvkm_secboot_ctor(const struct nvkm_secboot_func *, struct nvkm_acr *,
|
int nvkm_secboot_ctor(const struct nvkm_secboot_func *, struct nvkm_acr *,
|
||||||
struct nvkm_device *, int, struct nvkm_secboot *);
|
struct nvkm_device *, int, struct nvkm_secboot *);
|
||||||
int nvkm_secboot_falcon_reset(struct nvkm_secboot *);
|
int nvkm_secboot_falcon_reset(struct nvkm_secboot *);
|
||||||
|
Loading…
Reference in New Issue
Block a user