diff options
Diffstat (limited to 'drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c')
-rw-r--r-- | drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c | 1391 |
1 files changed, 60 insertions, 1331 deletions
diff --git a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c index ec48e4ace37a..813c4eb0b25f 100644 --- a/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c +++ b/drivers/gpu/drm/nouveau/nvkm/subdev/secboot/gm200.c | |||
@@ -20,1313 +20,84 @@ | |||
20 | * DEALINGS IN THE SOFTWARE. | 20 | * DEALINGS IN THE SOFTWARE. |
21 | */ | 21 | */ |
22 | 22 | ||
23 | /* | ||
24 | * Secure boot is the process by which NVIDIA-signed firmware is loaded into | ||
25 | * some of the falcons of a GPU. For production devices this is the only way | ||
26 | * for the firmware to access useful (but sensitive) registers. | ||
27 | * | ||
28 | * A Falcon microprocessor supporting advanced security modes can run in one of | ||
29 | * three modes: | ||
30 | * | ||
31 | * - Non-secure (NS). In this mode, functionality is similar to Falcon | ||
32 | * architectures before security modes were introduced (pre-Maxwell), but | ||
33 | * capability is restricted. In particular, certain registers may be | ||
34 | * inaccessible for reads and/or writes, and physical memory access may be | ||
35 | * disabled (on certain Falcon instances). This is the only possible mode that | ||
36 | * can be used if you don't have microcode cryptographically signed by NVIDIA. | ||
37 | * | ||
38 | * - Heavy Secure (HS). In this mode, the microprocessor is a black box - it's | ||
39 | * not possible to read or write any Falcon internal state or Falcon registers | ||
40 | * from outside the Falcon (for example, from the host system). The only way | ||
41 | * to enable this mode is by loading microcode that has been signed by NVIDIA. | ||
42 | * (The loading process involves tagging the IMEM block as secure, writing the | ||
43 | * signature into a Falcon register, and starting execution. The hardware will | ||
44 | * validate the signature, and if valid, grant HS privileges.) | ||
45 | * | ||
46 | * - Light Secure (LS). In this mode, the microprocessor has more privileges | ||
47 | * than NS but fewer than HS. Some of the microprocessor state is visible to | ||
48 | * host software to ease debugging. The only way to enable this mode is by HS | ||
49 | * microcode enabling LS mode. Some privileges available to HS mode are not | ||
50 | * available here. LS mode is introduced in GM20x. | ||
51 | * | ||
52 | * Secure boot consists in temporarily switching a HS-capable falcon (typically | ||
53 | * PMU) into HS mode in order to validate the LS firmwares of managed falcons, | ||
54 | * load them, and switch managed falcons into LS mode. Once secure boot | ||
55 | * completes, no falcon remains in HS mode. | ||
56 | * | ||
57 | * Secure boot requires a write-protected memory region (WPR) which can only be | ||
58 | * written by the secure falcon. On dGPU, the driver sets up the WPR region in | ||
59 | * video memory. On Tegra, it is set up by the bootloader and its location and | ||
60 | * size written into memory controller registers. | ||
61 | * | ||
62 | * The secure boot process takes place as follows: | ||
63 | * | ||
64 | * 1) A LS blob is constructed that contains all the LS firmwares we want to | ||
65 | * load, along with their signatures and bootloaders. | ||
66 | * | ||
67 | * 2) A HS blob (also called ACR) is created that contains the signed HS | ||
68 | * firmware in charge of loading the LS firmwares into their respective | ||
69 | * falcons. | ||
70 | * | ||
71 | * 3) The HS blob is loaded (via its own bootloader) and executed on the | ||
72 | * HS-capable falcon. It authenticates itself, switches the secure falcon to | ||
73 | * HS mode and setup the WPR region around the LS blob (dGPU) or copies the | ||
74 | * LS blob into the WPR region (Tegra). | ||
75 | * | ||
76 | * 4) The LS blob is now secure from all external tampering. The HS falcon | ||
77 | * checks the signatures of the LS firmwares and, if valid, switches the | ||
78 | * managed falcons to LS mode and makes them ready to run the LS firmware. | ||
79 | * | ||
80 | * 5) The managed falcons remain in LS mode and can be started. | ||
81 | * | ||
82 | */ | ||
83 | 23 | ||
84 | #include "priv.h" | 24 | #include "acr.h" |
25 | #include "gm200.h" | ||
85 | 26 | ||
86 | #include <core/gpuobj.h> | 27 | #include <core/gpuobj.h> |
87 | #include <core/firmware.h> | ||
88 | #include <subdev/fb.h> | 28 | #include <subdev/fb.h> |
89 | 29 | #include <engine/falcon.h> | |
90 | enum { | 30 | #include <subdev/mc.h> |
91 | FALCON_DMAIDX_UCODE = 0, | ||
92 | FALCON_DMAIDX_VIRT = 1, | ||
93 | FALCON_DMAIDX_PHYS_VID = 2, | ||
94 | FALCON_DMAIDX_PHYS_SYS_COH = 3, | ||
95 | FALCON_DMAIDX_PHYS_SYS_NCOH = 4, | ||
96 | }; | ||
97 | |||
98 | /** | ||
99 | * struct fw_bin_header - header of firmware files | ||
100 | * @bin_magic: always 0x3b1d14f0 | ||
101 | * @bin_ver: version of the bin format | ||
102 | * @bin_size: entire image size including this header | ||
103 | * @header_offset: offset of the firmware/bootloader header in the file | ||
104 | * @data_offset: offset of the firmware/bootloader payload in the file | ||
105 | * @data_size: size of the payload | ||
106 | * | ||
107 | * This header is located at the beginning of the HS firmware and HS bootloader | ||
108 | * files, to describe where the headers and data can be found. | ||
109 | */ | ||
110 | struct fw_bin_header { | ||
111 | u32 bin_magic; | ||
112 | u32 bin_ver; | ||
113 | u32 bin_size; | ||
114 | u32 header_offset; | ||
115 | u32 data_offset; | ||
116 | u32 data_size; | ||
117 | }; | ||
118 | |||
119 | /** | ||
120 | * struct fw_bl_desc - firmware bootloader descriptor | ||
121 | * @start_tag: starting tag of bootloader | ||
122 | * @desc_dmem_load_off: DMEM offset of flcn_bl_dmem_desc | ||
123 | * @code_off: offset of code section | ||
124 | * @code_size: size of code section | ||
125 | * @data_off: offset of data section | ||
126 | * @data_size: size of data section | ||
127 | * | ||
128 | * This structure is embedded in bootloader firmware files at to describe the | ||
129 | * IMEM and DMEM layout expected by the bootloader. | ||
130 | */ | ||
131 | struct fw_bl_desc { | ||
132 | u32 start_tag; | ||
133 | u32 dmem_load_off; | ||
134 | u32 code_off; | ||
135 | u32 code_size; | ||
136 | u32 data_off; | ||
137 | u32 data_size; | ||
138 | }; | ||
139 | |||
140 | |||
141 | /* | ||
142 | * | ||
143 | * LS blob structures | ||
144 | * | ||
145 | */ | ||
146 | |||
147 | /** | ||
148 | * struct lsf_ucode_desc - LS falcon signatures | ||
149 | * @prd_keys: signature to use when the GPU is in production mode | ||
150 | * @dgb_keys: signature to use when the GPU is in debug mode | ||
151 | * @b_prd_present: whether the production key is present | ||
152 | * @b_dgb_present: whether the debug key is present | ||
153 | * @falcon_id: ID of the falcon the ucode applies to | ||
154 | * | ||
155 | * Directly loaded from a signature file. | ||
156 | */ | ||
157 | struct lsf_ucode_desc { | ||
158 | u8 prd_keys[2][16]; | ||
159 | u8 dbg_keys[2][16]; | ||
160 | u32 b_prd_present; | ||
161 | u32 b_dbg_present; | ||
162 | u32 falcon_id; | ||
163 | }; | ||
164 | |||
165 | /** | ||
166 | * struct lsf_lsb_header - LS firmware header | ||
167 | * @signature: signature to verify the firmware against | ||
168 | * @ucode_off: offset of the ucode blob in the WPR region. The ucode | ||
169 | * blob contains the bootloader, code and data of the | ||
170 | * LS falcon | ||
171 | * @ucode_size: size of the ucode blob, including bootloader | ||
172 | * @data_size: size of the ucode blob data | ||
173 | * @bl_code_size: size of the bootloader code | ||
174 | * @bl_imem_off: offset in imem of the bootloader | ||
175 | * @bl_data_off: offset of the bootloader data in WPR region | ||
176 | * @bl_data_size: size of the bootloader data | ||
177 | * @app_code_off: offset of the app code relative to ucode_off | ||
178 | * @app_code_size: size of the app code | ||
179 | * @app_data_off: offset of the app data relative to ucode_off | ||
180 | * @app_data_size: size of the app data | ||
181 | * @flags: flags for the secure bootloader | ||
182 | * | ||
183 | * This structure is written into the WPR region for each managed falcon. Each | ||
184 | * instance is referenced by the lsb_offset member of the corresponding | ||
185 | * lsf_wpr_header. | ||
186 | */ | ||
187 | struct lsf_lsb_header { | ||
188 | struct lsf_ucode_desc signature; | ||
189 | u32 ucode_off; | ||
190 | u32 ucode_size; | ||
191 | u32 data_size; | ||
192 | u32 bl_code_size; | ||
193 | u32 bl_imem_off; | ||
194 | u32 bl_data_off; | ||
195 | u32 bl_data_size; | ||
196 | u32 app_code_off; | ||
197 | u32 app_code_size; | ||
198 | u32 app_data_off; | ||
199 | u32 app_data_size; | ||
200 | u32 flags; | ||
201 | #define LSF_FLAG_LOAD_CODE_AT_0 1 | ||
202 | #define LSF_FLAG_DMACTL_REQ_CTX 4 | ||
203 | #define LSF_FLAG_FORCE_PRIV_LOAD 8 | ||
204 | }; | ||
205 | |||
206 | /** | ||
207 | * struct lsf_wpr_header - LS blob WPR Header | ||
208 | * @falcon_id: LS falcon ID | ||
209 | * @lsb_offset: offset of the lsb_lsf_header in the WPR region | ||
210 | * @bootstrap_owner: secure falcon reponsible for bootstrapping the LS falcon | ||
211 | * @lazy_bootstrap: skip bootstrapping by ACR | ||
212 | * @status: bootstrapping status | ||
213 | * | ||
214 | * An array of these is written at the beginning of the WPR region, one for | ||
215 | * each managed falcon. The array is terminated by an instance which falcon_id | ||
216 | * is LSF_FALCON_ID_INVALID. | ||
217 | */ | ||
218 | struct lsf_wpr_header { | ||
219 | u32 falcon_id; | ||
220 | u32 lsb_offset; | ||
221 | u32 bootstrap_owner; | ||
222 | u32 lazy_bootstrap; | ||
223 | u32 status; | ||
224 | #define LSF_IMAGE_STATUS_NONE 0 | ||
225 | #define LSF_IMAGE_STATUS_COPY 1 | ||
226 | #define LSF_IMAGE_STATUS_VALIDATION_CODE_FAILED 2 | ||
227 | #define LSF_IMAGE_STATUS_VALIDATION_DATA_FAILED 3 | ||
228 | #define LSF_IMAGE_STATUS_VALIDATION_DONE 4 | ||
229 | #define LSF_IMAGE_STATUS_VALIDATION_SKIPPED 5 | ||
230 | #define LSF_IMAGE_STATUS_BOOTSTRAP_READY 6 | ||
231 | }; | ||
232 | |||
233 | |||
234 | /** | ||
235 | * struct ls_ucode_img_desc - descriptor of firmware image | ||
236 | * @descriptor_size: size of this descriptor | ||
237 | * @image_size: size of the whole image | ||
238 | * @bootloader_start_offset: start offset of the bootloader in ucode image | ||
239 | * @bootloader_size: size of the bootloader | ||
240 | * @bootloader_imem_offset: start off set of the bootloader in IMEM | ||
241 | * @bootloader_entry_point: entry point of the bootloader in IMEM | ||
242 | * @app_start_offset: start offset of the LS firmware | ||
243 | * @app_size: size of the LS firmware's code and data | ||
244 | * @app_imem_offset: offset of the app in IMEM | ||
245 | * @app_imem_entry: entry point of the app in IMEM | ||
246 | * @app_dmem_offset: offset of the data in DMEM | ||
247 | * @app_resident_code_offset: offset of app code from app_start_offset | ||
248 | * @app_resident_code_size: size of the code | ||
249 | * @app_resident_data_offset: offset of data from app_start_offset | ||
250 | * @app_resident_data_size: size of data | ||
251 | * | ||
252 | * A firmware image contains the code, data, and bootloader of a given LS | ||
253 | * falcon in a single blob. This structure describes where everything is. | ||
254 | * | ||
255 | * This can be generated from a (bootloader, code, data) set if they have | ||
256 | * been loaded separately, or come directly from a file. | ||
257 | */ | ||
258 | struct ls_ucode_img_desc { | ||
259 | u32 descriptor_size; | ||
260 | u32 image_size; | ||
261 | u32 tools_version; | ||
262 | u32 app_version; | ||
263 | char date[64]; | ||
264 | u32 bootloader_start_offset; | ||
265 | u32 bootloader_size; | ||
266 | u32 bootloader_imem_offset; | ||
267 | u32 bootloader_entry_point; | ||
268 | u32 app_start_offset; | ||
269 | u32 app_size; | ||
270 | u32 app_imem_offset; | ||
271 | u32 app_imem_entry; | ||
272 | u32 app_dmem_offset; | ||
273 | u32 app_resident_code_offset; | ||
274 | u32 app_resident_code_size; | ||
275 | u32 app_resident_data_offset; | ||
276 | u32 app_resident_data_size; | ||
277 | u32 nb_overlays; | ||
278 | struct {u32 start; u32 size; } load_ovl[64]; | ||
279 | u32 compressed; | ||
280 | }; | ||
281 | |||
282 | /** | ||
283 | * struct ls_ucode_img - temporary storage for loaded LS firmwares | ||
284 | * @node: to link within lsf_ucode_mgr | ||
285 | * @falcon_id: ID of the falcon this LS firmware is for | ||
286 | * @ucode_desc: loaded or generated map of ucode_data | ||
287 | * @ucode_header: header of the firmware | ||
288 | * @ucode_data: firmware payload (code and data) | ||
289 | * @ucode_size: size in bytes of data in ucode_data | ||
290 | * @wpr_header: WPR header to be written to the LS blob | ||
291 | * @lsb_header: LSB header to be written to the LS blob | ||
292 | * | ||
293 | * Preparing the WPR LS blob requires information about all the LS firmwares | ||
294 | * (size, etc) to be known. This structure contains all the data of one LS | ||
295 | * firmware. | ||
296 | */ | ||
297 | struct ls_ucode_img { | ||
298 | struct list_head node; | ||
299 | enum nvkm_secboot_falcon falcon_id; | ||
300 | |||
301 | struct ls_ucode_img_desc ucode_desc; | ||
302 | u32 *ucode_header; | ||
303 | u8 *ucode_data; | ||
304 | u32 ucode_size; | ||
305 | |||
306 | struct lsf_wpr_header wpr_header; | ||
307 | struct lsf_lsb_header lsb_header; | ||
308 | }; | ||
309 | |||
310 | /** | ||
311 | * struct ls_ucode_mgr - manager for all LS falcon firmwares | ||
312 | * @count: number of managed LS falcons | ||
313 | * @wpr_size: size of the required WPR region in bytes | ||
314 | * @img_list: linked list of lsf_ucode_img | ||
315 | */ | ||
316 | struct ls_ucode_mgr { | ||
317 | u16 count; | ||
318 | u32 wpr_size; | ||
319 | struct list_head img_list; | ||
320 | }; | ||
321 | |||
322 | |||
323 | /* | ||
324 | * | ||
325 | * HS blob structures | ||
326 | * | ||
327 | */ | ||
328 | |||
329 | /** | ||
330 | * struct hsf_fw_header - HS firmware descriptor | ||
331 | * @sig_dbg_offset: offset of the debug signature | ||
332 | * @sig_dbg_size: size of the debug signature | ||
333 | * @sig_prod_offset: offset of the production signature | ||
334 | * @sig_prod_size: size of the production signature | ||
335 | * @patch_loc: offset of the offset (sic) of where the signature is | ||
336 | * @patch_sig: offset of the offset (sic) to add to sig_*_offset | ||
337 | * @hdr_offset: offset of the load header (see struct hs_load_header) | ||
338 | * @hdr_size: size of above header | ||
339 | * | ||
340 | * This structure is embedded in the HS firmware image at | ||
341 | * hs_bin_hdr.header_offset. | ||
342 | */ | ||
343 | struct hsf_fw_header { | ||
344 | u32 sig_dbg_offset; | ||
345 | u32 sig_dbg_size; | ||
346 | u32 sig_prod_offset; | ||
347 | u32 sig_prod_size; | ||
348 | u32 patch_loc; | ||
349 | u32 patch_sig; | ||
350 | u32 hdr_offset; | ||
351 | u32 hdr_size; | ||
352 | }; | ||
353 | |||
354 | /** | ||
355 | * struct hsf_load_header - HS firmware load header | ||
356 | */ | ||
357 | struct hsf_load_header { | ||
358 | u32 non_sec_code_off; | ||
359 | u32 non_sec_code_size; | ||
360 | u32 data_dma_base; | ||
361 | u32 data_size; | ||
362 | u32 num_apps; | ||
363 | struct { | ||
364 | u32 sec_code_off; | ||
365 | u32 sec_code_size; | ||
366 | } app[0]; | ||
367 | }; | ||
368 | |||
369 | /** | ||
370 | * Convenience function to duplicate a firmware file in memory and check that | ||
371 | * it has the required minimum size. | ||
372 | */ | ||
373 | static void * | ||
374 | gm200_secboot_load_firmware(struct nvkm_subdev *subdev, const char *name, | ||
375 | size_t min_size) | ||
376 | { | ||
377 | const struct firmware *fw; | ||
378 | void *blob; | ||
379 | int ret; | ||
380 | |||
381 | ret = nvkm_firmware_get(subdev->device, name, &fw); | ||
382 | if (ret) | ||
383 | return ERR_PTR(ret); | ||
384 | if (fw->size < min_size) { | ||
385 | nvkm_error(subdev, "%s is smaller than expected size %zu\n", | ||
386 | name, min_size); | ||
387 | nvkm_firmware_put(fw); | ||
388 | return ERR_PTR(-EINVAL); | ||
389 | } | ||
390 | blob = kmemdup(fw->data, fw->size, GFP_KERNEL); | ||
391 | nvkm_firmware_put(fw); | ||
392 | if (!blob) | ||
393 | return ERR_PTR(-ENOMEM); | ||
394 | |||
395 | return blob; | ||
396 | } | ||
397 | |||
398 | |||
399 | /* | ||
400 | * Low-secure blob creation | ||
401 | */ | ||
402 | |||
403 | #define BL_DESC_BLK_SIZE 256 | ||
404 | /** | ||
405 | * Build a ucode image and descriptor from provided bootloader, code and data. | ||
406 | * | ||
407 | * @bl: bootloader image, including 16-bytes descriptor | ||
408 | * @code: LS firmware code segment | ||
409 | * @data: LS firmware data segment | ||
410 | * @desc: ucode descriptor to be written | ||
411 | * | ||
412 | * Return: allocated ucode image with corresponding descriptor information. desc | ||
413 | * is also updated to contain the right offsets within returned image. | ||
414 | */ | ||
415 | static void * | ||
416 | ls_ucode_img_build(const struct firmware *bl, const struct firmware *code, | ||
417 | const struct firmware *data, struct ls_ucode_img_desc *desc) | ||
418 | { | ||
419 | struct fw_bin_header *bin_hdr = (void *)bl->data; | ||
420 | struct fw_bl_desc *bl_desc = (void *)bl->data + bin_hdr->header_offset; | ||
421 | void *bl_data = (void *)bl->data + bin_hdr->data_offset; | ||
422 | u32 pos = 0; | ||
423 | void *image; | ||
424 | |||
425 | desc->bootloader_start_offset = pos; | ||
426 | desc->bootloader_size = ALIGN(bl_desc->code_size, sizeof(u32)); | ||
427 | desc->bootloader_imem_offset = bl_desc->start_tag * 256; | ||
428 | desc->bootloader_entry_point = bl_desc->start_tag * 256; | ||
429 | |||
430 | pos = ALIGN(pos + desc->bootloader_size, BL_DESC_BLK_SIZE); | ||
431 | desc->app_start_offset = pos; | ||
432 | desc->app_size = ALIGN(code->size, BL_DESC_BLK_SIZE) + | ||
433 | ALIGN(data->size, BL_DESC_BLK_SIZE); | ||
434 | desc->app_imem_offset = 0; | ||
435 | desc->app_imem_entry = 0; | ||
436 | desc->app_dmem_offset = 0; | ||
437 | desc->app_resident_code_offset = 0; | ||
438 | desc->app_resident_code_size = ALIGN(code->size, BL_DESC_BLK_SIZE); | ||
439 | |||
440 | pos = ALIGN(pos + desc->app_resident_code_size, BL_DESC_BLK_SIZE); | ||
441 | desc->app_resident_data_offset = pos - desc->app_start_offset; | ||
442 | desc->app_resident_data_size = ALIGN(data->size, BL_DESC_BLK_SIZE); | ||
443 | |||
444 | desc->image_size = ALIGN(bl_desc->code_size, BL_DESC_BLK_SIZE) + | ||
445 | desc->app_size; | ||
446 | |||
447 | image = kzalloc(desc->image_size, GFP_KERNEL); | ||
448 | if (!image) | ||
449 | return ERR_PTR(-ENOMEM); | ||
450 | |||
451 | memcpy(image + desc->bootloader_start_offset, bl_data, | ||
452 | bl_desc->code_size); | ||
453 | memcpy(image + desc->app_start_offset, code->data, code->size); | ||
454 | memcpy(image + desc->app_start_offset + desc->app_resident_data_offset, | ||
455 | data->data, data->size); | ||
456 | |||
457 | return image; | ||
458 | } | ||
459 | |||
460 | /** | ||
461 | * ls_ucode_img_load_generic() - load and prepare a LS ucode image | ||
462 | * | ||
463 | * Load the LS microcode, bootloader and signature and pack them into a single | ||
464 | * blob. Also generate the corresponding ucode descriptor. | ||
465 | */ | ||
466 | static int | ||
467 | ls_ucode_img_load_generic(struct nvkm_subdev *subdev, | ||
468 | struct ls_ucode_img *img, const char *falcon_name, | ||
469 | const u32 falcon_id) | ||
470 | { | ||
471 | const struct firmware *bl, *code, *data; | ||
472 | struct lsf_ucode_desc *lsf_desc; | ||
473 | char f[64]; | ||
474 | int ret; | ||
475 | |||
476 | img->ucode_header = NULL; | ||
477 | |||
478 | snprintf(f, sizeof(f), "gr/%s_bl", falcon_name); | ||
479 | ret = nvkm_firmware_get(subdev->device, f, &bl); | ||
480 | if (ret) | ||
481 | goto error; | ||
482 | |||
483 | snprintf(f, sizeof(f), "gr/%s_inst", falcon_name); | ||
484 | ret = nvkm_firmware_get(subdev->device, f, &code); | ||
485 | if (ret) | ||
486 | goto free_bl; | ||
487 | |||
488 | snprintf(f, sizeof(f), "gr/%s_data", falcon_name); | ||
489 | ret = nvkm_firmware_get(subdev->device, f, &data); | ||
490 | if (ret) | ||
491 | goto free_inst; | ||
492 | |||
493 | img->ucode_data = ls_ucode_img_build(bl, code, data, | ||
494 | &img->ucode_desc); | ||
495 | if (IS_ERR(img->ucode_data)) { | ||
496 | ret = PTR_ERR(img->ucode_data); | ||
497 | goto free_data; | ||
498 | } | ||
499 | img->ucode_size = img->ucode_desc.image_size; | ||
500 | |||
501 | snprintf(f, sizeof(f), "gr/%s_sig", falcon_name); | ||
502 | lsf_desc = gm200_secboot_load_firmware(subdev, f, sizeof(*lsf_desc)); | ||
503 | if (IS_ERR(lsf_desc)) { | ||
504 | ret = PTR_ERR(lsf_desc); | ||
505 | goto free_image; | ||
506 | } | ||
507 | /* not needed? the signature should already have the right value */ | ||
508 | lsf_desc->falcon_id = falcon_id; | ||
509 | memcpy(&img->lsb_header.signature, lsf_desc, sizeof(*lsf_desc)); | ||
510 | img->falcon_id = lsf_desc->falcon_id; | ||
511 | kfree(lsf_desc); | ||
512 | |||
513 | /* success path - only free requested firmware files */ | ||
514 | goto free_data; | ||
515 | |||
516 | free_image: | ||
517 | kfree(img->ucode_data); | ||
518 | free_data: | ||
519 | nvkm_firmware_put(data); | ||
520 | free_inst: | ||
521 | nvkm_firmware_put(code); | ||
522 | free_bl: | ||
523 | nvkm_firmware_put(bl); | ||
524 | error: | ||
525 | return ret; | ||
526 | } | ||
527 | |||
528 | typedef int (*lsf_load_func)(struct nvkm_subdev *, struct ls_ucode_img *); | ||
529 | |||
530 | static int | ||
531 | ls_ucode_img_load_fecs(struct nvkm_subdev *subdev, struct ls_ucode_img *img) | ||
532 | { | ||
533 | return ls_ucode_img_load_generic(subdev, img, "fecs", | ||
534 | NVKM_SECBOOT_FALCON_FECS); | ||
535 | } | ||
536 | |||
537 | static int | ||
538 | ls_ucode_img_load_gpccs(struct nvkm_subdev *subdev, struct ls_ucode_img *img) | ||
539 | { | ||
540 | return ls_ucode_img_load_generic(subdev, img, "gpccs", | ||
541 | NVKM_SECBOOT_FALCON_GPCCS); | ||
542 | } | ||
543 | |||
544 | /** | ||
545 | * ls_ucode_img_load() - create a lsf_ucode_img and load it | ||
546 | */ | ||
547 | static struct ls_ucode_img * | ||
548 | ls_ucode_img_load(struct nvkm_subdev *subdev, lsf_load_func load_func) | ||
549 | { | ||
550 | struct ls_ucode_img *img; | ||
551 | int ret; | ||
552 | |||
553 | img = kzalloc(sizeof(*img), GFP_KERNEL); | ||
554 | if (!img) | ||
555 | return ERR_PTR(-ENOMEM); | ||
556 | |||
557 | ret = load_func(subdev, img); | ||
558 | if (ret) { | ||
559 | kfree(img); | ||
560 | return ERR_PTR(ret); | ||
561 | } | ||
562 | |||
563 | return img; | ||
564 | } | ||
565 | |||
566 | static const lsf_load_func lsf_load_funcs[] = { | ||
567 | [NVKM_SECBOOT_FALCON_END] = NULL, /* reserve enough space */ | ||
568 | [NVKM_SECBOOT_FALCON_FECS] = ls_ucode_img_load_fecs, | ||
569 | [NVKM_SECBOOT_FALCON_GPCCS] = ls_ucode_img_load_gpccs, | ||
570 | }; | ||
571 | |||
572 | /** | ||
573 | * ls_ucode_img_populate_bl_desc() - populate a DMEM BL descriptor for LS image | ||
574 | * @img: ucode image to generate against | ||
575 | * @desc: descriptor to populate | ||
576 | * @sb: secure boot state to use for base addresses | ||
577 | * | ||
578 | * Populate the DMEM BL descriptor with the information contained in a | ||
579 | * ls_ucode_desc. | ||
580 | * | ||
581 | */ | ||
582 | static void | ||
583 | ls_ucode_img_populate_bl_desc(struct ls_ucode_img *img, u64 wpr_addr, | ||
584 | struct gm200_flcn_bl_desc *desc) | ||
585 | { | ||
586 | struct ls_ucode_img_desc *pdesc = &img->ucode_desc; | ||
587 | u64 addr_base; | ||
588 | |||
589 | addr_base = wpr_addr + img->lsb_header.ucode_off + | ||
590 | pdesc->app_start_offset; | ||
591 | |||
592 | memset(desc, 0, sizeof(*desc)); | ||
593 | desc->ctx_dma = FALCON_DMAIDX_UCODE; | ||
594 | desc->code_dma_base.lo = lower_32_bits( | ||
595 | (addr_base + pdesc->app_resident_code_offset)); | ||
596 | desc->code_dma_base.hi = upper_32_bits( | ||
597 | (addr_base + pdesc->app_resident_code_offset)); | ||
598 | desc->non_sec_code_size = pdesc->app_resident_code_size; | ||
599 | desc->data_dma_base.lo = lower_32_bits( | ||
600 | (addr_base + pdesc->app_resident_data_offset)); | ||
601 | desc->data_dma_base.hi = upper_32_bits( | ||
602 | (addr_base + pdesc->app_resident_data_offset)); | ||
603 | desc->data_size = pdesc->app_resident_data_size; | ||
604 | desc->code_entry_point = pdesc->app_imem_entry; | ||
605 | } | ||
606 | |||
607 | #define LSF_LSB_HEADER_ALIGN 256 | ||
608 | #define LSF_BL_DATA_ALIGN 256 | ||
609 | #define LSF_BL_DATA_SIZE_ALIGN 256 | ||
610 | #define LSF_BL_CODE_SIZE_ALIGN 256 | ||
611 | #define LSF_UCODE_DATA_ALIGN 4096 | ||
612 | |||
613 | /** | ||
614 | * ls_ucode_img_fill_headers - fill the WPR and LSB headers of an image | ||
615 | * @gsb: secure boot device used | ||
616 | * @img: image to generate for | ||
617 | * @offset: offset in the WPR region where this image starts | ||
618 | * | ||
619 | * Allocate space in the WPR area from offset and write the WPR and LSB headers | ||
620 | * accordingly. | ||
621 | * | ||
622 | * Return: offset at the end of this image. | ||
623 | */ | ||
624 | static u32 | ||
625 | ls_ucode_img_fill_headers(struct gm200_secboot *gsb, struct ls_ucode_img *img, | ||
626 | u32 offset) | ||
627 | { | ||
628 | struct lsf_wpr_header *whdr = &img->wpr_header; | ||
629 | struct lsf_lsb_header *lhdr = &img->lsb_header; | ||
630 | struct ls_ucode_img_desc *desc = &img->ucode_desc; | ||
631 | |||
632 | if (img->ucode_header) { | ||
633 | nvkm_fatal(&gsb->base.subdev, | ||
634 | "images withough loader are not supported yet!\n"); | ||
635 | return offset; | ||
636 | } | ||
637 | |||
638 | /* Fill WPR header */ | ||
639 | whdr->falcon_id = img->falcon_id; | ||
640 | whdr->bootstrap_owner = gsb->base.func->boot_falcon; | ||
641 | whdr->status = LSF_IMAGE_STATUS_COPY; | ||
642 | |||
643 | /* Align, save off, and include an LSB header size */ | ||
644 | offset = ALIGN(offset, LSF_LSB_HEADER_ALIGN); | ||
645 | whdr->lsb_offset = offset; | ||
646 | offset += sizeof(struct lsf_lsb_header); | ||
647 | |||
648 | /* | ||
649 | * Align, save off, and include the original (static) ucode | ||
650 | * image size | ||
651 | */ | ||
652 | offset = ALIGN(offset, LSF_UCODE_DATA_ALIGN); | ||
653 | lhdr->ucode_off = offset; | ||
654 | offset += img->ucode_size; | ||
655 | |||
656 | /* | ||
657 | * For falcons that use a boot loader (BL), we append a loader | ||
658 | * desc structure on the end of the ucode image and consider | ||
659 | * this the boot loader data. The host will then copy the loader | ||
660 | * desc args to this space within the WPR region (before locking | ||
661 | * down) and the HS bin will then copy them to DMEM 0 for the | ||
662 | * loader. | ||
663 | */ | ||
664 | lhdr->bl_code_size = ALIGN(desc->bootloader_size, | ||
665 | LSF_BL_CODE_SIZE_ALIGN); | ||
666 | lhdr->ucode_size = ALIGN(desc->app_resident_data_offset, | ||
667 | LSF_BL_CODE_SIZE_ALIGN) + lhdr->bl_code_size; | ||
668 | lhdr->data_size = ALIGN(desc->app_size, LSF_BL_CODE_SIZE_ALIGN) + | ||
669 | lhdr->bl_code_size - lhdr->ucode_size; | ||
670 | /* | ||
671 | * Though the BL is located at 0th offset of the image, the VA | ||
672 | * is different to make sure that it doesn't collide the actual | ||
673 | * OS VA range | ||
674 | */ | ||
675 | lhdr->bl_imem_off = desc->bootloader_imem_offset; | ||
676 | lhdr->app_code_off = desc->app_start_offset + | ||
677 | desc->app_resident_code_offset; | ||
678 | lhdr->app_code_size = desc->app_resident_code_size; | ||
679 | lhdr->app_data_off = desc->app_start_offset + | ||
680 | desc->app_resident_data_offset; | ||
681 | lhdr->app_data_size = desc->app_resident_data_size; | ||
682 | |||
683 | lhdr->flags = 0; | ||
684 | if (img->falcon_id == gsb->base.func->boot_falcon) | ||
685 | lhdr->flags = LSF_FLAG_DMACTL_REQ_CTX; | ||
686 | |||
687 | /* GPCCS will be loaded using PRI */ | ||
688 | if (img->falcon_id == NVKM_SECBOOT_FALCON_GPCCS) | ||
689 | lhdr->flags |= LSF_FLAG_FORCE_PRIV_LOAD; | ||
690 | |||
691 | /* Align (size bloat) and save off BL descriptor size */ | ||
692 | lhdr->bl_data_size = ALIGN(sizeof(struct gm200_flcn_bl_desc), | ||
693 | LSF_BL_DATA_SIZE_ALIGN); | ||
694 | /* | ||
695 | * Align, save off, and include the additional BL data | ||
696 | */ | ||
697 | offset = ALIGN(offset, LSF_BL_DATA_ALIGN); | ||
698 | lhdr->bl_data_off = offset; | ||
699 | offset += lhdr->bl_data_size; | ||
700 | |||
701 | return offset; | ||
702 | } | ||
703 | |||
704 | static void | ||
705 | ls_ucode_mgr_init(struct ls_ucode_mgr *mgr) | ||
706 | { | ||
707 | memset(mgr, 0, sizeof(*mgr)); | ||
708 | INIT_LIST_HEAD(&mgr->img_list); | ||
709 | } | ||
710 | |||
711 | static void | ||
712 | ls_ucode_mgr_cleanup(struct ls_ucode_mgr *mgr) | ||
713 | { | ||
714 | struct ls_ucode_img *img, *t; | ||
715 | |||
716 | list_for_each_entry_safe(img, t, &mgr->img_list, node) { | ||
717 | kfree(img->ucode_data); | ||
718 | kfree(img->ucode_header); | ||
719 | kfree(img); | ||
720 | } | ||
721 | } | ||
722 | |||
723 | static void | ||
724 | ls_ucode_mgr_add_img(struct ls_ucode_mgr *mgr, struct ls_ucode_img *img) | ||
725 | { | ||
726 | mgr->count++; | ||
727 | list_add_tail(&img->node, &mgr->img_list); | ||
728 | } | ||
729 | |||
730 | /** | ||
731 | * ls_ucode_mgr_fill_headers - fill WPR and LSB headers of all managed images | ||
732 | */ | ||
733 | static void | ||
734 | ls_ucode_mgr_fill_headers(struct gm200_secboot *gsb, struct ls_ucode_mgr *mgr) | ||
735 | { | ||
736 | struct ls_ucode_img *img; | ||
737 | u32 offset; | ||
738 | |||
739 | /* | ||
740 | * Start with an array of WPR headers at the base of the WPR. | ||
741 | * The expectation here is that the secure falcon will do a single DMA | ||
742 | * read of this array and cache it internally so it's ok to pack these. | ||
743 | * Also, we add 1 to the falcon count to indicate the end of the array. | ||
744 | */ | ||
745 | offset = sizeof(struct lsf_wpr_header) * (mgr->count + 1); | ||
746 | |||
747 | /* | ||
748 | * Walk the managed falcons, accounting for the LSB structs | ||
749 | * as well as the ucode images. | ||
750 | */ | ||
751 | list_for_each_entry(img, &mgr->img_list, node) { | ||
752 | offset = ls_ucode_img_fill_headers(gsb, img, offset); | ||
753 | } | ||
754 | |||
755 | mgr->wpr_size = offset; | ||
756 | } | ||
757 | |||
758 | /** | ||
759 | * ls_ucode_mgr_write_wpr - write the WPR blob contents | ||
760 | */ | ||
761 | static int | ||
762 | ls_ucode_mgr_write_wpr(struct gm200_secboot *gsb, struct ls_ucode_mgr *mgr, | ||
763 | struct nvkm_gpuobj *wpr_blob) | ||
764 | { | ||
765 | struct ls_ucode_img *img; | ||
766 | u32 pos = 0; | ||
767 | |||
768 | nvkm_kmap(wpr_blob); | ||
769 | |||
770 | list_for_each_entry(img, &mgr->img_list, node) { | ||
771 | nvkm_gpuobj_memcpy_to(wpr_blob, pos, &img->wpr_header, | ||
772 | sizeof(img->wpr_header)); | ||
773 | |||
774 | nvkm_gpuobj_memcpy_to(wpr_blob, img->wpr_header.lsb_offset, | ||
775 | &img->lsb_header, sizeof(img->lsb_header)); | ||
776 | |||
777 | /* Generate and write BL descriptor */ | ||
778 | if (!img->ucode_header) { | ||
779 | u8 desc[gsb->func->bl_desc_size]; | ||
780 | struct gm200_flcn_bl_desc gdesc; | ||
781 | |||
782 | ls_ucode_img_populate_bl_desc(img, gsb->wpr_addr, | ||
783 | &gdesc); | ||
784 | gsb->func->fixup_bl_desc(&gdesc, &desc); | ||
785 | nvkm_gpuobj_memcpy_to(wpr_blob, | ||
786 | img->lsb_header.bl_data_off, | ||
787 | &desc, gsb->func->bl_desc_size); | ||
788 | } | ||
789 | |||
790 | /* Copy ucode */ | ||
791 | nvkm_gpuobj_memcpy_to(wpr_blob, img->lsb_header.ucode_off, | ||
792 | img->ucode_data, img->ucode_size); | ||
793 | |||
794 | pos += sizeof(img->wpr_header); | ||
795 | } | ||
796 | |||
797 | nvkm_wo32(wpr_blob, pos, NVKM_SECBOOT_FALCON_INVALID); | ||
798 | |||
799 | nvkm_done(wpr_blob); | ||
800 | |||
801 | return 0; | ||
802 | } | ||
803 | |||
804 | /* Both size and address of WPR need to be 128K-aligned */ | ||
805 | #define WPR_ALIGNMENT 0x20000 | ||
806 | /** | ||
807 | * gm200_secboot_prepare_ls_blob() - prepare the LS blob | ||
808 | * | ||
809 | * For each securely managed falcon, load the FW, signatures and bootloaders and | ||
810 | * prepare a ucode blob. Then, compute the offsets in the WPR region for each | ||
811 | * blob, and finally write the headers and ucode blobs into a GPU object that | ||
812 | * will be copied into the WPR region by the HS firmware. | ||
813 | */ | ||
814 | static int | ||
815 | gm200_secboot_prepare_ls_blob(struct gm200_secboot *gsb) | ||
816 | { | ||
817 | struct nvkm_secboot *sb = &gsb->base; | ||
818 | struct nvkm_device *device = sb->subdev.device; | ||
819 | struct ls_ucode_mgr mgr; | ||
820 | int falcon_id; | ||
821 | int ret; | ||
822 | |||
823 | ls_ucode_mgr_init(&mgr); | ||
824 | |||
825 | /* Load all LS blobs */ | ||
826 | for_each_set_bit(falcon_id, &gsb->base.func->managed_falcons, | ||
827 | NVKM_SECBOOT_FALCON_END) { | ||
828 | struct ls_ucode_img *img; | ||
829 | |||
830 | img = ls_ucode_img_load(&sb->subdev, lsf_load_funcs[falcon_id]); | ||
831 | |||
832 | if (IS_ERR(img)) { | ||
833 | ret = PTR_ERR(img); | ||
834 | goto cleanup; | ||
835 | } | ||
836 | ls_ucode_mgr_add_img(&mgr, img); | ||
837 | } | ||
838 | |||
839 | /* | ||
840 | * Fill the WPR and LSF headers with the right offsets and compute | ||
841 | * required WPR size | ||
842 | */ | ||
843 | ls_ucode_mgr_fill_headers(gsb, &mgr); | ||
844 | mgr.wpr_size = ALIGN(mgr.wpr_size, WPR_ALIGNMENT); | ||
845 | |||
846 | /* Allocate GPU object that will contain the WPR region */ | ||
847 | ret = nvkm_gpuobj_new(device, mgr.wpr_size, WPR_ALIGNMENT, false, NULL, | ||
848 | &gsb->ls_blob); | ||
849 | if (ret) | ||
850 | goto cleanup; | ||
851 | |||
852 | nvkm_debug(&sb->subdev, "%d managed LS falcons, WPR size is %d bytes\n", | ||
853 | mgr.count, mgr.wpr_size); | ||
854 | |||
855 | /* If WPR address and size are not fixed, set them to fit the LS blob */ | ||
856 | if (!gsb->wpr_size) { | ||
857 | gsb->wpr_addr = gsb->ls_blob->addr; | ||
858 | gsb->wpr_size = gsb->ls_blob->size; | ||
859 | } | ||
860 | |||
861 | /* Write LS blob */ | ||
862 | ret = ls_ucode_mgr_write_wpr(gsb, &mgr, gsb->ls_blob); | ||
863 | if (ret) | ||
864 | nvkm_gpuobj_del(&gsb->ls_blob); | ||
865 | |||
866 | cleanup: | ||
867 | ls_ucode_mgr_cleanup(&mgr); | ||
868 | |||
869 | return ret; | ||
870 | } | ||
871 | |||
872 | /* | ||
873 | * High-secure blob creation | ||
874 | */ | ||
875 | |||
876 | /** | ||
877 | * gm200_secboot_hsf_patch_signature() - patch HS blob with correct signature | ||
878 | */ | ||
879 | static void | ||
880 | gm200_secboot_hsf_patch_signature(struct gm200_secboot *gsb, void *acr_image) | ||
881 | { | ||
882 | struct nvkm_secboot *sb = &gsb->base; | ||
883 | struct fw_bin_header *hsbin_hdr = acr_image; | ||
884 | struct hsf_fw_header *fw_hdr = acr_image + hsbin_hdr->header_offset; | ||
885 | void *hs_data = acr_image + hsbin_hdr->data_offset; | ||
886 | void *sig; | ||
887 | u32 sig_size; | ||
888 | |||
889 | /* Falcon in debug or production mode? */ | ||
890 | if ((nvkm_rd32(sb->subdev.device, sb->base + 0xc08) >> 20) & 0x1) { | ||
891 | sig = acr_image + fw_hdr->sig_dbg_offset; | ||
892 | sig_size = fw_hdr->sig_dbg_size; | ||
893 | } else { | ||
894 | sig = acr_image + fw_hdr->sig_prod_offset; | ||
895 | sig_size = fw_hdr->sig_prod_size; | ||
896 | } | ||
897 | |||
898 | /* Patch signature */ | ||
899 | memcpy(hs_data + fw_hdr->patch_loc, sig + fw_hdr->patch_sig, sig_size); | ||
900 | } | ||
901 | |||
902 | /** | ||
903 | * gm200_secboot_populate_hsf_bl_desc() - populate BL descriptor for HS image | ||
904 | */ | ||
905 | static void | ||
906 | gm200_secboot_populate_hsf_bl_desc(void *acr_image, | ||
907 | struct gm200_flcn_bl_desc *bl_desc) | ||
908 | { | ||
909 | struct fw_bin_header *hsbin_hdr = acr_image; | ||
910 | struct hsf_fw_header *fw_hdr = acr_image + hsbin_hdr->header_offset; | ||
911 | struct hsf_load_header *load_hdr = acr_image + fw_hdr->hdr_offset; | ||
912 | |||
913 | /* | ||
914 | * Descriptor for the bootloader that will load the ACR image into | ||
915 | * IMEM/DMEM memory. | ||
916 | */ | ||
917 | fw_hdr = acr_image + hsbin_hdr->header_offset; | ||
918 | load_hdr = acr_image + fw_hdr->hdr_offset; | ||
919 | memset(bl_desc, 0, sizeof(*bl_desc)); | ||
920 | bl_desc->ctx_dma = FALCON_DMAIDX_VIRT; | ||
921 | bl_desc->non_sec_code_off = load_hdr->non_sec_code_off; | ||
922 | bl_desc->non_sec_code_size = load_hdr->non_sec_code_size; | ||
923 | bl_desc->sec_code_off = load_hdr->app[0].sec_code_off; | ||
924 | bl_desc->sec_code_size = load_hdr->app[0].sec_code_size; | ||
925 | bl_desc->code_entry_point = 0; | ||
926 | /* | ||
927 | * We need to set code_dma_base to the virtual address of the acr_blob, | ||
928 | * and add this address to data_dma_base before writing it into DMEM | ||
929 | */ | ||
930 | bl_desc->code_dma_base.lo = 0; | ||
931 | bl_desc->data_dma_base.lo = load_hdr->data_dma_base; | ||
932 | bl_desc->data_size = load_hdr->data_size; | ||
933 | } | ||
934 | |||
935 | /** | ||
936 | * gm200_secboot_prepare_hs_blob - load and prepare a HS blob and BL descriptor | ||
937 | * | ||
938 | * @gsb secure boot instance to prepare for | ||
939 | * @fw name of the HS firmware to load | ||
940 | * @blob pointer to gpuobj that will be allocated to receive the HS FW payload | ||
941 | * @bl_desc pointer to the BL descriptor to write for this firmware | ||
942 | * @patch whether we should patch the HS descriptor (only for HS loaders) | ||
943 | */ | ||
944 | static int | ||
945 | gm200_secboot_prepare_hs_blob(struct gm200_secboot *gsb, const char *fw, | ||
946 | struct nvkm_gpuobj **blob, | ||
947 | struct gm200_flcn_bl_desc *bl_desc, bool patch) | ||
948 | { | ||
949 | struct nvkm_subdev *subdev = &gsb->base.subdev; | ||
950 | void *acr_image; | ||
951 | struct fw_bin_header *hsbin_hdr; | ||
952 | struct hsf_fw_header *fw_hdr; | ||
953 | void *acr_data; | ||
954 | struct hsf_load_header *load_hdr; | ||
955 | struct hsflcn_acr_desc *desc; | ||
956 | int ret; | ||
957 | |||
958 | acr_image = gm200_secboot_load_firmware(subdev, fw, 0); | ||
959 | if (IS_ERR(acr_image)) | ||
960 | return PTR_ERR(acr_image); | ||
961 | hsbin_hdr = acr_image; | ||
962 | |||
963 | /* Patch signature */ | ||
964 | gm200_secboot_hsf_patch_signature(gsb, acr_image); | ||
965 | |||
966 | acr_data = acr_image + hsbin_hdr->data_offset; | ||
967 | |||
968 | /* Patch descriptor? */ | ||
969 | if (patch) { | ||
970 | fw_hdr = acr_image + hsbin_hdr->header_offset; | ||
971 | load_hdr = acr_image + fw_hdr->hdr_offset; | ||
972 | desc = acr_data + load_hdr->data_dma_base; | ||
973 | gsb->func->fixup_hs_desc(gsb, desc); | ||
974 | } | ||
975 | |||
976 | /* Generate HS BL descriptor */ | ||
977 | gm200_secboot_populate_hsf_bl_desc(acr_image, bl_desc); | ||
978 | |||
979 | /* Create ACR blob and copy HS data to it */ | ||
980 | ret = nvkm_gpuobj_new(subdev->device, ALIGN(hsbin_hdr->data_size, 256), | ||
981 | 0x1000, false, NULL, blob); | ||
982 | if (ret) | ||
983 | goto cleanup; | ||
984 | |||
985 | nvkm_kmap(*blob); | ||
986 | nvkm_gpuobj_memcpy_to(*blob, 0, acr_data, hsbin_hdr->data_size); | ||
987 | nvkm_done(*blob); | ||
988 | |||
989 | cleanup: | ||
990 | kfree(acr_image); | ||
991 | |||
992 | return ret; | ||
993 | } | ||
994 | |||
995 | /* | ||
996 | * High-secure bootloader blob creation | ||
997 | */ | ||
998 | |||
999 | static int | ||
1000 | gm200_secboot_prepare_hsbl_blob(struct gm200_secboot *gsb) | ||
1001 | { | ||
1002 | struct nvkm_subdev *subdev = &gsb->base.subdev; | ||
1003 | |||
1004 | gsb->hsbl_blob = gm200_secboot_load_firmware(subdev, "acr/bl", 0); | ||
1005 | if (IS_ERR(gsb->hsbl_blob)) { | ||
1006 | int ret = PTR_ERR(gsb->hsbl_blob); | ||
1007 | |||
1008 | gsb->hsbl_blob = NULL; | ||
1009 | return ret; | ||
1010 | } | ||
1011 | |||
1012 | return 0; | ||
1013 | } | ||
1014 | 31 | ||
1015 | /** | 32 | /** |
1016 | * gm20x_secboot_prepare_blobs - load blobs common to all GM20X GPUs. | 33 | * gm200_secboot_run_blob() - run the given high-secure blob |
1017 | * | 34 | * |
1018 | * This includes the LS blob, HS ucode loading blob, and HS bootloader. | ||
1019 | * | ||
1020 | * The HS ucode unload blob is only used on dGPU. | ||
1021 | */ | 35 | */ |
1022 | int | 36 | int |
1023 | gm20x_secboot_prepare_blobs(struct gm200_secboot *gsb) | 37 | gm200_secboot_run_blob(struct nvkm_secboot *sb, struct nvkm_gpuobj *blob) |
1024 | { | ||
1025 | int ret; | ||
1026 | |||
1027 | /* Load and prepare the managed falcon's firmwares */ | ||
1028 | if (!gsb->ls_blob) { | ||
1029 | ret = gm200_secboot_prepare_ls_blob(gsb); | ||
1030 | if (ret) | ||
1031 | return ret; | ||
1032 | } | ||
1033 | |||
1034 | /* Load the HS firmware that will load the LS firmwares */ | ||
1035 | if (!gsb->acr_load_blob) { | ||
1036 | ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_load", | ||
1037 | &gsb->acr_load_blob, | ||
1038 | &gsb->acr_load_bl_desc, true); | ||
1039 | if (ret) | ||
1040 | return ret; | ||
1041 | } | ||
1042 | |||
1043 | /* Load the HS firmware bootloader */ | ||
1044 | if (!gsb->hsbl_blob) { | ||
1045 | ret = gm200_secboot_prepare_hsbl_blob(gsb); | ||
1046 | if (ret) | ||
1047 | return ret; | ||
1048 | } | ||
1049 | |||
1050 | return 0; | ||
1051 | } | ||
1052 | |||
1053 | static int | ||
1054 | gm200_secboot_prepare_blobs(struct gm200_secboot *gsb) | ||
1055 | { | ||
1056 | int ret; | ||
1057 | |||
1058 | ret = gm20x_secboot_prepare_blobs(gsb); | ||
1059 | if (ret) | ||
1060 | return ret; | ||
1061 | |||
1062 | /* dGPU only: load the HS firmware that unprotects the WPR region */ | ||
1063 | if (!gsb->acr_unload_blob) { | ||
1064 | ret = gm200_secboot_prepare_hs_blob(gsb, "acr/ucode_unload", | ||
1065 | &gsb->acr_unload_blob, | ||
1066 | &gsb->acr_unload_bl_desc, false); | ||
1067 | if (ret) | ||
1068 | return ret; | ||
1069 | } | ||
1070 | |||
1071 | return 0; | ||
1072 | } | ||
1073 | |||
1074 | static int | ||
1075 | gm200_secboot_blobs_ready(struct gm200_secboot *gsb) | ||
1076 | { | 38 | { |
39 | struct gm200_secboot *gsb = gm200_secboot(sb); | ||
1077 | struct nvkm_subdev *subdev = &gsb->base.subdev; | 40 | struct nvkm_subdev *subdev = &gsb->base.subdev; |
41 | struct nvkm_falcon *falcon = gsb->base.boot_falcon; | ||
42 | struct nvkm_vma vma; | ||
1078 | int ret; | 43 | int ret; |
1079 | 44 | ||
1080 | /* firmware already loaded, nothing to do... */ | 45 | ret = nvkm_falcon_get(falcon, subdev); |
1081 | if (gsb->firmware_ok) | ||
1082 | return 0; | ||
1083 | |||
1084 | ret = gsb->func->prepare_blobs(gsb); | ||
1085 | if (ret) { | ||
1086 | nvkm_error(subdev, "failed to load secure firmware\n"); | ||
1087 | return ret; | ||
1088 | } | ||
1089 | |||
1090 | gsb->firmware_ok = true; | ||
1091 | |||
1092 | return 0; | ||
1093 | } | ||
1094 | |||
1095 | |||
1096 | /* | ||
1097 | * Secure Boot Execution | ||
1098 | */ | ||
1099 | |||
1100 | /** | ||
1101 | * gm200_secboot_load_hs_bl() - load HS bootloader into DMEM and IMEM | ||
1102 | */ | ||
1103 | static void | ||
1104 | gm200_secboot_load_hs_bl(struct gm200_secboot *gsb, void *data, u32 data_size) | ||
1105 | { | ||
1106 | struct nvkm_device *device = gsb->base.subdev.device; | ||
1107 | struct fw_bin_header *hdr = gsb->hsbl_blob; | ||
1108 | struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset; | ||
1109 | void *blob_data = gsb->hsbl_blob + hdr->data_offset; | ||
1110 | void *hsbl_code = blob_data + hsbl_desc->code_off; | ||
1111 | void *hsbl_data = blob_data + hsbl_desc->data_off; | ||
1112 | u32 code_size = ALIGN(hsbl_desc->code_size, 256); | ||
1113 | const u32 base = gsb->base.base; | ||
1114 | u32 blk; | ||
1115 | u32 tag; | ||
1116 | int i; | ||
1117 | |||
1118 | /* | ||
1119 | * Copy HS bootloader data | ||
1120 | */ | ||
1121 | nvkm_wr32(device, base + 0x1c0, (0x00000000 | (0x1 << 24))); | ||
1122 | for (i = 0; i < hsbl_desc->data_size / 4; i++) | ||
1123 | nvkm_wr32(device, base + 0x1c4, ((u32 *)hsbl_data)[i]); | ||
1124 | |||
1125 | /* | ||
1126 | * Copy HS bootloader interface structure where the HS descriptor | ||
1127 | * expects it to be | ||
1128 | */ | ||
1129 | nvkm_wr32(device, base + 0x1c0, | ||
1130 | (hsbl_desc->dmem_load_off | (0x1 << 24))); | ||
1131 | for (i = 0; i < data_size / 4; i++) | ||
1132 | nvkm_wr32(device, base + 0x1c4, ((u32 *)data)[i]); | ||
1133 | |||
1134 | /* Copy HS bootloader code to end of IMEM */ | ||
1135 | blk = (nvkm_rd32(device, base + 0x108) & 0x1ff) - (code_size >> 8); | ||
1136 | tag = hsbl_desc->start_tag; | ||
1137 | nvkm_wr32(device, base + 0x180, ((blk & 0xff) << 8) | (0x1 << 24)); | ||
1138 | for (i = 0; i < code_size / 4; i++) { | ||
1139 | /* write new tag every 256B */ | ||
1140 | if ((i & 0x3f) == 0) { | ||
1141 | nvkm_wr32(device, base + 0x188, tag & 0xffff); | ||
1142 | tag++; | ||
1143 | } | ||
1144 | nvkm_wr32(device, base + 0x184, ((u32 *)hsbl_code)[i]); | ||
1145 | } | ||
1146 | nvkm_wr32(device, base + 0x188, 0); | ||
1147 | } | ||
1148 | |||
1149 | /** | ||
1150 | * gm200_secboot_setup_falcon() - set up the secure falcon for secure boot | ||
1151 | */ | ||
1152 | static int | ||
1153 | gm200_secboot_setup_falcon(struct gm200_secboot *gsb) | ||
1154 | { | ||
1155 | struct nvkm_device *device = gsb->base.subdev.device; | ||
1156 | struct fw_bin_header *hdr = gsb->hsbl_blob; | ||
1157 | struct fw_bl_desc *hsbl_desc = gsb->hsbl_blob + hdr->header_offset; | ||
1158 | /* virtual start address for boot vector */ | ||
1159 | u32 virt_addr = hsbl_desc->start_tag << 8; | ||
1160 | const u32 base = gsb->base.base; | ||
1161 | const u32 reg_base = base + 0xe00; | ||
1162 | u32 inst_loc; | ||
1163 | int ret; | ||
1164 | |||
1165 | ret = nvkm_secboot_falcon_reset(&gsb->base); | ||
1166 | if (ret) | 46 | if (ret) |
1167 | return ret; | 47 | return ret; |
1168 | 48 | ||
1169 | /* setup apertures - virtual */ | ||
1170 | nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_UCODE), 0x4); | ||
1171 | nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_VIRT), 0x0); | ||
1172 | /* setup apertures - physical */ | ||
1173 | nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_VID), 0x4); | ||
1174 | nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_SYS_COH), | ||
1175 | 0x4 | 0x1); | ||
1176 | nvkm_wr32(device, reg_base + 4 * (FALCON_DMAIDX_PHYS_SYS_NCOH), | ||
1177 | 0x4 | 0x2); | ||
1178 | |||
1179 | /* Set context */ | ||
1180 | if (nvkm_memory_target(gsb->inst->memory) == NVKM_MEM_TARGET_VRAM) | ||
1181 | inst_loc = 0x0; /* FB */ | ||
1182 | else | ||
1183 | inst_loc = 0x3; /* Non-coherent sysmem */ | ||
1184 | |||
1185 | nvkm_mask(device, base + 0x048, 0x1, 0x1); | ||
1186 | nvkm_wr32(device, base + 0x480, | ||
1187 | ((gsb->inst->addr >> 12) & 0xfffffff) | | ||
1188 | (inst_loc << 28) | (1 << 30)); | ||
1189 | |||
1190 | /* Set boot vector to code's starting virtual address */ | ||
1191 | nvkm_wr32(device, base + 0x104, virt_addr); | ||
1192 | |||
1193 | return 0; | ||
1194 | } | ||
1195 | |||
1196 | /** | ||
1197 | * gm200_secboot_run_hs_blob() - run the given high-secure blob | ||
1198 | */ | ||
1199 | static int | ||
1200 | gm200_secboot_run_hs_blob(struct gm200_secboot *gsb, struct nvkm_gpuobj *blob, | ||
1201 | struct gm200_flcn_bl_desc *desc) | ||
1202 | { | ||
1203 | struct nvkm_vma vma; | ||
1204 | u64 vma_addr; | ||
1205 | const u32 bl_desc_size = gsb->func->bl_desc_size; | ||
1206 | u8 bl_desc[bl_desc_size]; | ||
1207 | int ret; | ||
1208 | |||
1209 | /* Map the HS firmware so the HS bootloader can see it */ | 49 | /* Map the HS firmware so the HS bootloader can see it */ |
1210 | ret = nvkm_gpuobj_map(blob, gsb->vm, NV_MEM_ACCESS_RW, &vma); | 50 | ret = nvkm_gpuobj_map(blob, gsb->vm, NV_MEM_ACCESS_RW, &vma); |
1211 | if (ret) | 51 | if (ret) { |
52 | nvkm_falcon_put(falcon, subdev); | ||
1212 | return ret; | 53 | return ret; |
54 | } | ||
1213 | 55 | ||
1214 | /* Add the mapping address to the DMA bases */ | 56 | /* Reset and set the falcon up */ |
1215 | vma_addr = flcn64_to_u64(desc->code_dma_base) + vma.offset; | 57 | ret = nvkm_falcon_reset(falcon); |
1216 | desc->code_dma_base.lo = lower_32_bits(vma_addr); | ||
1217 | desc->code_dma_base.hi = upper_32_bits(vma_addr); | ||
1218 | vma_addr = flcn64_to_u64(desc->data_dma_base) + vma.offset; | ||
1219 | desc->data_dma_base.lo = lower_32_bits(vma_addr); | ||
1220 | desc->data_dma_base.hi = upper_32_bits(vma_addr); | ||
1221 | |||
1222 | /* Fixup the BL header */ | ||
1223 | gsb->func->fixup_bl_desc(desc, &bl_desc); | ||
1224 | |||
1225 | /* Reset the falcon and make it ready to run the HS bootloader */ | ||
1226 | ret = gm200_secboot_setup_falcon(gsb); | ||
1227 | if (ret) | 58 | if (ret) |
1228 | goto done; | 59 | goto end; |
60 | nvkm_falcon_bind_context(falcon, gsb->inst); | ||
1229 | 61 | ||
1230 | /* Load the HS bootloader into the falcon's IMEM/DMEM */ | 62 | /* Load the HS bootloader into the falcon's IMEM/DMEM */ |
1231 | gm200_secboot_load_hs_bl(gsb, &bl_desc, bl_desc_size); | 63 | ret = sb->acr->func->load(sb->acr, &gsb->base, blob, vma.offset); |
1232 | |||
1233 | /* Start the HS bootloader */ | ||
1234 | ret = nvkm_secboot_falcon_run(&gsb->base); | ||
1235 | if (ret) | 64 | if (ret) |
1236 | goto done; | 65 | goto end; |
1237 | |||
1238 | done: | ||
1239 | /* Restore the original DMA addresses */ | ||
1240 | vma_addr = flcn64_to_u64(desc->code_dma_base) - vma.offset; | ||
1241 | desc->code_dma_base.lo = lower_32_bits(vma_addr); | ||
1242 | desc->code_dma_base.hi = upper_32_bits(vma_addr); | ||
1243 | vma_addr = flcn64_to_u64(desc->data_dma_base) - vma.offset; | ||
1244 | desc->data_dma_base.lo = lower_32_bits(vma_addr); | ||
1245 | desc->data_dma_base.hi = upper_32_bits(vma_addr); | ||
1246 | |||
1247 | /* We don't need the ACR firmware anymore */ | ||
1248 | nvkm_gpuobj_unmap(&vma); | ||
1249 | 66 | ||
1250 | return ret; | 67 | /* Disable interrupts as we will poll for the HALT bit */ |
1251 | } | 68 | nvkm_mc_intr_mask(sb->subdev.device, falcon->owner->index, false); |
1252 | 69 | ||
1253 | /* | 70 | /* Set default error value in mailbox register */ |
1254 | * gm200_secboot_reset() - execute secure boot from the prepared state | 71 | nvkm_falcon_wr32(falcon, 0x040, 0xdeada5a5); |
1255 | * | ||
1256 | * Load the HS bootloader and ask the falcon to run it. This will in turn | ||
1257 | * load the HS firmware and run it, so once the falcon stops all the managed | ||
1258 | * falcons should have their LS firmware loaded and be ready to run. | ||
1259 | */ | ||
1260 | int | ||
1261 | gm200_secboot_reset(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon) | ||
1262 | { | ||
1263 | struct gm200_secboot *gsb = gm200_secboot(sb); | ||
1264 | int ret; | ||
1265 | 72 | ||
1266 | /* Make sure all blobs are ready */ | 73 | /* Start the HS bootloader */ |
1267 | ret = gm200_secboot_blobs_ready(gsb); | 74 | nvkm_falcon_set_start_addr(falcon, sb->acr->start_address); |
75 | nvkm_falcon_start(falcon); | ||
76 | ret = nvkm_falcon_wait_for_halt(falcon, 100); | ||
1268 | if (ret) | 77 | if (ret) |
1269 | return ret; | ||
1270 | |||
1271 | /* | ||
1272 | * Dummy GM200 implementation: perform secure boot each time we are | ||
1273 | * called on FECS. Since only FECS and GPCCS are managed and started | ||
1274 | * together, this ought to be safe. | ||
1275 | * | ||
1276 | * Once we have proper PMU firmware and support, this will be changed | ||
1277 | * to a proper call to the PMU method. | ||
1278 | */ | ||
1279 | if (falcon != NVKM_SECBOOT_FALCON_FECS) | ||
1280 | goto end; | 78 | goto end; |
1281 | 79 | ||
1282 | /* If WPR is set and we have an unload blob, run it to unlock WPR */ | 80 | /* If mailbox register contains an error code, then ACR has failed */ |
1283 | if (gsb->acr_unload_blob && | 81 | ret = nvkm_falcon_rd32(falcon, 0x040); |
1284 | gsb->falcon_state[NVKM_SECBOOT_FALCON_FECS] != NON_SECURE) { | 82 | if (ret) { |
1285 | ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_unload_blob, | 83 | nvkm_error(subdev, "ACR boot failed, ret 0x%08x", ret); |
1286 | &gsb->acr_unload_bl_desc); | 84 | ret = -EINVAL; |
1287 | if (ret) | 85 | goto end; |
1288 | return ret; | ||
1289 | } | 86 | } |
1290 | 87 | ||
1291 | /* Reload all managed falcons */ | ||
1292 | ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_load_blob, | ||
1293 | &gsb->acr_load_bl_desc); | ||
1294 | if (ret) | ||
1295 | return ret; | ||
1296 | |||
1297 | end: | 88 | end: |
1298 | gsb->falcon_state[falcon] = RESET; | 89 | /* Reenable interrupts */ |
1299 | return 0; | 90 | nvkm_mc_intr_mask(sb->subdev.device, falcon->owner->index, true); |
1300 | } | ||
1301 | 91 | ||
1302 | int | 92 | /* We don't need the ACR firmware anymore */ |
1303 | gm200_secboot_start(struct nvkm_secboot *sb, enum nvkm_secboot_falcon falcon) | 93 | nvkm_gpuobj_unmap(&vma); |
1304 | { | 94 | nvkm_falcon_put(falcon, subdev); |
1305 | struct gm200_secboot *gsb = gm200_secboot(sb); | ||
1306 | int base; | ||
1307 | |||
1308 | switch (falcon) { | ||
1309 | case NVKM_SECBOOT_FALCON_FECS: | ||
1310 | base = 0x409000; | ||
1311 | break; | ||
1312 | case NVKM_SECBOOT_FALCON_GPCCS: | ||
1313 | base = 0x41a000; | ||
1314 | break; | ||
1315 | default: | ||
1316 | nvkm_error(&sb->subdev, "cannot start unhandled falcon!\n"); | ||
1317 | return -EINVAL; | ||
1318 | } | ||
1319 | |||
1320 | nvkm_wr32(sb->subdev.device, base + 0x130, 0x00000002); | ||
1321 | gsb->falcon_state[falcon] = RUNNING; | ||
1322 | 95 | ||
1323 | return 0; | 96 | return ret; |
1324 | } | 97 | } |
1325 | 98 | ||
1326 | |||
1327 | |||
1328 | int | 99 | int |
1329 | gm200_secboot_init(struct nvkm_secboot *sb) | 100 | gm200_secboot_oneinit(struct nvkm_secboot *sb) |
1330 | { | 101 | { |
1331 | struct gm200_secboot *gsb = gm200_secboot(sb); | 102 | struct gm200_secboot *gsb = gm200_secboot(sb); |
1332 | struct nvkm_device *device = sb->subdev.device; | 103 | struct nvkm_device *device = sb->subdev.device; |
@@ -1361,24 +132,22 @@ gm200_secboot_init(struct nvkm_secboot *sb) | |||
1361 | nvkm_wo32(gsb->inst, 0x20c, upper_32_bits(vm_area_len - 1)); | 132 | nvkm_wo32(gsb->inst, 0x20c, upper_32_bits(vm_area_len - 1)); |
1362 | nvkm_done(gsb->inst); | 133 | nvkm_done(gsb->inst); |
1363 | 134 | ||
135 | if (sb->acr->func->oneinit) { | ||
136 | ret = sb->acr->func->oneinit(sb->acr, sb); | ||
137 | if (ret) | ||
138 | return ret; | ||
139 | } | ||
140 | |||
1364 | return 0; | 141 | return 0; |
1365 | } | 142 | } |
1366 | 143 | ||
1367 | static int | 144 | int |
1368 | gm200_secboot_fini(struct nvkm_secboot *sb, bool suspend) | 145 | gm200_secboot_fini(struct nvkm_secboot *sb, bool suspend) |
1369 | { | 146 | { |
1370 | struct gm200_secboot *gsb = gm200_secboot(sb); | ||
1371 | int ret = 0; | 147 | int ret = 0; |
1372 | int i; | ||
1373 | 148 | ||
1374 | /* Run the unload blob to unprotect the WPR region */ | 149 | if (sb->acr->func->fini) |
1375 | if (gsb->acr_unload_blob && | 150 | ret = sb->acr->func->fini(sb->acr, sb, suspend); |
1376 | gsb->falcon_state[NVKM_SECBOOT_FALCON_FECS] != NON_SECURE) | ||
1377 | ret = gm200_secboot_run_hs_blob(gsb, gsb->acr_unload_blob, | ||
1378 | &gsb->acr_unload_bl_desc); | ||
1379 | |||
1380 | for (i = 0; i < NVKM_SECBOOT_FALCON_END; i++) | ||
1381 | gsb->falcon_state[i] = NON_SECURE; | ||
1382 | 151 | ||
1383 | return ret; | 152 | return ret; |
1384 | } | 153 | } |
@@ -1388,11 +157,7 @@ gm200_secboot_dtor(struct nvkm_secboot *sb) | |||
1388 | { | 157 | { |
1389 | struct gm200_secboot *gsb = gm200_secboot(sb); | 158 | struct gm200_secboot *gsb = gm200_secboot(sb); |
1390 | 159 | ||
1391 | nvkm_gpuobj_del(&gsb->acr_unload_blob); | 160 | sb->acr->func->dtor(sb->acr); |
1392 | |||
1393 | kfree(gsb->hsbl_blob); | ||
1394 | nvkm_gpuobj_del(&gsb->acr_load_blob); | ||
1395 | nvkm_gpuobj_del(&gsb->ls_blob); | ||
1396 | 161 | ||
1397 | nvkm_vm_ref(NULL, &gsb->vm, gsb->pgd); | 162 | nvkm_vm_ref(NULL, &gsb->vm, gsb->pgd); |
1398 | nvkm_gpuobj_del(&gsb->pgd); | 163 | nvkm_gpuobj_del(&gsb->pgd); |
@@ -1405,50 +170,9 @@ gm200_secboot_dtor(struct nvkm_secboot *sb) | |||
1405 | static const struct nvkm_secboot_func | 170 | static const struct nvkm_secboot_func |
1406 | gm200_secboot = { | 171 | gm200_secboot = { |
1407 | .dtor = gm200_secboot_dtor, | 172 | .dtor = gm200_secboot_dtor, |
1408 | .init = gm200_secboot_init, | 173 | .oneinit = gm200_secboot_oneinit, |
1409 | .fini = gm200_secboot_fini, | 174 | .fini = gm200_secboot_fini, |
1410 | .reset = gm200_secboot_reset, | 175 | .run_blob = gm200_secboot_run_blob, |
1411 | .start = gm200_secboot_start, | ||
1412 | .managed_falcons = BIT(NVKM_SECBOOT_FALCON_FECS) | | ||
1413 | BIT(NVKM_SECBOOT_FALCON_GPCCS), | ||
1414 | .boot_falcon = NVKM_SECBOOT_FALCON_PMU, | ||
1415 | }; | ||
1416 | |||
1417 | /** | ||
1418 | * gm200_fixup_bl_desc - just copy the BL descriptor | ||
1419 | * | ||
1420 | * Use the GM200 descriptor format by default. | ||
1421 | */ | ||
1422 | static void | ||
1423 | gm200_secboot_fixup_bl_desc(const struct gm200_flcn_bl_desc *desc, void *ret) | ||
1424 | { | ||
1425 | memcpy(ret, desc, sizeof(*desc)); | ||
1426 | } | ||
1427 | |||
1428 | static void | ||
1429 | gm200_secboot_fixup_hs_desc(struct gm200_secboot *gsb, | ||
1430 | struct hsflcn_acr_desc *desc) | ||
1431 | { | ||
1432 | desc->ucode_blob_base = gsb->ls_blob->addr; | ||
1433 | desc->ucode_blob_size = gsb->ls_blob->size; | ||
1434 | |||
1435 | desc->wpr_offset = 0; | ||
1436 | |||
1437 | /* WPR region information for the HS binary to set up */ | ||
1438 | desc->wpr_region_id = 1; | ||
1439 | desc->regions.no_regions = 1; | ||
1440 | desc->regions.region_props[0].region_id = 1; | ||
1441 | desc->regions.region_props[0].start_addr = gsb->wpr_addr >> 8; | ||
1442 | desc->regions.region_props[0].end_addr = | ||
1443 | (gsb->wpr_addr + gsb->wpr_size) >> 8; | ||
1444 | } | ||
1445 | |||
1446 | static const struct gm200_secboot_func | ||
1447 | gm200_secboot_func = { | ||
1448 | .bl_desc_size = sizeof(struct gm200_flcn_bl_desc), | ||
1449 | .fixup_bl_desc = gm200_secboot_fixup_bl_desc, | ||
1450 | .fixup_hs_desc = gm200_secboot_fixup_hs_desc, | ||
1451 | .prepare_blobs = gm200_secboot_prepare_blobs, | ||
1452 | }; | 176 | }; |
1453 | 177 | ||
1454 | int | 178 | int |
@@ -1457,6 +181,12 @@ gm200_secboot_new(struct nvkm_device *device, int index, | |||
1457 | { | 181 | { |
1458 | int ret; | 182 | int ret; |
1459 | struct gm200_secboot *gsb; | 183 | struct gm200_secboot *gsb; |
184 | struct nvkm_acr *acr; | ||
185 | |||
186 | acr = acr_r361_new(BIT(NVKM_SECBOOT_FALCON_FECS) | | ||
187 | BIT(NVKM_SECBOOT_FALCON_GPCCS)); | ||
188 | if (IS_ERR(acr)) | ||
189 | return PTR_ERR(acr); | ||
1460 | 190 | ||
1461 | gsb = kzalloc(sizeof(*gsb), GFP_KERNEL); | 191 | gsb = kzalloc(sizeof(*gsb), GFP_KERNEL); |
1462 | if (!gsb) { | 192 | if (!gsb) { |
@@ -1465,15 +195,14 @@ gm200_secboot_new(struct nvkm_device *device, int index, | |||
1465 | } | 195 | } |
1466 | *psb = &gsb->base; | 196 | *psb = &gsb->base; |
1467 | 197 | ||
1468 | ret = nvkm_secboot_ctor(&gm200_secboot, device, index, &gsb->base); | 198 | ret = nvkm_secboot_ctor(&gm200_secboot, acr, device, index, &gsb->base); |
1469 | if (ret) | 199 | if (ret) |
1470 | return ret; | 200 | return ret; |
1471 | 201 | ||
1472 | gsb->func = &gm200_secboot_func; | ||
1473 | |||
1474 | return 0; | 202 | return 0; |
1475 | } | 203 | } |
1476 | 204 | ||
205 | |||
1477 | MODULE_FIRMWARE("nvidia/gm200/acr/bl.bin"); | 206 | MODULE_FIRMWARE("nvidia/gm200/acr/bl.bin"); |
1478 | MODULE_FIRMWARE("nvidia/gm200/acr/ucode_load.bin"); | 207 | MODULE_FIRMWARE("nvidia/gm200/acr/ucode_load.bin"); |
1479 | MODULE_FIRMWARE("nvidia/gm200/acr/ucode_unload.bin"); | 208 | MODULE_FIRMWARE("nvidia/gm200/acr/ucode_unload.bin"); |