diff --git a/efi/preinstall/check_host_security.go b/efi/preinstall/check_host_security.go
index 7e96fd46..4d673f9e 100644
--- a/efi/preinstall/check_host_security.go
+++ b/efi/preinstall/check_host_security.go
@@ -303,7 +303,12 @@ func checkDiscreteTPMPartialResetAttackMitigationStatusAMD64(env internal_efi.Ho
// checkHostSecurityARM64Platform selects the platform-specific firmware
// integrity check. Tests replace this to supply synthetic platforms.
var checkHostSecurityARM64Platform = func(env internal_efi.HostEnvironmentARM64, cpuManufacturer string) (platformFirmwareIntegrityConfig, error) {
- return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
+ switch cpuManufacturer {
+ case "NVIDIA":
+ return checkHostSecurityNVIDIA(env)
+ default:
+ return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
+ }
}
func checkHostSecurityARM64(env internal_efi.HostEnvironment, log *tcglog.Log) (platformFirmwareIntegrityConfig, error) {
diff --git a/efi/preinstall/check_host_security_nvidia.go b/efi/preinstall/check_host_security_nvidia.go
new file mode 100644
index 00000000..1bd2f751
--- /dev/null
+++ b/efi/preinstall/check_host_security_nvidia.go
@@ -0,0 +1,61 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2026 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package preinstall
+
+import (
+ "fmt"
+ "strings"
+
+ internal_efi "github.com/snapcore/secboot/internal/efi"
+)
+
+const nvidiaDGXSparkCPUVersion = "GB10"
+const nvidiaRTXSparkCPUVersionPrefix = "NVIDIA RTX Spark"
+
+// isNvidiaSparkCPUVersion reports whether cpuVersion identifies a supported NVIDIA
+// Spark platform: either the DGX Spark (exact match on "GB10") or any RTX Spark
+// variant (prefix match on "NVIDIA RTX Spark").
+func isNvidiaSparkCPUVersion(cpuVersion string) bool {
+ return cpuVersion == nvidiaDGXSparkCPUVersion || strings.HasPrefix(cpuVersion, nvidiaRTXSparkCPUVersionPrefix)
+}
+
+func checkHostSecurityNVIDIA(env internal_efi.HostEnvironmentARM64) (platformFirmwareIntegrityConfig, error) {
+ cpuVersion, err := env.CPUVersion()
+ if err != nil {
+ return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU version: %w", err)}
+ }
+
+ switch {
+ case isNvidiaSparkCPUVersion(cpuVersion):
+ return checkHostSecurityNVIDIASpark(env)
+ default:
+ return platformFirmwareIntegrityNone, &UnsupportedPlatformError{fmt.Errorf("unsupported NVIDIA CPU version: %s", cpuVersion)}
+ }
+}
+
+func checkHostSecurityNVIDIASpark(env internal_efi.HostEnvironmentARM64) (platformFirmwareIntegrityConfig, error) {
+ // TODO: Implement proper HW ROT fusing checks, once we have the documentation
+ // from NVIDIA to do so. This will involve checking fuses and will return
+ // platformFirmwareIntegrityVerified if set correctly.
+
+ // TODO: Implement proper debug authentication checks, once we have the documentation
+ // from NVIDIA to do so.
+ return platformFirmwareIntegrityVerified, nil
+}
diff --git a/efi/preinstall/check_host_security_nvidia_test.go b/efi/preinstall/check_host_security_nvidia_test.go
new file mode 100644
index 00000000..414488c1
--- /dev/null
+++ b/efi/preinstall/check_host_security_nvidia_test.go
@@ -0,0 +1,74 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2026 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package preinstall_test
+
+import (
+ "errors"
+
+ . "github.com/snapcore/secboot/efi/preinstall"
+ "github.com/snapcore/secboot/internal/efitest"
+ "github.com/snapcore/secboot/internal/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func (s *hostSecurityARM64Suite) TestCheckHostSecurityGoodDGXSparkVerified(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "GB10"),
+ efitest.WithSysfsDevices(makeArm64IOMMUDevices()...),
+ )
+ log := efitest.NewLog(c, &efitest.LogOptions{})
+
+ integrity, err := CheckHostSecurity(env, log)
+ c.Check(err, IsNil)
+ c.Check(integrity, Equals, PlatformFirmwareIntegrityVerified)
+}
+
+func (s *hostSecurityARM64Suite) TestCheckHostSecurityGoodRTXSparkVerified(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (5120-core GPU, 18-core CPU)"),
+ efitest.WithSysfsDevices(makeArm64IOMMUDevices()...),
+ )
+ log := efitest.NewLog(c, &efitest.LogOptions{})
+
+ integrity, err := CheckHostSecurity(env, log)
+ c.Check(err, IsNil)
+ c.Check(integrity, Equals, PlatformFirmwareIntegrityVerified)
+}
+
+func (s *hostSecurityARM64Suite) TestCheckHostSecurityGoodRTXSparkAlternativeSKUVerified(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (4096-core GPU, 16-core CPU)"),
+ efitest.WithSysfsDevices(makeArm64IOMMUDevices()...),
+ )
+ log := efitest.NewLog(c, &efitest.LogOptions{})
+
+ integrity, err := CheckHostSecurity(env, log)
+ c.Check(err, IsNil)
+ c.Check(integrity, Equals, PlatformFirmwareIntegrityVerified)
+}
+
+func (s *hostSecurityARM64Suite) TestCheckHostSecurityErrUnsupportedNVIDIACPUVersion(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(efitest.WithARM64Environment("NVIDIA", "N2X"))
+
+ _, err := CheckHostSecurity(env, nil)
+ c.Check(err, ErrorMatches, `unsupported platform: unsupported NVIDIA CPU version: N2X`)
+ var upe *UnsupportedPlatformError
+ c.Check(errors.As(err, &upe), testutil.IsTrue)
+}
diff --git a/efi/preinstall/check_host_security_test.go b/efi/preinstall/check_host_security_test.go
index 670cf328..9b81e2b0 100644
--- a/efi/preinstall/check_host_security_test.go
+++ b/efi/preinstall/check_host_security_test.go
@@ -683,6 +683,17 @@ func (s *hostSecurityARM64Suite) TestCheckDiscreteTPMPartialResetAttackMitigatio
c.Check(status, Equals, DtpmPartialResetAttackMitigationNotRequired)
}
+func (s *hostSecurityARM64Suite) TestCheckDiscreteTPMPartialResetAttackMitigationStatusUnavailableForNvidiaDGXSpark(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "GB10"),
+ efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
+ )
+
+ status, err := CheckDiscreteTPMPartialResetAttackMitigationStatus(env, makeArm64PCRResults(c))
+ c.Check(err, IsNil)
+ c.Check(status, Equals, DtpmPartialResetAttackMitigationUnavailable)
+}
+
func (s *hostSecuritySuite) TestCheckHostSecurityUnsupportedArchitecture(c *C) {
restore := MockRuntimeGOARCH("ppc64le")
defer restore()
diff --git a/efi/preinstall/check_tpm.go b/efi/preinstall/check_tpm.go
index 72593954..078ff680 100644
--- a/efi/preinstall/check_tpm.go
+++ b/efi/preinstall/check_tpm.go
@@ -533,7 +533,12 @@ func isTPMDiscreteARM64(env internal_efi.HostEnvironment) (bool, error) {
return false, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU manufacturer: %w", err)}
}
- return false, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
+ switch cpuManufacturer {
+ case "NVIDIA":
+ return isTPMDiscreteNvidia(arm64Env)
+ default:
+ return false, &UnsupportedPlatformError{fmt.Errorf("unsupported CPU manufacturer: %s", cpuManufacturer)}
+ }
}
// isTPMFirmwareOptee determines whether the default TPM is an OP-TEE firmware TPM,
diff --git a/efi/preinstall/check_tpm_nvidia.go b/efi/preinstall/check_tpm_nvidia.go
new file mode 100644
index 00000000..9041734d
--- /dev/null
+++ b/efi/preinstall/check_tpm_nvidia.go
@@ -0,0 +1,42 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2026 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package preinstall
+
+import (
+ "fmt"
+
+ internal_efi "github.com/snapcore/secboot/internal/efi"
+)
+
+// isTPMDiscreteNvidia determines whether the default TPM is discrete on NVIDIA systems
+func isTPMDiscreteNvidia(env internal_efi.HostEnvironmentARM64) (bool, error) {
+ cpuVersion, err := env.CPUVersion()
+ if err != nil {
+ return false, &UnsupportedPlatformError{fmt.Errorf("cannot determine CPU version: %w", err)}
+ }
+
+ switch {
+ // We just happen to know that the NVIDIA DGX Spark and RTX Spark have a dTPM
+ case isNvidiaSparkCPUVersion(cpuVersion):
+ return true, nil
+ default:
+ return false, &UnsupportedPlatformError{fmt.Errorf("unsupported NVIDIA CPU version: %s", cpuVersion)}
+ }
+}
diff --git a/efi/preinstall/check_tpm_nvidia_test.go b/efi/preinstall/check_tpm_nvidia_test.go
new file mode 100644
index 00000000..09b08811
--- /dev/null
+++ b/efi/preinstall/check_tpm_nvidia_test.go
@@ -0,0 +1,74 @@
+// -*- Mode: Go; indent-tabs-mode: t -*-
+
+/*
+ * Copyright (C) 2026 Canonical Ltd
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 3 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see .
+ *
+ */
+
+package preinstall_test
+
+import (
+ "errors"
+
+ . "github.com/snapcore/secboot/efi/preinstall"
+ "github.com/snapcore/secboot/internal/efitest"
+ "github.com/snapcore/secboot/internal/testutil"
+ . "gopkg.in/check.v1"
+)
+
+func (s *tpmARM64Suite) TestIsTPMDiscreteDGXSpark(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "GB10"),
+ efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
+ )
+
+ discrete, err := IsTPMDiscrete(env)
+ c.Check(err, IsNil)
+ c.Check(discrete, testutil.IsTrue)
+}
+
+func (s *tpmARM64Suite) TestIsTPMDiscreteRTXSpark(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (5120-core GPU, 18-core CPU)"),
+ efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
+ )
+
+ discrete, err := IsTPMDiscrete(env)
+ c.Check(err, IsNil)
+ c.Check(discrete, testutil.IsTrue)
+}
+
+func (s *tpmARM64Suite) TestIsTPMDiscreteRTXSparkAlternativeSKU(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "NVIDIA RTX Spark N1X (4096-core GPU, 16-core CPU)"),
+ efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
+ )
+
+ discrete, err := IsTPMDiscrete(env)
+ c.Check(err, IsNil)
+ c.Check(discrete, testutil.IsTrue)
+}
+
+func (s *tpmARM64Suite) TestIsTPMDiscreteErrUnsupportedNVIDIACPUVersion(c *C) {
+ env := efitest.NewMockHostEnvironmentWithOpts(
+ efitest.WithARM64Environment("NVIDIA", "N2X"),
+ efitest.WithSysfsDevices(makeArm64TPMDevice("tpm_crb")),
+ )
+
+ _, err := IsTPMDiscrete(env)
+ c.Check(err, ErrorMatches, `unsupported platform: unsupported NVIDIA CPU version: N2X`)
+ var upe *UnsupportedPlatformError
+ c.Check(errors.As(err, &upe), testutil.IsTrue)
+}
diff --git a/efi/preinstall/checks_fixture_test.go b/efi/preinstall/checks_fixture_test.go
index 51e9297f..c41b9a40 100644
--- a/efi/preinstall/checks_fixture_test.go
+++ b/efi/preinstall/checks_fixture_test.go
@@ -267,5 +267,19 @@ func runChecksPlatformHostFixtures() []runChecksHostFixture {
additionalExpectedFlags: RequireLockToPlatformFirmware,
arch: "arm64",
},
+ {
+ name: "nvidia-dgx-spark-tpm-crb",
+ capabilities: runChecksHostCapabilityValid |
+ runChecksHostCapabilityNotVirtualMachine |
+ runChecksHostCapabilityDiscreteTPM |
+ runChecksHostCapabilityStartupLocality0AccessibleFromOS |
+ runChecksHostCapabilityStartupLocality3AccessibleFromOS |
+ runChecksHostCapabilityStartupLocality4AccessibleFromOS,
+ environment: efitest.WithARM64Environment("NVIDIA", "GB10"),
+ virtualizationMode: internal_efi.VirtModeNone,
+ virtualizationDetection: internal_efi.DetectVirtModeAll,
+ sysfsDevices: newDevices("tpm_crb", true),
+ arch: "arm64",
+ },
}
}