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 28 void 29 nvkm_acr_lsfw_del(struct nvkm_acr_lsfw *lsfw) 30 { 31 nvkm_blob_dtor(&lsfw->img); 32 kfree(lsfw->sigs); 33 nvkm_firmware_put(lsfw->sig); 34 list_del(&lsfw->head); 35 kfree(lsfw); 36 } 37 38 void 39 nvkm_acr_lsfw_del_all(struct nvkm_acr *acr) 40 { 41 struct nvkm_acr_lsfw *lsfw, *lsft; 42 list_for_each_entry_safe(lsfw, lsft, &acr->lsfw, head) { 43 nvkm_acr_lsfw_del(lsfw); 44 } 45 } 46 47 static struct nvkm_acr_lsfw * 48 nvkm_acr_lsfw_get(struct nvkm_acr *acr, enum nvkm_acr_lsf_id id) 49 { 50 struct nvkm_acr_lsfw *lsfw; 51 list_for_each_entry(lsfw, &acr->lsfw, head) { 52 if (lsfw->id == id) 53 return lsfw; 54 } 55 return NULL; 56 } 57 58 struct nvkm_acr_lsfw * 59 nvkm_acr_lsfw_add(const struct nvkm_acr_lsf_func *func, struct nvkm_acr *acr, 60 struct nvkm_falcon *falcon, enum nvkm_acr_lsf_id id) 61 { 62 struct nvkm_acr_lsfw *lsfw; 63 64 if (!acr || list_empty(&acr->hsfw)) 65 return ERR_PTR(-ENOSYS); 66 67 lsfw = nvkm_acr_lsfw_get(acr, id); 68 if (lsfw && lsfw->func) { 69 nvkm_error(&acr->subdev, "LSFW %d redefined\n", id); 70 return ERR_PTR(-EEXIST); 71 } 72 73 if (!lsfw) { 74 if (!(lsfw = kzalloc(sizeof(*lsfw), GFP_KERNEL))) 75 return ERR_PTR(-ENOMEM); 76 77 lsfw->id = id; 78 list_add_tail(&lsfw->head, &acr->lsfw); 79 } 80 81 lsfw->func = func; 82 lsfw->falcon = falcon; 83 return lsfw; 84 } 85 86 static struct nvkm_acr_lsfw * 87 nvkm_acr_lsfw_load_sig_image_desc_(struct nvkm_subdev *subdev, 88 struct nvkm_falcon *falcon, 89 enum nvkm_acr_lsf_id id, 90 const char *path, int ver, 91 const struct nvkm_acr_lsf_func *func, 92 const struct firmware **pdesc) 93 { 94 struct nvkm_acr *acr = subdev->device->acr; 95 struct nvkm_acr_lsfw *lsfw; 96 int ret; 97 98 if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id)))) 99 return lsfw; 100 101 ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig); 102 if (ret) 103 goto done; 104 105 ret = nvkm_firmware_load_blob(subdev, path, "image", ver, &lsfw->img); 106 if (ret) 107 goto done; 108 109 ret = nvkm_firmware_load_name(subdev, path, "desc", ver, pdesc); 110 done: 111 if (ret) { 112 nvkm_acr_lsfw_del(lsfw); 113 return ERR_PTR(ret); 114 } 115 116 return lsfw; 117 } 118 119 static void 120 nvkm_acr_lsfw_from_desc(const struct nvfw_ls_desc_head *desc, 121 struct nvkm_acr_lsfw *lsfw) 122 { 123 lsfw->bootloader_size = ALIGN(desc->bootloader_size, 256); 124 lsfw->bootloader_imem_offset = desc->bootloader_imem_offset; 125 126 lsfw->app_size = ALIGN(desc->app_size, 256); 127 lsfw->app_start_offset = desc->app_start_offset; 128 lsfw->app_imem_entry = desc->app_imem_entry; 129 lsfw->app_resident_code_offset = desc->app_resident_code_offset; 130 lsfw->app_resident_code_size = desc->app_resident_code_size; 131 lsfw->app_resident_data_offset = desc->app_resident_data_offset; 132 lsfw->app_resident_data_size = desc->app_resident_data_size; 133 134 lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + 135 lsfw->bootloader_size; 136 lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - 137 lsfw->ucode_size; 138 } 139 140 int 141 nvkm_acr_lsfw_load_sig_image_desc(struct nvkm_subdev *subdev, 142 struct nvkm_falcon *falcon, 143 enum nvkm_acr_lsf_id id, 144 const char *path, int ver, 145 const struct nvkm_acr_lsf_func *func) 146 { 147 const struct firmware *fw; 148 struct nvkm_acr_lsfw *lsfw; 149 150 lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver, 151 func, &fw); 152 if (IS_ERR(lsfw)) 153 return PTR_ERR(lsfw); 154 155 nvkm_acr_lsfw_from_desc(&nvfw_ls_desc(subdev, fw->data)->head, lsfw); 156 nvkm_firmware_put(fw); 157 return 0; 158 } 159 160 int 161 nvkm_acr_lsfw_load_sig_image_desc_v1(struct nvkm_subdev *subdev, 162 struct nvkm_falcon *falcon, 163 enum nvkm_acr_lsf_id id, 164 const char *path, int ver, 165 const struct nvkm_acr_lsf_func *func) 166 { 167 const struct firmware *fw; 168 struct nvkm_acr_lsfw *lsfw; 169 170 lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver, 171 func, &fw); 172 if (IS_ERR(lsfw)) 173 return PTR_ERR(lsfw); 174 175 nvkm_acr_lsfw_from_desc(&nvfw_ls_desc_v1(subdev, fw->data)->head, lsfw); 176 nvkm_firmware_put(fw); 177 return 0; 178 } 179 180 int 181 nvkm_acr_lsfw_load_sig_image_desc_v2(struct nvkm_subdev *subdev, 182 struct nvkm_falcon *falcon, 183 enum nvkm_acr_lsf_id id, 184 const char *path, int ver, 185 const struct nvkm_acr_lsf_func *func) 186 { 187 const struct firmware *fw; 188 struct nvkm_acr_lsfw *lsfw; 189 const struct nvfw_ls_desc_v2 *desc; 190 int ret = 0; 191 192 lsfw = nvkm_acr_lsfw_load_sig_image_desc_(subdev, falcon, id, path, ver, func, &fw); 193 if (IS_ERR(lsfw)) 194 return PTR_ERR(lsfw); 195 196 desc = nvfw_ls_desc_v2(subdev, fw->data); 197 198 lsfw->secure_bootloader = desc->secure_bootloader; 199 lsfw->bootloader_size = ALIGN(desc->bootloader_size, 256); 200 lsfw->bootloader_imem_offset = desc->bootloader_imem_offset; 201 202 lsfw->app_size = ALIGN(desc->app_size, 256); 203 lsfw->app_start_offset = desc->app_start_offset; 204 lsfw->app_imem_entry = desc->app_imem_entry; 205 lsfw->app_resident_code_offset = desc->app_resident_code_offset; 206 lsfw->app_resident_code_size = desc->app_resident_code_size; 207 lsfw->app_resident_data_offset = desc->app_resident_data_offset; 208 lsfw->app_resident_data_size = desc->app_resident_data_size; 209 lsfw->app_imem_offset = desc->app_imem_offset; 210 lsfw->app_dmem_offset = desc->app_dmem_offset; 211 212 lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + lsfw->bootloader_size; 213 lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - lsfw->ucode_size; 214 215 nvkm_firmware_put(fw); 216 217 if (lsfw->secure_bootloader) { 218 const struct firmware *hsbl; 219 const struct nvfw_ls_hsbl_bin_hdr *hdr; 220 const struct nvfw_ls_hsbl_hdr *hshdr; 221 u32 loc, sig, cnt, *meta; 222 223 ret = nvkm_firmware_load_name(subdev, path, "hs_bl_sig", ver, &hsbl); 224 if (ret) 225 return ret; 226 227 hdr = nvfw_ls_hsbl_bin_hdr(subdev, hsbl->data); 228 hshdr = nvfw_ls_hsbl_hdr(subdev, hsbl->data + hdr->header_offset); 229 meta = (u32 *)(hsbl->data + hshdr->meta_data_offset); 230 loc = *(u32 *)(hsbl->data + hshdr->patch_loc); 231 sig = *(u32 *)(hsbl->data + hshdr->patch_sig); 232 cnt = *(u32 *)(hsbl->data + hshdr->num_sig); 233 234 lsfw->fuse_ver = meta[0]; 235 lsfw->engine_id = meta[1]; 236 lsfw->ucode_id = meta[2]; 237 lsfw->sig_size = hshdr->sig_prod_size / cnt; 238 lsfw->sig_nr = cnt; 239 lsfw->sigs = kmemdup(hsbl->data + hshdr->sig_prod_offset + sig, 240 lsfw->sig_nr * lsfw->sig_size, GFP_KERNEL); 241 nvkm_firmware_put(hsbl); 242 if (!lsfw->sigs) 243 ret = -ENOMEM; 244 } 245 246 return ret; 247 } 248 249 int 250 nvkm_acr_lsfw_load_bl_inst_data_sig(struct nvkm_subdev *subdev, 251 struct nvkm_falcon *falcon, 252 enum nvkm_acr_lsf_id id, 253 const char *path, int ver, 254 const struct nvkm_acr_lsf_func *func) 255 { 256 struct nvkm_acr *acr = subdev->device->acr; 257 struct nvkm_acr_lsfw *lsfw; 258 const struct firmware *bl = NULL, *inst = NULL, *data = NULL; 259 const struct nvfw_bin_hdr *hdr; 260 const struct nvfw_bl_desc *desc; 261 u32 *bldata; 262 int ret; 263 264 if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id)))) 265 return PTR_ERR(lsfw); 266 267 ret = nvkm_firmware_load_name(subdev, path, "bl", ver, &bl); 268 if (ret) 269 goto done; 270 271 hdr = nvfw_bin_hdr(subdev, bl->data); 272 desc = nvfw_bl_desc(subdev, bl->data + hdr->header_offset); 273 bldata = (void *)(bl->data + hdr->data_offset); 274 275 ret = nvkm_firmware_load_name(subdev, path, "inst", ver, &inst); 276 if (ret) 277 goto done; 278 279 ret = nvkm_firmware_load_name(subdev, path, "data", ver, &data); 280 if (ret) 281 goto done; 282 283 ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig); 284 if (ret) 285 goto done; 286 287 lsfw->bootloader_size = ALIGN(desc->code_size, 256); 288 lsfw->bootloader_imem_offset = desc->start_tag << 8; 289 290 lsfw->app_start_offset = lsfw->bootloader_size; 291 lsfw->app_imem_entry = 0; 292 lsfw->app_resident_code_offset = 0; 293 lsfw->app_resident_code_size = ALIGN(inst->size, 256); 294 lsfw->app_resident_data_offset = lsfw->app_resident_code_size; 295 lsfw->app_resident_data_size = ALIGN(data->size, 256); 296 lsfw->app_size = lsfw->app_resident_code_size + 297 lsfw->app_resident_data_size; 298 299 lsfw->img.size = lsfw->bootloader_size + lsfw->app_size; 300 if (!(lsfw->img.data = kzalloc(lsfw->img.size, GFP_KERNEL))) { 301 ret = -ENOMEM; 302 goto done; 303 } 304 305 memcpy(lsfw->img.data, bldata, lsfw->bootloader_size); 306 memcpy(lsfw->img.data + lsfw->app_start_offset + 307 lsfw->app_resident_code_offset, inst->data, inst->size); 308 memcpy(lsfw->img.data + lsfw->app_start_offset + 309 lsfw->app_resident_data_offset, data->data, data->size); 310 311 lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + 312 lsfw->bootloader_size; 313 lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - 314 lsfw->ucode_size; 315 316 done: 317 if (ret) 318 nvkm_acr_lsfw_del(lsfw); 319 nvkm_firmware_put(data); 320 nvkm_firmware_put(inst); 321 nvkm_firmware_put(bl); 322 return ret; 323 } 324 325 int 326 nvkm_acr_lsfw_load_bl_sig_net(struct nvkm_subdev *subdev, 327 struct nvkm_falcon *falcon, 328 enum nvkm_acr_lsf_id id, 329 const char *path, int ver, 330 const struct nvkm_acr_lsf_func *func, 331 const void *inst_data, u32 inst_size, 332 const void *data_data, u32 data_size) 333 { 334 struct nvkm_acr *acr = subdev->device->acr; 335 struct nvkm_acr_lsfw *lsfw; 336 const struct firmware _inst = { .data = inst_data, .size = inst_size }; 337 const struct firmware _data = { .data = data_data, .size = data_size }; 338 const struct firmware *bl = NULL, *inst = &_inst, *data = &_data; 339 const struct { 340 int bin_magic; 341 int bin_version; 342 int bin_size; 343 int header_offset; 344 int header_size; 345 } *hdr; 346 u32 *bldata; 347 int ret; 348 349 if (IS_ERR((lsfw = nvkm_acr_lsfw_add(func, acr, falcon, id)))) 350 return PTR_ERR(lsfw); 351 352 ret = nvkm_firmware_load_name(subdev, path, "bl", ver, &bl); 353 if (ret) 354 goto done; 355 356 hdr = (const void *)bl->data; 357 bldata = (void *)(bl->data + hdr->header_offset); 358 359 ret = nvkm_firmware_load_name(subdev, path, "sig", ver, &lsfw->sig); 360 if (ret) 361 goto done; 362 363 lsfw->bootloader_size = ALIGN(hdr->header_size, 256); 364 lsfw->bootloader_imem_offset = func->bl_entry; 365 366 lsfw->app_start_offset = lsfw->bootloader_size; 367 lsfw->app_imem_entry = 0; 368 lsfw->app_resident_code_offset = 0; 369 lsfw->app_resident_code_size = ALIGN(inst->size, 256); 370 lsfw->app_resident_data_offset = lsfw->app_resident_code_size; 371 lsfw->app_resident_data_size = ALIGN(data->size, 256); 372 lsfw->app_imem_offset = 0; 373 lsfw->app_dmem_offset = 0; 374 lsfw->app_size = lsfw->app_resident_code_size + lsfw->app_resident_data_size; 375 376 lsfw->img.size = lsfw->bootloader_size + lsfw->app_size; 377 if (!(lsfw->img.data = kzalloc(lsfw->img.size, GFP_KERNEL))) { 378 ret = -ENOMEM; 379 goto done; 380 } 381 382 memcpy(lsfw->img.data, bldata, lsfw->bootloader_size); 383 memcpy(lsfw->img.data + lsfw->app_start_offset + 384 lsfw->app_resident_code_offset, inst->data, inst->size); 385 memcpy(lsfw->img.data + lsfw->app_start_offset + 386 lsfw->app_resident_data_offset, data->data, data->size); 387 388 lsfw->ucode_size = ALIGN(lsfw->app_resident_data_offset, 256) + 389 lsfw->bootloader_size; 390 lsfw->data_size = lsfw->app_size + lsfw->bootloader_size - 391 lsfw->ucode_size; 392 393 done: 394 if (ret) 395 nvkm_acr_lsfw_del(lsfw); 396 nvkm_firmware_put(bl); 397 return ret; 398 } 399