nv: remaining firmware from /lib/firmware (#16088)

This commit is contained in:
Christopher Milan
2026-05-07 20:07:43 -07:00
committed by GitHub
parent 7ef901a81d
commit faabe6aa42
6 changed files with 171 additions and 22 deletions

25
extra/nv_gpu_driver/fw.h Normal file
View File

@@ -0,0 +1,25 @@
/* adapted from linux/drivers/gpu/drm/nouveau/include/nvfw/fw.h */
/* SPDX-License-Identifier: MIT */
#ifndef __NVFW_FW_H__
#define __NVFW_FW_H__
typedef unsigned int u32;
struct nvfw_bin_hdr {
u32 bin_magic;
u32 bin_ver;
u32 bin_size;
u32 header_offset;
u32 data_offset;
u32 data_size;
};
struct nvfw_bl_desc {
u32 start_tag;
u32 dmem_load_off;
u32 code_off;
u32 code_size;
u32 data_off;
u32 data_size;
};
#endif

52
extra/nv_gpu_driver/hs.h Normal file
View File

@@ -0,0 +1,52 @@
/* adapted from linux/drivers/gpu/drm/nouveau/include/nvfw/hs.h */
/* SPDX-License-Identifier: MIT */
#ifndef __NVFW_HS_H__
#define __NVFW_HS_H__
typedef unsigned int u32;
struct nvfw_hs_header {
u32 sig_dbg_offset;
u32 sig_dbg_size;
u32 sig_prod_offset;
u32 sig_prod_size;
u32 patch_loc;
u32 patch_sig;
u32 hdr_offset;
u32 hdr_size;
};
struct nvfw_hs_header_v2 {
u32 sig_prod_offset;
u32 sig_prod_size;
u32 patch_loc;
u32 patch_sig;
u32 meta_data_offset;
u32 meta_data_size;
u32 num_sig;
u32 header_offset;
u32 header_size;
};
struct nvfw_hs_load_header {
u32 non_sec_code_off;
u32 non_sec_code_size;
u32 data_dma_base;
u32 data_size;
u32 num_apps;
u32 apps[];
};
struct nvfw_hs_load_header_v2 {
u32 os_code_offset;
u32 os_code_size;
u32 os_data_offset;
u32 os_data_size;
u32 num_apps;
struct {
u32 offset;
u32 size;
u32 data_offset;
u32 data_size;
} app[];
};
#endif

View File

@@ -81,7 +81,7 @@ def __getattr__(nm):
*[f"{{}}/src/nvidia/inc/kernel/vgpu/{s}.h" for s in ["rpc_headers", "rpc_global_enums"]],
"{}/src/common/uproc/os/common/include/libos_init_args.h", "{}/src/common/shared/msgq/inc/msgq/msgq_priv.h",
"{}/src/nvidia/generated/g_rpc-structures.h", root/"extra/nv_gpu_driver/g_rpc-message-header.h", root/"extra/nv_gpu_driver/gsp_static_config.h",
root/"extra/nv_gpu_driver/vbios.h", root/"extra/nv_gpu_driver/pci_exp_table.h"
*[root/f"extra/nv_gpu_driver/{s}.h" for s in ["vbios", "pci_exp_table", "fw", "hs"]]
], args=[
"-DRPC_MESSAGE_STRUCTURES", "-DRPC_STRUCTURES", "-include", "{}/src/common/sdk/nvidia/inc/nvtypes.h", "-I{}/src/nvidia/generated",
"-I{}/src/common/inc", "-I{}/src/nvidia/inc", "-I{}/src/nvidia/interface/", "-I{}/src/nvidia/inc/kernel", "-I{}/src/nvidia/inc/libraries",

View File

@@ -4683,6 +4683,80 @@ class struct__NV_PCI_DATA_EXT_STRUCT(c.Struct):
struct__NV_PCI_DATA_EXT_STRUCT.register_fields([('signature', NvU32, 0), ('nvPciDataExtRev', NvU16, 4), ('nvPciDataExtLen', NvU16, 6), ('subimageLen', NvU16, 8), ('privLastImage', NvU8, 10), ('flags', NvU8, 11)])
NV_PCI_DATA_EXT_STRUCT: TypeAlias = struct__NV_PCI_DATA_EXT_STRUCT
PNV_PCI_DATA_EXT_STRUCT: TypeAlias = c.POINTER[struct__NV_PCI_DATA_EXT_STRUCT]
u32: TypeAlias = ctypes.c_uint32
@c.record
class struct_nvfw_bin_hdr(c.Struct):
SIZE = 24
bin_magic: int
bin_ver: int
bin_size: int
header_offset: int
data_offset: int
data_size: int
struct_nvfw_bin_hdr.register_fields([('bin_magic', u32, 0), ('bin_ver', u32, 4), ('bin_size', u32, 8), ('header_offset', u32, 12), ('data_offset', u32, 16), ('data_size', u32, 20)])
@c.record
class struct_nvfw_bl_desc(c.Struct):
SIZE = 24
start_tag: int
dmem_load_off: int
code_off: int
code_size: int
data_off: int
data_size: int
struct_nvfw_bl_desc.register_fields([('start_tag', u32, 0), ('dmem_load_off', u32, 4), ('code_off', u32, 8), ('code_size', u32, 12), ('data_off', u32, 16), ('data_size', u32, 20)])
@c.record
class struct_nvfw_hs_header(c.Struct):
SIZE = 32
sig_dbg_offset: int
sig_dbg_size: int
sig_prod_offset: int
sig_prod_size: int
patch_loc: int
patch_sig: int
hdr_offset: int
hdr_size: int
struct_nvfw_hs_header.register_fields([('sig_dbg_offset', u32, 0), ('sig_dbg_size', u32, 4), ('sig_prod_offset', u32, 8), ('sig_prod_size', u32, 12), ('patch_loc', u32, 16), ('patch_sig', u32, 20), ('hdr_offset', u32, 24), ('hdr_size', u32, 28)])
@c.record
class struct_nvfw_hs_header_v2(c.Struct):
SIZE = 36
sig_prod_offset: int
sig_prod_size: int
patch_loc: int
patch_sig: int
meta_data_offset: int
meta_data_size: int
num_sig: int
header_offset: int
header_size: int
struct_nvfw_hs_header_v2.register_fields([('sig_prod_offset', u32, 0), ('sig_prod_size', u32, 4), ('patch_loc', u32, 8), ('patch_sig', u32, 12), ('meta_data_offset', u32, 16), ('meta_data_size', u32, 20), ('num_sig', u32, 24), ('header_offset', u32, 28), ('header_size', u32, 32)])
@c.record
class struct_nvfw_hs_load_header(c.Struct):
SIZE = 20
non_sec_code_off: int
non_sec_code_size: int
data_dma_base: int
data_size: int
num_apps: int
apps: c.Array[ctypes.c_uint32, Literal[0]]
struct_nvfw_hs_load_header.register_fields([('non_sec_code_off', u32, 0), ('non_sec_code_size', u32, 4), ('data_dma_base', u32, 8), ('data_size', u32, 12), ('num_apps', u32, 16), ('apps', c.Array[u32, Literal[0]], 20)])
@c.record
class struct_nvfw_hs_load_header_v2(c.Struct):
SIZE = 20
os_code_offset: int
os_code_size: int
os_data_offset: int
os_data_size: int
num_apps: int
app: c.Array[struct_nvfw_hs_load_header_v2_app, Literal[0]]
@c.record
class struct_nvfw_hs_load_header_v2_app(c.Struct):
SIZE = 16
offset: int
size: int
data_offset: int
data_size: int
struct_nvfw_hs_load_header_v2_app.register_fields([('offset', u32, 0), ('size', u32, 4), ('data_offset', u32, 8), ('data_size', u32, 12)])
struct_nvfw_hs_load_header_v2.register_fields([('os_code_offset', u32, 0), ('os_code_size', u32, 4), ('os_data_offset', u32, 8), ('os_data_size', u32, 12), ('num_apps', u32, 16), ('app', c.Array[struct_nvfw_hs_load_header_v2_app, Literal[0]], 20)])
GSP_FW_WPR_META_VERIFIED = 0xa0a0a0a0a0a0a0a0
GSP_FW_WPR_META_REVISION = 1
GSP_FW_WPR_META_MAGIC = 0xdc3aae21371a60b3

View File

@@ -169,16 +169,19 @@ class NV_FLCN(NV_IP):
_, self.frts_image_sysmem = __patch(0x15, bytes(frts_cmd))
def prep_booter(self):
image = self.nvdev.extract_fw("kgspBinArchiveBooterLoadUcode", "image_prod_data")
sig = self.nvdev.extract_fw("kgspBinArchiveBooterLoadUcode", "sig_prod_data")
header = self.nvdev.extract_fw("kgspBinArchiveBooterLoadUcode", "header_prod_data")
patch_loc = int.from_bytes(self.nvdev.extract_fw("kgspBinArchiveBooterLoadUcode", "patch_loc_data"), 'little')
sig_len = len(sig) // int.from_bytes(self.nvdev.extract_fw("kgspBinArchiveBooterLoadUcode", "num_sigs_data"), 'little')
sha = {"ga102":"4497e3eff7e95c774b8a569d17b27c08c9650158d10b229d2be81cdcad9a085b",
"ad102":"8b293e19b637c5e22c87a2428d1c71bb13e0904e8a88ac6b3c6c1f2679c6e37a"}[self.nvdev.fw_name]
h = nv.struct_nvfw_bin_hdr.from_buffer_copy(b:=fetch_fw(f"nvidia/{self.nvdev.fw_name}/gsp", "booter_load-570.144.bin", sha))
lh = nv.struct_nvfw_hs_load_header_v2.from_buffer_copy(b, (hs:=nv.struct_nvfw_hs_header_v2.from_buffer_copy(b, h.header_offset)).header_offset)
app = nv.struct_nvfw_hs_load_header_v2_app.from_buffer_copy(b, hs.header_offset + ctypes.sizeof(nv.struct_nvfw_hs_load_header_v2))
patch_loc, patch_sig = struct.unpack_from("<I", b, hs.patch_loc)[0], struct.unpack_from("<I", b, hs.patch_sig)[0]
sig = b[(sig_off:=hs.sig_prod_offset + patch_sig):sig_off + (sig_len:=hs.sig_prod_size // struct.unpack_from("<I", b, hs.num_sig)[0])]
(patched_image:=bytearray(b[h.data_offset:h.data_offset + h.data_size]))[patch_loc:patch_loc+sig_len] = sig
patched_image = bytearray(image)
patched_image[patch_loc:patch_loc+sig_len] = sig[:sig_len]
_, self.booter_image_sysmem = self.nvdev._alloc_sysmem(len(patched_image), contiguous=True, data=patched_image)
_, _, self.booter_data_off, self.booter_data_sz, _, self.booter_code_off, self.booter_code_sz, _, _ = struct.unpack("9I", header)
self.booter_data_off, self.booter_data_sz, self.booter_code_off, self.booter_code_sz = lh.os_data_offset, lh.os_data_size, app.offset, app.size
def init_hw(self):
self.falcon, self.sec2 = 0x00110000, 0x00840000
@@ -297,7 +300,7 @@ class NV_FLCN_COT(NV_IP):
self.init_fmc_image()
def init_fmc_image(self):
_, sections, _ = elf_loader(fetch_fw(f"nvidia/{self.nvdev.fw_name.lower()}/gsp", "fmc-570.144.bin",
_, sections, _ = elf_loader(fetch_fw(f"nvidia/{self.nvdev.fw_name}/gsp", "fmc-570.144.bin",
"cb59a35c1d4bd1274d7267fd10243c29f843ff41c851b9cbd59f5af2ddd7fece"))
def _section(s): return next((sh.content for sh in sections if sh.name == s))
self.fmc_booter_image, self.fmc_booter_hash = _section("image"), memoryview(_section("hash")).cast('I')
@@ -414,8 +417,11 @@ class NV_GSP(NV_IP):
_, self.gsp_signature_sysmem = self.nvdev._alloc_sysmem(len(signature), contiguous=True, data=signature)
def init_boot_binary_image(self):
self.booter_image = self.nvdev.extract_fw("kgspBinArchiveGspRmBoot", "ucode_image_prod_data")
self.booter_desc = nv.RM_RISCV_UCODE_DESC.from_buffer_copy(self.nvdev.extract_fw("kgspBinArchiveGspRmBoot", "ucode_desc_prod_data"))
sha = {"ga102":"82428f532240727e95bb3083fbaaba9b2cc7b937314323f2d546ce7245f27fad",
"ad102":"65ab2e6b6e0fca95365c4deac79a34582abcfeb15b6ae234138f22e7183118a8",
"gb202":"d40b48e431d1707dc77af3605db358ed7a32ebfc2830eb74de2eddb4d3025071"}[self.nvdev.fw_name]
h = nv.struct_nvfw_bin_hdr.from_buffer_copy(b:=fetch_fw(f"nvidia/{self.nvdev.fw_name}/gsp", "bootloader-570.144.bin", sha))
self.booter_image, self.booter_desc = b[h.data_offset:h.data_offset+h.data_size], nv.RM_RISCV_UCODE_DESC.from_buffer_copy(b, h.header_offset)
_, self.booter_sysmem = self.nvdev._alloc_sysmem(len(self.booter_image), contiguous=True, data=self.booter_image)
def init_wpr_meta(self):

View File

@@ -1,5 +1,5 @@
from __future__ import annotations
import ctypes, time, functools, re, gzip, struct
import ctypes, time, functools, re
from tinygrad.helpers import getenv, DEBUG, fetch, getbits
from tinygrad.runtime.autogen import pci
from tinygrad.runtime.support.memory import TLSFAllocator, MemoryManager, AddrSpace
@@ -112,7 +112,7 @@ class NVDev:
self.chip_id = self.reg("NV_PMC_BOOT_0").read()
self.chip_details = self.reg("NV_PMC_BOOT_42").read_bitfields()
self.chip_name = {0x17: "GA1", 0x19: "AD1", 0x1b: "GB2"}[self.chip_details['architecture']] + f"{self.chip_details['implementation']:02d}"
self.fw_name = {"GB2": "GB202", "AD1": "AD102", "GA1": "GA102"}[self.chip_name[:3]]
self.fw_name = {"GB2": "gb202", "AD1": "ad102", "GA1": "ga102"}[self.chip_name[:3]]
self.mmu_ver, self.fmc_boot = (3, True) if self.chip_details['architecture'] >= 0x1a else (2, False)
self.flcn:NV_FLCN|NV_FLCN_COT = NV_FLCN_COT(self) if self.fmc_boot else NV_FLCN(self)
@@ -161,14 +161,6 @@ class NVDev:
url = f"https://raw.githubusercontent.com/NVIDIA/open-gpu-kernel-modules/8ec351aeb96a93a4bb69ccc12a542bf8a8df2b6f/{file}"
return fetch(url, subdir="defines").read_text()
def extract_fw(self, file:str, dname:str) -> bytes:
# Extracts the firmware binary from the given header
tname = file.replace("kgsp", "kgspGet")
text = self._download(f"src/nvidia/generated/g_bindata_{tname}_{self.fw_name}.c")
info, sl = text[text[:text.index(dnm:=f'{file}_{self.fw_name}_{dname}')].rindex("COMPRESSION:"):][:16], text[text.index(dnm) + len(dnm) + 7:]
image = bytes.fromhex(sl[:sl.find("};")].strip().replace("0x", "").replace(",", "").replace(" ", "").replace("\n", ""))
return gzip.decompress(struct.pack("<4BL2B", 0x1f, 0x8b, 8, 0, 0, 0, 3) + image) if "COMPRESSION: YES" in info else image
def include(self, file:str):
def _do_eval(s:str): return eval(s) # pylint: disable=eval-used