File Index
Files and directories
Sign in
FILE

gh100.c

File preview with syntax highlighting.

linux-6.19.14/drivers/gpu/drm/nouveau/nvkm/subdev/gsp/gh100.c C
  1/* SPDX-License-Identifier: MIT
  2 *
  3 * Copyright (c) 2025, NVIDIA CORPORATION. All rights reserved.
  4 */
  5#include "priv.h"
  6
  7#include <linux/elf.h>
  8#include <linux/crc32.h>
  9
 10#include <subdev/fb.h>
 11#include <subdev/fsp.h>
 12
 13#include <rm/r570/nvrm/gsp.h>
 14
 15#include <nvhw/drf.h>
 16#include <nvhw/ref/gh100/dev_falcon_v4.h>
 17#include <nvhw/ref/gh100/dev_riscv_pri.h>
 18
 19int
 20gh100_gsp_fini(struct nvkm_gsp *gsp, enum nvkm_suspend_state suspend)
 21{
 22	struct nvkm_falcon *falcon = &gsp->falcon;
 23	int ret, time = 4000;
 24
 25	/* Shutdown RM. */
 26	ret = r535_gsp_fini(gsp, suspend);
 27	if (ret && suspend)
 28		return ret;
 29
 30	/* Wait for RISC-V to halt. */
 31	do {
 32		u32 data = nvkm_falcon_rd32(falcon, falcon->addr2 + NV_PRISCV_RISCV_CPUCTL);
 33
 34		if (NVVAL_GET(data, NV_PRISCV, RISCV_CPUCTL, HALTED))
 35			return 0;
 36
 37		usleep_range(1000, 2000);
 38	} while(time--);
 39
 40	return -ETIMEDOUT;
 41}
 42
 43static bool
 44gh100_gsp_lockdown_released(struct nvkm_gsp *gsp, u32 *mbox0)
 45{
 46	u32 data;
 47
 48	/* Wait for GSP access via BAR0 to be allowed. */
 49	*mbox0 = nvkm_falcon_rd32(&gsp->falcon, NV_PFALCON_FALCON_MAILBOX0);
 50
 51	if (*mbox0 && (*mbox0 & 0xffffff00) == 0xbadf4100)
 52		return false;
 53
 54	/* Check if an error code has been reported. */
 55	if (*mbox0) {
 56		u32 mbox1 = nvkm_falcon_rd32(&gsp->falcon, NV_PFALCON_FALCON_MAILBOX1);
 57
 58		/* Any value that's not GSP_FMC_BOOT_PARAMS addr is an error. */
 59		if ((((u64)mbox1 << 32) | *mbox0) != gsp->fmc.args.addr)
 60			return true;
 61	}
 62
 63	/* Check if lockdown has been released. */
 64	data = nvkm_falcon_rd32(&gsp->falcon, NV_PFALCON_FALCON_HWCFG2);
 65	return !NVVAL_GET(data, NV_PFALCON, FALCON_HWCFG2, RISCV_BR_PRIV_LOCKDOWN);
 66}
 67
 68int
 69gh100_gsp_init(struct nvkm_gsp *gsp)
 70{
 71	struct nvkm_subdev *subdev = &gsp->subdev;
 72	struct nvkm_device *device = subdev->device;
 73	const bool resume = gsp->sr.meta.data != NULL;
 74	struct nvkm_gsp_mem *meta;
 75	GSP_FMC_BOOT_PARAMS *args;
 76	int ret, time = 4000;
 77	u32 rsvd_size;
 78	u32 mbox0;
 79
 80	if (!resume) {
 81		ret = nvkm_gsp_mem_ctor(gsp, sizeof(*args), &gsp->fmc.args);
 82		if (ret)
 83			return ret;
 84
 85		meta = &gsp->wpr_meta;
 86	} else {
 87		gsp->rm->api->gsp->set_rmargs(gsp, true);
 88		meta = &gsp->sr.meta;
 89	}
 90
 91	args = gsp->fmc.args.data;
 92
 93	args->bootGspRmParams.gspRmDescOffset = meta->addr;
 94	args->bootGspRmParams.gspRmDescSize = meta->size;
 95	args->bootGspRmParams.target = GSP_DMA_TARGET_COHERENT_SYSTEM;
 96	args->bootGspRmParams.bIsGspRmBoot = 1;
 97
 98	args->gspRmParams.target = GSP_DMA_TARGET_NONCOHERENT_SYSTEM;
 99	args->gspRmParams.bootArgsOffset = gsp->libos.addr;
100
101	rsvd_size = gsp->fb.heap.size;
102	if (gsp->rm->wpr->rsvd_size_pmu)
103		rsvd_size = ALIGN(rsvd_size + gsp->rm->wpr->rsvd_size_pmu, 0x200000);
104
105	ret = nvkm_fsp_boot_gsp_fmc(device->fsp, gsp->fmc.args.addr, rsvd_size, resume,
106				    gsp->fmc.fw.addr, gsp->fmc.hash, gsp->fmc.pkey, gsp->fmc.sig);
107	if (ret)
108		return ret;
109
110	do {
111		if (gh100_gsp_lockdown_released(gsp, &mbox0))
112			break;
113
114		usleep_range(1000, 2000);
115	} while(time--);
116
117	if (time < 0) {
118		nvkm_error(subdev, "GSP-FMC boot timed out\n");
119		return -ETIMEDOUT;
120	}
121
122	if (mbox0) {
123		nvkm_error(subdev, "GSP-FMC boot failed (mbox: 0x%08x)\n", mbox0);
124		return -EIO;
125	}
126
127	return r535_gsp_init(gsp);
128}
129
130static int
131gh100_gsp_wpr_meta_init(struct nvkm_gsp *gsp)
132{
133	GspFwWprMeta *meta;
134	int ret;
135
136	ret = nvkm_gsp_mem_ctor(gsp, sizeof(*meta), &gsp->wpr_meta);
137	if (ret)
138		return ret;
139
140	gsp->fb.size = nvkm_fb_vidmem_size(gsp->subdev.device);
141	gsp->fb.bios.vga_workspace.size = 128 * 1024;
142	gsp->fb.heap.size = gsp->rm->wpr->heap_size_non_wpr;
143
144	meta = gsp->wpr_meta.data;
145
146	meta->magic = GSP_FW_WPR_META_MAGIC;
147	meta->revision = GSP_FW_WPR_META_REVISION;
148
149	meta->sizeOfRadix3Elf = gsp->fw.len;
150	meta->sysmemAddrOfRadix3Elf = gsp->radix3.lvl0.addr;
151
152	meta->sizeOfBootloader = gsp->boot.fw.size;
153	meta->sysmemAddrOfBootloader = gsp->boot.fw.addr;
154	meta->bootloaderCodeOffset = gsp->boot.code_offset;
155	meta->bootloaderDataOffset = gsp->boot.data_offset;
156	meta->bootloaderManifestOffset = gsp->boot.manifest_offset;
157
158	meta->sysmemAddrOfSignature = gsp->sig.addr;
159	meta->sizeOfSignature = gsp->sig.size;
160
161	meta->nonWprHeapSize = gsp->fb.heap.size;
162	meta->gspFwHeapSize = tu102_gsp_wpr_heap_size(gsp);
163	meta->frtsSize = 0x100000;
164	meta->vgaWorkspaceSize = gsp->fb.bios.vga_workspace.size;
165	meta->pmuReservedSize = gsp->rm->wpr->rsvd_size_pmu;
166	return 0;
167}
168
169/* The sh_flags value for the binary blobs in the ELF image */
170#define FMC_SHF_FLAGS (SHF_MASKPROC | SHF_MASKOS | SHF_OS_NONCONFORMING | SHF_ALLOC)
171
172#define ELF_HDR_SIZE ((u8)sizeof(struct elf32_hdr))
173#define ELF_SHDR_SIZE ((u8)sizeof(struct elf32_shdr))
174
175/* The FMC ELF header must be exactly this */
176static const u8 elf_header[] = {
177	0x7f, 'E', 'L', 'F', 1, 1, 1, 0,
178	0, 0, 0, 0, 0, 0, 0, 0,
179
180	0, 0, 0, 0, 1, 0, 0, 0, /* e_type, e_machine, e_version */
181	0, 0, 0, 0, 0, 0, 0, 0, /* e_entry, e_phoff */
182
183	ELF_HDR_SIZE, 0, 0, 0, 0, 0, 0, 0, /* e_shoff, e_flags */
184	ELF_HDR_SIZE, 0, 0, 0, /* e_ehsize, e_phentsize */
185	0, 0, ELF_SHDR_SIZE, 0, /* e_phnum, e_shentsize */
186
187	6, 0, 1, 0, /* e_shnum, e_shstrndx */
188};
189
190/**
191 * elf_validate_sections - validate each section in the FMC ELF image
192 * @elf: ELF image
193 * @length: size of the entire ELF image
194 */
195static bool
196elf_validate_sections(const void *elf, size_t length)
197{
198	const struct elf32_hdr *ehdr = elf;
199	const struct elf32_shdr *shdr = elf + ehdr->e_shoff;
200
201	/* The offset of the first section */
202	Elf32_Off section_begin = ehdr->e_shoff + ehdr->e_shnum * ehdr->e_shentsize;
203
204	if (section_begin > length)
205		return false;
206
207	/* The first section header is the null section, so skip it */
208	for (unsigned int i = 1; i < ehdr->e_shnum; i++) {
209		if (i == ehdr->e_shstrndx) {
210			if (shdr[i].sh_type != SHT_STRTAB)
211				return false;
212			if (shdr[i].sh_flags != SHF_STRINGS)
213				return false;
214		} else {
215			if (shdr[i].sh_type != SHT_PROGBITS)
216				return false;
217			if (shdr[i].sh_flags != FMC_SHF_FLAGS)
218				return false;
219		}
220
221		/* Ensure that each section is inside the image */
222		if (shdr[i].sh_offset < section_begin ||
223		    (u64)shdr[i].sh_offset + shdr[i].sh_size > length)
224			return false;
225
226		/* Non-zero sh_info is a CRC */
227		if (shdr[i].sh_info) {
228			/* The kernel's CRC32 needs a pre- and post-xor to match standard CRCs */
229			u32 crc32 = crc32_le(~0, elf + shdr[i].sh_offset, shdr[i].sh_size) ^ ~0;
230
231			if (shdr[i].sh_info != crc32)
232				return false;
233		}
234	}
235
236	return true;
237}
238
239/**
240 * elf_section - return a pointer to the data for a given section
241 * @elf: ELF image
242 * @name: section name to search for
243 * @len: pointer to returned length of found section
244 */
245static const void *
246elf_section(const void *elf, const char *name, unsigned int *len)
247{
248	const struct elf32_hdr *ehdr = elf;
249	const struct elf32_shdr *shdr = elf + ehdr->e_shoff;
250	const char *names = elf + shdr[ehdr->e_shstrndx].sh_offset;
251
252	for (unsigned int i = 1; i < ehdr->e_shnum; i++) {
253		if (!strcmp(&names[shdr[i].sh_name], name)) {
254			*len = shdr[i].sh_size;
255			return elf + shdr[i].sh_offset;
256		}
257	}
258
259	return NULL;
260}
261
262int
263gh100_gsp_oneinit(struct nvkm_gsp *gsp)
264{
265	struct nvkm_subdev *subdev = &gsp->subdev;
266	struct nvkm_device *device = subdev->device;
267	struct nvkm_fsp *fsp = device->fsp;
268	const void *fw = gsp->fws.fmc->data;
269	const void *hash, *sig, *pkey, *img;
270	unsigned int img_len = 0, hash_len = 0, pkey_len = 0, sig_len = 0;
271	int ret;
272
273	if (gsp->fws.fmc->size < ELF_HDR_SIZE ||
274	    memcmp(fw, elf_header, sizeof(elf_header)) ||
275	    !elf_validate_sections(fw, gsp->fws.fmc->size)) {
276		nvkm_error(subdev, "fmc firmware image is invalid\n");
277		return -ENODATA;
278	}
279
280	hash = elf_section(fw, "hash", &hash_len);
281	sig = elf_section(fw, "signature", &sig_len);
282	pkey = elf_section(fw, "publickey", &pkey_len);
283	img = elf_section(fw, "image", &img_len);
284
285	if (!hash || !sig || !pkey || !img) {
286		nvkm_error(subdev, "fmc firmware image is invalid\n");
287		return -ENODATA;
288	}
289
290	if (!nvkm_fsp_verify_gsp_fmc(fsp, hash_len, pkey_len, sig_len))
291		return -EINVAL;
292
293	/* Load GSP-FMC FW into memory. */
294	ret = nvkm_gsp_mem_ctor(gsp, img_len, &gsp->fmc.fw);
295	if (ret)
296		return ret;
297
298	memcpy(gsp->fmc.fw.data, img, img_len);
299
300	gsp->fmc.hash = kmemdup(hash, hash_len, GFP_KERNEL);
301	gsp->fmc.pkey = kmemdup(pkey, pkey_len, GFP_KERNEL);
302	gsp->fmc.sig = kmemdup(sig, sig_len, GFP_KERNEL);
303	if (!gsp->fmc.hash || !gsp->fmc.pkey || !gsp->fmc.sig)
304		return -ENOMEM;
305
306	ret = r535_gsp_oneinit(gsp);
307	if (ret)
308		return ret;
309
310	return gh100_gsp_wpr_meta_init(gsp);
311}
312
313static const struct nvkm_gsp_func
314gh100_gsp = {
315	.flcn = &ga102_gsp_flcn,
316
317	.sig_section = ".fwsignature_gh100",
318
319	.dtor = r535_gsp_dtor,
320	.oneinit = gh100_gsp_oneinit,
321	.init = gh100_gsp_init,
322	.fini = gh100_gsp_fini,
323
324	.rm.gpu = &gh100_gpu,
325};
326
327int
328gh100_gsp_load(struct nvkm_gsp *gsp, int ver, const struct nvkm_gsp_fwif *fwif)
329{
330	int ret;
331
332	ret = tu102_gsp_load_rm(gsp, fwif);
333	if (ret)
334		goto done;
335
336	ret = nvkm_gsp_load_fw(gsp, "fmc", fwif->ver, &gsp->fws.fmc);
337
338done:
339	if (ret)
340		nvkm_gsp_dtor_fws(gsp);
341
342	return ret;
343}
344
345static struct nvkm_gsp_fwif
346gh100_gsps[] = {
347	{ 0, gh100_gsp_load, &gh100_gsp, &r570_rm_gh100, "570.144" },
348	{}
349};
350
351int
352gh100_gsp_new(struct nvkm_device *device, enum nvkm_subdev_type type, int inst,
353	      struct nvkm_gsp **pgsp)
354{
355	return nvkm_gsp_new_(gh100_gsps, device, type, inst, pgsp);
356}
357
358NVKM_GSP_FIRMWARE_FMC(gh100, 570.144);
~/ Read-only file preview.