aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-27 15:17:39 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-27 15:17:39 -0400
commit559dfe7bb24d95fbbc32fd571c7f53e13e42342c (patch)
treef609afa83501aa72af800654f0695ccaa514a6ef
parent3063037b9945c3d5d3b9b34d02764c93103ebb27 (diff)
Switch 2 GPU memory: svc 0x80, gpu sub-session jobs, VM range, SM 0x808
- svc 0x80 (address, size, mask 0x20, attr 0x20) marks memory GPU accessible for nn::gpu::sdk::CreateGpuAccessibleMemory; accept it. - gpu 22's sub-session is served by the gpu object; sub 101 registers memory, sub 211 submits a job whose id event is signalled at once. - gpu 203 reports [0x8000000, 0xC000000000) as the in-process VirtualMachine range that serves AllocSpace (NVN reserves fixed VA at 0x8000000 up to 512 GiB). - Report SM 0x808: NVN2's engine class table is only returned for it. With this NVN device init allocates its GPU memory and opens /dev/nvhost-tsg-gpu.
-rw-r--r--src/core/hle/kernel/svc.cpp9
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp4
-rw-r--r--src/core/hle/service/nx2_gsv.h37
3 files changed, 40 insertions, 10 deletions
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index d2e45fabb6..0d4b2937c2 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2512,7 +2512,14 @@ void Call(Core::System& system, u32 imm) {
LOG_INFO(Kernel_SVC, "svc {:#04x} in [0]={:#x} [1]={:#x} [2]={:#x} [3]={:#x}", imm,
GetArg64(args, 0), GetArg64(args, 1), GetArg64(args, 2), GetArg64(args, 3));
}
- if (process.Is64Bit()) {
+ if (imm == 0x80) {
+ // Switch 2 only. nn::gpu::sdk::CreateGpuAccessibleMemory and nn::gs native memory call it
+ // as (address, size, mask = 0x20, attr = 0x20), like svcSetMemoryAttribute with a new
+ // "GPU accessible" attribute. Emulated guest memory is always GPU-visible: accept it.
+ LOG_WARNING(Kernel_SVC, "(STUBBED) Switch 2 svc 0x80 addr={:#x} size={:#x} mask={:#x} attr={:#x}",
+ GetArg64(args, 0), GetArg64(args, 1), GetArg64(args, 2), GetArg64(args, 3));
+ args[0] = 0;
+ } else if (process.Is64Bit()) {
Call64(system, imm, args);
} else {
Call32(system, imm, args);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index 07776d3434..db9ae85cf0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -142,8 +142,8 @@ void ApplyNx2Characteristics(GC& gc) {
gc.arch = 0x170; // Ampere
gc.impl = 0xE; // chip id 0x17E as listed in the Switch 2 NvRm chip table
gc.num_tpc_per_gpc = 0x6;
- gc.sm_arch_sm_version = 0x807; // sm_87 (guess)
- gc.sm_arch_spa_version = 0x807;
+ gc.sm_arch_sm_version = 0x808; // NVN2 only accepts SM 0x808 (its class table lookup)
+ gc.sm_arch_spa_version = 0x808;
gc.threed_class = 0xC797; // AMPERE_B
gc.compute_class = 0xC7C0; // AMPERE_COMPUTE_B
gc.gpfifo_class = 0xC56F; // AMPERE_CHANNEL_GPFIFO_A
diff --git a/src/core/hle/service/nx2_gsv.h b/src/core/hle/service/nx2_gsv.h
index a7d9817dd2..e8f31d0556 100644
--- a/src/core/hle/service/nx2_gsv.h
+++ b/src/core/hle/service/nx2_gsv.h
@@ -112,6 +112,9 @@ public:
{22, &INx2GpuSession::OpenSubSession, "OpenSubSession (guessed)"},
{33, &INx2GpuSession::GetCount33, "Unknown33 (u32 count)"},
{203, &INx2GpuSession::GetVaRange, "GetVaRange (guessed)"},
+ // Sub-session commands (gpu 22 hands out a second session to this same object).
+ {101, &INx2GpuSession::SubRegisterMemory, "Sub101 RegisterMemory (guessed)"},
+ {211, &INx2GpuSession::SubSubmitJob, "Sub211 SubmitJob (guessed)"},
});
}
@@ -161,22 +164,42 @@ private:
}
// Used by nn::gpu::sdk::CreateGpuAddressSpace: three u64s after the result, a kind (< 5, 0 =
- // none) and what looks like a GPU VA range. Report kind 1, [0x10000000, +64 GiB).
+ // none) and the GPU VA range of the in-process VirtualMachine that serves AllocSpace
+ // (nn::gpu::sdk::util::ExecuteVirtualMachineAllocSpace). NVN reserves fixed VA from 0x8000000
+ // up to 512 GiB, so report the same range NvRm gives AllocAsEx: [0x8000000, 0xC000000000).
void GetVaRange(HLERequestContext& ctx) {
LOG_WARNING(Service, "(STUBBED) nx2:gpu TIPC 203 [2]={:#x}", ctx.CommandBuffer()[2]);
constexpr u64 kind = 1;
- constexpr u64 start = 0x10000000ULL;
- constexpr u64 size = 64ULL << 30;
+ constexpr u64 start = 0x8000000ULL;
+ constexpr u64 size = 0xC000000000ULL - start;
TipcReplyWords(ctx, {static_cast<u32>(kind), static_cast<u32>(kind >> 32),
static_cast<u32>(start), static_cast<u32>(start >> 32),
static_cast<u32>(size), static_cast<u32>(size >> 32)});
}
void OpenSubSession(HLERequestContext& ctx) {
- LOG_WARNING(Service, "(STUBBED) nx2:gpu TIPC 22, returning a nx2:gpu-sub session");
- ReturnRawSession(system, ctx,
- std::make_shared<INx2StubInterface>(
- system, INx2StubInterface::InternName("nx2:gpu-sub")));
+ // Served by this object so sub-session jobs can signal the per-id events.
+ LOG_WARNING(Service, "(STUBBED) nx2:gpu TIPC 22, returning a sub-session on nx2:gpu");
+ ReturnRawSession(system, ctx, std::static_pointer_cast<INx2GpuSession>(shared_from_this()));
+ }
+
+ // Sub 101: (start u64, last u64, flags...) after CreateGpuAccessibleMemory's svc 0x80.
+ void SubRegisterMemory(HLERequestContext& ctx) {
+ const auto* b = ctx.CommandBuffer();
+ LOG_WARNING(Service, "(STUBBED) nx2:gpu sub 101 start={:#x} last={:#x} [6]={:#x} [7]={:#x}",
+ u64{b[2]} | (u64{b[3]} << 32), u64{b[4]} | (u64{b[5]} << 32), b[6], b[7]);
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+ }
+
+ // Sub 211: job submission; word 2 is the job/event id the SDK then waits on. Nothing runs
+ // here, so complete it at once.
+ void SubSubmitJob(HLERequestContext& ctx) {
+ const u32 id = ctx.CommandBuffer()[2];
+ LOG_WARNING(Service, "(STUBBED) nx2:gpu sub 211 id={}, signalling completion", id);
+ EventFor(id)->Signal(system.Kernel());
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
}
KernelHelpers::ServiceContext m_context;