diff options
| author | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-27 15:27:35 -0400 |
|---|---|---|
| committer | Takoroka <137927095+Takoroka@users.noreply.github.com> | 2026-10-27 15:27:35 -0400 |
| commit | 5cb4786f3e25136145fa71c17da7a65be35ff7dd (patch) | |
| tree | 25609a1954783e0687c9a717789638585003e59b /src/core | |
| parent | 559dfe7bb24d95fbbc32fd571c7f53e13e42342c (diff) | |
nvdrv: stub device for nvgpu nodes Switch 1 never had
Unknown /dev/nvhost-* nodes (first: /dev/nvhost-tsg-gpu, opened by the
Switch 2 NvRm during NVN device init) open as nx2_stub_device: every
ioctl succeeds with the input echoed and the rest zeroed, and is logged.
With this NVN device init completes and the title reaches
nn::wsi::ounce::native::NativeWindow::Acquire (first frame).
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 1 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nx2_stub_device.h | 54 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 15 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.h | 2 |
4 files changed, 72 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 231f0db451..6058ce82ce 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -866,6 +866,7 @@ add_library(core STATIC hle/service/nvdrv/devices/nvhost_vic.h hle/service/nvdrv/devices/nvmap.cpp hle/service/nvdrv/devices/nvmap.h + hle/service/nvdrv/devices/nx2_stub_device.h hle/service/nvdrv/nvdata.h hle/service/nvdrv/nvdrv.cpp hle/service/nvdrv/nvdrv.h diff --git a/src/core/hle/service/nvdrv/devices/nx2_stub_device.h b/src/core/hle/service/nvdrv/devices/nx2_stub_device.h new file mode 100644 index 0000000000..1dc2f8b7fa --- /dev/null +++ b/src/core/hle/service/nvdrv/devices/nx2_stub_device.h @@ -0,0 +1,54 @@ +// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <algorithm> +#include <string> + +#include "common/logging.h" +#include "core/hle/service/nvdrv/devices/nvdevice.h" + +namespace Service::Nvidia::Devices { + +// Device node that Switch 2 nvgpu drivers open but Switch 1 never had (e.g. /dev/nvhost-tsg-gpu). +// Every ioctl succeeds with a zeroed reply and is logged, so the driver's use of it shows up. +class nx2_stub_device final : public nvdevice { +public: + explicit nx2_stub_device(Core::System& system_, std::string name_) + : nvdevice{system_}, name{std::move(name_)} {} + + NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<u8> output) override { + return Stub(fd, command, input, output, {}); + } + NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input, + std::span<const u8> inline_input, std::span<u8> output) override { + return Stub(fd, command, input, output, {}); + } + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, + std::span<u8> inline_output) override { + return Stub(fd, command, input, output, inline_output); + } + + void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override { + LOG_WARNING(Service_NVDRV, "(STUBBED) {} opened as fd {}", name, fd); + } + void OnClose(DeviceFD fd) override {} + +private: + NvResult Stub(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output, + std::span<u8> inline_output) { + LOG_WARNING(Service_NVDRV, "(STUBBED) {} fd={} ioctl={:08X} group={:01X} command={:02X} in={:#x}", + name, fd, command.raw, command.group, command.cmd, input.size()); + // Echo the input (in/out ioctls keep their fields), zero the rest. + std::fill(output.begin(), output.end(), u8{0}); + std::copy_n(input.begin(), std::min(input.size(), output.size()), output.begin()); + std::fill(inline_output.begin(), inline_output.end(), u8{0}); + return NvResult::Success; + } + + std::string name; +}; + +} // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index b252a2efa5..5cac2693c5 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -23,6 +23,7 @@ #include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h" #include "core/hle/service/nvdrv/devices/nvhost_vic.h" #include "core/hle/service/nvdrv/devices/nvmap.h" +#include "core/hle/service/nvdrv/devices/nx2_stub_device.h" #include "core/hle/service/nvdrv/nvdrv.h" #include "core/hle/service/nvdrv/nvdrv_interface.h" #include "core/hle/service/nvdrv/nvmemp.h" @@ -125,6 +126,11 @@ void LoopProcess(Core::System& system) { Module::Module(Core::System& system) : container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} { + nx2_stub_builder = [this, &system](DeviceFD fd, const std::string& name) { + auto device = std::make_shared<Devices::nx2_stub_device>(system, name); + open_files.emplace(fd, device); + return std::static_pointer_cast<Devices::nvdevice>(device); + }; builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { auto device = std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); return open_files.emplace(fd, std::move(device)).first; @@ -181,6 +187,15 @@ NvResult Module::VerifyFD(DeviceFD fd) const { DeviceFD Module::Open(const std::string& device_name, NvCore::SessionId session_id) { auto it = builders.find(device_name); + if (it == builders.end() && device_name.starts_with("/dev/nvhost-")) { + // Newer nvgpu nodes used by Switch 2 drivers (e.g. /dev/nvhost-tsg-gpu): serve them with + // a logged stub instead of failing the open. + LOG_WARNING(Service_NVDRV, "Opening unknown device {} as a Switch 2 stub", device_name); + const DeviceFD fd = next_fd++; + auto device = nx2_stub_builder(fd, device_name); + device->OnOpen(session_id, fd); + return fd; + } if (it == builders.end()) { LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name); return INVALID_NVDRV_FD; diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index f503f108c3..ba8ab6a40e 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h @@ -98,6 +98,8 @@ private: friend class EventInterface; /// Manages syncpoints on the host + /// Builds a logged stub for nvgpu device nodes only Switch 2 drivers use. + std::function<std::shared_ptr<Devices::nvdevice>(DeviceFD, const std::string&)> nx2_stub_builder; NvCore::Container container; /// Id to use for the next open file descriptor. |
