cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

lsfw.c (7347B)


      1/*
      2 * Copyright 2019 Red Hat Inc.
      3 *
      4 * Permission is hereby granted, free of charge, to any person obtaining a
      5 * copy of this software and associated documentation files (the "Software"),
      6 * to deal in the Software without restriction, including without limitation
      7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
      8 * and/or sell copies of the Software, and to permit persons to whom the
      9 * Software is furnished to do so, subject to the following conditions:
     10 *
     11 * The above copyright notice and this permission notice shall be included in
     12 * all copies or substantial portions of the Software.
     13 *
     14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
     17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
     18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
     19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
     20 * OTHER DEALINGS IN THE SOFTWARE.
     21 */
     22#include "priv.h"
     23#include <core/falcon.h>
     24#include <core/firmware.h>
     25#include <nvfw/fw.h>
     26#include <nvfw/ls.h>
     27
     28void
     29nvkm_acr_lsfw_del(struct nvkm_acr_lsfw *lsfw)
     30{
     31	nvkm_blob_dtor(&lsfw->img);
     32	nvkm_firmware_put(lsfw->sig);
     33	list_del(&lsfw->head);
     34	kfree(lsfw);
     35}
     36
     37void
     38nvkm_acr_lsfw_del_all(struct nvkm_acr *acr)
     39{
     40	struct nvkm_acr_lsfw *lsfw, *lsft;
     41	list_for_each_entry_safe(lsfw, lsft, &acr->lsfw, head) {
     42		nvkm_acr_lsfw_del(lsfw);
     43	}
     44}
     45
     46static struct nvkm_acr_lsfw *
     47nvkm_acr_lsfw_get(struct nvkm_acr *acr, enum nvkm_acr_lsf_id id)
     48{
     49	struct nvkm_acr_lsfw *lsfw;
     50	list_for_each_entry(lsfw, &acr->lsfw, head) {
     51		if (lsfw->id == id)
     52			return lsfw;
     53	}
     54	return NULL;
     55}
     56
     57struct nvkm_acr_lsfw *
     58nvkm_acr_lsfw_add(const struct nvkm_acr_lsf_func *func, struct nvkm_acr *acr,
     59		 struct nvkm_falcon *falcon, enum nvkm_acr_lsf_id id)
     60{
     61	struct nvkm_acr_lsfw *lsfw;
     62
     63	if (!acr || list_empty(&acr->hsfw))
     64		return ERR_PTR(-ENOSYS);
     65
     66	lsfw = nvkm_acr_lsfw_get(acr, id);
     67	if (lsfw && lsfw->func) {
     68		nvkm_error(&acr->subdev, "LSFW %d redefined\n", id);
     69		return ERR_PTR(-EEXIST);
     70	}
     71
     72	if (!lsfw) {
     73		if (!(lsfw = kzalloc(sizeof(*lsfw), GFP_KERNEL)))
     74			return ERR_PTR(-ENOMEM);
     75
     76		lsfw->id = id;
     77		list_add_tail(&lsfw->head, &acr->lsfw);
     78	}
     79
     80	lsfw->func = func;
     81	lsfw->falcon = falcon;
     82	return lsfw;
     83}
     84
     85static struct nvkm_acr_lsfw *
     86nvkm_acr_lsfw_load_sig_image_desc_(struct nvkm_subdev *subdev,
     87				   struct nvkm_falcon *falcon,
     88				   enum nvkm_acr_lsf_id id,
     89				   const char *path, int ver,
     90				   const struct nvkm_acr_lsf_func *func,
     91				   const struct firmware **pdesc)
     92{
     93	struct nvkm_acr *acr = subdev->device->acr;
     94	struct nvkm_acr_lsfw *lsfw;
     95	int ret;
     96
     97	if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id))))
     98		return lsfw;
     99
    100	ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig);
    101	if (ret)
    102		goto done;
    103
    104	ret = nvkm_firmware_load_blob(subdev, path, "image", ver, &lsfw->img);
    105	if (ret)
    106		goto done;
    107
    108	ret = nvkm_firmware_load_name(subdev, path, "desc", ver, pdesc);
    109done:
    110	if (ret) {
    111		nvkm_acr_lsfw_del(lsfw);
    112		return ERR_PTR(ret);
    113	}
    114
    115	return lsfw;
    116}
    117
    118static void
    119nvkm_acr_lsfw_from_desc(const struct nvfw_ls_desc_head *desc,
    120			struct nvkm_acr_lsfw *lsfw)
    121{
    122	lsfw->bootloader_size = ALIGN(desc->bootloader_size, 256);
    123	lsfw->bootloader_imem_offset = desc->bootloader_imem_offset;
    124
    125	lsfw->app_size = ALIGN(desc->app_size, 256);
    126	lsfw->app_start_offset = desc->app_start_offset;
    127	lsfw->app_imem_entry = desc->app_imem_entry;
    128	lsfw->app_resident_code_offset = desc->app_resident_code_offset;
    129	lsfw->app_resident_code_size = desc->app_resident_code_size;
    130	lsfw->app_resident_data_offset = desc->app_resident_data_offset;
    131	lsfw->app_resident_data_size = desc->app_resident_data_size;
    132
    133	lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) +
    134			   lsfw->bootloader_size;
    135	lsfw->data_size = lsfw->app_size + lsfw->bootloader_size -
    136			  lsfw->ucode_size;
    137}
    138
    139int
    140nvkm_acr_lsfw_load_sig_image_desc(struct nvkm_subdev *subdev,
    141				  struct nvkm_falcon *falcon,
    142				  enum nvkm_acr_lsf_id id,
    143				  const char *path, int ver,
    144				  const struct nvkm_acr_lsf_func *func)
    145{
    146	const struct firmware *fw;
    147	struct nvkm_acr_lsfw *lsfw;
    148
    149	lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver,
    150						  func, &fw);
    151	if (IS_ERR(lsfw))
    152		return PTR_ERR(lsfw);
    153
    154	nvkm_acr_lsfw_from_desc(&nvfw_ls_desc(subdev, fw->data)->head, lsfw);
    155	nvkm_firmware_put(fw);
    156	return 0;
    157}
    158
    159int
    160nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *subdev,
    161				     struct nvkm_falcon *falcon,
    162				     enum nvkm_acr_lsf_id id,
    163				     const char *path, int ver,
    164				     const struct nvkm_acr_lsf_func *func)
    165{
    166	const struct firmware *fw;
    167	struct nvkm_acr_lsfw *lsfw;
    168
    169	lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver,
    170						  func, &fw);
    171	if (IS_ERR(lsfw))
    172		return PTR_ERR(lsfw);
    173
    174	nvkm_acr_lsfw_from_desc(&nvfw_ls_desc_v1(subdev, fw->data)->head, lsfw);
    175	nvkm_firmware_put(fw);
    176	return 0;
    177}
    178
    179int
    180nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *subdev,
    181				    struct nvkm_falcon *falcon,
    182				    enum nvkm_acr_lsf_id id,
    183				    const char *path, int ver,
    184				    const struct nvkm_acr_lsf_func *func)
    185{
    186	struct nvkm_acr *acr = subdev->device->acr;
    187	struct nvkm_acr_lsfw *lsfw;
    188	const struct firmware *bl = NULL, *inst = NULL, *data = NULL;
    189	const struct nvfw_bin_hdr *hdr;
    190	const struct nvfw_bl_desc *desc;
    191	u32 *bldata;
    192	int ret;
    193
    194	if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id))))
    195		return PTR_ERR(lsfw);
    196
    197	ret = nvkm_firmware_load_name(subdev, path, "bl", ver, &bl);
    198	if (ret)
    199		goto done;
    200
    201	hdr = nvfw_bin_hdr(subdev, bl->data);
    202	desc = nvfw_bl_desc(subdev, bl->data + hdr->header_offset);
    203	bldata = (void *)(bl->data + hdr->data_offset);
    204
    205	ret = nvkm_firmware_load_name(subdev, path, "inst", ver, &inst);
    206	if (ret)
    207		goto done;
    208
    209	ret = nvkm_firmware_load_name(subdev, path, "data", ver, &data);
    210	if (ret)
    211		goto done;
    212
    213	ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig);
    214	if (ret)
    215		goto done;
    216
    217	lsfw->bootloader_size = ALIGN(desc->code_size, 256);
    218	lsfw->bootloader_imem_offset = desc->start_tag << 8;
    219
    220	lsfw->app_start_offset = lsfw->bootloader_size;
    221	lsfw->app_imem_entry = 0;
    222	lsfw->app_resident_code_offset = 0;
    223	lsfw->app_resident_code_size = ALIGN(inst->size, 256);
    224	lsfw->app_resident_data_offset = lsfw->app_resident_code_size;
    225	lsfw->app_resident_data_size = ALIGN(data->size, 256);
    226	lsfw->app_size = lsfw->app_resident_code_size +
    227			 lsfw->app_resident_data_size;
    228
    229	lsfw->img.size = lsfw->bootloader_size + lsfw->app_size;
    230	if (!(lsfw->img.data = kzalloc(lsfw->img.size, GFP_KERNEL))) {
    231		ret = -ENOMEM;
    232		goto done;
    233	}
    234
    235	memcpy(lsfw->img.data, bldata, lsfw->bootloader_size);
    236	memcpy(lsfw->img.data + lsfw->app_start_offset +
    237	       lsfw->app_resident_code_offset, inst->data, inst->size);
    238	memcpy(lsfw->img.data + lsfw->app_start_offset +
    239	       lsfw->app_resident_data_offset, data->data, data->size);
    240
    241	lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) +
    242			   lsfw->bootloader_size;
    243	lsfw->data_size = lsfw->app_size + lsfw->bootloader_size -
    244			  lsfw->ucode_size;
    245
    246done:
    247	if (ret)
    248		nvkm_acr_lsfw_del(lsfw);
    249	nvkm_firmware_put(data);
    250	nvkm_firmware_put(inst);
    251	nvkm_firmware_put(bl);
    252	return ret;
    253}