aboutsummaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
authorTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 03:39:29 -0400
committerTakoroka <137927095+Takoroka@users.noreply.github.com>2026-10-29 03:39:29 -0400
commitea6c1193fbfa95e586bb6d129dc684163a12cb3e (patch)
treee4d23143900184630deeabe27eab1321dac4a428 /src/core
parent0bb5055b6541c74f47603a8dff0569a509cbaf18 (diff)
Revert "Import experimental NS2 support and accumulated GPU fixes"
This reverts commit 535b676970. The Switch 2 support comes from the nx2 work instead, merged next.
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt14
-rw-r--r--src/core/arm/dynarmic/arm_dynarmic_64.cpp3
-rw-r--r--src/core/device_memory_manager.inc3
-rw-r--r--src/core/file_sys/program_metadata.cpp55
-rw-r--r--src/core/file_sys/program_metadata.h8
-rw-r--r--src/core/hle/kernel/k_memory_block.h4
-rw-r--r--src/core/hle/kernel/k_page_table_base.cpp3
-rw-r--r--src/core/hle/kernel/k_process.cpp1
-rw-r--r--src/core/hle/kernel/k_process.h5
-rw-r--r--src/core/hle/kernel/kernel.cpp12
-rw-r--r--src/core/hle/kernel/svc.cpp4
-rw-r--r--src/core/hle/kernel/svc.h2
-rw-r--r--src/core/hle/kernel/svc/svc_info.cpp27
-rw-r--r--src/core/hle/kernel/svc/svc_ipc.cpp19
-rw-r--r--src/core/hle/kernel/svc/svc_memory.cpp25
-rw-r--r--src/core/hle/kernel/svc/svc_synchronization.cpp21
-rw-r--r--src/core/hle/kernel/svc/svc_thread.cpp11
-rw-r--r--src/core/hle/kernel/svc_types.h1
-rw-r--r--src/core/hle/service/am/applet.h1
-rw-r--r--src/core/hle/service/am/service/application_functions.cpp14
-rw-r--r--src/core/hle/service/am/service/application_functions.h2
-rw-r--r--src/core/hle/service/am/service/application_proxy.cpp19
-rw-r--r--src/core/hle/service/am/service/application_proxy.h6
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.cpp11
-rw-r--r--src/core/hle/service/am/service/application_proxy_service.h4
-rw-r--r--src/core/hle/service/am/service/gpu_memory_registration.h22
-rw-r--r--src/core/hle/service/am/service/gpu_session.cpp633
-rw-r--r--src/core/hle/service/am/service/gpu_session.h45
-rw-r--r--src/core/hle/service/am/service/graphics_scaling_parameters_functions.cpp45
-rw-r--r--src/core/hle/service/am/service/graphics_scaling_parameters_functions.h34
-rw-r--r--src/core/hle/service/am/service/graphics_session.cpp33
-rw-r--r--src/core/hle/service/am/service/graphics_session.h19
-rw-r--r--src/core/hle/service/am/service/graphics_supervisor.cpp1612
-rw-r--r--src/core/hle/service/am/service/graphics_supervisor.h93
-rw-r--r--src/core/hle/service/am/service/graphics_supervisor_protocol.h37
-rw-r--r--src/core/hle/service/am/service/graphics_syncpoint_cache.h49
-rw-r--r--src/core/hle/service/am/service/native_image_layout.h40
-rw-r--r--src/core/hle/service/am/service/performance_functions.cpp19
-rw-r--r--src/core/hle/service/am/service/performance_functions.h16
-rw-r--r--src/core/hle/service/am/service/self_controller.cpp45
-rw-r--r--src/core/hle/service/am/service/self_controller.h3
-rw-r--r--src/core/hle/service/audio/audio.cpp64
-rw-r--r--src/core/hle/service/hid/hid_server.cpp80
-rw-r--r--src/core/hle/service/hid/hid_server.h24
-rw-r--r--src/core/hle/service/ngc/ngc.cpp50
-rw-r--r--src/core/hle/service/nvdrv/core/syncpoint_manager.cpp8
-rw-r--r--src/core/hle/service/nvdrv/core/syncpoint_manager.h3
-rw-r--r--src/core/hle/service/nvdrv/devices/gpu_address_space_layout.h34
-rw-r--r--src/core/hle/service/nvdrv/devices/native_gpu_characteristics.h67
-rw-r--r--src/core/hle/service/nvdrv/devices/native_gpu_context.h23
-rw-r--r--src/core/hle/service/nvdrv/devices/native_gpu_kind.h51
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp61
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h4
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp290
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h34
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp99
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h11
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.cpp85
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.h38
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp19
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.cpp25
-rw-r--r--src/core/hle/service/nvdrv/nvdrv_interface.h2
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.cpp9
-rw-r--r--src/core/hle/service/nvnflinger/buffer_queue_producer.h2
-rw-r--r--src/core/hle/service/service.cpp28
-rw-r--r--src/core/launch_params.cpp2
-rw-r--r--src/core/loader/deconstructed_rom_directory.cpp39
-rw-r--r--src/core/loader/deconstructed_rom_directory.h1
-rw-r--r--src/core/loader/loader.cpp7
71 files changed, 68 insertions, 4139 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 168037e5dc..1b578f67ba 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -460,18 +460,6 @@ add_library(core STATIC
hle/service/am/service/application_proxy.h
hle/service/am/service/application_proxy_service.cpp
hle/service/am/service/application_proxy_service.h
- hle/service/am/service/performance_functions.cpp
- hle/service/am/service/performance_functions.h
- hle/service/am/service/gpu_session.cpp
- hle/service/am/service/gpu_session.h
- hle/service/am/service/graphics_session.cpp
- hle/service/am/service/graphics_session.h
- hle/service/am/service/graphics_supervisor.cpp
- hle/service/am/service/graphics_supervisor.h
- hle/service/am/service/graphics_supervisor_protocol.h
- hle/service/am/service/graphics_syncpoint_cache.h
- hle/service/am/service/graphics_scaling_parameters_functions.cpp
- hle/service/am/service/graphics_scaling_parameters_functions.h
hle/service/am/service/audio_controller.cpp
hle/service/am/service/audio_controller.h
hle/service/am/service/common_state_getter.cpp
@@ -867,8 +855,6 @@ add_library(core STATIC
hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
hle/service/nvdrv/devices/nvhost_gpu.cpp
hle/service/nvdrv/devices/nvhost_gpu.h
- hle/service/nvdrv/devices/nvhost_tsg_gpu.cpp
- hle/service/nvdrv/devices/nvhost_tsg_gpu.h
hle/service/nvdrv/devices/nvhost_nvdec.cpp
hle/service/nvdrv/devices/nvhost_nvdec.h
hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
index b5190e40cf..894857a86d 100644
--- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp
+++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp
@@ -194,7 +194,6 @@ void ArmDynarmic64::MakeJit(Common::PageTable* page_table, std::size_t address_s
// Callbacks
config.callbacks = std::addressof(*m_cb);
- config.enable_pauth_returns = m_cb->m_process && m_cb->m_process->UsesPAuthReturns();
// Memory
if (page_table) {
@@ -445,8 +444,6 @@ void ArmDynarmic64::ClearInstructionCache() {
}
void ArmDynarmic64::InvalidateCacheRange(u64 addr, std::size_t size) {
- // Refetch the source page too, including instructions restored by the debugger.
- m_cb->last_code_addr = u64(-1);
m_jit->InvalidateCacheRange(addr, size);
}
diff --git a/src/core/device_memory_manager.inc b/src/core/device_memory_manager.inc
index 0087548978..97c2706abb 100644
--- a/src/core/device_memory_manager.inc
+++ b/src/core/device_memory_manager.inc
@@ -21,7 +21,6 @@
#include "common/scope_exit.h"
#include "common/settings.h"
#include "core/device_memory.h"
-#include "core/hle/kernel/board/nintendo/nx/k_system_control.h"
#include "core/device_memory_manager.h"
#include "core/memory.h"
@@ -173,7 +172,7 @@ template <typename Traits>
DeviceMemoryManager<Traits>::DeviceMemoryManager(const DeviceMemory& device_memory_)
: physical_base{uintptr_t(device_memory_.buffer.BackingBasePointer())}
, device_inter{nullptr}
- , compressed_device_addr(Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize() >> Memory::YUZU_PAGEBITS)
+ , compressed_device_addr(1ULL << ((Settings::values.memory_layout_mode.GetValue() == Settings::MemoryLayout::Memory_4Gb ? physical_min_bits : physical_max_bits) - Memory::YUZU_PAGEBITS))
, tracked_entries(device_as_size >> Memory::YUZU_PAGEBITS)
{
impl = std::make_unique<DeviceMemoryManagerAllocator<Traits>>();
diff --git a/src/core/file_sys/program_metadata.cpp b/src/core/file_sys/program_metadata.cpp
index b528523e67..63ca9d3fe3 100644
--- a/src/core/file_sys/program_metadata.cpp
+++ b/src/core/file_sys/program_metadata.cpp
@@ -20,10 +20,6 @@ ProgramMetadata::ProgramMetadata() = default;
ProgramMetadata::~ProgramMetadata() = default;
Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
- uses_extended_acid = false;
- if (!file) {
- return Loader::ResultStatus::ErrorBadNPDMHeader;
- }
const std::size_t total_size = file->GetSize();
if (total_size < sizeof(Header)) {
return Loader::ResultStatus::ErrorBadNPDMHeader;
@@ -33,55 +29,17 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
return Loader::ResultStatus::ErrorBadNPDMHeader;
}
- if (npdm_header.magic != std::array{'M', 'E', 'T', 'A'}) {
- return Loader::ResultStatus::ErrorBadNPDMHeader;
- }
-
- const auto contains = [](u64 offset, u64 size, u64 limit) {
- return offset <= limit && size <= limit - offset;
- };
- const u64 acid_offset = npdm_header.acid_offset;
- const u64 acid_size = npdm_header.acid_size;
- const u64 aci_offset = npdm_header.aci_offset;
- const u64 aci_size = npdm_header.aci_size;
- if (acid_offset < sizeof(Header) || !contains(acid_offset, acid_size, total_size)) {
+ if (sizeof(AcidHeader) != file->ReadObject(&acid_header, npdm_header.acid_offset)) {
return Loader::ResultStatus::ErrorBadACIDHeader;
}
- const auto read_acid = [&](u64 body_offset) {
- return contains(body_offset, sizeof(AcidHeader), acid_size) &&
- file->ReadObject(&acid_header, acid_offset + body_offset) == sizeof(AcidHeader) &&
- acid_header.magic == std::array{'A', 'C', 'I', 'D'};
- };
- if (!read_acid(0x200)) {
- if (!read_acid(0x300)) {
- return Loader::ResultStatus::ErrorBadACIDHeader;
- }
- uses_extended_acid = true;
- }
-
- if (aci_offset < sizeof(Header) || !contains(aci_offset, aci_size, total_size) ||
- aci_size < sizeof(AciHeader) ||
- sizeof(AciHeader) != file->ReadObject(&aci_header, aci_offset) ||
- aci_header.magic != std::array{'A', 'C', 'I', '0'}) {
+ if (sizeof(AciHeader) != file->ReadObject(&aci_header, npdm_header.aci_offset)) {
return Loader::ResultStatus::ErrorBadACIHeader;
}
- constexpr u64 fac_read_size = 4 + sizeof(FileAccessControl::permissions) +
- sizeof(FileAccessControl::unknown);
- if (acid_header.fac_size < fac_read_size ||
- !contains(acid_header.fac_offset, acid_header.fac_size, acid_size)) {
- return Loader::ResultStatus::ErrorBadFileAccessControl;
- }
- constexpr u64 fah_read_size = 4 + sizeof(FileAccessHeader::permissions) + 4 * sizeof(u32);
- if (aci_header.fah_size < fah_read_size ||
- !contains(aci_header.fah_offset, aci_header.fah_size, aci_size)) {
- return Loader::ResultStatus::ErrorBadFileAccessHeader;
- }
-
// Load acid_file_access per-component instead of the entire struct, since this struct does not
// reflect the layout of the real data.
- std::size_t current_offset = acid_offset + acid_header.fac_offset;
+ std::size_t current_offset = acid_header.fac_offset;
if (sizeof(FileAccessControl::version) != file->ReadBytes(&acid_file_access.version,
sizeof(FileAccessControl::version),
current_offset)) {
@@ -99,7 +57,7 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
}
// Load aci_file_access per-component instead of the entire struct, same as acid_file_access
- current_offset = aci_offset + aci_header.fah_offset;
+ current_offset = aci_header.fah_offset;
if (sizeof(FileAccessHeader::version) != file->ReadBytes(&aci_file_access.version,
sizeof(FileAccessHeader::version),
current_offset)) {
@@ -131,10 +89,6 @@ Loader::ResultStatus ProgramMetadata::Load(VirtualFile file) {
return Loader::ResultStatus::ErrorBadFileAccessHeader;
}
- if (aci_header.kac_size % sizeof(u32) != 0 ||
- !contains(aci_header.kac_offset, aci_header.kac_size, aci_size)) {
- return Loader::ResultStatus::ErrorBadKernelCapabilityDescriptors;
- }
aci_kernel_capabilities.resize(aci_header.kac_size / sizeof(u32));
const u64 read_size = aci_header.kac_size;
const u64 read_offset = npdm_header.aci_offset + aci_header.kac_offset;
@@ -174,7 +128,6 @@ void ProgramMetadata::LoadManual(bool is_64_bit, ProgramAddressSpaceType address
u32 main_thread_stack_size, u64 title_id,
u64 filesystem_permissions, u32 system_resource_size,
KernelCapabilityDescriptors capabilities) {
- uses_extended_acid = false;
npdm_header.has_64_bit_instructions.Assign(is_64_bit);
npdm_header.address_space_type.Assign(address_space);
npdm_header.main_thread_priority = static_cast<u8>(main_thread_prio);
diff --git a/src/core/file_sys/program_metadata.h b/src/core/file_sys/program_metadata.h
index eb4cf11894..115e6d6cd1 100644
--- a/src/core/file_sys/program_metadata.h
+++ b/src/core/file_sys/program_metadata.h
@@ -77,9 +77,6 @@ public:
u8 GetMainThreadCore() const;
u32 GetMainThreadStackSize() const;
u64 GetTitleID() const;
- bool UsesExtendedAcid() const {
- return uses_extended_acid;
- }
u64 GetFilesystemPermissions() const;
u32 GetSystemResourceSize() const;
PoolPartition GetPoolPartition() const;
@@ -119,6 +116,8 @@ private:
static_assert(sizeof(Header) == 0x80, "NPDM header structure size is wrong");
struct AcidHeader {
+ std::array<u8, 0x100> signature;
+ std::array<u8, 0x100> nca_modulus;
std::array<char, 4> magic;
u32_le nca_size;
std::array<u8, 0x4> reserved;
@@ -140,7 +139,7 @@ private:
INSERT_PADDING_BYTES(0x8);
};
- static_assert(sizeof(AcidHeader) == 0x40, "ACID header body size is wrong");
+ static_assert(sizeof(AcidHeader) == 0x240, "ACID header structure size is wrong");
struct AciHeader {
std::array<char, 4> magic;
@@ -178,7 +177,6 @@ private:
};
Header npdm_header{};
- bool uses_extended_acid{};
AciHeader aci_header{};
AcidHeader acid_header{};
diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h
index 2abca31d87..f6543bdb3a 100644
--- a/src/core/hle/kernel/k_memory_block.h
+++ b/src/core/hle/kernel/k_memory_block.h
@@ -195,9 +195,7 @@ enum class KMemoryAttribute : u8 {
Uncached = static_cast<u8>(Svc::MemoryAttribute::Uncached),
PermissionLocked = static_cast<u8>(Svc::MemoryAttribute::PermissionLocked),
- GpuAccessible = static_cast<u8>(Svc::MemoryAttribute::GpuAccessible),
-
- SetMask = Uncached | PermissionLocked | GpuAccessible,
+ SetMask = Uncached | PermissionLocked,
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryAttribute);
diff --git a/src/core/hle/kernel/k_page_table_base.cpp b/src/core/hle/kernel/k_page_table_base.cpp
index fd5d2c2dce..2a0a7d49d5 100644
--- a/src/core/hle/kernel/k_page_table_base.cpp
+++ b/src/core/hle/kernel/k_page_table_base.cpp
@@ -2102,8 +2102,7 @@ Result KPageTableBase::SetMemoryAttribute(KProcessAddress addr, size_t size, KMe
constexpr KMemoryAttribute AttributeTestMask =
~(KMemoryAttribute::SetMask | KMemoryAttribute::DeviceShared);
const KMemoryState state_test_mask =
- (True(mask & (KMemoryAttribute::Uncached | KMemoryAttribute::GpuAccessible))
- ? KMemoryState::FlagCanChangeAttribute
+ (True(mask & KMemoryAttribute::Uncached) ? KMemoryState::FlagCanChangeAttribute
: KMemoryState::None) |
(True(mask & KMemoryAttribute::PermissionLocked) ? KMemoryState::FlagCanPermissionLock
: KMemoryState::None);
diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp
index 813d8e9402..27d1b1bfc4 100644
--- a/src/core/hle/kernel/k_process.cpp
+++ b/src/core/hle/kernel/k_process.cpp
@@ -1260,7 +1260,6 @@ Result KProcess::LoadFromMetadata(KernelCore& kernel, const FileSys::ProgramMeta
// Assign remaining properties.
m_ideal_core_id = metadata.GetMainThreadCore();
- m_uses_pauth_returns = metadata.UsesExtendedAcid();
// Set up emulation context.
this->InitializeInterfaces(kernel);
diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h
index ca96591ed0..b5693751c3 100644
--- a/src/core/hle/kernel/k_process.h
+++ b/src/core/hle/kernel/k_process.h
@@ -135,7 +135,6 @@ private:
bool m_is_signaled : 1 = false;
bool m_is_initialized : 1 = false;
bool m_is_application : 1 = false;
- bool m_uses_pauth_returns : 1 = false;
bool m_is_default_application_system_resource : 1 = false;
bool m_is_suspended : 1 = false;
bool m_is_immortal : 1 = false;
@@ -249,10 +248,6 @@ public:
return m_is_application;
}
- bool UsesPAuthReturns() const {
- return m_uses_pauth_returns;
- }
-
bool IsDefaultApplicationSystemResource() const {
return m_is_default_application_system_resource;
}
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index c7beb9c3ce..4f1d849209 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -120,13 +120,13 @@ struct KernelCore::Impl {
}
void TerminateAllProcesses() {
- auto& kernel = system.Kernel();
- // Applet cleanup can remove processes while termination waits for its threads.
- auto processes = kernel.GetProcessList();
- for (auto& process : processes) {
- process->Terminate(kernel);
- kernel.RemoveProcess(process.GetPointerUnsafe());
+ std::scoped_lock lk{process_list_lock};
+ for (auto& process : process_list) {
+ process->Terminate(system.Kernel());
+ process->Close(system.Kernel());
+ process = nullptr;
}
+ process_list.clear();
}
void Shutdown(KernelCore& kernel) {
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index c91ae43dd8..3542d5a3b6 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -2370,10 +2370,6 @@ static void Call32(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {
static void Call64(Core::System& system, u32 imm, std::span<uint64_t, 8> args) {
switch (SvcId(imm)) {
- case SvcId::SetGpuMemoryAttribute:
- args[0] = SetGpuMemoryAttribute(system, args[0], args[1],
- static_cast<u32>(args[2]), static_cast<u32>(args[3])).raw;
- return;
case SvcId::SetHeapSize: return SvcWrap_SetHeapSize64(system, args);
case SvcId::SetMemoryPermission: return SvcWrap_SetMemoryPermission64(system, args);
case SvcId::SetMemoryAttribute: return SvcWrap_SetMemoryAttribute64(system, args);
diff --git a/src/core/hle/kernel/svc.h b/src/core/hle/kernel/svc.h
index 422b8b8719..356c1c109a 100644
--- a/src/core/hle/kernel/svc.h
+++ b/src/core/hle/kernel/svc.h
@@ -22,7 +22,6 @@ namespace Kernel::Svc {
Result SetHeapSize(Core::System& system, uint64_t* out_address, uint64_t size);
Result SetMemoryPermission(Core::System& system, uint64_t address, uint64_t size, MemoryPermission perm);
Result SetMemoryAttribute(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
-Result SetGpuMemoryAttribute(Core::System& system, uint64_t address, uint64_t size, uint32_t mask, uint32_t attr);
Result MapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result UnmapMemory(Core::System& system, uint64_t dst_address, uint64_t src_address, uint64_t size);
Result QueryMemory(Core::System& system, uint64_t out_memory_info, PageInfo* out_page_info, uint64_t address);
@@ -505,7 +504,6 @@ enum class SvcId : u32 {
CreateResourceLimit = 0x7d,
SetResourceLimitLimitValue = 0x7e,
CallSecureMonitor = 0x7f,
- SetGpuMemoryAttribute = 0x80,
MapInsecureMemory = 0x90,
UnmapInsecureMemory = 0x91,
};
diff --git a/src/core/hle/kernel/svc/svc_info.cpp b/src/core/hle/kernel/svc/svc_info.cpp
index aea7407542..863bb58fa8 100644
--- a/src/core/hle/kernel/svc/svc_info.cpp
+++ b/src/core/hle/kernel/svc/svc_info.cpp
@@ -14,32 +14,11 @@
#include "core/hle/kernel/svc_version.h"
namespace Kernel::Svc {
-namespace {
-// Identified from the extended SDK's RemoteRegionManager initialization.
-constexpr InfoType RemoteRegionAddress = static_cast<InfoType>(29);
-constexpr InfoType RemoteRegionSize = static_cast<InfoType>(30);
-constexpr InfoType RemoteMemoryUsed = static_cast<InfoType>(31);
-constexpr InfoType RemoteMemoryTotal = static_cast<InfoType>(32);
-constexpr InfoType MemoryMappingAlignment = static_cast<InfoType>(33);
-} // namespace
/// Gets system/memory information for the current process
Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle handle, u64 info_sub_id) {
LOG_TRACE(Kernel_SVC, "called info_id={:#x}, info_sub_id={:#x}, handle={:#08x}", info_id_type, info_sub_id, handle);
u32 info_id = u32(info_id_type);
- if (info_id_type == RemoteRegionAddress || info_id_type == RemoteRegionSize ||
- info_id_type == RemoteMemoryUsed || info_id_type == RemoteMemoryTotal ||
- info_id_type == MemoryMappingAlignment) {
- R_UNLESS(info_sub_id == 0, ResultInvalidEnumValue);
- const auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
- KScopedAutoObject process = handle_table.GetObject<KProcess>(system.Kernel(), handle);
- R_UNLESS(process.IsNotNull(), ResultInvalidHandle);
- R_UNLESS(process->UsesPAuthReturns(), ResultInvalidEnumValue);
- // Remote mappings are absent; ordinary mappings use the kernel page size.
- *result = info_id_type == MemoryMappingAlignment ? PageSize : 0;
- LOG_DEBUG(Kernel_SVC, "Extended memory info_id={:#x}, value={:#x}", info_id, *result);
- R_SUCCEED();
- }
switch (info_id_type) {
case InfoType::CoreMask:
case InfoType::PriorityMask:
@@ -145,8 +124,7 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
default:
break;
}
- LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id={:#x}, sub_id={:#x}, handle={:#x}",
- info_id, info_sub_id, handle);
+ LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id={:#016x}", info_id);
R_THROW(ResultInvalidEnumValue);
}
case InfoType::DebuggerAttached:
@@ -280,8 +258,7 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED();
}
default:
- LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id={:#x}, sub_id={:#x}, handle={:#x}",
- info_id, info_sub_id, handle);
+ LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id={:#016x}", info_id);
R_THROW(ResultInvalidEnumValue);
}
}
diff --git a/src/core/hle/kernel/svc/svc_ipc.cpp b/src/core/hle/kernel/svc/svc_ipc.cpp
index fadde6c093..875590d6f7 100644
--- a/src/core/hle/kernel/svc/svc_ipc.cpp
+++ b/src/core/hle/kernel/svc/svc_ipc.cpp
@@ -13,7 +13,6 @@
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_server_session.h"
#include "core/hle/kernel/k_session.h"
-#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/svc.h"
#include "core/hle/kernel/svc_results.h"
@@ -143,23 +142,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
/// Makes a blocking IPC call to a service.
Result SendSyncRequest(Core::System& system, Handle session_handle) {
- auto& process = GetCurrentProcess(system.Kernel());
- if (!process.UsesPAuthReturns()) {
- R_RETURN(SendSyncRequestImpl(system.Kernel(), 0, 0, session_handle));
- }
- const auto tls = GetCurrentThread(system.Kernel()).GetTlsAddress();
- const u64 header = process.GetMemory().Read64(tls);
- const bool trace_tipc = (header & 0xffff) >= 16;
- if (trace_tipc) {
- LOG_DEBUG(Kernel_SVC, "TIPC send handle={:#x}, header={:#x}, special={:#x}",
- session_handle, header, process.GetMemory().Read64(tls + 8));
- }
- const auto result = SendSyncRequestImpl(system.Kernel(), 0, 0, session_handle);
- if (trace_tipc) {
- LOG_DEBUG(Kernel_SVC, "TIPC receive result={:#x}, header={:#x}, data={:#x}",
- result.raw, process.GetMemory().Read64(tls), process.GetMemory().Read64(tls + 8));
- }
- R_RETURN(result);
+ R_RETURN(SendSyncRequestImpl(system.Kernel(), 0, 0, session_handle));
}
Result SendSyncRequestWithUserBuffer(Core::System& system, uint64_t message, uint64_t buffer_size,
diff --git a/src/core/hle/kernel/svc/svc_memory.cpp b/src/core/hle/kernel/svc/svc_memory.cpp
index 53c0d43456..970912fe50 100644
--- a/src/core/hle/kernel/svc/svc_memory.cpp
+++ b/src/core/hle/kernel/svc/svc_memory.cpp
@@ -126,31 +126,6 @@ Result SetMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask,
R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
// Set the memory attribute.
- const auto result = page_table.SetMemoryAttribute(address, size,
- static_cast<KMemoryAttribute>(mask),
- static_cast<KMemoryAttribute>(attr));
- if (GetCurrentProcess(system.Kernel()).UsesPAuthReturns()) {
- LOG_DEBUG(Kernel_SVC, "native memory attribute result={:#x}", result.raw);
- }
- R_RETURN(result);
-}
-
-// Captured native SDK callers set bit 0x20 before registering GPU-accessible
-// memory and clear it during destruction. This tracks eligibility on real mapped
-// memory; GPU mappings and submission remain separate operations.
-Result SetGpuMemoryAttribute(Core::System& system, u64 address, u64 size, u32 mask, u32 attr) {
- auto& process = GetCurrentProcess(system.Kernel());
- R_UNLESS(process.UsesPAuthReturns(), ResultNotImplemented);
- LOG_DEBUG(Kernel_SVC, "GPU memory address={:#x}, size={:#x}, mask={:#x}, attr={:#x}",
- address, size, mask, attr);
- R_UNLESS(Common::IsAligned(address, PageSize), ResultInvalidAddress);
- R_UNLESS(size > 0 && Common::IsAligned(size, PageSize), ResultInvalidSize);
- R_UNLESS(address < address + size, ResultInvalidCurrentMemory);
- constexpr u32 SupportedMask = static_cast<u32>(MemoryAttribute::GpuAccessible);
- R_UNLESS((attr & ~mask) == 0 && ((mask | attr) & ~SupportedMask) == 0,
- ResultInvalidCombination);
- auto& page_table = process.GetPageTable();
- R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory);
R_RETURN(page_table.SetMemoryAttribute(address, size, static_cast<KMemoryAttribute>(mask),
static_cast<KMemoryAttribute>(attr)));
}
diff --git a/src/core/hle/kernel/svc/svc_synchronization.cpp b/src/core/hle/kernel/svc/svc_synchronization.cpp
index 2f72f60215..2b019c52d1 100644
--- a/src/core/hle/kernel/svc/svc_synchronization.cpp
+++ b/src/core/hle/kernel/svc/svc_synchronization.cpp
@@ -15,24 +15,13 @@
namespace Kernel::Svc {
-namespace {
-void LogInvalidNativeSyncHandle(Core::System& system, const char* operation, Handle handle) {
- if (!GetCurrentProcess(system.Kernel()).UsesPAuthReturns()) { return; }
- const auto& context = GetCurrentThread(system.Kernel()).GetContext();
- LOG_DEBUG(Kernel_SVC, "native {} invalid handle={:#x}, pc={:#x}, lr={:#x}, fp={:#x}",
- operation, handle, context.pc, context.lr, context.fp);
-}
-}
-
/// Close a handle
Result CloseHandle(Core::System& system, Handle handle) {
LOG_TRACE(Kernel_SVC, "Closing handle {:#08x}", handle);
// Remove the handle.
- if (!GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(system.Kernel(), handle)) {
- LogInvalidNativeSyncHandle(system, "CloseHandle", handle);
- R_THROW(ResultInvalidHandle);
- }
+ R_UNLESS(GetCurrentProcess(system.Kernel()).GetHandleTable().Remove(system.Kernel(), handle),
+ ResultInvalidHandle);
R_SUCCEED();
}
@@ -60,7 +49,6 @@ Result ResetSignal(Core::System& system, Handle handle) {
}
}
- LogInvalidNativeSyncHandle(system, "ResetSignal", handle);
R_THROW(ResultInvalidHandle);
}
@@ -84,10 +72,7 @@ Result WaitSynchronization(Core::System& system, int32_t* out_index, u64 user_ha
R_UNLESS(GetCurrentMemory(system.Kernel()).ReadBlock(user_handles, handles.data(), sizeof(Handle) * num_handles), ResultInvalidPointer);
// Convert the handles to objects.
- if (!handle_table.GetMultipleObjects<KSynchronizationObject>(system.Kernel(), objs.data(), handles.data(), num_handles)) {
- for (s32 i = 0; i < num_handles; ++i) { LogInvalidNativeSyncHandle(system, "WaitSynchronization set", handles[i]); }
- R_THROW(ResultInvalidHandle);
- }
+ R_UNLESS(handle_table.GetMultipleObjects<KSynchronizationObject>(system.Kernel(), objs.data(), handles.data(), num_handles), ResultInvalidHandle);
}
// Ensure handles are closed when we're done.
diff --git a/src/core/hle/kernel/svc/svc_thread.cpp b/src/core/hle/kernel/svc/svc_thread.cpp
index b4eb0b5719..dbca13dd26 100644
--- a/src/core/hle/kernel/svc/svc_thread.cpp
+++ b/src/core/hle/kernel/svc/svc_thread.cpp
@@ -16,11 +16,8 @@
namespace Kernel::Svc {
namespace {
-bool IsValidVirtualCoreId(const KProcess& process, int32_t core_id) {
- // Extended processes use the kernel's existing virtual-core mapping.
- const auto core_count = process.UsesPAuthReturns() ? Core::Hardware::NumVirtualCores
- : Core::Hardware::NUM_CPU_CORES;
- return 0 <= core_id && core_id < static_cast<int32_t>(core_count);
+constexpr bool IsValidVirtualCoreId(int32_t core_id) {
+ return (0 <= core_id && core_id < static_cast<int32_t>(Core::Hardware::NUM_CPU_CORES));
}
} // Anonymous namespace
@@ -41,7 +38,7 @@ Result CreateThread(Core::System& system, Handle* out_handle, u64 entry_point, u
}
// Validate arguments.
- R_UNLESS(IsValidVirtualCoreId(process, core_id), ResultInvalidCoreId);
+ R_UNLESS(IsValidVirtualCoreId(core_id), ResultInvalidCoreId);
R_UNLESS(((1ull << core_id) & process.GetCoreMask()) != 0, ResultInvalidCoreId);
R_UNLESS(HighestThreadPriority <= priority && priority <= LowestThreadPriority,
@@ -265,7 +262,7 @@ Result SetThreadCoreMask(Core::System& system, Handle thread_handle, s32 core_id
R_UNLESS(affinity_mask != 0, ResultInvalidCombination);
// Validate the core id.
- if (IsValidVirtualCoreId(GetCurrentProcess(system.Kernel()), core_id)) {
+ if (IsValidVirtualCoreId(core_id)) {
R_UNLESS(((1ULL << core_id) & affinity_mask) != 0, ResultInvalidCombination);
} else {
R_UNLESS(core_id == IdealCoreNoUpdate || core_id == IdealCoreDontCare,
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h
index c7b68cc0df..b0f4796da4 100644
--- a/src/core/hle/kernel/svc_types.h
+++ b/src/core/hle/kernel/svc_types.h
@@ -50,7 +50,6 @@ enum class MemoryAttribute : u32 {
DeviceShared = (1 << 2),
Uncached = (1 << 3),
PermissionLocked = (1 << 4),
- GpuAccessible = (1 << 5),
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryAttribute);
diff --git a/src/core/hle/service/am/applet.h b/src/core/hle/service/am/applet.h
index 69d2876363..571fa65219 100644
--- a/src/core/hle/service/am/applet.h
+++ b/src/core/hle/service/am/applet.h
@@ -84,7 +84,6 @@ struct Applet {
// Application functions
bool game_play_recording_supported{};
bool media_playback_state{};
- bool graphics_scale_changed_notification_enabled{};
GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled};
bool jit_service_launched{};
bool application_crash_report_enabled{};
diff --git a/src/core/hle/service/am/service/application_functions.cpp b/src/core/hle/service/am/service/application_functions.cpp
index f86806dd3c..90d292c4a2 100644
--- a/src/core/hle/service/am/service/application_functions.cpp
+++ b/src/core/hle/service/am/service/application_functions.cpp
@@ -118,8 +118,7 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
{220, nullptr, "Unknown220"}, // [20.0.0+]
{300, nullptr, "CreateMovieWriter"}, // [19.0.0+]
{310, nullptr, "Unknown310"}, // [20.0.0+]
- {320, D<&IApplicationFunctions::GetScreenShotAndContinuousRecordingInitiallyEnabled>,
- "GetScreenShotAndContinuousRecordingInitiallyEnabled"},
+ {320, nullptr, "Unknown320"}, // [20.0.0+]
{330, D<&IApplicationFunctions::Unknown330>, "Unknown330"}, // [20.0.0+]
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
@@ -545,17 +544,6 @@ Result IApplicationFunctions::GetUnknownEvent210(
R_SUCCEED();
}
-Result IApplicationFunctions::GetScreenShotAndContinuousRecordingInitiallyEnabled(
- Out<bool> out_screenshot_enabled, Out<bool> out_recording_enabled) {
- std::scoped_lock lk{m_applet->lock};
- *out_screenshot_enabled = m_applet->screenshot_permission != ScreenshotPermission::Disable;
- *out_recording_enabled = m_applet->game_play_recording_supported &&
- m_applet->game_play_recording_state == GamePlayRecordingState::Enabled;
- LOG_DEBUG(Service_AM, "called, screenshot={}, recording={}", *out_screenshot_enabled,
- *out_recording_enabled);
- R_SUCCEED();
-}
-
Result IApplicationFunctions::Unknown330(Out<u8> out) {
LOG_DEBUG(Service_AM, "called");
*out = 0;
diff --git a/src/core/hle/service/am/service/application_functions.h b/src/core/hle/service/am/service/application_functions.h
index 172b712f14..b97ed7e25e 100644
--- a/src/core/hle/service/am/service/application_functions.h
+++ b/src/core/hle/service/am/service/application_functions.h
@@ -82,8 +82,6 @@ private:
Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result CreateApplicationAndRequestToStart(u64 application_id);
Result GetUnknownEvent210(OutCopyHandle<Kernel::KReadableEvent> out_event);
- Result GetScreenShotAndContinuousRecordingInitiallyEnabled(
- Out<bool> out_screenshot_enabled, Out<bool> out_recording_enabled);
Result Unknown330(Out<u8> out);
Result PrepareForJit();
diff --git a/src/core/hle/service/am/service/application_proxy.cpp b/src/core/hle/service/am/service/application_proxy.cpp
index 02502ae764..df438e1e17 100644
--- a/src/core/hle/service/am/service/application_proxy.cpp
+++ b/src/core/hle/service/am/service/application_proxy.cpp
@@ -11,9 +11,7 @@
#include "core/hle/service/am/service/common_state_getter.h"
#include "core/hle/service/am/service/debug_functions.h"
#include "core/hle/service/am/service/display_controller.h"
-#include "core/hle/service/am/service/graphics_scaling_parameters_functions.h"
#include "core/hle/service/am/service/library_applet_creator.h"
-#include "core/hle/service/am/service/performance_functions.h"
#include "core/hle/service/am/service/process_winding_controller.h"
#include "core/hle/service/am/service/self_controller.h"
#include "core/hle/service/am/service/window_controller.h"
@@ -35,9 +33,6 @@ IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Appl
{10, D<&IApplicationProxy::GetProcessWindingController>, "GetProcessWindingController"},
{11, D<&IApplicationProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
{20, D<&IApplicationProxy::GetApplicationFunctions>, "GetApplicationFunctions"},
- {40, D<&IApplicationProxy::GetPerformanceFunctions>, "GetPerformanceFunctions"},
- {60, D<&IApplicationProxy::GetGraphicsScalingParametersFunctions>,
- "GetGraphicsScalingParametersFunctions"},
{1000, D<&IApplicationProxy::GetDebugFunctions>, "GetDebugFunctions"},
};
// clang-format on
@@ -111,18 +106,4 @@ Result IApplicationProxy::GetApplicationFunctions(
R_SUCCEED();
}
-Result IApplicationProxy::GetPerformanceFunctions(
- Out<SharedPointer<IPerformanceFunctions>> out_functions) {
- LOG_DEBUG(Service_AM, "called");
- *out_functions = std::make_shared<IPerformanceFunctions>(system);
- R_SUCCEED();
-}
-
-Result IApplicationProxy::GetGraphicsScalingParametersFunctions(
- Out<SharedPointer<IGraphicsScalingParametersFunctions>> out_functions) {
- LOG_DEBUG(Service_AM, "called");
- *out_functions = std::make_shared<IGraphicsScalingParametersFunctions>(system, m_applet);
- R_SUCCEED();
-}
-
} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/application_proxy.h b/src/core/hle/service/am/service/application_proxy.h
index aa1ab1938a..b56f597605 100644
--- a/src/core/hle/service/am/service/application_proxy.h
+++ b/src/core/hle/service/am/service/application_proxy.h
@@ -17,9 +17,7 @@ class IApplicationFunctions;
class ICommonStateGetter;
class IDebugFunctions;
class IDisplayController;
-class IGraphicsScalingParametersFunctions;
class ILibraryAppletCreator;
-class IPerformanceFunctions;
class IProcessWindingController;
class ISelfController;
class IWindowController;
@@ -45,10 +43,6 @@ private:
Result GetApplicationFunctions(
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
- Result GetPerformanceFunctions(Out<SharedPointer<IPerformanceFunctions>> out_functions);
- Result GetGraphicsScalingParametersFunctions(
- Out<SharedPointer<IGraphicsScalingParametersFunctions>> out_functions);
-
private:
WindowSystem& m_window_system;
Kernel::KProcess* const m_process;
diff --git a/src/core/hle/service/am/service/application_proxy_service.cpp b/src/core/hle/service/am/service/application_proxy_service.cpp
index da11cce94d..7727951d8c 100644
--- a/src/core/hle/service/am/service/application_proxy_service.cpp
+++ b/src/core/hle/service/am/service/application_proxy_service.cpp
@@ -19,8 +19,6 @@ IApplicationProxyService::IApplicationProxyService(Core::System& system_,
: ServiceFramework{system_, "appletOE"}, m_window_system{window_system} {
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
- {10, D<&IApplicationProxyService::OpenApplicationProxyWithFlags>,
- "OpenApplicationProxyWithFlags"},
};
RegisterHandlers(functions);
}
@@ -42,15 +40,6 @@ Result IApplicationProxyService::OpenApplicationProxy(
}
}
-Result IApplicationProxyService::OpenApplicationProxyWithFlags(
- Out<SharedPointer<IApplicationProxy>> out_application_proxy, u32 flags, ClientProcessId pid,
- InCopyHandle<Kernel::KProcess> process_handle) {
- LOG_DEBUG(Service_AM, "called, flags={:#x}", flags);
- // The extended SDK supplies an additional u32 before the process ID.
- R_UNLESS(flags == 0 || flags == 2, ResultUnknown);
- R_RETURN(OpenApplicationProxy(out_application_proxy, pid, process_handle));
-}
-
std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
return m_window_system.GetByAppletResourceUserId(process_id.pid);
}
diff --git a/src/core/hle/service/am/service/application_proxy_service.h b/src/core/hle/service/am/service/application_proxy_service.h
index 5812f6133a..fce860a7c1 100644
--- a/src/core/hle/service/am/service/application_proxy_service.h
+++ b/src/core/hle/service/am/service/application_proxy_service.h
@@ -26,10 +26,6 @@ private:
Result OpenApplicationProxy(Out<SharedPointer<IApplicationProxy>> out_application_proxy,
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle);
- Result OpenApplicationProxyWithFlags(
- Out<SharedPointer<IApplicationProxy>> out_application_proxy, u32 flags, ClientProcessId pid,
- InCopyHandle<Kernel::KProcess> process_handle);
-
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
diff --git a/src/core/hle/service/am/service/gpu_memory_registration.h b/src/core/hle/service/am/service/gpu_memory_registration.h
deleted file mode 100644
index 37ac7fd377..0000000000
--- a/src/core/hle/service/am/service/gpu_memory_registration.h
+++ /dev/null
@@ -1,22 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-#pragma once
-#include <optional>
-#include <span>
-#include "common/common_types.h"
-
-namespace Service::AM {
-struct GpuMemoryRegistration {
- u64 begin;
- u64 end;
- u8 flags;
- u8 device;
-};
-
-constexpr std::optional<GpuMemoryRegistration> DecodeGpuMemoryRegistration(std::span<const u32> packet) {
- if (packet.size() < 8 || packet[0] != 0x75 || packet[1] != 6) return std::nullopt;
- // The SDK writes STRB at offsets 0x18 and 0x1c, leaving three padding bytes.
- return GpuMemoryRegistration{u64{packet[2]} | (u64{packet[3]} << 32),
- u64{packet[4]} | (u64{packet[5]} << 32), static_cast<u8>(packet[6]), static_cast<u8>(packet[7])};
-}
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/gpu_session.cpp b/src/core/hle/service/am/service/gpu_session.cpp
deleted file mode 100644
index a83381d7bc..0000000000
--- a/src/core/hle/service/am/service/gpu_session.cpp
+++ /dev/null
@@ -1,633 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <algorithm>
-#include <cstring>
-#include <mutex>
-#include <vector>
-#include "common/swap.h"
-#include "common/alignment.h"
-#include "core/hle/service/nvdrv/core/nvmap.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_client_session.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/svc_results.h"
-#include "core/hle/service/am/service/graphics_session.h"
-#include "core/hle/service/am/service/gpu_session.h"
-#include "core/hle/service/am/service/gpu_memory_registration.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nvdrv/nvdrv.h"
-#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
-#include "core/hle/service/nvdrv/devices/native_gpu_kind.h"
-
-namespace Service::AM {
-struct GpuDeviceRegistry {
- GpuDeviceRegistry(Core::System& system, std::shared_ptr<Nvidia::Module> module_, Kernel::KProcess* process_)
- : context{system, "GpuDevices"}, module{std::move(module_)}, process{process_} {
- process->Open(context.kernel);
- }
- ~GpuDeviceRegistry() {
- for (const auto& fd : address_spaces) { if (fd) { module->Close(*fd); } }
- if (nv_session) { module->GetContainer().CloseSession(Nvidia::NvCore::SessionId{*nv_session}); }
- process->Close(context.kernel);
- for (auto* event : events) { context.CloseEvent(event); }
- }
- KernelHelpers::ServiceContext context;
- std::array<Kernel::KEvent*, 64> events{};
- struct Device { u64 name; u64 debug_label; };
- std::mutex mutex;
- std::shared_ptr<Nvidia::Module> module;
- Kernel::KProcess* process;
- std::array<std::optional<s32>, 8> address_spaces{};
- std::array<bool, 8> address_space_registered{};
- std::optional<size_t> nv_session;
- std::array<std::optional<Device>, 256> devices{};
-};
-namespace {
-class IGpuWorker final : public ServiceFramework<IGpuWorker> {
-public:
- IGpuWorker(Core::System& system, std::shared_ptr<Nvidia::Module> module,
- Kernel::KProcess* process, std::shared_ptr<GpuDeviceRegistry> devices)
- : ServiceFramework{system, "IGpuWorker"}, m_devices{std::move(devices)},
- m_module{std::move(module)}, m_process{process} {
- m_process->Open(kernel);
- static const FunctionInfo functions[] = {
- {101, &IGpuWorker::CreateGpuAccessibleMemory, "CreateGpuAccessibleMemory"},
- {102, &IGpuWorker::DestroyGpuAccessibleMemory, "DestroyGpuAccessibleMemory"},
- {211, &IGpuWorker::NormalMapGpuMemory4K, "NormalMapGpuMemory4K"},
- {212, &IGpuWorker::NormalModifyGpuMemory4K, "NormalModifyGpuMemory4K"},
- {213, &IGpuWorker::NormalUnmapGpuMemory4K, "NormalUnmapGpuMemory4K"},
- {214, &IGpuWorker::CreateSparseRegion, "CreateSparseRegion"},
- {215, &IGpuWorker::DestroySparseRegion, "DestroySparseRegion"},
- };
- RegisterHandlersTipc(functions);
- }
- ~IGpuWorker() override {
- for (const auto& mapping : m_mappings) {
- if (auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(mapping.as_id)) {
- as->UnmapNative4K(mapping.address, mapping.size);
- }
- }
- for (const auto& region : m_sparse_regions) {
- if (auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(region.as_id)) {
- as->DestroyNativeSparseRegion(region.address, region.size);
- }
- }
- auto& nvmap = m_module->GetContainer().GetNvMapFile();
- for (const auto id : m_memory) {
- if (const auto info = nvmap.FreeHandle(id, false); info && info->can_unlock) {
- const auto result = m_process->GetPageTable().UnlockForDeviceAddressSpace(
- info->address, info->size);
- if (result.IsError()) {
- LOG_ERROR(Service_AM, "GPU memory cleanup failed: {:#x}", result.raw);
- }
- }
- }
- if (m_nv_session) {
- m_module->GetContainer().CloseSession(Nvidia::NvCore::SessionId{*m_nv_session});
- }
- m_process->Close(kernel);
- }
- Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) override {
- if (!ctx.IsTipc() || handlers_tipc.contains(ctx.GetCommand())) {
- return ServiceFrameworkBase::HandleSyncRequest(session, ctx);
- }
- const auto guard = LockService();
- InvokeRequestTipc(ctx);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultNotImplemented.raw);
- return system.IsPoweredOn() ? ctx.WriteToOutgoingCommandBuffer() : ResultSuccess;
- }
-private:
- struct Mapping { u32 as_id; u64 address; u64 size; u32 memory_id; };
- std::vector<Mapping> m_mappings;
- std::vector<Mapping> m_sparse_regions;
- static u64 ReadPair(const u32* packet, size_t index) {
- return u64{packet[index]} | (u64{packet[index + 1]} << 32);
- }
- bool OwnsAddressSpace(u32 id) const {
- for (size_t i = 0; i < m_devices->address_spaces.size(); ++i) {
- if (m_devices->address_spaces[i] &&
- static_cast<u32>(*m_devices->address_spaces[i]) == id &&
- m_devices->address_space_registered[i]) { return true; }
- }
- return false;
- }
- void CreateSparseRegion(HLERequestContext& ctx) {
- const std::scoped_lock device_lock{m_devices->mutex};
- const auto* p = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- const u64 begin = ReadPair(p, 3), end = ReadPair(p, 5);
- const u32 notification = p[11];
- if (p[0] == 0xe6 && p[1] == 10 && notification < m_devices->events.size() && m_devices->events[notification]) {
- result = Kernel::ResultNotFound;
- const u32 shift = p[7] & 0xff, device = p[9] & 0xff;
- if (OwnsAddressSpace(p[2]) && device < m_devices->devices.size() && m_devices->devices[device]) {
- result = Kernel::ResultInvalidArgument;
- if ((shift == 12 || shift == 16) && (p[8] & 0xff) <= 1 && (p[10] & 0xff) <= 1 &&
- end >= begin && end != ~u64{0} && Common::IsAligned(begin, 1ULL << shift) &&
- Common::IsAligned(end - begin + 1, 1ULL << shift)) {
- const auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(p[2]);
- result = as && as->CreateNativeSparseRegion(begin, end - begin + 1) == Nvidia::NvResult::Success
- ? ResultSuccess : Kernel::ResultInvalidCurrentMemory;
- if (result.IsSuccess()) { m_sparse_regions.push_back({p[2], begin, end - begin + 1, 0}); }
- }
- }
- m_devices->events[notification]->Signal(kernel);
- }
- LOG_DEBUG(Service_AM, "GPU sparse region as={}, VA={:#x}..{:#x}, result={:#x}", p[2], begin, end, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void DestroySparseRegion(HLERequestContext& ctx) {
- const std::scoped_lock device_lock{m_devices->mutex};
- const auto* p = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- const u64 begin = ReadPair(p, 3), end = ReadPair(p, 5);
- const u32 notification = p[8];
- if (p[0] == 0xe7 && p[1] == 7 && (p[7] & 0xff) <= 1 &&
- notification < m_devices->events.size() && m_devices->events[notification]) {
- const auto it = std::find_if(m_sparse_regions.begin(), m_sparse_regions.end(), [&](const auto& region) {
- return region.as_id == p[2] && region.address == begin && end >= begin && region.size == end - begin + 1;
- });
- result = Kernel::ResultNotFound;
- if (it != m_sparse_regions.end()) {
- const auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(p[2]);
- if (as && as->DestroyNativeSparseRegion(begin, it->size) == Nvidia::NvResult::Success) {
- std::erase_if(m_mappings, [&](const auto& mapping) {
- return mapping.as_id == p[2] && mapping.address >= begin && mapping.address <= end;
- });
- m_sparse_regions.erase(it);
- result = ResultSuccess;
- }
- }
- m_devices->events[notification]->Signal(kernel);
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- Result MapMemory(const u32* packet, u8& selected_kind) {
- R_UNLESS(OwnsAddressSpace(packet[2]), Kernel::ResultNotFound);
- R_UNLESS(std::find(m_memory.begin(), m_memory.end(), packet[7]) != m_memory.end(),
- Kernel::ResultNotFound);
- R_UNLESS(packet[15] < m_devices->devices.size() && m_devices->devices[packet[15]],
- Kernel::ResultNotFound);
- R_UNLESS(packet[10] == 0 && packet[11] <= 1 && packet[14] == 0 && packet[16] <= 1,
- Kernel::ResultNotImplemented);
- const auto kind = Nvidia::Devices::SelectNativeMemoryKind(
- static_cast<u8>(packet[12]), static_cast<u8>(packet[13]));
- R_UNLESS(kind, Kernel::ResultNotImplemented);
- const u64 begin = ReadPair(packet, 3), end = ReadPair(packet, 5);
- R_UNLESS(end >= begin && end != ~u64{0}, Kernel::ResultInvalidSize);
- R_UNLESS(m_mappings.size() < 1024, Kernel::ResultOutOfResource);
- const auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(packet[2]);
- R_UNLESS(as, Kernel::ResultNotFound);
- const auto result = as->MapNative4K(packet[7], begin, ReadPair(packet, 8),
- end - begin + 1, kind->backend);
- R_UNLESS(result == Nvidia::NvResult::Success, Kernel::ResultInvalidCurrentMemory);
- m_mappings.push_back({packet[2], begin, end - begin + 1, packet[7]});
- selected_kind = kind->selected;
- R_SUCCEED();
- }
- void NormalMapGpuMemory4K(HLERequestContext& ctx) {
- std::array<u32, 18> words;
- std::copy_n(ctx.CommandBuffer(), words.size(), words.begin());
- // These arguments are single-byte TIPC fields; SDK padding is not zeroed.
- for (size_t i = 10; i <= 16; ++i) { words[i] &= 0xff; }
- const auto* packet = words.data();
- const std::scoped_lock device_lock{m_devices->mutex};
- Result result = Kernel::ResultInvalidCombination;
- u8 selected_kind{};
- if (packet[0] == 0xe3 && packet[1] == 16 && packet[17] < m_devices->events.size() &&
- m_devices->events[packet[17]]) {
- result = MapMemory(packet, selected_kind);
- m_devices->events[packet[17]]->Signal(kernel);
- LOG_DEBUG(Service_AM, "GPU map4K as={}, memory={}, VA={:#x}..{:#x}, permission={}, cache={}, kinds={:#x}/{:#x}, mode={}, sync={}, notification={}, selected={:#x}, result={:#x}",
- packet[2], packet[7], ReadPair(packet, 3), ReadPair(packet, 5), packet[10],
- packet[11], packet[12], packet[13], packet[14], packet[16], packet[17], selected_kind, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push<u32>(selected_kind);
- }
- void NormalModifyGpuMemory4K(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const std::scoped_lock device_lock{m_devices->mutex};
- Result result = Kernel::ResultInvalidCombination;
- u8 selected{};
- const u64 begin = ReadPair(packet, 3), end = ReadPair(packet, 5);
- const auto requested = static_cast<u8>(packet[7]);
- const auto fallback = static_cast<u8>(packet[8]);
- if (packet[0] == 0xe4 && packet[1] == 9 && (packet[9] & 0xff) <= 1 &&
- packet[10] < m_devices->events.size() && m_devices->events[packet[10]]) {
- result = Kernel::ResultNotFound;
- const auto kind = Nvidia::Devices::SelectNativeMemoryKind(requested, fallback);
- const auto owner = std::find_if(m_mappings.begin(), m_mappings.end(), [&](const auto& mapping) {
- return mapping.as_id == packet[2] && begin >= mapping.address &&
- begin - mapping.address < mapping.size && end >= begin &&
- end - mapping.address < mapping.size;
- });
- if (kind && OwnsAddressSpace(packet[2]) && owner != m_mappings.end()) {
- const auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(packet[2]);
- if (as && as->ModifyNativeKind(begin, end - begin + 1, requested, fallback) ==
- Nvidia::NvResult::Success) {
- selected = kind->selected;
- result = ResultSuccess;
- }
- }
- m_devices->events[packet[10]]->Signal(kernel);
- }
- LOG_DEBUG(Service_AM, "GPU modify4K as={}, VA={:#x}..{:#x}, kinds={:#x}/{:#x}, sync={}, notification={}, selected={}, result={:#x}",
- packet[2], begin, end, requested, fallback, packet[9], packet[10], selected, result.raw);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push<u32>(selected);
- }
- void NormalUnmapGpuMemory4K(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const std::scoped_lock device_lock{m_devices->mutex};
- Result result = Kernel::ResultInvalidCombination;
- u64 unmapped{};
- if (packet[0] == 0xe5 && packet[1] == 7 && (packet[7] & 0xff) <= 1 &&
- packet[8] < m_devices->events.size() && m_devices->events[packet[8]]) {
- const u64 begin = ReadPair(packet, 3), end = ReadPair(packet, 5);
- const auto it = std::find_if(m_mappings.begin(), m_mappings.end(), [&](const auto& mapping) {
- return mapping.as_id == packet[2] && mapping.address == begin &&
- end >= begin && end - begin + 1 == mapping.size;
- });
- result = Kernel::ResultNotFound;
- if (it != m_mappings.end()) {
- const auto as = m_module->GetDevice<Nvidia::Devices::nvhost_as_gpu>(it->as_id);
- result = Kernel::ResultInvalidState;
- if (as && as->UnmapNative4K(it->address, it->size) == Nvidia::NvResult::Success) {
- unmapped = it->size;
- m_mappings.erase(it);
- result = ResultSuccess;
- }
- }
- m_devices->events[packet[8]]->Signal(kernel);
- LOG_DEBUG(Service_AM, "GPU unmap4K as={}, VA={:#x}..{:#x}, bytes={:#x}, result={:#x}",
- packet[2], begin, end, unmapped, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result.raw);
- rb.Push(unmapped);
- }
- Result RegisterMemory(u64 begin, u64 end, u32 flags, u32 device, u32& id) {
- R_UNLESS(flags == 0, Kernel::ResultNotImplemented);
- R_UNLESS(device < m_devices->devices.size(), Kernel::ResultNotFound);
- const std::scoped_lock device_lock{m_devices->mutex};
- R_UNLESS(m_devices->devices[device], Kernel::ResultNotFound);
- R_UNLESS(end >= begin && end != ~u64{0}, Kernel::ResultInvalidSize);
- const u64 size = end - begin + 1;
- R_UNLESS(Common::IsAligned(begin, Kernel::PageSize), Kernel::ResultInvalidAddress);
- R_UNLESS(Common::IsAligned(size, Kernel::PageSize), Kernel::ResultInvalidSize);
- R_UNLESS(m_memory.size() < 1024, Kernel::ResultOutOfResource);
- auto& page_table = m_process->GetPageTable();
- R_UNLESS(page_table.Contains(begin, size), Kernel::ResultInvalidCurrentMemory);
- for (u64 address = begin; address <= end;) {
- Kernel::KMemoryInfo info{};
- Kernel::Svc::PageInfo page{};
- R_TRY(page_table.QueryInfo(&info, &page, address));
- R_UNLESS(True(info.m_attribute & Kernel::KMemoryAttribute::GpuAccessible),
- Kernel::ResultInvalidCurrentMemory);
- const u64 next = info.m_address + info.m_size;
- R_UNLESS(next > address, Kernel::ResultInvalidCurrentMemory);
- address = next;
- }
- if (!m_nv_session) {
- m_nv_session = m_module->GetContainer().OpenSession(m_process).id;
- }
- auto& nvmap = m_module->GetContainer().GetNvMapFile();
- std::shared_ptr<Nvidia::NvCore::NvMap::Handle> handle;
- R_UNLESS(nvmap.CreateHandle(size, handle) == Nvidia::NvResult::Success,
- Kernel::ResultOutOfResource);
- bool is_io{};
- const auto lock_result = page_table.LockForMapDeviceAddressSpace(
- &is_io, begin, size, Kernel::KMemoryPermission::None, true, true);
- if (lock_result.IsError()) {
- nvmap.FreeHandle(handle->id, false);
- R_RETURN(lock_result);
- }
- const auto alloc_result = handle->Alloc({}, Kernel::PageSize, 0, begin,
- Nvidia::NvCore::SessionId{*m_nv_session});
- if (alloc_result != Nvidia::NvResult::Success) {
- page_table.UnlockForDeviceAddressSpace(begin, size);
- nvmap.FreeHandle(handle->id, false);
- R_RETURN(Kernel::ResultOutOfResource);
- }
- id = handle->id;
- m_memory.push_back(id);
- R_SUCCEED();
- }
- Result ReleaseMemory(u32 id, u32 notification) {
- const std::scoped_lock device_lock{m_devices->mutex};
- R_UNLESS(notification < m_devices->events.size() && m_devices->events[notification],
- Kernel::ResultInvalidCombination);
- const auto it = std::find(m_memory.begin(), m_memory.end(), id);
- R_UNLESS(it != m_memory.end(), Kernel::ResultNotFound);
- auto& nvmap = m_module->GetContainer().GetNvMapFile();
- auto handle = nvmap.GetHandle(id);
- R_UNLESS(handle, Kernel::ResultNotFound);
- {
- const std::scoped_lock handle_lock{handle->mutex};
- // No asynchronous GPU work is implemented yet. Never report release
- // completion for memory still retained or pinned by another user.
- R_UNLESS(handle->pins == 0 && handle->internal_dupes == 0 && handle->dupes == 1,
- Kernel::ResultBusy);
- }
- // FreeHandle uses the final shared reference to decide when CPU memory
- // may be unshared. Drop this temporary inspection reference first.
- handle.reset();
- const auto info = nvmap.FreeHandle(id, false);
- R_UNLESS(info && info->can_unlock, Kernel::ResultInvalidState);
- m_memory.erase(it);
- R_TRY(m_process->GetPageTable().UnlockForDeviceAddressSpace(info->address, info->size));
- m_devices->events[notification]->Signal(kernel);
- R_SUCCEED();
- }
- void DestroyGpuAccessibleMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const auto result = packet[0] == 0x76 && packet[1] == 2
- ? ReleaseMemory(packet[2], packet[3]) : Kernel::ResultInvalidCombination;
- LOG_DEBUG(Service_AM, "GPU memory release id={}, notification={}, result={:#x}",
- packet[2], packet[3], result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void CreateGpuAccessibleMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- u32 id{};
- Result result = Kernel::ResultInvalidCombination;
- if (const auto request = DecodeGpuMemoryRegistration(std::span<const u32>{packet, 8})) {
- result = RegisterMemory(request->begin, request->end, request->flags, request->device, id);
- LOG_DEBUG(Service_AM, "GPU memory {:#x}..{:#x}, device={}, raw_device={:#x}, flags={}, id={}, result={:#x}",
- request->begin, request->end, request->device, packet[7], request->flags, id, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push(id);
- }
- std::shared_ptr<GpuDeviceRegistry> m_devices;
- std::optional<size_t> m_nv_session;
- std::vector<u32> m_memory;
- std::shared_ptr<Nvidia::Module> m_module;
- Kernel::KProcess* const m_process;
-};
-} // namespace
-
-IGpuSession::IGpuSession(Core::System& system, std::shared_ptr<Nvidia::Module> module,
- Kernel::KProcess* process, bool legacy_protocol)
- : ServiceFramework{system, "IGpuSession"},
- m_process{process}, m_module{std::move(module)}, m_legacy_protocol{legacy_protocol} {
- m_process->Open(kernel);
- m_devices = std::make_shared<GpuDeviceRegistry>(system, m_module, m_process);
- static const FunctionInfo functions[] = {
- {11, &IGpuSession::GetNotificationRange, "GetNotificationRange"},
- {12, &IGpuSession::GetNotificationEvent, "GetNotificationEvent"},
- {21, &IGpuSession::RequestWorker, "RequestWorker"},
- {22, &IGpuSession::AcquireWorker, "AcquireWorker"},
- {33, &IGpuSession::CreateAddressSpace, "CreateAddressSpace"},
- {41, &IGpuSession::CreateGraphicsDevice, "CreateGraphicsDevice"},
- {42, &IGpuSession::DestroyGraphicsDevice, "DestroyGraphicsDevice"},
- {201, &IGpuSession::GetAddressSpacePartition, "GetLegacyGsvPartition"},
- {202, &IGpuSession::GetAddressSpacePartition, "GetGsvPartition"},
- {203, &IGpuSession::GetAddressSpacePartition, "GetUserPartition"},
- };
- RegisterHandlersTipc(functions);
-}
-
-IGpuSession::~IGpuSession() {
- if (m_worker) { m_worker->Close(kernel); }
- m_process->Close(kernel);
-}
-
-Result IGpuSession::HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) {
- if (!ctx.IsTipc() || handlers_tipc.contains(ctx.GetCommand())) {
- return ServiceFrameworkBase::HandleSyncRequest(session, ctx);
- }
- const auto guard = LockService();
- InvokeRequestTipc(ctx);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultNotImplemented.raw);
- return system.IsPoweredOn() ? ctx.WriteToOutgoingCommandBuffer() : ResultSuccess;
-}
-
-Result IGpuSession::RegisterAddressSpace(u32 id) {
- const auto guard = LockService();
- const std::scoped_lock device_lock{m_devices->mutex};
- for (size_t i = 0; i < m_devices->address_spaces.size(); ++i) {
- if (m_devices->address_spaces[i] && static_cast<u32>(*m_devices->address_spaces[i]) == id) {
- m_devices->address_space_registered[i] = true;
- R_SUCCEED();
- }
- }
- R_THROW(Kernel::ResultNotFound);
-}
-
-void IGpuSession::GetAddressSpacePartition(HLERequestContext& ctx) {
- const std::scoped_lock device_lock{m_devices->mutex};
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- std::array<u64, 9> values{};
- const bool legacy_user = m_legacy_protocol && (ctx.GetCommand() == 201 || ctx.GetCommand() == 202);
- const bool user = legacy_user || ctx.GetCommand() == 203;
- if (!user) {
- values[0] = ~u64{0}; // No supervisor-owned partition is reserved by this adapter.
- }
- if (packet[0] == 16 + ctx.GetCommand() && packet[1] == 1) {
- const u32 id = packet[2];
- const bool exists = std::any_of(m_devices->address_spaces.begin(), m_devices->address_spaces.end(),
- [id](const auto& fd) { return fd && static_cast<u32>(*fd) == id; });
- result = exists ? ResultSuccess : Kernel::ResultNotFound;
- if (exists && user) {
- std::array<u8, 64> input{};
- std::array<u8, 64> output{};
- const u32_le buffer_size{48};
- std::memcpy(input.data() + 8, &buffer_size, sizeof(buffer_size));
- Nvidia::Ioctl command{};
- command.raw = 0xc0404108;
- if (m_module->Ioctl1(static_cast<s32>(id), command, input, output) ==
- Nvidia::NvResult::Success) {
- std::array<Nvidia::Devices::nvhost_as_gpu::VaRegion, 2> regions;
- std::memcpy(regions.data(), output.data() + 16, sizeof(regions));
- const u64 end = regions[1].offset + regions[1].pages * regions[1].page_size - 1;
- if (legacy_user) {
- const auto& region = regions[ctx.GetCommand() == 201 ? 0 : 1];
- values[0] = region.offset;
- values[1] = region.offset + region.pages * region.page_size - 1;
- } else {
- values[0] = 1;
- values[1] = regions[0].offset;
- values[2] = end;
- }
- } else {
- result = Kernel::ResultInvalidState;
- }
- }
- LOG_DEBUG(Service_AM, "GPU partition command={}, id={}, begin={:#x}, end={:#x}, result={:#x}",
- ctx.GetCommand(), id, user ? values[1] : values[0],
- user ? values[2] : values[1], result.raw);
- }
- IPC::ResponseBuilder rb{ctx, user && !legacy_user ? 20U : 6U};
- rb.Push(result.raw);
- for (size_t i = 0; i < (user && !legacy_user ? values.size() : size_t{2}); ++i) {
- rb.Push(values[i]);
- }
-}
-
-void IGpuSession::CreateAddressSpace(HLERequestContext& ctx) {
- const std::scoped_lock device_lock{m_devices->mutex};
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- u32 id{};
- if (packet[0] == 0x31 && packet[1] == 1 && packet[2] == 0) {
- result = Kernel::ResultOutOfResource;
- for (auto& slot : m_devices->address_spaces) {
- if (slot) {
- continue;
- }
- if (!m_devices->nv_session) {
- m_devices->nv_session = m_module->GetContainer().OpenSession(m_process).id;
- }
- const auto fd = m_module->Open("/dev/nvhost-as-gpu",
- Nvidia::NvCore::SessionId{*m_devices->nv_session});
- if (fd == Nvidia::INVALID_NVDRV_FD) {
- break;
- }
- std::array<u8, 40> input{};
- std::array<u8, 40> output{};
- const u32_le big_page_size{0x20000};
- std::memcpy(input.data() + 8, &big_page_size, sizeof(big_page_size));
- Nvidia::Ioctl command{};
- command.raw = 0x40284109;
- const auto nv_result = m_module->Ioctl1(fd, command, input, output);
- if (nv_result == Nvidia::NvResult::Success) {
- slot = fd;
- id = fd;
- result = ResultSuccess;
- } else {
- m_module->Close(fd);
- result = Kernel::ResultInvalidState;
- }
- break;
- }
- }
- LOG_DEBUG(Service_AM, "GPU address space id={}, result={:#x}", id, result.raw);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push(id);
-}
-
-void IGpuSession::CreateGraphicsDevice(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- u32 id{};
- if (packet[0] == 0x39 && packet[1] == 6) {
- const u64 name = u64{packet[2]} | (u64{packet[3]} << 32);
- const u64 flags = u64{packet[4]} | (u64{packet[5]} << 32);
- const u64 debug_label = u64{packet[6]} | (u64{packet[7]} << 32);
- result = flags == 0 ? Kernel::ResultOutOfResource : Kernel::ResultNotImplemented;
- if (flags == 0) {
- const std::scoped_lock device_lock{m_devices->mutex};
- for (u32 candidate = 1; candidate < m_devices->devices.size(); ++candidate) {
- if (!m_devices->devices[candidate]) {
- id = candidate;
- m_devices->devices[id] = GpuDeviceRegistry::Device{name, debug_label};
- result = ResultSuccess;
- break;
- }
- }
- }
- LOG_DEBUG(Service_AM, "graphics device name={:#x}, flags={:#x}, id={}, result={:#x}",
- name, flags, id, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push(id);
-}
-
-void IGpuSession::DestroyGraphicsDevice(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x3a && packet[1] == 1) {
- const u8 id = static_cast<u8>(packet[2]);
- const std::scoped_lock device_lock{m_devices->mutex};
- result = m_devices->devices[id] ? ResultSuccess : Kernel::ResultNotFound;
- m_devices->devices[id].reset();
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGpuSession::GetNotificationRange(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const Result result = packet[0] == 0x1b && packet[1] == 0
- ? ResultSuccess : Kernel::ResultInvalidCombination;
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result.raw);
- rb.Push<u32>(0);
- rb.Push<u32>(static_cast<u32>(m_devices->events.size() - 1));
- LOG_DEBUG(Service_AM, "GPU notification range 0..{}", m_devices->events.size() - 1);
-}
-
-void IGpuSession::GetNotificationEvent(HLERequestContext& ctx) {
- const std::scoped_lock device_lock{m_devices->mutex};
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- Kernel::KReadableEvent* readable{};
- if (packet[0] == 0x1c && packet[1] == 1 && packet[2] < m_devices->events.size()) {
- const u32 index = packet[2];
- if (!m_devices->events[index]) { m_devices->events[index] = m_devices->context.CreateEvent("GpuNotification"); }
- if (m_devices->events[index]) {
- readable = &m_devices->events[index]->GetReadableEvent();
- readable->Open(kernel);
- result = ResultSuccess;
- } else { result = Kernel::ResultOutOfResource; }
- LOG_DEBUG(Service_AM, "GPU notification event index={}, result={:#x}", index, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(readable);
-}
-
-void IGpuSession::RequestWorker(HLERequestContext& ctx) {
- const std::scoped_lock device_lock{m_devices->mutex};
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x25 && packet[1] == 1 && packet[2] < m_devices->events.size()) {
- const u32 index = packet[2];
- if (!m_devices->events[index]) {
- result = Kernel::ResultInvalidState;
- } else {
- result = ResultSuccess;
- if (!m_worker) {
- result = CreateGraphicsSession(system, ctx,
- std::make_shared<IGpuWorker>(system, m_module, m_process, m_devices), &m_worker);
- }
- if (result.IsSuccess()) { m_devices->events[index]->Signal(kernel); }
- }
- LOG_DEBUG(Service_AM, "GPU worker request index={}, result={:#x}", index, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGpuSession::AcquireWorker(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- Kernel::KClientSession* client{};
- if (packet[0] == 0x26 && packet[1] == 0) {
- if (m_worker) {
- client = m_worker;
- client->Open(kernel);
- result = ResultSuccess;
- } else { result = Kernel::ResultInvalidState; }
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(client);
- LOG_DEBUG(Service_AM, "GPU worker acquisition result={:#x}", result.raw);
-}
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/gpu_session.h b/src/core/hle/service/am/service/gpu_session.h
deleted file mode 100644
index e8f580bef1..0000000000
--- a/src/core/hle/service/am/service/gpu_session.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <array>
-#include <optional>
-#include "core/hle/service/service.h"
-#include "core/hle/service/kernel_helpers.h"
-
-namespace Kernel {
-class KClientSession;
-class KProcess;
-class KEvent;
-}
-namespace Service::Nvidia { class Module; }
-namespace Service::AM {
-
-struct GpuDeviceRegistry;
-
-class IGpuSession final : public ServiceFramework<IGpuSession> {
-public:
- IGpuSession(Core::System& system, std::shared_ptr<Nvidia::Module> module,
- Kernel::KProcess* process, bool legacy_protocol = false);
- ~IGpuSession() override;
- Result RegisterAddressSpace(u32 id);
- Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) override;
-
-private:
- void GetAddressSpacePartition(HLERequestContext& ctx);
- void CreateAddressSpace(HLERequestContext& ctx);
- void CreateGraphicsDevice(HLERequestContext& ctx);
- void DestroyGraphicsDevice(HLERequestContext& ctx);
- void GetNotificationRange(HLERequestContext& ctx);
- void GetNotificationEvent(HLERequestContext& ctx);
- void RequestWorker(HLERequestContext& ctx);
- void AcquireWorker(HLERequestContext& ctx);
-
- std::shared_ptr<GpuDeviceRegistry> m_devices;
- Kernel::KClientSession* m_worker{};
- Kernel::KProcess* const m_process;
- std::shared_ptr<Nvidia::Module> m_module;
- const bool m_legacy_protocol;
-};
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_scaling_parameters_functions.cpp b/src/core/hle/service/am/service/graphics_scaling_parameters_functions.cpp
deleted file mode 100644
index 931c81850d..0000000000
--- a/src/core/hle/service/am/service/graphics_scaling_parameters_functions.cpp
+++ /dev/null
@@ -1,45 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "core/hle/service/am/applet.h"
-#include "core/hle/service/am/service/graphics_scaling_parameters_functions.h"
-#include "core/hle/service/cmif_serialization.h"
-
-namespace Service::AM {
-
-IGraphicsScalingParametersFunctions::IGraphicsScalingParametersFunctions(
- Core::System& system, std::shared_ptr<Applet> applet)
- : ServiceFramework{system, "IGraphicsScalingParametersFunctions"}, m_applet{std::move(applet)} {
- static const FunctionInfo functions[] = {
- {10, D<&IGraphicsScalingParametersFunctions::GetGraphicsScalingParameters>,
- "GetGraphicsScalingParameters"},
- {1000, nullptr, "SetSupportingGraphicsScalingParametersForDebug"},
- {1010, nullptr, "SetGpuQuotaForDebug"},
- {1020, nullptr, "ClearGpuQuotaForDebug"},
- {1030, nullptr, "SetScreenRatioForDebug"},
- {1040, nullptr, "ClearScreenRatioForDebug"},
- {1050, D<&IGraphicsScalingParametersFunctions::SetGraphicsScaleChangedNotificationEnabled>,
- "SetGraphicsScaleChangedNotificationEnabled"},
- };
- RegisterHandlers(functions);
-}
-
-IGraphicsScalingParametersFunctions::~IGraphicsScalingParametersFunctions() = default;
-
-Result IGraphicsScalingParametersFunctions::GetGraphicsScalingParameters(
- Out<GraphicsScalingParameters> out_parameters) {
- // Prototype policy: lowest SDK scale (10 maps to public scale 0), unit screen ratio.
- // The ratio field interpretation is inferred from the adjacent debug API.
- *out_parameters = {10, 1, 1};
- LOG_DEBUG(Service_AM, "called, prototype scale=10, screen ratio=1/1");
- R_SUCCEED();
-}
-
-Result IGraphicsScalingParametersFunctions::SetGraphicsScaleChangedNotificationEnabled(bool enabled) {
- LOG_DEBUG(Service_AM, "called, enabled={}", enabled);
- std::scoped_lock lk{m_applet->lock};
- m_applet->graphics_scale_changed_notification_enabled = enabled;
- R_SUCCEED();
-}
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_scaling_parameters_functions.h b/src/core/hle/service/am/service/graphics_scaling_parameters_functions.h
deleted file mode 100644
index 7c92cb53f4..0000000000
--- a/src/core/hle/service/am/service/graphics_scaling_parameters_functions.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include "core/hle/service/cmif_types.h"
-#include "core/hle/service/service.h"
-
-namespace Service::AM {
-
-struct Applet;
-
-struct GraphicsScalingParameters {
- u32 graphics_scale;
- u32 screen_ratio_numerator;
- u32 screen_ratio_denominator;
-};
-static_assert(sizeof(GraphicsScalingParameters) == 12);
-
-class IGraphicsScalingParametersFunctions final
- : public ServiceFramework<IGraphicsScalingParametersFunctions> {
-public:
- explicit IGraphicsScalingParametersFunctions(Core::System& system,
- std::shared_ptr<Applet> applet);
- ~IGraphicsScalingParametersFunctions() override;
-
-private:
- Result GetGraphicsScalingParameters(Out<GraphicsScalingParameters> out_parameters);
- Result SetGraphicsScaleChangedNotificationEnabled(bool enabled);
-
- const std::shared_ptr<Applet> m_applet;
-};
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_session.cpp b/src/core/hle/service/am/service/graphics_session.cpp
deleted file mode 100644
index 902e7f9706..0000000000
--- a/src/core/hle/service/am/service/graphics_session.cpp
+++ /dev/null
@@ -1,33 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "core/core.h"
-#include "core/hle/kernel/k_client_session.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.h"
-#include "core/hle/kernel/k_session.h"
-#include "core/hle/kernel/svc_results.h"
-#include "core/hle/service/am/service/graphics_session.h"
-#include "core/hle/service/server_manager.h"
-
-namespace Service::AM {
-Result CreateGraphicsSession(Core::System& system, HLERequestContext& ctx,
- std::shared_ptr<SessionRequestHandler> handler,
- Kernel::KClientSession** out_client) {
- auto& kernel = system.Kernel();
- Kernel::KScopedResourceReservation reservation(
- kernel, Kernel::GetCurrentProcessPointer(kernel), Kernel::LimitableResource::SessionCountMax);
- R_UNLESS(reservation.Succeeded(), Kernel::ResultLimitReached);
- auto* session = Kernel::KSession::Create(kernel);
- R_UNLESS(session != nullptr, Kernel::ResultOutOfResource);
- session->Initialize(kernel, nullptr, 0);
- reservation.Commit();
- Kernel::KSession::Register(kernel, session);
- auto& server = ctx.GetManager()->GetServerManager();
- auto manager = std::make_shared<SessionRequestManager>(kernel, server);
- manager->SetSessionHandler(std::move(handler));
- R_TRY(server.RegisterSession(&session->GetServerSession(), std::move(manager)));
- *out_client = &session->GetClientSession();
- R_SUCCEED();
-}
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_session.h b/src/core/hle/service/am/service/graphics_session.h
deleted file mode 100644
index 698b5ee8ee..0000000000
--- a/src/core/hle/service/am/service/graphics_session.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <memory>
-#include "core/hle/result.h"
-
-namespace Core { class System; }
-namespace Kernel { class KClientSession; }
-namespace Service {
-class HLERequestContext;
-class SessionRequestHandler;
-}
-namespace Service::AM {
-Result CreateGraphicsSession(Core::System& system, HLERequestContext& ctx,
- std::shared_ptr<SessionRequestHandler> handler,
- Kernel::KClientSession** out_client);
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_supervisor.cpp b/src/core/hle/service/am/service/graphics_supervisor.cpp
deleted file mode 100644
index 7759f575e7..0000000000
--- a/src/core/hle/service/am/service/graphics_supervisor.cpp
+++ /dev/null
@@ -1,1612 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <algorithm>
-#include <atomic>
-#include <bit>
-#include <array>
-#include "common/alignment.h"
-#include "core/hle/service/nvdrv/core/nvmap.h"
-#include "core/core.h"
-#include "core/core_timing.h"
-#include "core/hle/service/nvnflinger/buffer_queue_producer.h"
-#include "core/hle/service/nvnflinger/ui/graphic_buffer.h"
-#include "core/hle/kernel/k_client_session.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.h"
-#include "core/hle/kernel/k_session.h"
-#include "core/hle/kernel/k_readable_event.h"
-#include "core/hle/kernel/k_transfer_memory.h"
-#include "core/hle/kernel/k_event.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/svc_results.h"
-#include "core/hle/service/am/service/graphics_supervisor.h"
-#include "core/hle/service/am/service/graphics_session.h"
-#include "core/hle/service/am/service/gpu_session.h"
-#include "core/hle/service/am/service/graphics_supervisor_protocol.h"
-#include "core/hle/service/am/service/graphics_syncpoint_cache.h"
-#include "core/hle/service/am/service/native_image_layout.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/nvdrv/nvdrv_interface.h"
-#include "core/hle/service/nvdrv/core/container.h"
-#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
-#include "core/hle/service/server_manager.h"
-#include "core/hle/service/sm/sm.h"
-#include "core/hle/service/vi/application_display_service.h"
-#include "core/hle/service/vi/container.h"
-#include "core/hle/service/vi/manager_root_service.h"
-#include "core/hle/service/vi/vi_types.h"
-
-namespace Service::AM {
-struct NativeImageRegistry {
- struct Image {
- u32 id;
- u32 memory_id;
- std::array<u32, 16> preference;
- u64 size;
- bool window_pool{};
- };
- NativeImageRegistry(Kernel::KernelCore& kernel_, Kernel::KProcess* process_)
- : kernel{kernel_}, process{process_} {
- process->Open(kernel);
- }
- ~NativeImageRegistry() {
- if (module) {
- for (const auto& image : images) {
- ReleaseMemory(image.memory_id);
- }
- }
- if (memory_session) {
- module->GetContainer().CloseSession(*memory_session);
- }
- process->Close(kernel);
- }
- void ReleaseMemory(u32 id) {
- const auto info = module->GetContainer().GetNvMapFile().FreeHandle(id, true);
- if (info && info->can_unlock && info->address != 0) {
- process->GetPageTable().UnlockForDeviceAddressSpace(info->address, info->size);
- }
- }
- Kernel::KernelCore& kernel;
- Kernel::KProcess* process;
- std::mutex mutex;
- std::shared_ptr<Nvidia::Module> module;
- std::optional<Nvidia::NvCore::SessionId> memory_session;
- std::vector<Image> images;
-};
-using NativeImage = NativeImageRegistry::Image;
-
-
-namespace {
-
-// TIPC payloads follow a 32-bit result, so these handlers push result.raw.
-
-class ISyncpointSupervisor final : public ServiceFramework<ISyncpointSupervisor> {
-public:
- ISyncpointSupervisor(Core::System& system, std::shared_ptr<Nvidia::Module> module)
- : ServiceFramework{system, "ISyncpointSupervisor"}, m_module{std::move(module)},
- m_context{system, "NativeSyncpoint"} {
- static const FunctionInfo functions[] = {
- {0, &ISyncpointSupervisor::ExchangeClientToken, "ExchangeClientToken"},
- {1, &ISyncpointSupervisor::GetMaximumEventCount, "GetMaximumEventCount"},
- {21, &ISyncpointSupervisor::SetEventCount, "SetEventCount"},
- {22, &ISyncpointSupervisor::GetEvent, "GetEvent"},
- {201, &ISyncpointSupervisor::ArmEvent, "ArmEvent"},
- {202, &ISyncpointSupervisor::CancelEvent, "CancelEvent"},
- {103, &ISyncpointSupervisor::QueryCounter, "QueryCounter"},
- };
- RegisterHandlersTipc(functions);
- }
-
- ~ISyncpointSupervisor() override {
- if (m_poll) system.CoreTiming().UnscheduleEvent(m_poll);
- for (auto& event : m_events) m_context.CloseEvent(event.event);
- }
-
- Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) override {
- if (!ctx.IsTipc() || handlers_tipc.contains(ctx.GetCommand())) {
- return ServiceFrameworkBase::HandleSyncRequest(session, ctx);
- }
- const auto guard = LockService();
- LOG_DEBUG(Service_AM, "syncpoint unsupported command={}, words={:08x}", ctx.GetCommand(),
- fmt::join(std::span<const u32>(ctx.CommandBuffer() + 2, std::min<u32>(ctx.CommandBuffer()[1], 32)), ","));
- InvokeRequestTipc(ctx);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultNotImplemented.raw);
- return system.IsPoweredOn() ? ctx.WriteToOutgoingCommandBuffer() : ResultSuccess;
- }
-
-private:
- static constexpr u32 MaximumEventCount = 63;
-
- void ExchangeClientToken(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const Result result = packet[0] == 0x10 && packet[1] == 2
- ? ResultSuccess : Kernel::ResultInvalidCombination;
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result.raw);
- rb.Push(token);
- LOG_DEBUG(Service_AM, "syncpoint token={:#x}, result={:#x}", token, result.raw);
- }
- void GetMaximumEventCount(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const Result result = packet[0] == 0x11 && packet[1] == 0
- ? ResultSuccess : Kernel::ResultInvalidCombination;
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push(MaximumEventCount);
- LOG_DEBUG(Service_AM, "syncpoint maximum events={}", MaximumEventCount);
- }
-
- void SetEventCount(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x25 && packet[1] == 1 && packet[2] <= MaximumEventCount) {
- m_event_count = packet[2];
- result = ResultSuccess;
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- LOG_DEBUG(Service_AM, "syncpoint event count={}, result={:#x}", m_event_count, result.raw);
- }
-
- void GetEvent(HLERequestContext& ctx) {
- const auto* p = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- Kernel::KReadableEvent* readable{};
- if (p[0] == 0x26 && p[1] == 1 && p[2] < m_event_count) {
- auto& event = m_events[p[2]];
- if (!event.event) event.event = m_context.CreateEvent("SyncpointCompletion");
- result = event.event ? ResultSuccess : Kernel::ResultOutOfResource;
- if (event.event) {
- readable = &event.event->GetReadableEvent();
- readable->Open(kernel);
- }
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(readable);
- }
- void RefreshEvents() {
- auto& manager = m_module->GetContainer().GetSyncpointManager();
- for (auto& event : m_events) {
- if (!event.pending) continue;
- const auto current = manager.ReadAllocatedSyncpoint(event.id);
- if (current && event.last_observed != *current) {
- event.last_observed = *current;
- LOG_INFO(Service_AM, "Syncpoint wait progress: id={}, current={}, target={}", event.id, *current, event.threshold);
- }
- if (current && static_cast<s32>(*current - event.threshold) >= 0) {
- event.pending = false;
- event.event->Signal(kernel);
- }
- }
- }
- void ArmEvent(HLERequestContext& ctx) {
- const auto* p = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- const u32 id = ~p[3];
- if (p[0] == 0xd9 && p[1] == 5 && p[2] < m_event_count &&
- p[5] == 0 && p[6] == 0 &&
- m_module->GetContainer().GetSyncpointManager().ReadAllocatedSyncpoint(id)) {
- auto& event = m_events[p[2]];
- if (!event.event) event.event = m_context.CreateEvent("SyncpointCompletion");
- result = event.event ? ResultSuccess : Kernel::ResultOutOfResource;
- if (event.event) {
- event.event->Clear(kernel);
- event.id = id;
- event.threshold = p[4];
- event.last_observed = ~u32{0};
- LOG_INFO(Service_AM, "Arm syncpoint wait: slot={}, id={}, target={}", p[2], id, event.threshold);
- event.pending = true;
- RefreshEvents();
- if (!m_poll) {
- m_poll = Core::Timing::CreateEvent("NativeSyncpointCompletion",
- [this](s64, std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- RefreshEvents();
- return std::nullopt;
- });
- system.CoreTiming().ScheduleLoopingEvent(std::chrono::milliseconds{1},
- std::chrono::milliseconds{1}, m_poll);
- }
- }
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- LOG_DEBUG(Service_AM, "syncpoint arm event={}, id={}, threshold={}, result={:#x}",
- p[2], id, p[4], result.raw);
- }
- void CancelEvent(HLERequestContext& ctx) {
- const auto* p = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (p[0] == 0xda && p[1] == 1 && p[2] < m_event_count) {
- auto& event = m_events[p[2]];
- event.pending = false;
- // The native SDK waits for this event after cancelling a timed wait
- // before it releases the event slot. Cancellation acknowledges that
- // the wait is retired; it does not advance the syncpoint counter.
- if (event.event) event.event->Signal(kernel);
- result = ResultSuccess;
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
-
- void QueryCounter(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- u64 value{};
- if (packet[0] == 0x77 && packet[1] == 1) {
- const u32 id = ~packet[2];
- auto current = m_module->GetContainer().GetSyncpointManager().ReadAllocatedSyncpoint(id);
- result = current ? ResultSuccess : Kernel::ResultNotFound;
- value = current.value_or(0);
- LOG_DEBUG(Service_AM, "query syncpoint id={}, value={}, result={:#x}", id, value, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 5};
- rb.Push(result.raw);
- rb.Push(value);
- rb.Push<u32>(0); // Existing NVDRV counters use 32-bit modular comparisons.
- }
-
- std::shared_ptr<Nvidia::Module> m_module;
- u32 m_event_count{};
- struct CompletionEvent {
- Kernel::KEvent* event{};
- u32 id{};
- u32 threshold{};
- u32 last_observed = ~u32{0};
- bool pending{};
- };
- KernelHelpers::ServiceContext m_context;
- std::array<CompletionEvent, MaximumEventCount> m_events{};
- std::shared_ptr<Core::Timing::EventType> m_poll;
-};
-
-class IVi2Session final : public ServiceFramework<IVi2Session> {
- struct ClientState {
- u64 token{};
- u32 slots{};
- std::optional<u64> display;
- std::optional<u64> layer;
- u64 available{0x7fff};
- u32 retire_notification{};
- u64 output_encoding{0x14};
- u32 available_notification{};
- std::shared_ptr<android::BufferQueueProducer> producer;
- std::array<std::optional<s32>, 15> queued{};
- std::optional<size_t> player_display;
- };
-
-public:
- explicit IVi2Session(Core::System& system, u64 aruid, std::shared_ptr<NativeImageRegistry> images) : ServiceFramework{system, "IVi2Session"}, m_images{std::move(images)}, m_aruid{aruid}, m_context{system, "Vi2Session"} {
- static const FunctionInfo functions[] = {
- {1, &IVi2Session::GetSessionLimit, "GetNotificationLimit"},
- {11, &IVi2Session::GetNotificationEvent, "GetNotificationEvent"},
- {13, &IVi2Session::ReleaseNotificationEvent, "ReleaseNotificationEvent"},
- {21, &IVi2Session::GetNotifications, "GetNotifications"},
- {31, &IVi2Session::DuplicateVsyncEvent, "GetDisplayEvent"},
- {32, &IVi2Session::DuplicateDisplayEvent, "DuplicateDisplayEvent"},
- {3, &IVi2Session::GetSessionLimit, "GetSessionLimit"},
- {5, &IVi2Session::GetSessionLimit, "GetRequestGroupLimit"},
- {51, &IVi2Session::ConfigureRequestGroups, "ConfigureRequestGroups"},
- {101, &IVi2Session::OpenDisplay, "OpenDisplay"},
- {102, &IVi2Session::CloseDisplay, "CloseDisplay"},
- {111, &IVi2Session::OpenEndpoint, "OpenEndpoint"},
- {112, &IVi2Session::CloseEndpoint, "CloseEndpoint"},
- {201, &IVi2Session::RegisterClientState, "RegisterClientState"},
- {202, &IVi2Session::UnregisterClientState, "UnregisterClientState"},
- {212, &IVi2Session::GetClientAvailability, "GetClientAvailability"},
- {229, &IVi2Session::PresentClientBuffer, "PresentClientBuffer"},
- {228, &IVi2Session::CancelClientBuffer, "CancelClientBuffer"},
- {351, &IVi2Session::SetClientOutputEncoding, "SetClientOutputEncoding"},
- {261, &IVi2Session::SetDisplayCapability, "SetDisplayCapability261"},
- {265, &IVi2Session::SetDisplayCapability, "SetDisplayCapability265"},
- {267, &IVi2Session::SetDisplayCapability, "SetDisplayCapability267"},
- {271, &IVi2Session::SetDisplayCapability, "SetDisplayCapability271"},
- {251, &IVi2Session::BindClientDisplay, "BindClientDisplay"},
- {252, &IVi2Session::UnbindClientDisplay, "UnbindClientDisplay"},
- };
- RegisterHandlersTipc(functions);
- }
-
- ~IVi2Session() override {
- if (m_release_poll) system.CoreTiming().UnscheduleEvent(m_release_poll);
- if (m_display_service) {
- for (auto& state : m_client_states) {
- if (state.layer) m_display_service->GetContainer()->DestroyManagedLayer(*state.layer);
- }
- }
- if (m_default_display) { m_display_service->CloseDisplay(*m_default_display); }
- for (auto* event : m_display_change_events) m_context.CloseEvent(event);
- m_context.CloseEvent(m_event);
- }
-
- Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) override {
- if (!ctx.IsTipc() || handlers_tipc.contains(ctx.GetCommand())) {
- return ServiceFrameworkBase::HandleSyncRequest(session, ctx);
- }
- const auto guard = LockService();
- LOG_DEBUG(Service_AM, "VI2 unsupported command={}, words={:08x}", ctx.GetCommand(),
- fmt::join(std::span<const u32>(ctx.CommandBuffer() + 2, std::min<u32>(ctx.CommandBuffer()[1], 32)), ","));
- InvokeRequestTipc(ctx);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultNotImplemented.raw);
- return system.IsPoweredOn() ? ctx.WriteToOutgoingCommandBuffer() : ResultSuccess;
- }
-private:
- void SetDisplayCapability(HLERequestContext& ctx) {
- const auto* p = ctx.CommandBuffer();
- const u64 name = u64{p[2]} | (u64{p[3]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (p[0] == ctx.GetCommand() + 16 && p[1] == 3 && p[4] <= 1) {
- result = name == 0x00746c7561666564ULL && m_default_display
- ? ResultSuccess : Kernel::ResultNotFound;
- if (result.IsSuccess()) {
- // Per-client display mode capabilities do not change the host video mode.
- m_display_capabilities[(ctx.GetCommand() - 261) / 2] = p[4] != 0;
- }
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void DuplicateVsyncEvent(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- Kernel::KReadableEvent* readable{};
- if (packet[0] == 0x2f && packet[1] == 1 && packet[2] < 5) {
- result = m_display_service && m_default_display
- ? ResultSuccess : Kernel::ResultInvalidState;
- if (result.IsSuccess() && !m_vsync_event) {
- result = m_display_service->GetDisplayVsyncEvent(&m_vsync_event, *m_default_display);
- }
- if (result.IsSuccess()) {
- if (packet[2] == 0) {
- readable = m_vsync_event;
- } else {
- // Fixed host display properties have no change to report until changed.
- auto*& event = m_display_change_events[packet[2] - 1];
- if (!event) event = m_context.CreateEvent("DisplayPropertyChange");
- if (event) readable = &event->GetReadableEvent();
- else result = Kernel::ResultOutOfResource;
- }
- if (readable) readable->Open(kernel);
- }
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(readable);
- LOG_DEBUG(Service_AM, "VI2 vsync event result={:#x}", result.raw);
- }
- void DuplicateDisplayEvent(HLERequestContext& ctx) {
- const auto* p = ctx.CommandBuffer();
- auto source = ctx.GetObjectFromHandle<Kernel::KReadableEvent>(ctx.GetCopyHandle(0));
- const Result result = p[0] == 0x30 && p[1] == 0x80000001 && p[4] <= 1 && source.IsNotNull()
- ? ResultSuccess : Kernel::ResultInvalidCombination;
- Kernel::KReadableEvent* readable{};
- if (result.IsSuccess()) {
- readable = source.GetPointerUnsafe();
- readable->Open(kernel);
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(readable);
- }
- static std::optional<size_t> GetPlayerDisplayIndex(u64 name) {
- if ((name & 0xffffffffffffULL) != 0x726579616c70ULL || (name >> 56) != 0) {
- return std::nullopt;
- }
- const u32 player = (name >> 48) & 0xff;
- if (player < '1' || player > '3') return std::nullopt;
- return player - '1';
- }
- Result OpenDefaultDisplay(u64 name, u32 flags) {
- if (const auto player = GetPlayerDisplayIndex(name)) {
- R_UNLESS(flags < m_notifications.size() * 32, Kernel::ResultInvalidCombination);
- R_UNLESS(m_player_display_references[*player] < 1024, Kernel::ResultOutOfResource);
- // GameShare's detached player displays retain their own lifetime;
- // they do not target the host's default display compositor.
- m_player_display_notifications[*player] = flags;
- ++m_player_display_references[*player];
- R_SUCCEED();
- }
- // The native display token is an eight-byte name; command 101 returns
- // only a result. Retain the real VI display ID for later operations.
- R_UNLESS(name == 0x00746c7561666564ULL, Kernel::ResultNotFound);
- R_UNLESS(flags == 1, Kernel::ResultNotImplemented);
- R_UNLESS(m_display_references < 1024, Kernel::ResultOutOfResource);
- if (!m_display_service) {
- const auto root = system.ServiceManager().GetService<VI::IManagerRootService>("vi:m", true);
- R_UNLESS(root, Kernel::ResultInvalidState);
- R_TRY(root->GetDisplayService(&m_display_service, VI::Policy::Compositor));
- }
- if (!m_default_display) {
- u64 id{};
- R_TRY(m_display_service->OpenDefaultDisplay(&id));
- m_default_display = id;
- }
- m_display_notification = flags;
- ++m_display_references;
- R_SUCCEED();
- }
- void OpenDisplay(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 name = u64{packet[2]} | (u64{packet[3]} << 32);
- const auto result = packet[0] == 0x75 && packet[1] == 3
- ? OpenDefaultDisplay(name, packet[4]) : Kernel::ResultInvalidCombination;
- LOG_DEBUG(Service_AM, "VI2 open display name={:#x}, flags={:#x}, references={}, result={:#x}",
- name, packet[4], m_display_references, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void CloseDisplay(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- const u64 name = u64{packet[2]} | (u64{packet[3]} << 32);
- if (packet[0] == 0x76 && packet[1] == 2 && GetPlayerDisplayIndex(name)) {
- const auto player = *GetPlayerDisplayIndex(name);
- result = Kernel::ResultNotFound;
- if (m_player_display_references[player]) {
- if (--m_player_display_references[player] == 0) {
- const auto notification = m_player_display_notifications[player];
- m_notifications[notification / 32] |= 1U << (notification % 32);
- if (m_event) m_event->Signal(kernel);
- }
- result = ResultSuccess;
- }
- } else if (packet[0] == 0x76 && packet[1] == 2 && name == 0x00746c7561666564ULL) {
- result = Kernel::ResultNotFound;
- if (m_default_display && m_display_references) {
- result = ResultSuccess;
- if (m_display_references == 1) {
- result = m_display_service->CloseDisplay(*m_default_display);
- if (result.IsSuccess()) { m_default_display.reset(); }
- }
- if (result.IsSuccess()) {
- --m_display_references;
- if (!m_display_references) {
- m_notifications[m_display_notification / 32] |= 1U << (m_display_notification % 32);
- if (m_event) m_event->Signal(kernel);
- LOG_DEBUG(Service_AM, "VI2 display retired notification={}", m_display_notification);
- }
- }
- }
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void RegisterClientState(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- const u32 first = packet[4];
- const u32 second = packet[5];
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0xd9 && packet[1] == 4 && token != 0 &&
- first < 32 && second < 32 && first != second) {
- const u32 slots = (1U << first) | (1U << second);
- const auto existing = std::ranges::find(m_client_states, token, &ClientState::token);
- const auto free = std::ranges::find(m_client_states, u64{0}, &ClientState::token);
- result = Kernel::ResultInvalidState;
- if (existing == m_client_states.end() && !(m_client_slots & slots)) {
- result = Kernel::ResultOutOfResource;
- if (free != m_client_states.end()) {
- // The SDK sends its object address as an opaque identity, not a
- // service-accessible buffer. Keep the associated slots session-local.
- *free = {token, slots};
- free->retire_notification = first;
- free->available_notification = second;
- m_client_slots |= slots;
- result = ResultSuccess;
- }
- }
- }
- LOG_DEBUG(Service_AM, "VI2 register client state token={:#x}, slots={}/{}, result={:#x}",
- token, first, second, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void UnregisterClientState(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0xda && packet[1] == 2 && token != 0) {
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (state != m_client_states.end()) {
- if (m_default_endpoint == token) { m_default_endpoint.reset(); }
- if (state->layer) m_display_service->GetContainer()->DestroyManagedLayer(*state->layer);
- m_notifications[state->retire_notification / 32] |= 1U << (state->retire_notification % 32);
- if (m_event) m_event->Signal(kernel);
- LOG_DEBUG(Service_AM, "VI2 client retired token={:#x}, notification={}", token, state->retire_notification);
- m_client_slots &= ~state->slots;
- *state = {};
- result = ResultSuccess;
- }
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void GetClientAvailability(HLERequestContext& ctx) {
- RefreshReleasedBuffers();
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- u64 id{};
- if (packet[0] == 0xe4 && packet[1] == 2 && token) {
- auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (state != m_client_states.end() && m_default_display) {
- result = ResultSuccess;
- if (state->player_display) {
- id = 0;
- } else if (!state->layer) {
- result = m_display_service->GetContainer()->CreateManagedLayer(&id, *m_default_display, m_aruid);
- if (result.IsSuccess()) state->layer = id;
- } else {
- id = *state->layer;
- }
- }
- }
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- const u64 available = result.IsSuccess() ? state->available : 0;
- LOG_DEBUG(Service_AM, "VI2 client availability token={:#x}, layer={}, mask={:#x}, result={:#x}", token, id, available, result.raw);
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result.raw);
- rb.Push(available);
- }
- void CancelClientBuffer(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- const u32 slot = GraphicsSupervisorProtocol::DecodeBufferSlot(packet[4]);
- Result result = Kernel::ResultInvalidCombination;
- u64 available{};
- if (packet[0] == 0xf4 && packet[1] == 19 && slot < 15) {
- auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (token && state != m_client_states.end()) {
- // Unlike present (229), cancel has no image or input GPU fence.
- state->available |= u64{1} << slot;
- available = state->available;
- result = ResultSuccess;
- }
- }
- LOG_DEBUG(Service_AM, "VI2 cancel buffer token={:#x}, slot={}, mask={:#x}, result={:#x}", token, slot, available, result.raw);
- IPC::ResponseBuilder rb{ctx, 8};
- rb.Push(result.raw);
- rb.Push(available);
- for (u32 i = 0; i < 4; ++i) rb.Push<u32>(0);
- }
- void RefreshReleasedBuffers() {
- for (auto& state : m_client_states) {
- if (!state.producer || !m_images->module) continue;
- bool changed{};
- for (size_t slot = 0; slot < state.queued.size(); ++slot) {
- if (!state.queued[slot]) continue;
- const auto fence = state.producer->GetReleasedBufferFence(*state.queued[slot]);
- if (!fence) continue;
- bool complete = true;
- for (u32 i = 0; i < fence->num_fences; ++i) {
- const auto& point = fence->fences[i];
- if (point.id != ~u32{0}) {
- const auto counter = m_images->module->GetContainer().GetSyncpointManager().ReadAllocatedSyncpoint(point.id);
- if (!counter || static_cast<s32>(*counter - point.value) < 0) {
- complete = false;
- }
- }
- }
- if (!complete) continue;
- state.queued[slot].reset();
- state.available |= u64{1} << slot;
- LOG_DEBUG(Service_AM, "Native display buffer retired: slot={}, mask={:#x}", slot, state.available);
- changed = true;
- }
- if (changed) {
- m_notifications[state.available_notification / 32] |= 1U << (state.available_notification % 32);
- if (m_event) m_event->Signal(kernel);
- }
- }
- }
- Result QueueNativeImage(ClientState& state, const u32* packet) {
- const u32 slot = GraphicsSupervisorProtocol::DecodeBufferSlot(packet[4]);
- R_UNLESS(!state.player_display, Kernel::ResultNotImplemented);
- R_UNLESS(state.layer && state.display && slot < 15 && !state.queued[slot], Kernel::ResultInvalidState);
- const std::scoped_lock images_lock{m_images->mutex};
- const auto image = std::ranges::find(m_images->images, packet[5], &NativeImage::id);
- R_UNLESS(image != m_images->images.end() && image->window_pool && m_images->module, Kernel::ResultNotFound);
- // The observed presentation is a four-byte color image with the
- // backend's 16-GOB block height and no byte offset within its pool.
- R_UNLESS(packet[6] == 0 && packet[7] == image->preference[2] && packet[8] == 3 &&
- image->preference[4] == 7 &&
- (state.output_encoding == 0x14 || state.output_encoding == 0x5),
- Kernel::ResultNotImplemented);
- const u32 fence_id = ~packet[22];
- R_UNLESS(packet[23] == 0 && packet[25] == 0 &&
- (fence_id == ~u32{0} || m_images->module->GetContainer().GetSyncpointManager().IsSyncpointAllocated(fence_id)),
- Kernel::ResultInvalidCombination);
- if (!state.producer) {
- R_TRY(m_display_service->GetContainer()->GetLayerProducerHandle(&state.producer, *state.layer));
- android::QueueBufferOutput output{};
- R_UNLESS(state.producer->Connect({}, android::NativeWindowApi::Egl, false, &output) == android::Status::NoError,
- Kernel::ResultInvalidState);
- R_UNLESS(state.producer->SetBufferCount(16) == android::Status::NoError, Kernel::ResultInvalidState);
- s32 binder{};
- R_TRY(m_display_service->GetContainer()->OpenLayer(&binder, *state.layer, m_aruid));
- R_TRY(m_display_service->GetContainer()->SetLayerVisibility(*state.layer, true));
- }
- auto native = std::make_shared<android::NvGraphicBuffer>();
- native->width = static_cast<s32>((image->preference[2] & 0xffffU) + 1);
- native->height = static_cast<s32>((image->preference[2] >> 16) + 1);
- native->stride = static_cast<s32>(image->preference[5] * 16);
- native->format = android::PixelFormat::Rgba8888;
- native->external_format = native->format;
- native->buffer_id = image->memory_id;
- auto buffer = std::make_shared<android::GraphicBuffer>(m_images->module->GetContainer().GetNvMapFile(), native);
- s32 queue_slot{};
- R_UNLESS(state.producer->AttachBuffer(&queue_slot, buffer) == android::Status::NoError, Kernel::ResultOutOfResource);
- android::QueueBufferInput input{};
- android::QueueBufferOutput output{};
- input.crop = {0, 0, native->width, native->height};
- input.swap_interval = 1;
- input.fence = android::Fence::NoFence();
- if (fence_id != ~u32{0}) {
- input.fence.num_fences = 1;
- input.fence.fences[0] = {static_cast<s32>(fence_id), packet[24]};
- }
- if (state.producer->QueueBuffer(queue_slot, input, &output) != android::Status::NoError) {
- state.producer->CancelBuffer(queue_slot, input.fence);
- return Kernel::ResultInvalidState;
- }
- state.queued[slot] = queue_slot;
- state.available &= ~(u64{1} << slot);
- if (!m_release_poll) {
- m_release_poll = Core::Timing::CreateEvent("NativeViBufferRelease", [this](s64, std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- RefreshReleasedBuffers();
- return std::nullopt;
- });
- system.CoreTiming().ScheduleLoopingEvent(std::chrono::milliseconds{1}, std::chrono::milliseconds{1}, m_release_poll);
- }
- LOG_INFO(Service_AM, "Native image queued for display: image={}, slot={}, fence={}/{}, dimensions={}x{}",
- image->id, slot, fence_id, packet[24], native->width, native->height);
- R_SUCCEED();
- }
- void PresentClientBuffer(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- RefreshReleasedBuffers();
- Result result = Kernel::ResultInvalidCombination;
- u64 available{};
- if (packet[0] == 0xf5 && packet[1] == 24) {
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (token && state != m_client_states.end()) {
- result = QueueNativeImage(*state, packet);
- available = state->available;
- }
- }
- LOG_DEBUG(Service_AM, "VI2 present token={:#x}, image={}, slot={}, mask={:#x}, result={:#x}", token, packet[5], packet[4], available, result.raw);
- IPC::ResponseBuilder rb{ctx, 8};
- rb.Push(result.raw);
- rb.Push(available);
- for (u32 i = 0; i < 4; ++i) rb.Push<u32>(0);
- }
- void SetClientOutputEncoding(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- const u64 encoding = u64{packet[4]} | (u64{packet[5]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x16f && packet[1] == 4) {
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (token && state != m_client_states.end()) {
- result = Kernel::ResultNotImplemented;
- // Only the SDK's observed default output encoding is supported.
- if (encoding == 0x14 || encoding == 0x5) {
- state->output_encoding = encoding;
- result = ResultSuccess;
- }
- }
- }
- LOG_DEBUG(Service_AM, "VI2 output encoding token={:#x}, encoding={:#x}, result={:#x}", token, encoding, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void BindClientDisplay(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- const u64 name = u64{packet[4]} | (u64{packet[5]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x10b && packet[1] == 4) {
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (token && state != m_client_states.end() && GetPlayerDisplayIndex(name)) {
- const auto player = *GetPlayerDisplayIndex(name);
- result = Kernel::ResultInvalidState;
- if (m_player_display_references[player] && !state->display) {
- result = ResultSuccess;
- if (state->layer) {
- result = m_display_service->GetContainer()->DestroyManagedLayer(*state->layer);
- }
- if (result.IsSuccess()) {
- state->layer.reset();
- state->display = name;
- state->player_display = player;
- }
- }
- } else if (token && state != m_client_states.end() && name == 0x00746c7561666564ULL &&
- m_default_display && m_display_references) {
- result = Kernel::ResultInvalidState;
- if (!state->display) {
- state->display = m_default_display;
- result = ResultSuccess;
- }
- }
- }
- LOG_DEBUG(Service_AM, "VI2 bind client token={:#x}, display={:#x}, result={:#x}",
- token, name, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void UnbindClientDisplay(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 token = u64{packet[2]} | (u64{packet[3]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x10c && packet[1] == 2) {
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (token && state != m_client_states.end() && state->display) {
- state->display.reset();
- state->player_display.reset();
- result = ResultSuccess;
- }
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void OpenEndpoint(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 name = u64{packet[2]} | (u64{packet[3]} << 32);
- const u64 display_name = u64{packet[4]} | (u64{packet[5]} << 32);
- const u64 token = u64{packet[6]} | (u64{packet[7]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x7f && packet[1] == 6) {
- const auto state = std::ranges::find(m_client_states, token, &ClientState::token);
- result = Kernel::ResultNotFound;
- if (token && state != m_client_states.end() && state->display &&
- m_default_display == state->display && name == 0x00746c7561666564ULL &&
- display_name == name) {
- result = Kernel::ResultInvalidState;
- if (!m_default_endpoint) {
- m_default_endpoint = token;
- result = ResultSuccess;
- }
- }
- }
- LOG_DEBUG(Service_AM, "VI2 open endpoint name={:#x}, display={:#x}, client={:#x}, result={:#x}",
- name, display_name, token, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void CloseEndpoint(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 name = u64{packet[2]} | (u64{packet[3]} << 32);
- const u64 display_name = u64{packet[4]} | (u64{packet[5]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x80 && packet[1] == 4 && name == 0x00746c7561666564ULL &&
- display_name == name) {
- result = Kernel::ResultNotFound;
- if (m_default_endpoint) {
- m_default_endpoint.reset();
- result = ResultSuccess;
- }
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void ConfigureRequestGroups(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x43 && packet[1] == 1 && packet[2] < 8) {
- m_request_group_limit = packet[2];
- m_request_groups_initialized = true;
- result = ResultSuccess;
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void GetSessionLimit(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const Result result = packet[0] == 16 + ctx.GetCommand() && packet[1] == 0
- ? ResultSuccess : Kernel::ResultInvalidCombination;
- // The SDK converts this inclusive upper group index into 32 client slots.
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push<u32>(ctx.GetCommand() == 5 ? 7 : 0);
- }
-
- void GetNotifications(HLERequestContext& ctx) {
- Result result = Kernel::ResultInvalidSize;
- if (ctx.GetWriteBufferSize() >= sizeof(m_notifications)) {
- ctx.WriteBuffer(m_notifications);
- LOG_DEBUG(Service_AM, "VI2 notifications={:08x}", fmt::join(m_notifications, ","));
- m_notifications.fill(0);
- if (m_event) m_event->Clear(kernel);
- result = ResultSuccess;
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void ReleaseNotificationEvent(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const auto result = packet[0] == 0x1d && packet[1] == 1 && packet[2] == 0
- ? ResultSuccess : Kernel::ResultInvalidCombination;
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- }
- void GetNotificationEvent(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- Kernel::KReadableEvent* readable{};
- if (packet[0] == 0x1b && packet[1] == 1 && packet[2] == 0) {
- if (!m_event) {
- m_event = m_context.CreateEvent("Vi2Notification");
- }
- result = m_event ? ResultSuccess : Kernel::ResultOutOfResource;
- if (m_event) {
- if (std::ranges::any_of(m_notifications, [](u32 value) { return value != 0; })) m_event->Signal(kernel);
- readable = &m_event->GetReadableEvent();
- readable->Open(kernel);
- }
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(readable);
- }
-
- std::shared_ptr<NativeImageRegistry> m_images;
- std::shared_ptr<Core::Timing::EventType> m_release_poll;
- std::array<ClientState, 16> m_client_states{};
- u32 m_client_slots{};
- std::shared_ptr<VI::IApplicationDisplayService> m_display_service;
- Kernel::KReadableEvent* m_vsync_event{};
- std::array<Kernel::KEvent*, 4> m_display_change_events{};
- std::optional<u64> m_default_display;
- std::array<bool, 6> m_display_capabilities{};
- u32 m_display_references{};
- u32 m_display_notification{};
- std::array<u32, 3> m_player_display_references{};
- std::array<u32, 3> m_player_display_notifications{};
- bool m_request_groups_initialized{};
- u32 m_request_group_limit{};
- std::optional<u64> m_default_endpoint;
- std::array<u32, 32> m_notifications{};
- const u64 m_aruid;
- KernelHelpers::ServiceContext m_context;
- Kernel::KEvent* m_event{};
-};
-
-} // namespace
-
-
-IGraphicsSupervisor::IGraphicsSupervisor(Core::System& system, Kernel::KProcess* process, u64 aruid)
- : ServiceFramework{system, "IGraphicsSupervisor"}, m_context{system, "GraphicsSupervisor"},
- m_syncpoint_cache_event{m_context}, m_process{process}, m_aruid{aruid} {
- m_process->Open(kernel);
- m_image_registry = std::make_shared<NativeImageRegistry>(kernel, m_process);
- static const FunctionInfo functions[] = {
- {4, &IGraphicsSupervisor::Initialize, "Initialize"},
- {11, &IGraphicsSupervisor::BindProcess, "BindProcess"},
- {101, &IGraphicsSupervisor::CompleteBootstrap, "CompleteBootstrap"},
- {115, &IGraphicsSupervisor::ConfigureNativeMemory, "ConfigureNativeMemory"},
- {111, &IGraphicsSupervisor::CreateNativeMemory, "CreateNativeMemory"},
- {112, &IGraphicsSupervisor::DestroyNativeMemory, "DestroyNativeMemory"},
- {114, &IGraphicsSupervisor::BindNativeMemory, "BindNativeMemory"},
- {201, &IGraphicsSupervisor::InitializeSyncpointContext, "InitializeSyncpointContext"},
- {202, &IGraphicsSupervisor::GetSyncpointSession, "GetSyncpointSession"},
- {204, &IGraphicsSupervisor::BindSyncpointMemory, "BindSyncpointMemory"},
- {301, &IGraphicsSupervisor::InitializeDisplayContext, "InitializeDisplayContext"},
- {305, &IGraphicsSupervisor::OpenDisplaySession, "OpenDisplaySession"},
- {314, &IGraphicsSupervisor::ConfigureNativeWindowImagePool, "DestroyNativeWindowAliasImagePool"},
- {315, &IGraphicsSupervisor::ConfigureNativeWindowImagePool, "CreateNativeWindowAliasImagePool"},
- {401, &IGraphicsSupervisor::InitializeGpuContext, "InitializeGpuContext"},
- {402, &IGraphicsSupervisor::InitializeGpuContext, "ActivateGpuContext"},
- {423, &IGraphicsSupervisor::BindNativeGpuMemory, "BindNativeGpuMemory"},
- {429, &IGraphicsSupervisor::CreateNativeImage, "CreateNativeImage"},
- {430, &IGraphicsSupervisor::DestroyNativeImage, "DestroyNativeImage"},
- {434, &IGraphicsSupervisor::RegisterGpuAddressSpace, "RegisterGpuAddressSpace"},
- {497, &IGraphicsSupervisor::OpenGpuSession, "OpenGpuSession"},
- {1101, &IGraphicsSupervisor::InitializeFrameContext, "InitializeFrameContext"},
- {1102, &IGraphicsSupervisor::InitializeFrameContext, "ActivateFrameContext"},
- {1402, &IGraphicsSupervisor::GetNvidiaDriver, "GetNvidiaDriver"},
- {1501, &IGraphicsSupervisor::InitializeImageContext, "InitializeImageContext1501"},
- {435, &IGraphicsSupervisor::CalculateImageRequirements, "CalculateNativeImageSize"},
- {1510, &IGraphicsSupervisor::CalculateImageRequirements, "CalculateImageRequirements"},
- {1502, &IGraphicsSupervisor::InitializeImageContext, "InitializeImageContext1502"},
- };
- RegisterHandlersTipc(functions);
-}
-
-IGraphicsSupervisor::~IGraphicsSupervisor() {
- if (m_cache_poll) {
- system.CoreTiming().UnscheduleEvent(m_cache_poll);
- }
- if (m_syncpoint_rw) {
- m_syncpoint_rw->Close(kernel);
- m_syncpoint_ro->Close(kernel);
- }
- if (m_nv_module) {
- auto& nvmap = m_nv_module->GetContainer().GetNvMapFile();
- for (const auto id : m_native_memories) {
- if (const auto info = nvmap.FreeHandle(id, false); info && info->can_unlock && info->address != 0) {
- m_process->GetPageTable().UnlockForDeviceAddressSpace(info->address, info->size);
- }
- }
- if (m_native_memory_session) {
- m_nv_module->GetContainer().CloseSession(Nvidia::NvCore::SessionId{*m_native_memory_session});
- }
- }
- m_context.CloseEvent(m_syncpoint_request_event);
- m_process->Close(kernel);
-}
-
-Result IGraphicsSupervisor::HandleSyncRequest(Kernel::KServerSession& session,
- HLERequestContext& ctx) {
- if (!ctx.IsTipc() || handlers_tipc.contains(ctx.GetCommand())) {
- return ServiceFrameworkBase::HandleSyncRequest(session, ctx);
- }
- const auto guard = LockService();
- InvokeRequestTipc(ctx);
- // Unsupported TIPC must return an error instead of leaving request data as a reply.
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultNotImplemented.raw);
- return system.IsPoweredOn() ? ctx.WriteToOutgoingCommandBuffer() : ResultSuccess;
-}
-
-void IGraphicsSupervisor::Initialize(HLERequestContext& ctx) {
- const auto request = GraphicsSupervisorProtocol::DecodeBootstrap(
- std::span<const u32>{ctx.CommandBuffer(), IPC::COMMAND_BUFFER_LENGTH});
- Result result = Kernel::ResultInvalidCombination;
- if (request) {
- auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(request->process_handle);
- const bool empty_remote_memory = std::ranges::all_of(
- request->parameters, [](u64 value) { return value == 0; });
- if (process.IsNull() || process.GetPointerUnsafe() != m_process) {
- result = Kernel::ResultInvalidHandle;
- } else if (m_phase != Phase::Created) {
- result = Kernel::ResultInvalidState;
- } else if (request->applet_resource_user_id != m_aruid) {
- result = Kernel::ResultInvalidArgument;
- } else if ((request->flags != 0x8000000000000001ULL && request->flags != 0x8000000000000005ULL && request->flags != 0x8000000000000006ULL && request->flags != 0x8000000000000007ULL) || !empty_remote_memory) {
- result = Kernel::ResultNotImplemented;
- } else {
- m_phase = Phase::Initialized;
- result = ResultSuccess;
- }
- LOG_DEBUG(Service_AM, "graphics bootstrap aruid={:#x}, flags={:#x}, result={:#x}",
- request->applet_resource_user_id, request->flags, result.raw);
- }
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::BindProcess(HLERequestContext& ctx) {
- Result result = Kernel::ResultInvalidCombination;
- const auto* packet = ctx.CommandBuffer();
- if (packet[0] == 0x1b && packet[1] == 0x80000000 && packet[2] == 2) {
- auto process = ctx.GetObjectFromHandle<Kernel::KProcess>(ctx.GetCopyHandle(0));
- if (process.IsNull() || process.GetPointerUnsafe() != m_process) {
- result = Kernel::ResultInvalidHandle;
- } else if (m_phase != Phase::Initialized) {
- result = Kernel::ResultInvalidState;
- } else {
- m_phase = Phase::ProcessBound;
- result = ResultSuccess;
- }
- }
- LOG_DEBUG(Service_AM, "graphics process binding result={:#x}", result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::CompleteBootstrap(HLERequestContext& ctx) {
- Result result = Kernel::ResultInvalidCombination;
- const auto* packet = ctx.CommandBuffer();
- if (packet[0] == 0x75 && packet[1] == 0) {
- if (m_phase != Phase::ProcessBound) {
- result = Kernel::ResultInvalidState;
- } else {
- m_phase = Phase::Ready;
- result = ResultSuccess;
- }
- }
- LOG_DEBUG(Service_AM, "graphics bootstrap completion result={:#x}", result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::InitializeImageContext(HLERequestContext& ctx) {
- Result result = Kernel::ResultInvalidCombination;
- const auto* packet = ctx.CommandBuffer();
- if (packet[0] == 16 + ctx.GetCommand() && packet[1] == 0) {
- if (m_phase != Phase::Ready) {
- result = Kernel::ResultInvalidState;
- } else if (ctx.GetCommand() == 1501) {
- m_image_context_initialized = true;
- result = ResultSuccess;
- } else if (m_image_context_initialized) {
- m_image_formats_initialized = true;
- result = ResultSuccess;
- } else {
- result = Kernel::ResultInvalidState;
- }
- }
- LOG_DEBUG(Service_AM, "empty image context command={}, result={:#x}",
- ctx.GetCommand(), result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::OpenGpuSession(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- Kernel::KClientSession* client{};
- const u64 flags = u64{packet[2]} | (u64{packet[3]} << 32);
- if (packet[0] == 0x201 && packet[1] == 2 && (flags == 3 || flags == 4)) {
- if (m_phase != Phase::Ready || !m_nv_module) {
- result = Kernel::ResultInvalidState;
- } else {
- auto handler = std::make_shared<IGpuSession>(system, m_nv_module, m_process, flags == 3);
- result = CreateGraphicsSession(system, ctx, handler, &client);
- if (result.IsSuccess()) {
- if (flags == 3) { m_image_formats_initialized = true; }
- std::erase_if(m_gpu_sessions, [](const auto& item) { return item.expired(); });
- m_gpu_sessions.emplace_back(handler);
- }
- }
- }
- LOG_DEBUG(Service_AM, "GPU control session flags={:#x}, result={:#x}", flags, result.raw);
- // This SDK reads the move-handle slot before the result, including on failure.
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(client);
-}
-
-void IGraphicsSupervisor::RegisterGpuAddressSpace(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x1c2 && packet[1] == 1) {
- result = m_gpu_context_ready ? Kernel::ResultNotFound : Kernel::ResultInvalidState;
- if (m_gpu_context_ready) {
- for (const auto& item : m_gpu_sessions) {
- if (auto handler = item.lock()) {
- result = handler->RegisterAddressSpace(packet[2]);
- if (result.IsSuccess()) {
- break;
- }
- }
- }
- }
- }
- LOG_DEBUG(Service_AM, "register GPU address space id={}, result={:#x}", packet[2], result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::InitializeDisplayContext(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x13d && packet[1] == 0) {
- result = m_phase == Phase::Ready ? ResultSuccess : Kernel::ResultInvalidState;
- if (result.IsSuccess()) {
- m_display_context_initialized = true;
- }
- }
- LOG_DEBUG(Service_AM, "display context initialization result={:#x}", result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::OpenDisplaySession(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Kernel::KClientSession* client{};
- const u64 flags = u64{packet[2]} | (u64{packet[3]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x141 && packet[1] == 2 && (flags == 0x300010000ULL || flags == 0x300020000ULL)) {
- result = m_display_context_initialized ? ResultSuccess : Kernel::ResultInvalidState;
- if (result.IsSuccess()) {
- result = CreateGraphicsSession(system, ctx, std::make_shared<IVi2Session>(system, m_aruid, m_image_registry),
- &client);
- }
- }
- LOG_DEBUG(Service_AM, "VI2 session flags={:#x}, result={:#x}", flags, result.raw);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(result.raw);
- ctx.AddMoveObject(client);
-}
-
-void IGraphicsSupervisor::InitializeGpuContext(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 16 + ctx.GetCommand() && packet[1] == 0) {
- if (m_phase != Phase::Ready) {
- result = Kernel::ResultInvalidState;
- } else if (ctx.GetCommand() == 401) {
- m_gpu_context_initialized = true;
- result = ResultSuccess;
- } else if (m_gpu_context_initialized) {
- m_gpu_context_ready = true;
- result = ResultSuccess;
- } else {
- result = Kernel::ResultInvalidState;
- }
- }
- LOG_DEBUG(Service_AM, "GPU context command={}, result={:#x}", ctx.GetCommand(), result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::InitializeFrameContext(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 16 + ctx.GetCommand() && packet[1] == 0) {
- if (m_phase != Phase::Ready) {
- result = Kernel::ResultInvalidState;
- } else if (ctx.GetCommand() == 1101) {
- m_frame_context_initialized = true;
- result = ResultSuccess;
- } else if (m_frame_context_initialized) {
- m_frame_context_ready = true;
- result = ResultSuccess;
- } else {
- result = Kernel::ResultInvalidState;
- }
- }
- LOG_DEBUG(Service_AM, "empty frame context command={}, result={:#x}", ctx.GetCommand(), result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::ConfigureNativeMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x83 && packet[1] == 2 && packet[3] == 0 &&
- (packet[2] == 0 || packet[2] == 2)) {
- result = m_phase == Phase::Ready ? ResultSuccess : Kernel::ResultInvalidState;
- }
- // Clear the optional Gpuk-memory mode: Eden currently provides the NVDRV path.
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(result.raw);
- rb.Push<u64>(0);
- LOG_DEBUG(Service_AM, "native memory uses NVDRV-compatible mode, result={:#x}", result.raw);
-}
-
-void IGraphicsSupervisor::InitializeSyncpointContext(HLERequestContext& ctx) {
- Result result = Kernel::ResultInvalidCombination;
- const auto* packet = ctx.CommandBuffer();
- if (packet[0] == 0xd9 && packet[1] == 0) {
- if (m_phase != Phase::Ready) {
- result = Kernel::ResultInvalidState;
- } else {
- m_syncpoint_context_initialized = true;
- result = ResultSuccess;
- }
- }
- LOG_DEBUG(Service_AM, "syncpoint context initialization result={:#x}", result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::GetSyncpointSession(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidState;
- Kernel::KClientSession* client{};
- if (packet[0] == 0xda && packet[1] == 0 && m_syncpoint_context_initialized && m_nv_module) {
- result = CreateGraphicsSession(system, ctx,
- std::make_shared<ISyncpointSupervisor>(system, m_nv_module), &client);
- }
- if (result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- return;
- }
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess.raw);
- rb.PushMoveObjects(ctx, client);
- LOG_DEBUG(Service_AM, "opened syncpoint-supervisor session");
-}
-
-void IGraphicsSupervisor::GetNvidiaDriver(HLERequestContext& ctx) {
- const auto Fail = [&](Result result) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
- };
- const auto* packet = ctx.CommandBuffer();
- if (packet[0] != 0x58a || packet[1] != 0) {
- Fail(Kernel::ResultInvalidCombination);
- return;
- }
- if (m_phase != Phase::Ready) {
- Fail(Kernel::ResultInvalidState);
- return;
- }
- auto source = system.ServiceManager().GetService<Nvidia::NVDRV>("nvdrv:s", true);
- if (!source) {
- Fail(Kernel::ResultNotFound);
- return;
- }
- m_nv_module = source->GetModule();
- Kernel::KClientSession* client{};
- const auto result = CreateGraphicsSession(system, ctx,
- std::make_shared<Nvidia::NVDRV>(system, m_nv_module, "nvdrv:gsv", m_process, m_aruid),
- &client);
- if (result.IsError()) {
- Fail(result);
- return;
- }
- LOG_DEBUG(Service_AM, "opened process-bound NVDRV session for aruid={:#x}", m_aruid);
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess.raw);
- rb.PushMoveObjects(ctx, client);
-}
-
-void IGraphicsSupervisor::BindSyncpointMemory(HLERequestContext& ctx) {
- using namespace GraphicsSyncpointCache;
- const auto Fail = [&](Result result) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 2};
- rb.Push(result.raw);
- ctx.AddMoveObject(nullptr);
- ctx.AddMoveObject(nullptr);
- };
- const auto* packet = ctx.CommandBuffer();
- if (packet[0] != 0xdc || packet[1] != 0x80000006 || packet[2] != 4 ||
- packet[5] != 1 || packet[6] != 0x1ff || packet[7] != 0x1000 || packet[8] != 0 ||
- packet[9] != 0x2000 || packet[10] != 0) {
- Fail(Kernel::ResultInvalidCombination);
- return;
- }
- if (!m_syncpoint_context_initialized || !m_nv_module || m_syncpoint_rw) {
- Fail(Kernel::ResultInvalidState);
- return;
- }
- auto rw = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(0));
- auto ro = ctx.GetObjectFromHandle<Kernel::KTransferMemory>(ctx.GetCopyHandle(1));
- if (rw.IsNull() || ro.IsNull() || rw->GetOwner() != m_process || ro->GetOwner() != m_process ||
- rw.GetPointerUnsafe() == ro.GetPointerUnsafe()) {
- Fail(Kernel::ResultInvalidHandle);
- return;
- }
- if (rw->GetSize() != 0x1000 || ro->GetSize() != 0x2000) {
- Fail(Kernel::ResultInvalidSize);
- return;
- }
- auto* request_event = m_context.CreateEvent("SyncpointCacheRequest");
- if (request_event == nullptr) {
- Fail(Kernel::ResultOutOfResource);
- return;
- }
- m_syncpoint_request_event = request_event;
- m_syncpoint_rw = rw.GetPointerUnsafe();
- m_syncpoint_ro = ro.GetPointerUnsafe();
- m_syncpoint_rw->Open(kernel);
- m_syncpoint_ro->Open(kernel);
- auto& memory = m_process->GetMemory();
- const auto rw_base = rw->GetSourceAddress();
- const auto ro_base = ro->GetSourceAddress();
- const std::array<u8, 0x2000> zeros{};
- memory.WriteBlock(rw_base, zeros.data(), 0x1000);
- memory.WriteBlock(ro_base, zeros.data(), 0x2000);
- memory.WriteBlock(ro_base, Header.data(), sizeof(Header));
- for (u32 id = 0; id < CounterCount; ++id) {
- memory.Write64(ro_base + ValuesOffset + id * sizeof(u64), Unallocated);
- }
- m_cache_poll = Core::Timing::CreateEvent("GraphicsSyncpointCache",
- [this](s64, std::chrono::nanoseconds) -> std::optional<std::chrono::nanoseconds> {
- const auto guard = LockService();
- this->RefreshSyncpointCache();
- return std::nullopt;
- });
- system.CoreTiming().ScheduleLoopingEvent(std::chrono::milliseconds{1},
- std::chrono::milliseconds{1}, m_cache_poll);
- request_event->Open(kernel);
- auto* completed = m_syncpoint_cache_event.GetHandle();
- completed->Open(kernel);
- IPC::ResponseBuilder rb{ctx, 2, 0, 2};
- rb.Push(ResultSuccess.raw);
- ctx.AddMoveObject(request_event);
- ctx.AddMoveObject(completed);
- LOG_DEBUG(Service_AM, "bound syncpoint cache: {} real counters, rw={:#x}, ro={:#x}",
- CounterCount, GetInteger(rw_base), GetInteger(ro_base));
-}
-
-void IGraphicsSupervisor::RefreshSyncpointCache() {
- using namespace GraphicsSyncpointCache;
- if (!m_syncpoint_rw || !system.IsPoweredOn()) {
- return;
- }
- auto& memory = m_process->GetMemory();
- const auto rw = m_syncpoint_rw->GetSourceAddress();
- const auto ro = m_syncpoint_ro->GetSourceAddress();
- const u64 requests = memory.Read64(rw + GroupRequestOffset);
- const u64 acknowledgements = memory.Read64(ro + GroupAckOffset);
- u64 groups = (requests ^ acknowledgements) & ((1ULL << GroupCount) - 1);
- if (groups == 0) {
- return;
- }
- auto& syncpoints = m_nv_module->GetContainer().GetSyncpointManager();
- while (groups) {
- const u32 group = static_cast<u32>(std::countr_zero(groups));
- groups &= groups - 1;
- const u64 requested_slots = memory.Read64(rw + SlotRequestOffset + group * sizeof(u64));
- u64 slots = requested_slots ^ memory.Read64(ro + SlotAckOffset + group * sizeof(u64));
- while (slots) {
- const u32 bit = static_cast<u32>(std::countr_zero(slots));
- slots &= slots - 1;
- const u32 id = group * 64 + bit;
- const auto address = ro + ValuesOffset + id * sizeof(u64);
- const auto value = syncpoints.ReadAllocatedSyncpoint(id);
- const u64 updated = m_counter_values[id].Observe(value);
- memory.Write64(address, updated);
- }
- std::atomic_thread_fence(std::memory_order_release);
- memory.Write64(ro + SlotAckOffset + group * sizeof(u64), requested_slots);
- }
- std::atomic_thread_fence(std::memory_order_release);
- memory.Write64(ro + GroupAckOffset, requests);
- m_syncpoint_request_event->Clear(kernel);
- m_syncpoint_cache_event.Signal(kernel);
-}
-
-void IGraphicsSupervisor::CalculateImageRequirements(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- std::optional<NativeImageRequirements> requirements;
- const bool gpu_image = ctx.GetCommand() == 435;
- if (packet[0] == (gpu_image ? 0x1c3U : 0x5f6U) && packet[1] == 17 &&
- packet[3] == (gpu_image ? 1U : 2U)) {
- result = Kernel::ResultInvalidState;
- if (m_phase == Phase::Ready && m_image_formats_initialized) {
- requirements = CalculateNativeImageRequirements(std::span{packet + 2, 16}, packet[18]);
- result = requirements ? ResultSuccess : Kernel::ResultNotImplemented;
- }
- }
- LOG_DEBUG(Service_AM, "native image requirements dimensions={:#x}, block={}, pitch={}, size={:#x}, alignment={:#x}, result={:#x}",
- packet[4], packet[6], packet[7], requirements ? requirements->size : 0,
- requirements ? requirements->alignment : 0, result.raw);
- IPC::ResponseBuilder rb{ctx, gpu_image ? 4U : 6U};
- rb.Push(result.raw);
- rb.Push<u64>(requirements ? requirements->size : 0);
- if (!gpu_image) { rb.Push<u64>(requirements ? requirements->alignment : 0); }
-}
-void IGraphicsSupervisor::CreateNativeMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const u64 size = u64{packet[3]} | (u64{packet[4]} << 32);
- Result result = Kernel::ResultInvalidCombination;
- u32 id{};
- if (packet[0] == 0x7f && packet[1] == 3 && (packet[2] & 0xff) == 3) {
- result = Kernel::ResultInvalidState;
- if (m_phase == Phase::Ready && m_image_formats_initialized && m_nv_module) {
- result = Kernel::ResultInvalidSize;
- if (size && size <= (1ULL << 32) && Common::IsAligned(size, Kernel::PageSize)) {
- result = Kernel::ResultOutOfResource;
- if (m_native_memories.size() < 1024) {
- auto& nvmap = m_nv_module->GetContainer().GetNvMapFile();
- std::shared_ptr<Nvidia::NvCore::NvMap::Handle> handle;
- if (nvmap.CreateHandle(size, handle) == Nvidia::NvResult::Success) {
- id = handle->id;
- m_native_memories.push_back(id);
- result = ResultSuccess;
- }
- }
- }
- }
- }
- LOG_DEBUG(Service_AM, "native memory create size={:#x}, id={}, result={:#x}", size, id, result.raw);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push(id);
-}
-
-Result IGraphicsSupervisor::BindNativeMemoryBacking(u32 id, u64 address, u64 size, u64 flags, u64 offset) {
- R_UNLESS(m_nv_module && std::ranges::find(m_native_memories, id) != m_native_memories.end(),
- Kernel::ResultNotFound);
- R_UNLESS((flags == 0 || flags == 2) && offset == 0, Kernel::ResultNotImplemented);
- auto handle = m_nv_module->GetContainer().GetNvMapFile().GetHandle(id);
- R_UNLESS(handle && !handle->allocated, Kernel::ResultInvalidState);
- R_UNLESS(size && size == handle->size && address != 0 && address + size > address,
- Kernel::ResultInvalidSize);
- R_UNLESS(Common::IsAligned(address, Kernel::PageSize), Kernel::ResultInvalidAddress);
- auto& page_table = m_process->GetPageTable();
- R_UNLESS(page_table.Contains(address, size), Kernel::ResultInvalidCurrentMemory);
- if (flags == 2) {
- for (u64 current = address; current < address + size;) {
- Kernel::KMemoryInfo info{};
- Kernel::Svc::PageInfo page{};
- R_TRY(page_table.QueryInfo(&info, &page, current));
- R_UNLESS(True(info.m_attribute & Kernel::KMemoryAttribute::GpuAccessible),
- Kernel::ResultInvalidCurrentMemory);
- const u64 next = info.m_address + info.m_size;
- R_UNLESS(next > current, Kernel::ResultInvalidCurrentMemory);
- current = next;
- }
- }
- bool is_io{};
- R_TRY(page_table.LockForMapDeviceAddressSpace(&is_io, address, size,
- Kernel::KMemoryPermission::None, true, true));
- if (is_io) {
- page_table.UnlockForDeviceAddressSpace(address, size);
- R_RETURN(Kernel::ResultNotImplemented);
- }
- if (!m_native_memory_session) {
- m_native_memory_session = m_nv_module->GetContainer().OpenSession(m_process).id;
- }
- const auto result = handle->Alloc({}, Kernel::PageSize, 0, address,
- Nvidia::NvCore::SessionId{*m_native_memory_session});
- if (result != Nvidia::NvResult::Success) {
- page_table.UnlockForDeviceAddressSpace(address, size);
- R_RETURN(Kernel::ResultOutOfResource);
- }
- R_SUCCEED();
-}
-
-void IGraphicsSupervisor::BindNativeMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const auto pair = [&](size_t i) { return u64{packet[i]} | (u64{packet[i + 1]} << 32); };
- const auto result = packet[0] == 0x82 && packet[1] == 9
- ? BindNativeMemoryBacking(packet[2], pair(3), pair(5), pair(7), pair(9))
- : Kernel::ResultInvalidCombination;
- LOG_DEBUG(Service_AM, "native memory bind id={}, address={:#x}, size={:#x}, flags={:#x}, result={:#x}",
- packet[2], pair(3), pair(5), pair(7), result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-Result IGraphicsSupervisor::ReleaseNativeMemory(u32 id) {
- const auto it = std::ranges::find(m_native_memories, id);
- R_UNLESS(m_nv_module && it != m_native_memories.end(), Kernel::ResultNotFound);
- auto& nvmap = m_nv_module->GetContainer().GetNvMapFile();
- auto handle = nvmap.GetHandle(id);
- R_UNLESS(handle, Kernel::ResultNotFound);
- {
- const std::scoped_lock lock{handle->mutex};
- R_UNLESS(handle->pins == 0 && handle->internal_dupes == 0 && handle->dupes == 1,
- Kernel::ResultBusy);
- }
- const bool allocated = handle->allocated;
- handle.reset();
- const auto info = nvmap.FreeHandle(id, false);
- m_native_memories.erase(it);
- if (allocated) {
- R_UNLESS(info && info->can_unlock, Kernel::ResultInvalidState);
- R_TRY(m_process->GetPageTable().UnlockForDeviceAddressSpace(info->address, info->size));
- }
- R_SUCCEED();
-}
-
-void IGraphicsSupervisor::DestroyNativeMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const auto result = packet[0] == 0x80 && packet[1] == 1
- ? ReleaseNativeMemory(packet[2]) : Kernel::ResultInvalidCombination;
- LOG_DEBUG(Service_AM, "native memory destroy id={}, result={:#x}", packet[2], result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::BindNativeGpuMemory(HLERequestContext& ctx) {
- const auto* packet = ctx.CommandBuffer();
- const auto pair = [&](size_t i) { return u64{packet[i]} | (u64{packet[i + 1]} << 32); };
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x1b7 && packet[1] == 12 && pair(10) == 0 && pair(12) == 0) {
- result = Kernel::ResultNotFound;
- if (m_nv_module) {
- auto& container = m_nv_module->GetContainer();
- const auto parent = container.GetNvMapFile().GetHandle(packet[7]);
- if (parent && parent->allocated) {
- const auto* session = container.GetSession(parent->session_id);
- const u64 offset = pair(8);
- const u64 address = pair(3);
- const u64 size = pair(5);
- if (session && session->process == m_process && offset <= parent->size &&
- size <= parent->size - offset && parent->address + offset >= parent->address &&
- address == parent->address + offset) {
- result = BindNativeMemoryBacking(packet[2], address, size, 2, 0);
- }
- }
- }
- }
- LOG_DEBUG(Service_AM, "native GPU memory bind id={}, parent={}, address={:#x}, size={:#x}, offset={:#x}, result={:#x}",
- packet[2], packet[7], pair(3), pair(5), pair(8), result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::CreateNativeImage(HLERequestContext& ctx) {
- const std::scoped_lock images_lock{m_image_registry->mutex};
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- u32 id{};
- if (packet[0] == 0x1bd && packet[1] == 18 && packet[3] == 1) {
- result = Kernel::ResultInvalidState;
- if (m_phase == Phase::Ready && m_gpu_context_ready && m_image_formats_initialized && m_nv_module) {
- const auto requirements = CalculateNativeImageRequirements(std::span{packet + 2, 16}, packet[18]);
- result = Kernel::ResultNotImplemented;
- if (requirements) {
- result = Kernel::ResultNotFound;
- auto& nvmap = m_nv_module->GetContainer().GetNvMapFile();
- const auto memory = nvmap.GetHandle(packet[19]);
- if (std::ranges::find(m_native_memories, packet[19]) != m_native_memories.end() &&
- memory && memory->allocated) {
- result = Kernel::ResultInvalidSize;
- if (memory->size >= requirements->size) {
- result = Kernel::ResultOutOfResource;
- if (m_image_registry->images.size() < 1024 && m_next_native_image_id != 0 &&
- memory->Duplicate(true) == Nvidia::NvResult::Success) {
- NativeImage image{m_next_native_image_id++, packet[19], {}, requirements->size};
- std::copy_n(packet + 2, image.preference.size(), image.preference.begin());
- id = image.id;
- if (!m_image_registry->module) {
- m_image_registry->module = m_nv_module;
- m_image_registry->memory_session = m_nv_module->GetContainer().OpenSession(m_process);
- }
- m_image_registry->images.push_back(image);
- result = ResultSuccess;
- }
- }
- }
- }
- }
- }
- LOG_DEBUG(Service_AM, "native image create memory={}, count={}, id={}, result={:#x}",
- packet[19], packet[18], id, result.raw);
- IPC::ResponseBuilder rb{ctx, 3};
- rb.Push(result.raw);
- rb.Push(id);
-}
-
-void IGraphicsSupervisor::DestroyNativeImage(HLERequestContext& ctx) {
- const std::scoped_lock images_lock{m_image_registry->mutex};
- const auto* packet = ctx.CommandBuffer();
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == 0x1be && packet[1] == 1) {
- const auto image = std::ranges::find(m_image_registry->images, packet[2], &NativeImage::id);
- result = Kernel::ResultNotFound;
- if (m_nv_module && image != m_image_registry->images.end()) {
- result = Kernel::ResultBusy;
- if (!image->window_pool) {
- m_image_registry->ReleaseMemory(image->memory_id);
- m_image_registry->images.erase(image);
- result = ResultSuccess;
- }
- }
- }
- LOG_DEBUG(Service_AM, "native image destroy id={}, result={:#x}", packet[2], result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-void IGraphicsSupervisor::ConfigureNativeWindowImagePool(HLERequestContext& ctx) {
- const std::scoped_lock images_lock{m_image_registry->mutex};
- const auto* packet = ctx.CommandBuffer();
- const bool create = ctx.GetCommand() == 315;
- Result result = Kernel::ResultInvalidCombination;
- if (packet[0] == (create ? 0x14bU : 0x14aU) && packet[1] == (create ? 2U : 1U)) {
- const auto image = std::ranges::find(m_image_registry->images, packet[2], &NativeImage::id);
- result = Kernel::ResultNotFound;
- if (image != m_image_registry->images.end()) {
- result = Kernel::ResultNotImplemented;
- if (!create || packet[3] == 1) {
- result = Kernel::ResultInvalidState;
- if (image->window_pool != create) {
- image->window_pool = create;
- result = ResultSuccess;
- }
- }
- }
- }
- LOG_DEBUG(Service_AM, "native window image pool id={}, create={}, result={:#x}",
- packet[2], create, result.raw);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result.raw);
-}
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_supervisor.h b/src/core/hle/service/am/service/graphics_supervisor.h
deleted file mode 100644
index 4163c2c150..0000000000
--- a/src/core/hle/service/am/service/graphics_supervisor.h
+++ /dev/null
@@ -1,93 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <vector>
-
-#include "core/hle/service/service.h"
-#include "core/hle/service/am/service/graphics_syncpoint_cache.h"
-#include "core/hle/service/kernel_helpers.h"
-#include "core/hle/service/os/event.h"
-
-namespace Kernel {
-class KProcess;
-class KTransferMemory;
-class KEvent;
-}
-
-namespace Core::Timing {
-struct EventType;
-}
-namespace Service::Nvidia {
-class Module;
-}
-
-namespace Service::AM {
-struct NativeImageRegistry;
-
-class IGpuSession;
-
-class IGraphicsSupervisor final : public ServiceFramework<IGraphicsSupervisor> {
-public:
- explicit IGraphicsSupervisor(Core::System& system, Kernel::KProcess* process, u64 aruid);
- ~IGraphicsSupervisor() override;
- Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) override;
-
-private:
- enum class Phase { Created, Initialized, ProcessBound, Ready };
- void Initialize(HLERequestContext& ctx);
- void BindProcess(HLERequestContext& ctx);
- void CompleteBootstrap(HLERequestContext& ctx);
- void InitializeImageContext(HLERequestContext& ctx);
- void GetNvidiaDriver(HLERequestContext& ctx);
- void CalculateImageRequirements(HLERequestContext& ctx);
- void CreateNativeMemory(HLERequestContext& ctx);
- void CreateNativeImage(HLERequestContext& ctx);
- void DestroyNativeImage(HLERequestContext& ctx);
- void ConfigureNativeWindowImagePool(HLERequestContext& ctx);
- void BindNativeMemory(HLERequestContext& ctx);
- void BindNativeGpuMemory(HLERequestContext& ctx);
- void DestroyNativeMemory(HLERequestContext& ctx);
- Result BindNativeMemoryBacking(u32 id, u64 address, u64 size, u64 flags, u64 offset);
- Result ReleaseNativeMemory(u32 id);
- void ConfigureNativeMemory(HLERequestContext& ctx);
- void InitializeFrameContext(HLERequestContext& ctx);
- void RegisterGpuAddressSpace(HLERequestContext& ctx);
- void OpenGpuSession(HLERequestContext& ctx);
- void OpenDisplaySession(HLERequestContext& ctx);
- void InitializeDisplayContext(HLERequestContext& ctx);
- void InitializeGpuContext(HLERequestContext& ctx);
- void InitializeSyncpointContext(HLERequestContext& ctx);
- void GetSyncpointSession(HLERequestContext& ctx);
- void BindSyncpointMemory(HLERequestContext& ctx);
- void RefreshSyncpointCache();
-
- std::vector<std::weak_ptr<IGpuSession>> m_gpu_sessions;
- std::shared_ptr<Nvidia::Module> m_nv_module;
- std::optional<size_t> m_native_memory_session;
- std::vector<u32> m_native_memories;
- std::shared_ptr<NativeImageRegistry> m_image_registry;
- u32 m_next_native_image_id{1};
- std::shared_ptr<Core::Timing::EventType> m_cache_poll;
- std::array<GraphicsSyncpointCache::CounterValue, GraphicsSyncpointCache::CounterCount>
- m_counter_values{};
- Kernel::KTransferMemory* m_syncpoint_rw{};
- Kernel::KTransferMemory* m_syncpoint_ro{};
- Kernel::KEvent* m_syncpoint_request_event{};
- KernelHelpers::ServiceContext m_context;
- Event m_syncpoint_cache_event;
- bool m_syncpoint_context_initialized{};
- Kernel::KProcess* const m_process;
- const u64 m_aruid;
- Phase m_phase{Phase::Created};
- bool m_display_context_initialized{};
- bool m_gpu_context_initialized{};
- bool m_gpu_context_ready{};
- bool m_frame_context_initialized{};
- bool m_frame_context_ready{};
- bool m_image_context_initialized{};
- bool m_image_formats_initialized{};
-};
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/graphics_supervisor_protocol.h b/src/core/hle/service/am/service/graphics_supervisor_protocol.h
deleted file mode 100644
index 7762ced531..0000000000
--- a/src/core/hle/service/am/service/graphics_supervisor_protocol.h
+++ /dev/null
@@ -1,37 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <array>
-#include <optional>
-#include <span>
-#include "common/common_types.h"
-
-namespace Service::AM::GraphicsSupervisorProtocol {
-
-constexpr u8 DecodeBufferSlot(u32 packed) {
- return static_cast<u8>(packed);
-}
-
-struct BootstrapRequest {
- u32 process_handle;
- u64 applet_resource_user_id;
- u64 flags;
- std::array<u64, 4> parameters;
-};
-
-inline std::optional<BootstrapRequest> DecodeBootstrap(std::span<const u32> packet) {
- // Captured remote-memory bootstrap: TIPC 4, one copied handle, 48 data bytes.
- if (packet.size() < 16 || packet[0] != 0x14 || packet[1] != 0x8000000c ||
- packet[2] != 2) {
- return std::nullopt;
- }
- const auto Read64 = [&](size_t index) {
- return u64{packet[index]} | (u64{packet[index + 1]} << 32);
- };
- return BootstrapRequest{packet[3], Read64(4), Read64(6),
- {Read64(8), Read64(10), Read64(12), Read64(14)}};
-}
-
-} // namespace Service::AM::GraphicsSupervisorProtocol
diff --git a/src/core/hle/service/am/service/graphics_syncpoint_cache.h b/src/core/hle/service/am/service/graphics_syncpoint_cache.h
deleted file mode 100644
index 23361b006c..0000000000
--- a/src/core/hle/service/am/service/graphics_syncpoint_cache.h
+++ /dev/null
@@ -1,49 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <array>
-#include <limits>
-#include <optional>
-#include "common/common_types.h"
-
-namespace Service::AM::GraphicsSyncpointCache {
-constexpr u32 ValuesOffset = 0x40;
-constexpr u32 GroupAckOffset = 0x640;
-constexpr u32 SlotAckOffset = 0x648;
-constexpr u32 GroupRequestOffset = 0;
-constexpr u32 SlotRequestOffset = 8;
-constexpr u32 CounterCount = 192;
-constexpr u32 GroupCount = (CounterCount + 63) / 64;
-constexpr u64 Unallocated = (std::numeric_limits<u64>::max)();
-
-constexpr std::array<u32, 8> Header{
- 1, 0, CounterCount - 1, ValuesOffset, GroupRequestOffset,
- GroupAckOffset, SlotRequestOffset, SlotAckOffset};
-static_assert(ValuesOffset + CounterCount * sizeof(u64) <= GroupAckOffset);
-static_assert(SlotAckOffset + GroupCount * sizeof(u64) <= 0x2000);
-static_assert(SlotRequestOffset + GroupCount * sizeof(u64) <= 0x1000);
-
-constexpr u64 ExtendCounter(u64 previous, u32 current) {
- if (previous == Unallocated) {
- return current;
- }
- u64 high = previous & 0xffffffff00000000ULL;
- if (current < static_cast<u32>(previous)) {
- high += 1ULL << 32;
- }
- return high | current;
-}
-struct CounterValue {
- u64 previous{Unallocated};
-
- u64 Observe(std::optional<u32> current) {
- if (!current) {
- return Unallocated;
- }
- previous = ExtendCounter(previous, *current);
- return previous;
- }
-};
-} // namespace Service::AM::GraphicsSyncpointCache
diff --git a/src/core/hle/service/am/service/native_image_layout.h b/src/core/hle/service/am/service/native_image_layout.h
deleted file mode 100644
index eb45fc470d..0000000000
--- a/src/core/hle/service/am/service/native_image_layout.h
+++ /dev/null
@@ -1,40 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <optional>
-#include <span>
-#include "common/common_types.h"
-
-namespace Service::AM {
-
-struct NativeImageRequirements {
- u64 size;
- u64 alignment;
-};
-
-// Experimental inter-module block image layout, restricted to the observed
-// four-byte color format. Row pitch is in 64-byte GOBs; block height is in pixels.
-inline std::optional<NativeImageRequirements> CalculateNativeImageRequirements(
- std::span<const u32> preference, u32 count) {
- if (preference.size() != 16 || count != 1 || preference[0] != 0 ||
- (preference[1] != 1 && preference[1] != 2) || preference[3] != 0 || preference[6] != 1 ||
- preference[7] != 1 || preference[4] < 3 || preference[4] > 8) {
- return std::nullopt;
- }
- for (size_t i = 8; i < preference.size(); ++i) {
- if (preference[i] != 0) { return std::nullopt; }
- }
- const u64 width = (preference[2] & 0xffffU) + 1;
- const u64 height = (preference[2] >> 16) + 1;
- const u64 pitch_gobs = preference[5];
- if (pitch_gobs < (width * 4 + 63) / 64 || pitch_gobs > 4096) {
- return std::nullopt;
- }
- const u64 block_height = 1ULL << preference[4];
- const u64 aligned_height = (height + block_height - 1) & ~(block_height - 1);
- return NativeImageRequirements{pitch_gobs * 64 * aligned_height, 64 * block_height};
-}
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/performance_functions.cpp b/src/core/hle/service/am/service/performance_functions.cpp
deleted file mode 100644
index 71a46cc5b5..0000000000
--- a/src/core/hle/service/am/service/performance_functions.cpp
+++ /dev/null
@@ -1,19 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include "core/hle/service/am/service/performance_functions.h"
-
-namespace Service::AM {
-
-IPerformanceFunctions::IPerformanceFunctions(Core::System& system)
- : ServiceFramework{system, "IPerformanceFunctions"} {
- static const FunctionInfo functions[] = {
- {0, nullptr, "IsCpuOverclockEnabled"},
- {1, nullptr, "SetCpuOverclockEnabled"},
- };
- RegisterHandlers(functions);
-}
-
-IPerformanceFunctions::~IPerformanceFunctions() = default;
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/performance_functions.h b/src/core/hle/service/am/service/performance_functions.h
deleted file mode 100644
index 12195d1217..0000000000
--- a/src/core/hle/service/am/service/performance_functions.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include "core/hle/service/service.h"
-
-namespace Service::AM {
-
-class IPerformanceFunctions final : public ServiceFramework<IPerformanceFunctions> {
-public:
- explicit IPerformanceFunctions(Core::System& system);
- ~IPerformanceFunctions() override;
-};
-
-} // namespace Service::AM
diff --git a/src/core/hle/service/am/service/self_controller.cpp b/src/core/hle/service/am/service/self_controller.cpp
index 45b9120093..3a654b9daa 100644
--- a/src/core/hle/service/am/service/self_controller.cpp
+++ b/src/core/hle/service/am/service/self_controller.cpp
@@ -5,17 +5,10 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging.h"
-#include "core/hle/kernel/k_scoped_resource_reservation.h"
-#include "core/hle/kernel/k_session.h"
-#include "core/hle/kernel/k_client_session.h"
-#include "core/hle/kernel/k_thread.h"
#include "core/hle/result.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/service/self_controller.h"
-#include "core/hle/service/am/service/graphics_supervisor.h"
-#include "core/hle/service/ipc_helpers.h"
-#include "core/hle/service/server_manager.h"
#include "core/hle/service/caps/caps_su.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
@@ -80,7 +73,6 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
{230, D<&ISelfController::Unknown230>, "Unknown230"},
{240, D<&ISelfController::Unknown240>, "Unknown240"},
{1000, nullptr, "GetDebugStorageChannel"},
- {2000, &ISelfController::GetGraphicsSupervisor, "GetGraphicsSupervisor"},
};
// clang-format on
@@ -92,47 +84,10 @@ ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet>
}
ISelfController::~ISelfController() {
- if (m_graphics_supervisor_session != nullptr) {
- m_graphics_supervisor_session->Close(kernel);
- }
std::scoped_lock lk{m_applet->lock};
m_applet->display_layer_manager.Finalize();
}
-void ISelfController::GetGraphicsSupervisor(HLERequestContext& ctx) {
- if (m_graphics_supervisor_session != nullptr) {
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(ctx, m_graphics_supervisor_session);
- return;
- }
- Kernel::KScopedResourceReservation reservation(
- kernel, Kernel::GetCurrentProcessPointer(kernel), Kernel::LimitableResource::SessionCountMax);
- if (!reservation.Succeeded()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultLimitReached);
- return;
- }
- auto* session = Kernel::KSession::Create(kernel);
- if (session == nullptr) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultOutOfResource);
- return;
- }
- session->Initialize(kernel, nullptr, 0);
- reservation.Commit();
- Kernel::KSession::Register(kernel, session);
- auto& server = ctx.GetManager()->GetServerManager();
- auto manager = std::make_shared<SessionRequestManager>(kernel, server);
- manager->SetSessionHandler(std::make_shared<IGraphicsSupervisor>(system, m_process, m_applet->aruid.pid));
- server.RegisterSession(&session->GetServerSession(), std::move(manager));
- LOG_DEBUG(Service_AM, "created graphics-supervisor session");
- m_graphics_supervisor_session = &session->GetClientSession();
- IPC::ResponseBuilder rb{ctx, 2, 1};
- rb.Push(ResultSuccess);
- rb.PushCopyObjects(ctx, m_graphics_supervisor_session);
-}
-
Result ISelfController::Exit() {
LOG_DEBUG(Service_AM, "called");
diff --git a/src/core/hle/service/am/service/self_controller.h b/src/core/hle/service/am/service/self_controller.h
index 52970ed4a8..c9f480f575 100644
--- a/src/core/hle/service/am/service/self_controller.h
+++ b/src/core/hle/service/am/service/self_controller.h
@@ -12,7 +12,6 @@
namespace Kernel {
class KReadableEvent;
-class KClientSession;
}
namespace Service::Capture {
@@ -31,7 +30,6 @@ public:
~ISelfController() override;
private:
- void GetGraphicsSupervisor(HLERequestContext& ctx);
Result Exit();
Result LockExit();
Result UnlockExit();
@@ -72,7 +70,6 @@ private:
Result Unknown230(u32 in_val, Out<u16> out_val);
Result Unknown240(u32 in_val);
- Kernel::KClientSession* m_graphics_supervisor_session{};
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};
diff --git a/src/core/hle/service/audio/audio.cpp b/src/core/hle/service/audio/audio.cpp
index 63d578462f..fde766a275 100644
--- a/src/core/hle/service/audio/audio.cpp
+++ b/src/core/hle/service/audio/audio.cpp
@@ -5,8 +5,6 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
-#include "core/hle/kernel/svc_results.h"
-#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/audio/audio.h"
#include "core/hle/service/audio/audio_controller.h"
#include "core/hle/service/audio/audio_in_manager.h"
@@ -20,57 +18,6 @@
namespace Service::Audio {
-class INativeAudioManager final : public ServiceFramework<INativeAudioManager> {
-public:
- INativeAudioManager(Core::System& system_, std::shared_ptr<IAudioInManager> input,
- std::shared_ptr<IAudioOutManager> output,
- std::shared_ptr<IAudioRendererManager> renderer)
- : ServiceFramework{system_, "aud:u"}, m_input{std::move(input)},
- m_output{std::move(output)}, m_renderer{std::move(renderer)} {
- static const FunctionInfo functions[] = {
- {0, &INativeAudioManager::GetAudioInManager, "GetAudioInManager"},
- {1, &INativeAudioManager::GetAudioOutManager, "GetAudioOutManager"},
- {2, &INativeAudioManager::GetAudioRendererManager, "GetAudioRendererManager"},
- };
- RegisterHandlers(functions);
- }
-
- Result HandleSyncRequest(Kernel::KServerSession& session, HLERequestContext& ctx) override {
- if (!ctx.IsTipc()) {
- return ServiceFrameworkBase::HandleSyncRequest(session, ctx);
- }
- const auto guard = LockService();
- LOG_WARNING(Service_Audio, "Native audio unsupported command={}, words={:08x}", ctx.GetCommand(),
- fmt::join(std::span<const u32>(ctx.CommandBuffer() + 2,
- std::min<u32>(ctx.CommandBuffer()[1], 32)), ","));
- InvokeRequestTipc(ctx);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(Kernel::ResultNotImplemented.raw);
- return system.IsPoweredOn() ? ctx.WriteToOutgoingCommandBuffer() : ResultSuccess;
- }
-
-private:
- void GetAudioInManager(HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface(ctx, m_input);
- }
- void GetAudioOutManager(HLERequestContext& ctx) {
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface(ctx, m_output);
- }
- void GetAudioRendererManager(HLERequestContext& ctx) {
- LOG_DEBUG(Service_Audio, "Native user client opens existing audio renderer manager");
- IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface(ctx, m_renderer);
- }
- std::shared_ptr<IAudioInManager> m_input;
- std::shared_ptr<IAudioOutManager> m_output;
- std::shared_ptr<IAudioRendererManager> m_renderer;
-};
-
class IAudioOutManagerForApplet final : public ServiceFramework<IAudioOutManagerForApplet> {
public:
explicit IAudioOutManagerForApplet(Core::System& system_)
@@ -246,23 +193,18 @@ void LoopProcess(Core::System& system) {
server_manager->RegisterNamedService("audrec:d", std::make_shared<IFinalOutputRecorderManagerForDebugger>(system), 30);
server_manager->RegisterNamedService("audren:d", std::make_shared<IAudioRendererManagerForDebugger>(system), 30);
- auto audio_input = std::make_shared<IAudioInManager>(system);
- server_manager->RegisterNamedService("audin:u", audio_input, 30);
+ server_manager->RegisterNamedService("audin:u", std::make_shared<IAudioInManager>(system), 30);
server_manager->RegisterNamedService("audin:a", std::make_shared<IAudioInManagerForApplet>(system), 30);
- auto audio_output = std::make_shared<IAudioOutManager>(system);
- server_manager->RegisterNamedService("audout:u", audio_output, 30);
+ server_manager->RegisterNamedService("audout:u", std::make_shared<IAudioOutManager>(system), 30);
server_manager->RegisterNamedService("audout:a", std::make_shared<IAudioOutManagerForApplet>(system), 30);
server_manager->RegisterNamedService("auddev", std::make_shared<IAudioSnoopManager>(system), 30);
// Depends on audout:u and audin:u on ctor!
server_manager->RegisterNamedService("audctl", std::make_shared<IAudioController>(system), 30);
server_manager->RegisterNamedService("audrec:a", std::make_shared<IFinalOutputRecorderManagerForApplet>(system), 30);
server_manager->RegisterNamedService("audrec:u", std::make_shared<IFinalOutputRecorderManager>(system), 30);
- auto audio_renderer = std::make_shared<IAudioRendererManager>(system);
- server_manager->RegisterNamedService("audren:u", audio_renderer, 30);
+ server_manager->RegisterNamedService("audren:u", std::make_shared<IAudioRendererManager>(system), 30);
server_manager->RegisterNamedService("audren:a", std::make_shared<IAudioRendererManagerForApplet>(system), 30);
server_manager->RegisterNamedService("hwopus", std::make_shared<IHardwareOpusDecoderManager>(system), 25);
- server_manager->RegisterNamedService("aud:u",
- std::make_shared<INativeAudioManager>(system, audio_input, audio_output, audio_renderer), 30);
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index 7ddb944abe..9689bce8dd 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -132,7 +132,6 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
{210, C<&IHidServer::EndPermitVibrationSession>, "EndPermitVibrationSession"},
{211, C<&IHidServer::IsVibrationDeviceMounted>, "IsVibrationDeviceMounted"},
{212, C<&IHidServer::SendVibrationValueInBool>, "SendVibrationValueInBool"},
- {214, C<&IHidServer::SendNativeVibrationValues>, "SendNativeVibrationValues"},
{300, C<&IHidServer::ActivateConsoleSixAxisSensor>, "ActivateConsoleSixAxisSensor"},
{301, C<&IHidServer::StartConsoleSixAxisSensor>, "StartConsoleSixAxisSensor"},
{302, C<&IHidServer::StopConsoleSixAxisSensor>, "StopConsoleSixAxisSensor"},
@@ -238,11 +237,6 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
{3013, nullptr, "SetDebugPadGenericPadMap"}, //21.0.0+
{3014, nullptr, "GetDebugPadKeyboardMap"}, //21.0.0+
{3015, nullptr, "SetDebugPadKeyboardMap"}, //21.0.0+
- {3110, C<&IHidServer::RegisterJcmsMemory>, "RegisterJcmsMemory"},
- {3136, C<&IHidServer::SetNmouseButtonConfigJoyLeftJcms>, "SetNmouseButtonConfigJoyLeftJcms"},
- {3137, C<&IHidServer::SetNmouseButtonConfigJoyRightJcms>, "SetNmouseButtonConfigJoyRightJcms"},
- {3138, C<&IHidServer::SetMergedNmouseSourceTypes>, "SetMergedNmouseSourceTypes"},
- {3139, C<&IHidServer::RegisterNativeInputMemory>, "RegisterNativeInputMemory"},
{3150, C<&IHidServer::SetMouseLibraryVersion>, "SetMouseLibraryVersion"}, //21.0.0+
// What? -- {12010, nullptr, "SetButtonConfigLeft"},
};
@@ -251,11 +245,7 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
RegisterHandlers(functions);
}
-IHidServer::~IHidServer() {
- for (const auto& registration : native_input_memories) {
- registration.memory->Close(kernel);
- }
-}
+IHidServer::~IHidServer() = default;
Result IHidServer::CreateAppletResource(OutInterface<IAppletResource> out_applet_resource,
ClientAppletResourceUserId aruid) {
@@ -994,17 +984,6 @@ Result IHidServer::SendVibrationValues(
R_SUCCEED();
}
-Result IHidServer::SendNativeVibrationValues(
- u16 flags, AppletResourceUserId aruid,
- InArray<Core::HID::VibrationDeviceHandle, BufferAttr_HipcPointer> vibration_handles,
- InArray<Core::HID::VibrationValue, BufferAttr_HipcPointer> vibration_values) {
- static u32 diagnostic_batches{};
- if (diagnostic_batches++ < 8) LOG_INFO(Service_HID, "Native vibration batch flags={:#x}, aruid={}, handles={}, values={}",
- flags, aruid.pid, vibration_handles.size(), vibration_values.size());
- R_UNLESS(flags == 0 || flags == 2, IPC::ResultNotSupported);
- R_RETURN(SendVibrationValues(ClientAppletResourceUserId{aruid.pid}, vibration_handles, vibration_values));
-}
-
Result IHidServer::SendVibrationGcErmCommand(
Core::HID::VibrationDeviceHandle vibration_device_handle, ClientAppletResourceUserId aruid,
Core::HID::VibrationGcErmCommand gc_erm_command) {
@@ -1492,63 +1471,6 @@ Result IHidServer::SetTouchScreenResolution(u32 width, u32 height,
R_SUCCEED();
}
-Result IHidServer::RegisterNativeInputMemory(
- u8 mode, u32 parameter0, u32 parameter1, u32 parameter2,
- ClientAppletResourceUserId aruid, u64 size,
- InCopyHandle<Kernel::KTransferMemory> memory) {
- LOG_INFO(Service_HID, "Native input memory mode={}, parameters={:#x}/{:#x}/{:#x}, aruid={}, size={:#x}",
- mode, parameter0, parameter1, parameter2, aruid.pid, size);
- R_UNLESS(memory.Get() && memory->GetOwner()->UsesPAuthReturns() &&
- memory->GetOwner()->GetProcessId() == aruid.pid, Kernel::ResultInvalidHandle);
- R_UNLESS(mode <= 1 && size && size == memory->GetSize() && size <= 0x1000000,
- Kernel::ResultInvalidSize);
- R_UNLESS(native_input_memories.size() < 64, Kernel::ResultOutOfResource);
- const auto existing = std::ranges::find(native_input_memories, memory.Get(), &NativeInputMemory::memory);
- R_UNLESS(existing == native_input_memories.end(), Kernel::ResultInvalidState);
- memory->Open(kernel);
- native_input_memories.push_back({memory.Get(), aruid.pid, size, {mode, parameter0, parameter1, parameter2}});
- // Retain the real guest-owned input buffer. No Joy-Con mouse samples are
- // produced while those devices are disconnected.
- R_SUCCEED();
-}
-
-Result IHidServer::RegisterJcmsMemory(ClientAppletResourceUserId aruid, u64 size,
- InCopyHandle<Kernel::KTransferMemory> memory) {
- LOG_INFO(Service_HID, "Native Joy-Con mouse memory: aruid={}, size={:#x}", aruid.pid, size);
- return RegisterNativeInputMemory(1, 0, 0, 0, aruid, size, memory);
-}
-
-Result IHidServer::SetMergedNmouseSourceTypes(u32 source_types, ClientAppletResourceUserId aruid) {
- LOG_INFO(Service_HID, "Native merged mouse sources: types={:#x}, aruid={}", source_types, aruid.pid);
- R_UNLESS((source_types & ~6U) == 0, Kernel::ResultInvalidCombination);
- const auto memory = std::ranges::find_if(native_input_memories, [&](const auto& registration) {
- return registration.aruid == aruid.pid && registration.parameters[0] == 0;
- });
- R_UNLESS(memory != native_input_memories.end(), Kernel::ResultNotFound);
- memory->merged_source_types = source_types;
- R_SUCCEED();
-}
-
-Result IHidServer::SetNmouseButtonConfiguration(ClientAppletResourceUserId aruid, u64 configuration,
- size_t side) {
- LOG_INFO(Service_HID, "Native Joy-Con mouse buttons: side={}, config={:#x}, aruid={}",
- side, configuration, aruid.pid);
- const auto memory = std::ranges::find_if(native_input_memories, [&](const auto& registration) {
- return registration.aruid == aruid.pid && registration.parameters[0] == 0;
- });
- R_UNLESS(memory != native_input_memories.end(), Kernel::ResultNotFound);
- memory->jcms_button_configurations[side] = configuration;
- R_SUCCEED();
-}
-
-Result IHidServer::SetNmouseButtonConfigJoyLeftJcms(ClientAppletResourceUserId aruid, u64 configuration) {
- return SetNmouseButtonConfiguration(aruid, configuration, 0);
-}
-
-Result IHidServer::SetNmouseButtonConfigJoyRightJcms(ClientAppletResourceUserId aruid, u64 configuration) {
- return SetNmouseButtonConfiguration(aruid, configuration, 1);
-}
-
Result IHidServer::SetMouseLibraryVersion(ClientAppletResourceUserId aruid) {
LOG_INFO(Service_HID, "(STUBBED) called, applet_resource_user_id={}", aruid.pid);
diff --git a/src/core/hle/service/hid/hid_server.h b/src/core/hle/service/hid/hid_server.h
index 45097f361d..57a1a04b9c 100644
--- a/src/core/hle/service/hid/hid_server.h
+++ b/src/core/hle/service/hid/hid_server.h
@@ -6,8 +6,6 @@
#pragma once
-#include <array>
-#include <vector>
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
@@ -177,10 +175,6 @@ private:
ClientAppletResourceUserId aruid,
InArray<Core::HID::VibrationDeviceHandle, BufferAttr_HipcPointer> vibration_handles,
InArray<Core::HID::VibrationValue, BufferAttr_HipcPointer> vibration_values);
- Result SendNativeVibrationValues(
- u16 flags, AppletResourceUserId aruid,
- InArray<Core::HID::VibrationDeviceHandle, BufferAttr_HipcPointer> vibration_handles,
- InArray<Core::HID::VibrationValue, BufferAttr_HipcPointer> vibration_values);
Result SendVibrationGcErmCommand(Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid,
Core::HID::VibrationGcErmCommand gc_erm_command);
@@ -271,24 +265,6 @@ private:
Result SetTouchScreenResolution(u32 width, u32 height, ClientAppletResourceUserId aruid);
Result SetMouseLibraryVersion(ClientAppletResourceUserId aruid);
- Result RegisterNativeInputMemory(u8 mode, u32 parameter0, u32 parameter1, u32 parameter2,
- ClientAppletResourceUserId aruid, u64 size,
- InCopyHandle<Kernel::KTransferMemory> memory);
- Result RegisterJcmsMemory(ClientAppletResourceUserId aruid, u64 size,
- InCopyHandle<Kernel::KTransferMemory> memory);
- Result SetMergedNmouseSourceTypes(u32 source_types, ClientAppletResourceUserId aruid);
- Result SetNmouseButtonConfigJoyLeftJcms(ClientAppletResourceUserId aruid, u64 configuration);
- Result SetNmouseButtonConfigJoyRightJcms(ClientAppletResourceUserId aruid, u64 configuration);
- Result SetNmouseButtonConfiguration(ClientAppletResourceUserId aruid, u64 configuration, size_t side);
- struct NativeInputMemory {
- Kernel::KTransferMemory* memory;
- u64 aruid;
- u64 size;
- std::array<u32, 4> parameters;
- u32 merged_source_types{};
- std::array<u64, 2> jcms_button_configurations{};
- };
- std::vector<NativeInputMemory> native_input_memories;
std::shared_ptr<ResourceManager> resource_manager;
std::shared_ptr<HidFirmwareSettings> firmware_settings;
};
diff --git a/src/core/hle/service/ngc/ngc.cpp b/src/core/hle/service/ngc/ngc.cpp
index 2c79336d93..e79108a1eb 100644
--- a/src/core/hle/service/ngc/ngc.cpp
+++ b/src/core/hle/service/ngc/ngc.cpp
@@ -7,7 +7,6 @@
#include "common/string_util.h"
#include "core/core.h"
#include "core/hle/kernel/k_client_session.h"
-#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/result.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/cmif_types.h"
@@ -183,8 +182,6 @@ public:
explicit IUserShimScopedObject(Core::System& system_) : ServiceFramework(system_, "IUserShimScopedObject") {
// clang-format off
static const FunctionInfo functions[] = {
- {1, D<&IUserShimScopedObject::GetRequiredMemorySize>, "GetRequiredMemorySize"},
- {300, D<&IUserShimScopedObject::GetGuestHidSharedMemory>, "GetGuestHidSharedMemory"},
{450, nullptr, "InitializeForSaveData"},
{451, nullptr, "FinalizeForSaveData"},
{452, D<&IUserShimScopedObject::OpenSaveData>, "OpenSaveData"},
@@ -198,50 +195,6 @@ public:
RegisterHandlers(functions);
}
- ~IUserShimScopedObject() override {
- if (m_guest_hid_memory) {
- m_guest_hid_memory->Close(kernel);
- }
- }
-
- struct GuestHidMemoryConfig {
- u64 size;
- u64 offset;
- };
-
- Result GetRequiredMemorySize(Out<u32> out_size, u8 type, u8 mode, s32 guest_count) {
- LOG_INFO(Service_NGC, "GameShare work memory query type={}, mode={}, guests={}", type, mode, guest_count);
- R_UNLESS(type <= 1 && mode == 1 && guest_count >= 0 && guest_count <= 3,
- IPC::ResultNotSupported);
- // The disconnected implementation reserves one page for its session
- // control state. Streaming/encoding work is not implemented.
- *out_size = 0x1000;
- R_SUCCEED();
- }
-
- Result GetGuestHidSharedMemory(Out<GuestHidMemoryConfig> out_config,
- OutCopyHandle<Kernel::KSharedMemory> out_memory) {
- // Three guest pad blocks, touch rings, and JCMS rings. Empty rings and
- // zero style sets describe no connected GameShare guests.
- constexpr u64 GuestHidMemorySize = 0x84000;
- if (!m_guest_hid_memory) {
- auto* memory = Kernel::KSharedMemory::Create(kernel);
- const auto result = memory->Initialize(kernel, system.DeviceMemory(), nullptr,
- Kernel::Svc::MemoryPermission::ReadWrite, Kernel::Svc::MemoryPermission::Read,
- GuestHidMemorySize);
- if (R_FAILED(result)) {
- memory->Close(kernel);
- R_RETURN(result);
- }
- Kernel::KSharedMemory::Register(kernel, memory);
- m_guest_hid_memory = memory;
- }
- *out_config = GuestHidMemoryConfig{GuestHidMemorySize, 0};
- *out_memory = m_guest_hid_memory;
- LOG_DEBUG(Service_NGC, "GameShare guest HID memory size={:#x}, no guests connected", GuestHidMemorySize);
- R_SUCCEED();
- }
-
Result OpenSaveData(Account::Uid unk0, Out<SaveDataHandle> unk1) {
LOG_WARNING(Service_NGC, "stubbed");
R_THROW(IPC::ResultNotSupported);
@@ -257,9 +210,6 @@ public:
// to implement
R_SUCCEED();
}
-
-private:
- Kernel::KSharedMemory* m_guest_hid_memory{};
};
class IUserService final : public ServiceFramework<IUserService> {
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
index 8b929a7ef3..c4c4c25932 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp
@@ -63,14 +63,6 @@ void SyncpointManager::FreeSyncpoint(u32 id) {
syncpoint.reserved = false;
}
-std::optional<u32> SyncpointManager::ReadAllocatedSyncpoint(u32 id) {
- std::lock_guard lock(reservation_lock);
- if (id >= SyncpointCount || !syncpoints[id].reserved) {
- return std::nullopt;
- }
- return UpdateMin(id);
-}
-
bool SyncpointManager::IsSyncpointAllocated(u32 id) const {
return (id < SyncpointCount) && syncpoints[id].reserved;
}
diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
index 42e1d547b8..7728ff5967 100644
--- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h
+++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h
@@ -7,7 +7,6 @@
#include <array>
#include <atomic>
#include <mutex>
-#include <optional>
#include "common/common_types.h"
#include "core/hle/service/nvdrv/nvdata.h"
@@ -39,8 +38,6 @@ enum class ChannelType : u32 {
*/
class SyncpointManager final {
public:
- std::optional<u32> ReadAllocatedSyncpoint(u32 id);
-
explicit SyncpointManager(Tegra::Host1x::Host1x& host1x);
~SyncpointManager();
diff --git a/src/core/hle/service/nvdrv/devices/gpu_address_space_layout.h b/src/core/hle/service/nvdrv/devices/gpu_address_space_layout.h
deleted file mode 100644
index a54ebb18d7..0000000000
--- a/src/core/hle/service/nvdrv/devices/gpu_address_space_layout.h
+++ /dev/null
@@ -1,34 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include "common/common_types.h"
-
-namespace Service::Nvidia::Devices {
-
-struct GpuAddressSpaceLayout {
- u64 start;
- u64 split;
- u64 end;
-};
-
-constexpr GpuAddressSpaceLayout GetGpuAddressSpaceLayout(bool extended) {
- // Leave room for other 4 KiB allocations beyond the native bootstrap
- // reservation of 0x7ff8000000 bytes.
- // Both layouts fit within the GPU's reported 40-bit virtual address width.
- return {0x8000000, extended ? 3ULL << 38 : 1ULL << 34,
- extended ? 1ULL << 40 : 1ULL << 37};
-}
-
-constexpr u32 GetGpuAddressSpaceBigPageSize(bool extended, u32 requested) {
- // The native SDK passes its preferred allocation size here. A preference for
- // ordinary 4 KiB mappings still needs a separate large-page pool in NVDRV.
- return extended && requested == 0x1000 ? 0x10000 : requested;
-}
-
-constexpr u64 GpuPageAddress(u32 page, u32 page_bits) {
- return static_cast<u64>(page) << page_bits;
-}
-
-} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/native_gpu_characteristics.h b/src/core/hle/service/nvdrv/devices/native_gpu_characteristics.h
deleted file mode 100644
index 44f45cab75..0000000000
--- a/src/core/hle/service/nvdrv/devices/native_gpu_characteristics.h
+++ /dev/null
@@ -1,67 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <array>
-#include <cstring>
-#include <span>
-#include "common/common_types.h"
-#include "common/swap.h"
-
-namespace Service::Nvidia::Devices {
-
-inline constexpr size_t NativeGpuCharacteristicsSize = 0xd0;
-
-inline std::array<u8, NativeGpuCharacteristicsSize> MakeNativeGpuCharacteristics(
- std::span<const u8, 0xa0> legacy) {
- std::array<u8, NativeGpuCharacteristicsSize> result{};
- // The GPU description and engine classes share the legacy prefix. The native
- // SDK consumes signed ioctl interface levels where the legacy ABI has topology.
- std::memcpy(result.data(), legacy.data(), 0x70);
- // Select the SDK's native control ABI, whose normal mappings support
- // 4 KiB CPU/GPU aliases. Engine execution remains a separate implementation.
- const u32_le native_arch{0x170};
- const u32_le native_impl{0xe};
- std::memcpy(result.data(), &native_arch, sizeof(native_arch));
- std::memcpy(result.data() + 4, &native_impl, sizeof(native_impl));
- // Native NVN's built-in shader table accepts Ampere SM 8.x. Carrying the
- // inherited Maxwell SM 5.3 value here rejects its initialization shaders.
- const u32_le native_sm_version{0x807};
- std::memcpy(result.data() + 0x3c, &native_sm_version, sizeof(native_sm_version));
- std::memcpy(result.data() + 0x40, &native_sm_version, sizeof(native_sm_version));
- // Native NVN maps CPU buffers into its shared VA reservation. Those buffers
- // are 4 KiB aligned, so large pages must remain optional for allocation.
- const u32_le preferred_page_size{0x1000};
- std::memcpy(result.data() + 0x28, &preferred_page_size, sizeof(preferred_page_size));
- u32_le available_page_sizes;
- std::memcpy(&available_page_sizes, legacy.data() + 0x34, sizeof(available_page_sizes));
- available_page_sizes = (static_cast<u32>(available_page_sizes) & 0x10000) | 0x1000;
- std::memcpy(result.data() + 0x34, &available_page_sizes, sizeof(available_page_sizes));
- u64_le flags;
- std::memcpy(&flags, legacy.data() + 0x50, sizeof(flags));
- // Native SDK class enumeration filters 2D/3D/compute/inline families
- // with bits 40..43 before selecting context identities from its profile.
- // The native SDK gates ModifyKind (AS ioctl 12) on capability bit 34.
- flags = static_cast<u64>(flags) | (1ULL << 8) | (1ULL << 22) | (1ULL << 26) | (1ULL << 34) | (0xfULL << 40);
- std::memcpy(result.data() + 0x50, &flags, sizeof(flags));
- constexpr std::array<s16, 9> levels{
- 0x1c, // GPU control: GetGpuTime
- 11, // TSG: bind/unbind channel with native subcontext IDs
- -1, // GPU debugger device is unavailable
- 0x1d, // Channel: SetTimeslice
- 0x14, // Address space: Remap
- 0, 0, 0, 0, // Additional interfaces have not been implemented.
- };
- for (size_t i = 0; i < levels.size(); ++i) {
- const u16_le value{static_cast<u16>(levels[i])};
- std::memcpy(result.data() + 0x70 + i * sizeof(value), &value, sizeof(value));
- }
- // The native SDK allocates shared queue subcontexts locally, then binds
- // each channel with TSG ioctl 11. Each emulated channel retains its own state.
- const u32_le max_subcontexts{64};
- std::memcpy(result.data() + 0xb4, &max_subcontexts, sizeof(max_subcontexts));
- return result;
-}
-
-} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/native_gpu_context.h b/src/core/hle/service/nvdrv/devices/native_gpu_context.h
deleted file mode 100644
index 7c7131f211..0000000000
--- a/src/core/hle/service/nvdrv/devices/native_gpu_context.h
+++ /dev/null
@@ -1,23 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <optional>
-#include "common/common_types.h"
-
-namespace Service::Nvidia::Devices {
-
-// Native profile context identities. This classifies allocation metadata;
-// engine method execution is handled separately by the GPU frontend.
-inline std::optional<u32> GetNativeGpuContextSlot(u32 identity) {
- switch (identity) {
- case 0xc797: return 1;
- case 0xc7c0: return 2;
- case 0xc7b5: return 4;
- case 0xc56f: return 5;
- default: return std::nullopt;
- }
-}
-
-} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/native_gpu_kind.h b/src/core/hle/service/nvdrv/devices/native_gpu_kind.h
deleted file mode 100644
index ecf3781162..0000000000
--- a/src/core/hle/service/nvdrv/devices/native_gpu_kind.h
+++ /dev/null
@@ -1,51 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <optional>
-#include "common/common_types.h"
-#include "video_core/pte_kind.h"
-
-namespace Service::Nvidia::Devices {
-
-inline std::optional<u8> TranslateNativeUncompressedKind(u8 kind, u8 fallback) {
- // NVIDIA's Turing MMU uses 6 for GENERIC_MEMORY and 7 for INVALID:
- // open-gpu-doc/manuals/turing/tu104/dev_mmu.ref.txt. Eden's older kind
- // numbering uses 0xfe for generic memory. Equal kinds need no compression.
- if (kind != fallback) { return std::nullopt; }
- switch (kind) {
- case 0: return static_cast<u8>(Tegra::PTEKind::PITCH);
- case 1: return static_cast<u8>(Tegra::PTEKind::Z16);
- case 3: return static_cast<u8>(Tegra::PTEKind::S8Z24);
- case 6: return static_cast<u8>(Tegra::PTEKind::GENERIC_16BX2);
- default: return std::nullopt;
- }
-}
-
-struct NativeMemoryKind {
- u8 backend;
- u8 selected;
-};
-
-inline std::optional<NativeMemoryKind> SelectNativeMemoryKind(u8 requested, u8 fallback) {
- if (const auto kind = TranslateNativeUncompressedKind(requested, fallback)) {
- return NativeMemoryKind{*kind, requested};
- }
- // The native caller supplies an uncompressed alternative explicitly. Return
- // that selected native kind so the SDK invalidates its compressed preference.
- if (requested == 8 && fallback == 6) {
- return NativeMemoryKind{static_cast<u8>(Tegra::PTEKind::GENERIC_16BX2), 6};
- }
- // TU104 kind 0x0c is the compressible S8Z24 variant; kind 3 is
- // the caller's uncompressed S8Z24 alternative (dev_mmu.ref.txt).
- if (requested == 0xb && fallback == 1) {
- return NativeMemoryKind{static_cast<u8>(Tegra::PTEKind::Z16), 1};
- }
- if (requested == 0xc && fallback == 3) {
- return NativeMemoryKind{static_cast<u8>(Tegra::PTEKind::S8Z24), 3};
- }
- return std::nullopt;
-}
-
-} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index cbcee2a938..d23ec63bae 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -27,9 +27,7 @@ namespace Service::Nvidia::Devices {
/// implement the ioctl interface.
class nvdevice {
public:
- enum class Type { Other, GpuChannel, GpuTsg, GpuAddressSpace };
- explicit nvdevice(Core::System& system_, Type type_ = Type::Other) : system{system_}, type{type_} {}
- Type GetType() const { return type; }
+ explicit nvdevice(Core::System& system_) : system{system_} {}
virtual ~nvdevice() = default;
/**
@@ -82,8 +80,6 @@ public:
protected:
Core::System& system;
-private:
- const Type type;
};
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 0db83215ca..b8a8979315 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -5,24 +5,17 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <boost/container/small_vector.hpp>
-#include <cstdlib>
-#include <fstream>
-#include <filesystem>
-#include "core/frontend/framebuffer_layout.h"
-#include "video_core/renderer_base.h"
#include "common/adpf.h"
#include "common/assert.h"
#include "common/logging.h"
#include "core/core.h"
-#include "core/hle/kernel/k_process.h"
#include "core/core_timing.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvdrv/devices/nvdisp_disp0.h"
#include "core/perf_stats.h"
#include "video_core/gpu.h"
-#include "video_core/host1x/host1x.h"
namespace Service::Nvidia::Devices {
@@ -74,9 +67,6 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
output_fences.reserve(sorted_layers.size());
for (auto& layer : sorted_layers) {
- const auto handle = nvmap.GetHandle(layer.buffer_handle);
- const auto* session = handle ? container.GetSession(handle->session_id) : nullptr;
- const bool native_tiling = session && session->process->UsesPAuthReturns();
output_layers.emplace_back(Tegra::FramebufferConfig{
.address = nvmap.GetHandleAddress(layer.buffer_handle),
.offset = layer.offset,
@@ -87,7 +77,6 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
.transform_flags = layer.transform,
.crop_rect = layer.crop_rect,
.blending = ConvertBlending(layer.blending),
- .native_tiling = native_tiling,
.layer_stack_mask = layer.layer_stack_mask,
});
@@ -98,56 +87,6 @@ void nvdisp_disp0::Composite(std::span<const Nvnflinger::HwcLayer> sorted_layers
}
}
- const char* capture = std::getenv("EDEN_NATIVE_FRAME_CAPTURE");
- const bool sequence = std::getenv("EDEN_NATIVE_FRAME_SEQUENCE") != nullptr;
- const bool on_demand = std::getenv("EDEN_NATIVE_FRAME_ON_DEMAND") != nullptr;
- const bool requested = on_demand && !output_layers.empty() &&
- !diagnostic_frame_pending->load() && std::filesystem::exists("native-frame.request");
- if (requested) std::filesystem::remove("native-frame.request");
- const bool sample_frame = requested || (capture && std::string_view{capture} == "1" && !output_layers.empty() &&
- diagnostic_frame_count < (sequence ? 36000U : 3840U) && ++diagnostic_frame_count != 0 &&
- (sequence ? (diagnostic_frame_count == 1 || diagnostic_frame_count % 120 == 0)
- : !diagnostic_visible_frame->load()));
- if (sample_frame && !diagnostic_frame_pending->exchange(true)) {
- for (const auto& fence : output_fences) {
- LOG_INFO(Service_NVDRV, "Native composite waits for syncpoint={}/{}, current={}", fence.id, fence.value,
- system.Host1x().GetSyncpointManager().GetGuestSyncpointValue(fence.id));
- }
- LOG_INFO(Service_NVDRV, "Native composite submitted: layers={}, address={:#x}", output_layers.size(), output_layers.front().address);
- const auto layout = Layout::DefaultFrameLayout(1920, 1080);
- auto pixels = std::make_shared<std::vector<u8>>(layout.width * layout.height * 4);
- const bool first = diagnostic_frame_count == 1;
- auto pending = diagnostic_frame_pending;
- auto visible = diagnostic_visible_frame;
- system.GPU().Renderer().RequestScreenshot(pixels->data(), [pixels, layout, first, pending, visible, sequence, on_demand](bool invert_y) {
- std::array<u8, 18> header{};
- header[2] = 2;
- header[12] = static_cast<u8>(layout.width & 255);
- header[13] = static_cast<u8>(layout.width >> 8);
- header[14] = static_cast<u8>(layout.height & 255);
- header[15] = static_cast<u8>(layout.height >> 8);
- header[16] = 32;
- header[17] = invert_y ? 8 : 0x28;
- bool nonblack{};
- for (size_t i = 0; i < pixels->size(); i += 4) {
- if ((*pixels)[i] || (*pixels)[i + 1] || (*pixels)[i + 2]) {
- nonblack = true;
- break;
- }
- }
- const auto save = [&](const char* path) {
- std::ofstream out(path, std::ios::binary);
- out.write(reinterpret_cast<const char*>(header.data()), header.size());
- out.write(reinterpret_cast<const char*>(pixels->data()), pixels->size());
- return out.good();
- };
- if (first) save("native-first-frame.tga");
- const bool saved = (first || nonblack || sequence || on_demand) ? save("native-latest-frame.tga") : true;
- if (nonblack && !visible->load() && save("native-visible-frame.tga")) visible->store(true);
- LOG_INFO(Service_NVDRV, "Captured composited frame: {}x{}, saved={}, nonblack={}", layout.width, layout.height, saved, nonblack);
- pending->store(false);
- }, layout);
- }
system.GPU().RequestComposite(std::move(output_layers), std::move(output_fences));
Common::ADPF::ReportFrameInterval();
system.SpeedLimiter().DoSpeedLimiting(system.CoreTiming().GetGlobalTimeUs());
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index f795144ebe..ff0bfb2ec9 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -6,7 +6,6 @@
#pragma once
-#include <atomic>
#include <memory>
#include <vector>
#include "common/common_types.h"
@@ -46,9 +45,6 @@ public:
Kernel::KEvent* QueryEvent(u32 event_id) override;
private:
- u32 diagnostic_frame_count{};
- std::shared_ptr<std::atomic_bool> diagnostic_frame_pending{std::make_shared<std::atomic_bool>(false)};
- std::shared_ptr<std::atomic_bool> diagnostic_visible_frame{std::make_shared<std::atomic_bool>(false)};
NvCore::Container& container;
NvCore::NvMap& nvmap;
};
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index 947ea6088f..3c9e42f602 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -6,7 +6,6 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include <cstring>
-#include <limits>
#include <utility>
#include "common/alignment.h"
@@ -14,13 +13,10 @@
#include "common/common_types.h"
#include "common/logging.h"
#include "core/core.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/service/nvdrv/devices/gpu_address_space_layout.h"
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/core/nvmap.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_as_gpu.h"
-#include "core/hle/service/nvdrv/devices/native_gpu_kind.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "video_core/control/channel_state.h"
@@ -31,12 +27,10 @@
namespace Service::Nvidia::Devices {
nvhost_as_gpu::nvhost_as_gpu(Core::System& system_, Module& module_, NvCore::Container& core)
- : nvdevice{system_, Type::GpuAddressSpace}, module{module_}, container{core}, nvmap{core.GetNvMapFile()}, vm{},
+ : nvdevice{system_}, module{module_}, container{core}, nvmap{core.GetNvMapFile()}, vm{},
gmmu{} {}
-nvhost_as_gpu::~nvhost_as_gpu() {
- if (m_owner_process) { m_owner_process->Close(system.Kernel()); }
-}
+nvhost_as_gpu::~nvhost_as_gpu() = default;
NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::span<u8> output) {
@@ -57,10 +51,6 @@ NvResult nvhost_as_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> i
return WrapFixed(this, &nvhost_as_gpu::GetVARegions1, input, output);
case 0x9:
return WrapFixed(this, &nvhost_as_gpu::AllocAsEx, input, output);
- case 0xb:
- return WrapFixed(this, &nvhost_as_gpu::GetSyncpointShimInfo, input, output);
- case 0xc:
- return WrapFixed(this, &nvhost_as_gpu::ModifyKind, input, output);
case 0x14:
return WrapVariable(this, &nvhost_as_gpu::Remap, input, output);
default:
@@ -100,139 +90,11 @@ NvResult nvhost_as_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> i
return NvResult::NotImplemented;
}
-void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
- m_fd = fd;
- if (const auto* session = container.GetSession(session_id)) {
- m_owner_process = session->process;
- m_owner_process->Open(system.Kernel());
- m_extended_abi = m_owner_process->UsesPAuthReturns();
- }
-}
+void nvhost_as_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
void nvhost_as_gpu::OnClose(DeviceFD fd) {}
-NvResult nvhost_as_gpu::CreateNativeSparseRegion(u64 address, u64 size) {
- if (!m_extended_abi || !size || !Common::IsAligned(address, VM::YUZU_PAGESIZE) ||
- !Common::IsAligned(size, VM::YUZU_PAGESIZE) || (size >> VM::PAGE_SIZE_BITS) > 0xffffffffULL) {
- return NvResult::BadParameter;
- }
- {
- const std::scoped_lock lock{mutex};
- if (!vm.initialised || address < vm.va_range_start || address >= vm.va_range_split ||
- size > vm.va_range_split - address) { return NvResult::BadParameter; }
- const auto next = allocation_map.lower_bound(address);
- if ((next != allocation_map.end() && next->first < address + size) ||
- (next != allocation_map.begin() && std::prev(next)->first + std::prev(next)->second.size > address)) {
- return NvResult::BadParameter;
- }
- }
- IoctlAllocSpace reservation{};
- reservation.pages = static_cast<u32>(size >> VM::PAGE_SIZE_BITS);
- reservation.page_size = VM::YUZU_PAGESIZE;
- reservation.flags = MappingFlags::Fixed | MappingFlags::Sparse;
- reservation.offset = address;
- return AllocateSpace(reservation);
-}
-
-NvResult nvhost_as_gpu::DestroyNativeSparseRegion(u64 address, u64 size) {
- {
- const std::scoped_lock lock{mutex};
- const auto it = allocation_map.find(address);
- if (!m_extended_abi || it == allocation_map.end() || !it->second.sparse || it->second.size != size) {
- return NvResult::BadParameter;
- }
- }
- IoctlFreeSpace release{};
- release.offset = address;
- release.pages = static_cast<u32>(size >> VM::PAGE_SIZE_BITS);
- release.page_size = VM::YUZU_PAGESIZE;
- return FreeSpace(release);
-}
-
-NvResult nvhost_as_gpu::MapNative4K(u32 handle_id, u64 address, u64 buffer_offset, u64 size, u8 kind) {
- if (!m_extended_abi || !size || !Common::IsAligned(address, VM::YUZU_PAGESIZE) ||
- !Common::IsAligned(size, VM::YUZU_PAGESIZE) ||
- !Common::IsAligned(buffer_offset, VM::YUZU_PAGESIZE)) {
- return NvResult::BadParameter;
- }
- const auto handle = nvmap.GetHandle(handle_id);
- if (!handle || buffer_offset > handle->orig_size || size > handle->orig_size - buffer_offset) {
- return NvResult::BadParameter;
- }
- bool sparse_reservation = false;
- {
- const std::scoped_lock lock{mutex};
- if (!vm.initialised || address < vm.va_range_start || address >= vm.va_range_split ||
- size > vm.va_range_split - address) {
- return NvResult::BadParameter;
- }
- const auto upper = allocation_map.upper_bound(address);
- if (upper != allocation_map.begin()) {
- const auto owner = std::prev(upper);
- sparse_reservation = owner->second.sparse && address >= owner->first &&
- address - owner->first < owner->second.size && size <= owner->second.size - (address - owner->first);
- }
- const auto next = allocation_map.lower_bound(address);
- if (!sparse_reservation && ((next != allocation_map.end() && next->first < address + size) ||
- (next != allocation_map.begin() &&
- std::prev(next)->first + std::prev(next)->second.size > address))) {
- return NvResult::BadParameter;
- }
- }
- IoctlAllocSpace reservation{};
- reservation.pages = static_cast<u32>(size >> VM::PAGE_SIZE_BITS);
- reservation.page_size = VM::YUZU_PAGESIZE;
- reservation.flags = MappingFlags::Fixed;
- reservation.offset = address;
- const auto reserved = sparse_reservation ? NvResult::Success : AllocateSpace(reservation);
- if (reserved != NvResult::Success) { return reserved; }
- IoctlMapBufferEx mapping{};
- mapping.flags = MappingFlags::Fixed;
- mapping.kind = kind;
- mapping.handle = handle_id;
- mapping.page_size = VM::YUZU_PAGESIZE;
- mapping.buffer_offset = static_cast<s64>(buffer_offset);
- mapping.mapping_size = size;
- mapping.offset = static_cast<s64>(address);
- const auto result = MapBufferEx(mapping);
- if (result != NvResult::Success && !sparse_reservation) {
- nvmap.UnpinHandle(handle_id);
- IoctlFreeSpace release{};
- release.offset = address;
- release.pages = reservation.pages;
- release.page_size = VM::YUZU_PAGESIZE;
- FreeSpace(release);
- }
- return result;
-}
-
-NvResult nvhost_as_gpu::UnmapNative4K(u64 address, u64 size) {
- if (!m_extended_abi || !size || !Common::IsAligned(address, VM::YUZU_PAGESIZE) ||
- !Common::IsAligned(size, VM::YUZU_PAGESIZE)) {
- return NvResult::BadParameter;
- }
- bool sparse_mapping = false;
- {
- const std::scoped_lock lock{mutex};
- const auto it = mapping_map.find(address);
- sparse_mapping = it != mapping_map.end() && it->second.sparse_alloc && it->second.size == size;
- }
- if (sparse_mapping) {
- IoctlUnmapBuffer unmap{};
- unmap.offset = address;
- return UnmapBuffer(unmap);
- }
- IoctlFreeSpace release{};
- release.offset = address;
- release.pages = static_cast<u32>(size >> VM::PAGE_SIZE_BITS);
- release.page_size = VM::YUZU_PAGESIZE;
- return FreeSpace(release);
-}
-
-
NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
- LOG_DEBUG(Service_NVDRV, "called, flags={:#x}, as_fd={}, big_page_size={:#x}, reserved={:#x}, VA={:#x}/{:#x}/{:#x}",
- params.flags, params.as_fd, params.big_page_size, params.reserved,
- params.va_range_start, params.va_range_split, params.va_range_end);
+ LOG_DEBUG(Service_NVDRV, "called, big_page_size={:#x}", params.big_page_size);
std::scoped_lock lock(mutex);
@@ -241,43 +103,21 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
return NvResult::InvalidState;
}
- std::shared_ptr<nvhost_as_gpu> shared_parent;
- if (m_extended_abi && params.as_fd != 0) {
- if (params.as_fd == m_fd || params.flags != 5 || params.big_page_size != 0x1000 ||
- params.reserved != 0 || params.va_range_split != 0) { return NvResult::BadParameter; }
- const auto device = module.GetDevice<nvdevice>(params.as_fd);
- if (!device || device->GetType() != Type::GpuAddressSpace) { return NvResult::BadParameter; }
- shared_parent = std::static_pointer_cast<nvhost_as_gpu>(device);
- if (!shared_parent->m_extended_abi || !shared_parent->vm.initialised ||
- shared_parent->m_owner_process != m_owner_process ||
- params.va_range_start < shared_parent->vm.va_range_start ||
- params.va_range_start >= params.va_range_end ||
- params.va_range_end > shared_parent->vm.va_range_split) { return NvResult::BadParameter; }
- }
-
- const u32 big_page_size = GetGpuAddressSpaceBigPageSize(m_extended_abi, params.big_page_size);
- if (big_page_size) {
- if (!std::has_single_bit(big_page_size)) {
- LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: {:#x}!", big_page_size);
+ if (params.big_page_size) {
+ if (!std::has_single_bit(params.big_page_size)) {
+ LOG_ERROR(Service_NVDRV, "Non power-of-2 big page size: {:#x}!", params.big_page_size);
return NvResult::BadValue;
}
- if ((big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES) == 0) {
- LOG_ERROR(Service_NVDRV, "Unsupported big page size: {:#x}!", big_page_size);
+ if ((params.big_page_size & VM::SUPPORTED_BIG_PAGE_SIZES) == 0) {
+ LOG_ERROR(Service_NVDRV, "Unsupported big page size: {:#x}!", params.big_page_size);
return NvResult::BadValue;
}
- vm.big_page_size = big_page_size;
- vm.big_page_size_bits = static_cast<u32>(std::countr_zero(big_page_size));
-
- vm.va_range_start = big_page_size << VM::VA_START_SHIFT;
- }
+ vm.big_page_size = params.big_page_size;
+ vm.big_page_size_bits = static_cast<u32>(std::countr_zero(params.big_page_size));
- if (m_extended_abi && !params.va_range_start) {
- const auto layout = GetGpuAddressSpaceLayout(true);
- vm.va_range_start = layout.start;
- vm.va_range_split = layout.split;
- vm.va_range_end = layout.end;
+ vm.va_range_start = params.big_page_size << VM::VA_START_SHIFT;
}
// If this is unspecified then default values should be used
@@ -287,12 +127,6 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
vm.va_range_end = params.va_range_end;
}
- if (shared_parent) {
- // Native flags 5 expose the parent's small-page region as a separate
- // reservation view. GPU mappings must resolve through the same page table.
- vm.va_range_split = params.va_range_end;
- }
-
const u64 max_big_page_bits = Common::Log2Ceil(vm.va_range_end);
const auto start_pages{static_cast<u32>(vm.va_range_start >> VM::PAGE_SIZE_BITS)};
@@ -301,17 +135,11 @@ NvResult nvhost_as_gpu::AllocAsEx(IoctlAllocAsEx& params) {
const auto start_big_pages{static_cast<u32>(vm.va_range_split >> vm.big_page_size_bits)};
const auto end_big_pages{
- static_cast<u32>(vm.va_range_end >> vm.big_page_size_bits)};
+ static_cast<u32>((vm.va_range_end - vm.va_range_split) >> vm.big_page_size_bits)};
vm.big_page_allocator.emplace(start_big_pages, end_big_pages);
- if (shared_parent) {
- m_shared_parent = std::move(shared_parent);
- gmmu = m_shared_parent->gmmu;
- LOG_DEBUG(Service_NVDRV, "native AS view fd={} shares page table with fd={}", m_fd, params.as_fd);
- } else {
- gmmu = std::make_shared<Tegra::MemoryManager>(system, max_big_page_bits, vm.va_range_split, vm.big_page_size_bits, VM::PAGE_SIZE_BITS);
- system.GPU().InitAddressSpace(*gmmu);
- }
+ gmmu = std::make_unique<Tegra::MemoryManager>(system, max_big_page_bits, vm.va_range_split, vm.big_page_size_bits, VM::PAGE_SIZE_BITS);
+ system.GPU().InitAddressSpace(*gmmu);
vm.initialised = true;
return NvResult::Success;
@@ -331,7 +159,7 @@ NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
return NvResult::BadValue;
}
- if (!m_extended_abi && params.page_size != vm.big_page_size &&
+ if (params.page_size != vm.big_page_size &&
((params.flags & MappingFlags::Sparse) != MappingFlags::None)) {
UNIMPLEMENTED_MSG("Sparse small pages are not implemented!");
return NvResult::NotImplemented;
@@ -356,7 +184,7 @@ NvResult nvhost_as_gpu::AllocateSpace(IoctlAllocSpace& params) {
u64 size{static_cast<u64>(params.pages) * params.page_size};
if ((params.flags & MappingFlags::Sparse) != MappingFlags::None) {
- gmmu->MapSparse(params.offset, size, params.page_size != VM::YUZU_PAGESIZE);
+ gmmu->MapSparse(params.offset, size);
}
allocation_map[params.offset] = {
@@ -389,7 +217,6 @@ bool nvhost_as_gpu::FreeMappingLocked(u64 offset) noexcept {
gmmu->Unmap(offset, mapping.size);
}
mapping_map.erase(offset);
- map_buffer_offsets.erase(static_cast<s64>(offset));
return true;
}
return false;
@@ -424,77 +251,6 @@ NvResult nvhost_as_gpu::FreeSpace(IoctlFreeSpace& params) {
return NvResult::BadValue;
}
-NvResult nvhost_as_gpu::GetNativeSyncpointShim(u64& address, u32& stride, u32& count) {
- if (!m_extended_abi || !vm.initialised) { return NvResult::NotSupported; }
- address = vm.va_range_split - VM::YUZU_PAGESIZE;
- if (!m_syncpoint_shim_reserved) {
- IoctlAllocSpace allocation{};
- allocation.pages = 1;
- allocation.page_size = VM::YUZU_PAGESIZE;
- allocation.flags = MappingFlags::Fixed;
- allocation.offset = address;
- const auto result = AllocateSpace(allocation);
- if (result != NvResult::Success) { return result; }
- m_syncpoint_shim_reserved = true;
- gmmu->SetNativeSyncpointShim(address);
- }
- stride = sizeof(u32);
- count = 192;
- return NvResult::Success;
-}
-
-NvResult nvhost_as_gpu::GetSyncpointShimInfo(IoctlSyncpointShimInfo& params) {
- u64 address{};
- u32 stride{}, count{};
- const auto result = GetNativeSyncpointShim(address, stride, count);
- params.address = address;
- params.stride = stride;
- params.count = count;
- LOG_DEBUG(Service_NVDRV, "native syncpoint shim address={:#x}, stride={}, count={}, result={}",
- address, stride, count, static_cast<u32>(result));
- return result;
-}
-
-NvResult nvhost_as_gpu::ModifyNativeKind(u64 address, u64 size, u8 requested, u8 fallback) {
- IoctlModifyKind params{};
- params.compressed_kind = requested;
- params.uncompressed_kind = fallback;
- params.mapping_base = address;
- params.size = size;
- return ModifyKind(params);
-}
-
-NvResult nvhost_as_gpu::ModifyKind(IoctlModifyKind& params) {
- const u32 requested = params.compressed_kind;
- const u32 fallback = params.uncompressed_kind;
- const u64 base = params.mapping_base;
- const u64 offset = params.buffer_offset;
- const u64 size = params.size;
- LOG_DEBUG(Service_NVDRV, "native modify kind base={:#x}, offset={:#x}, size={:#x}, kinds={:#x}/{:#x}",
- base, offset, size, requested, fallback);
- if (!m_extended_abi || params.reserved != 0 || fallback > 255 ||
- (requested > 255 && requested != 0xffff) || !size ||
- offset > std::numeric_limits<u64>::max() - base ||
- !Common::IsAligned(base + offset, VM::YUZU_PAGESIZE) ||
- !Common::IsAligned(size, VM::YUZU_PAGESIZE)) {
- return NvResult::BadParameter;
- }
- const auto kind = SelectNativeMemoryKind(static_cast<u8>(requested == 0xffff ? fallback : requested),
- static_cast<u8>(fallback));
- if (!kind) { return NvResult::NotSupported; }
- const std::scoped_lock lock{mutex};
- const u64 address = base + offset;
- auto it = mapping_map.upper_bound(address);
- if (!vm.initialised || it == mapping_map.begin()) { return NvResult::BadParameter; }
- --it;
- const auto& mapping = it->second;
- const u64 delta = address - it->first;
- if (delta >= mapping.size || size > mapping.size - delta) { return NvResult::BadParameter; }
- gmmu->Map(address, mapping.ptr + delta, size, static_cast<Tegra::PTEKind>(kind->backend),
- mapping.big_page);
- return NvResult::Success;
-}
-
NvResult nvhost_as_gpu::Remap(std::span<IoctlRemapEntry> entries) {
LOG_DEBUG(Service_NVDRV, "called, num_entries={:#x}", entries.size());
@@ -658,13 +414,7 @@ NvResult nvhost_as_gpu::UnmapBuffer(IoctlUnmapBuffer& params) {
NvResult nvhost_as_gpu::BindChannel(IoctlBindChannel& params) {
LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
- const auto device = module.GetDevice<nvdevice>(params.fd);
- if (!device || device->GetType() != nvdevice::Type::GpuChannel) { return NvResult::BadParameter; }
- const auto gpu_channel_device = std::static_pointer_cast<nvhost_gpu>(device);
- if (!vm.initialised || !gmmu || (gpu_channel_device->channel_state->initialized &&
- gpu_channel_device->channel_state->memory_manager != gmmu.get())) { return NvResult::InvalidState; }
- gpu_channel_device->channel_state->memory_manager_owner =
- std::shared_ptr<Tegra::MemoryManager>(module.GetDevice<nvhost_as_gpu>(m_fd), gmmu.get());
+ auto gpu_channel_device = module.GetDevice<nvhost_gpu>(params.fd);
gpu_channel_device->channel_state->memory_manager = gmmu.get();
return NvResult::Success;
}
@@ -674,13 +424,13 @@ void nvhost_as_gpu::GetVARegionsImpl(IoctlGetVaRegions& params) {
params.regions = std::array<VaRegion, 2>{
VaRegion{
- .offset = GpuPageAddress(vm.small_page_allocator->GetVAStart(), VM::PAGE_SIZE_BITS),
+ .offset = vm.small_page_allocator->GetVAStart() << VM::PAGE_SIZE_BITS,
.page_size = VM::YUZU_PAGESIZE,
._pad0_{},
.pages = vm.small_page_allocator->GetVALimit() - vm.small_page_allocator->GetVAStart(),
},
VaRegion{
- .offset = GpuPageAddress(vm.big_page_allocator->GetVAStart(), vm.big_page_size_bits),
+ .offset = vm.big_page_allocator->GetVAStart() << vm.big_page_size_bits,
.page_size = vm.big_page_size,
._pad0_{},
.pages = vm.big_page_allocator->GetVALimit() - vm.big_page_allocator->GetVAStart(),
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index 8c7306e42a..b13b1c9efa 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -64,13 +64,6 @@ public:
Kernel::KEvent* QueryEvent(u32 event_id) override;
- NvResult CreateNativeSparseRegion(u64 address, u64 size);
- NvResult DestroyNativeSparseRegion(u64 address, u64 size);
- NvResult MapNative4K(u32 handle, u64 address, u64 buffer_offset, u64 size, u8 kind);
- NvResult UnmapNative4K(u64 address, u64 size);
- NvResult GetNativeSyncpointShim(u64& address, u32& stride, u32& count);
- NvResult ModifyNativeKind(u64 address, u64 size, u8 requested, u8 fallback);
-
struct VaRegion {
u64 offset;
u32 page_size;
@@ -152,25 +145,6 @@ private:
static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(VaRegion) * 2,
"IoctlGetVaRegions is incorrect size");
- struct IoctlSyncpointShimInfo {
- u64_le address;
- u32_le stride;
- u32_le count;
- };
- static_assert(sizeof(IoctlSyncpointShimInfo) == 16);
- NvResult GetSyncpointShimInfo(IoctlSyncpointShimInfo& params);
-
- struct IoctlModifyKind {
- u16_le compressed_kind;
- u16_le uncompressed_kind;
- u32_le reserved;
- u64_le buffer_offset;
- u64_le size;
- u64_le mapping_base;
- };
- static_assert(sizeof(IoctlModifyKind) == 32);
- NvResult ModifyKind(IoctlModifyKind& params);
-
NvResult AllocAsEx(IoctlAllocAsEx& params);
NvResult AllocateSpace(IoctlAllocSpace& params);
NvResult Remap(std::span<IoctlRemapEntry> params);
@@ -222,12 +196,6 @@ private:
std::map<u64, Allocation> allocation_map;
std::mutex mutex; //!< Locks all AS operations
- bool m_extended_abi{};
- bool m_syncpoint_shim_reserved{};
- DeviceFD m_fd{-1};
- Kernel::KProcess* m_owner_process{};
- std::shared_ptr<nvhost_as_gpu> m_shared_parent;
-
struct VM {
static constexpr u32 YUZU_PAGESIZE{0x1000};
static constexpr u32 PAGE_SIZE_BITS{static_cast<u32>(std::countr_zero<u32>(YUZU_PAGESIZE))};
@@ -251,7 +219,7 @@ private:
bool initialised{};
} vm;
- std::shared_ptr<Tegra::MemoryManager> gmmu;
+ std::unique_ptr<Tegra::MemoryManager> gmmu;
};
} // namespace Service::Nvidia::Devices
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 6684352b00..14cdd8fda4 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -4,7 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <algorithm>
#include <cstring>
#include "common/assert.h"
#include "common/logging.h"
@@ -12,7 +11,6 @@
#include "core/core_timing.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
-#include "core/hle/service/nvdrv/devices/native_gpu_characteristics.h"
#include "core/hle/service/nvdrv/nvdrv.h"
namespace Service::Nvidia::Devices {
@@ -96,25 +94,6 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8>
case 'G':
switch (command.cmd) {
case 0x5:
- if (command.raw == 0xc0e04705) {
- constexpr size_t packet_size = 0x10 + NativeGpuCharacteristicsSize;
- if (input.size() < packet_size || output.size() < packet_size ||
- inline_output.size() < NativeGpuCharacteristicsSize) {
- return NvResult::BadParameter;
- }
- IoctlCharacteristics legacy{};
- GetCharacteristics3(legacy, {});
- const auto native = MakeNativeGpuCharacteristics(
- std::span<const u8, 0xa0>{reinterpret_cast<const u8*>(&legacy.gc), 0xa0});
- std::fill(output.begin(), output.end(), u8{});
- std::fill(inline_output.begin(), inline_output.end(), u8{});
- std::memcpy(output.data(), input.data(), 0x10);
- const u64_le size{NativeGpuCharacteristicsSize};
- std::memcpy(output.data(), &size, sizeof(size));
- std::memcpy(output.data() + 0x10, native.data(), native.size());
- std::memcpy(inline_output.data(), native.data(), native.size());
- return NvResult::Success;
- }
return WrapFixedInlOut(this, &nvhost_ctrl_gpu::GetCharacteristics3, input, output,
inline_output);
case 0x6:
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index 6b9678e440..1e571be4c9 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -4,8 +4,6 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstdlib>
-#include <fstream>
#include <cstring>
#include "common/assert.h"
#include "common/logging.h"
@@ -16,13 +14,11 @@
#include "core/hle/service/nvdrv/core/syncpoint_manager.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
-#include "core/hle/service/nvdrv/devices/native_gpu_context.h"
#include "core/hle/service/nvdrv/nvdrv.h"
#include "core/memory.h"
#include "video_core/control/channel_state.h"
#include "video_core/engines/puller.h"
#include "video_core/gpu.h"
-#include "video_core/memory_manager.h"
#include "video_core/host1x/host1x.h"
namespace Service::Nvidia::Devices {
@@ -37,7 +33,7 @@ Tegra::CommandHeader BuildFenceAction(Tegra::Engines::Puller::FenceOperation op,
nvhost_gpu::nvhost_gpu(Core::System& system_, EventInterface& events_interface_,
NvCore::Container& core_)
- : nvdevice{system_, Type::GpuChannel}, events_interface{events_interface_}, core{core_},
+ : nvdevice{system_}, events_interface{events_interface_}, core{core_},
syncpoint_manager{core_.GetSyncpointManager()}, nvmap{core.GetNvMapFile()},
channel_state{system.GPU().AllocateChannel()} {
channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false);
@@ -132,7 +128,6 @@ NvResult nvhost_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
void nvhost_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
sessions[fd] = session_id;
- channel_state->native_abi = UsesNativeAbi();
}
void nvhost_gpu::OnClose(DeviceFD fd) {
@@ -285,9 +280,6 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
s32_le ctx_class_number_index =
GetObjectContextClassNumberIndex(static_cast<CtxClasses>(params.class_num));
- if (const auto native_slot = GetNativeGpuContextSlot(params.class_num)) {
- if (UsesNativeAbi()) { ctx_class_number_index = *native_slot; }
- }
if (ctx_class_number_index < 0) {
LOG_ERROR(Service_NVDRV, "Invalid class number for object context: {:#x}",
params.class_num);
@@ -319,13 +311,13 @@ static boost::container::small_vector<Tegra::CommandHeader, 512> BuildWaitComman
}
static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementCommandList(
- NvFence fence, u32 increment_count = 2) {
+ NvFence fence) {
boost::container::small_vector<Tegra::CommandHeader, 512> result{
Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointPayload, 1,
Tegra::SubmissionMode::Increasing),
{}};
- for (u32 count = 0; count < increment_count; ++count) {
+ for (u32 count = 0; count < 2; ++count) {
result.push_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::SyncpointOperation, 1,
Tegra::SubmissionMode::Increasing));
result.push_back(
@@ -336,12 +328,12 @@ static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementC
}
static boost::container::small_vector<Tegra::CommandHeader, 512> BuildIncrementWithWfiCommandList(
- NvFence fence, u32 increment_count = 2) {
+ NvFence fence) {
boost::container::small_vector<Tegra::CommandHeader, 512> result{
Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForIdle, 1,
Tegra::SubmissionMode::Increasing),
{}};
- auto increment_list{BuildIncrementCommandList(fence, increment_count)};
+ auto increment_list{BuildIncrementCommandList(fence)};
result.insert(result.end(), increment_list.begin(), increment_list.end());
return result;
}
@@ -359,41 +351,6 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
system.GPU().InitChannel(*channel_state, channel_state->program_id);
}
- if (UsesNativeAbi() && native_submit_logs++ < 8) {
- LOG_DEBUG(Service_NVDRV, "native submit channel={}, initialized={}, entries={}, flags={:#x}, fence={}:{}",
- channel_state->bind_id, channel_state->initialized, entries.command_lists.size(),
- params.flags.raw, params.fence.id, params.fence.value);
- for (size_t i = 0; i < std::min<size_t>(entries.command_lists.size(), 4); ++i) {
- const auto& entry = entries.command_lists[i];
- std::array<u32, 16> words{};
- const size_t bytes = std::min<size_t>(entry.size * sizeof(u32), sizeof(words));
- const bool mapped = channel_state->memory_manager && bytes &&
- channel_state->memory_manager->IsFullyMappedRange(entry.addr, bytes);
- if (mapped) { channel_state->memory_manager->ReadBlockUnsafe(entry.addr, words.data(), bytes); }
- if (mapped && entry.size > 1000 && std::getenv("EDEN_NATIVE_FRAME_CAPTURE")) {
- std::vector<u32> contents(static_cast<size_t>(entry.size));
- channel_state->memory_manager->ReadBlockUnsafe(entry.addr, contents.data(), contents.size() * sizeof(u32));
- std::ofstream dump("native-init-channel-" + std::to_string(channel_state->bind_id) + "-" + std::to_string(i) + ".bin", std::ios::binary);
- dump.write(reinterpret_cast<const char*>(contents.data()), contents.size() * sizeof(u32));
- }
- LOG_DEBUG(Service_NVDRV, "native pushbuffer entry={} raw={:#x}, address={:#x}, words={}, mapped={}, data={:08x}",
- i, entry.raw, static_cast<u64>(entry.addr), static_cast<u64>(entry.size),
- mapped, fmt::join(words, ","));
- }
- }
-
- if (UsesNativeAbi() && std::getenv("EDEN_NATIVE_FRAME_CAPTURE") && native_submit_logs < 100) {
- for (size_t i = 0; i < entries.command_lists.size(); ++i) {
- const auto& entry = entries.command_lists[i];
- const auto bytes = static_cast<size_t>(entry.size) * sizeof(u32);
- if (!bytes || bytes > 0x100000 || !channel_state->memory_manager->IsFullyMappedRange(entry.addr, bytes)) continue;
- std::vector<u32> contents(static_cast<size_t>(entry.size));
- channel_state->memory_manager->ReadBlockUnsafe(entry.addr, contents.data(), bytes);
- std::ofstream dump("native-submit-" + std::to_string(channel_state->bind_id) + "-" + std::to_string(native_submit_logs) + "-" + std::to_string(i) + ".bin", std::ios::binary);
- dump.write(reinterpret_cast<const char*>(contents.data()), bytes);
- }
- }
-
const auto bind_id = channel_state->bind_id;
auto& flags = params.flags;
@@ -408,8 +365,6 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
}
}
- const u32 native_completion = UsesNativeAbi() && flags.increment_value.Value() && !flags.fence_increment.Value() ? params.fence.value : 0;
- if (native_completion > 64) return NvResult::BadParameter;
params.fence.id = channel_syncpoint;
u32 increment{(flags.fence_increment.Value() != 0 ? 2 : 0) +
@@ -427,14 +382,6 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
}
}
- if (native_completion) {
- // The native C56F stream reports its completion count without emitting
- // host syncpoint methods. Order actual increments after that GPU work.
- gpu.PushGPUEntries(bind_id, Tegra::CommandList{flags.suppress_wfi.Value()
- ? BuildIncrementCommandList(params.fence, native_completion)
- : BuildIncrementWithWfiCommandList(params.fence, native_completion)});
- LOG_DEBUG(Service_NVDRV, "Native ordered completion: syncpoint={}, increments={}, target={}", channel_syncpoint, native_completion, params.fence.value);
- }
flags.raw = 0;
return NvResult::Success;
@@ -516,46 +463,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) {
return sm_exception_breakpoint_pause_report_event;
case 3:
return error_notifier_event;
- case 7:
- // The native SDK requests this event immediately before configuring
- // CHANNEL_SET_ERROR_NOTIFIER, then wraps it in its channel error wait.
- return UsesNativeAbi() ? error_notifier_event : nullptr;
default:
LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id);
return nullptr;
}
}
-NvResult nvhost_gpu::BindToTsg(DeviceFD group, Kernel::KProcess* process, std::shared_ptr<Tegra::NativeMacroContext> macros) {
- const std::scoped_lock lock{tsg_mutex};
- if (tsg_group) { return NvResult::Busy; }
- bool owned{};
- for (const auto& [fd, session_id] : sessions) {
- const auto* session = core.GetSession(session_id);
- owned |= session && session->process == process;
- }
- if (!owned) { return NvResult::AccessDenied; }
- if (channel_state->native_abi) {
- channel_state->native_macro_context = std::move(macros);
- if (channel_state->payload) {
- channel_state->payload->maxwell_3d.SetNativeMacroContext(channel_state->native_macro_context);
- }
- }
- tsg_group = group;
- return NvResult::Success;
-}
-
-void nvhost_gpu::UnbindFromTsg(DeviceFD group) {
- const std::scoped_lock lock{tsg_mutex};
- if (tsg_group == group) { tsg_group.reset(); }
-}
-
-bool nvhost_gpu::UsesNativeAbi() const {
- for (const auto& [fd, session_id] : sessions) {
- const auto* session = core.GetSession(session_id);
- if (session && session->process && session->process->UsesPAuthReturns()) { return true; }
- }
- return false;
-}
-
} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index 8219e4afea..70a6b1bd68 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -7,8 +7,6 @@
#pragma once
#include <memory>
-#include <mutex>
-#include <optional>
#include <vector>
#include "common/bit_field.h"
#include "common/common_funcs.h"
@@ -22,10 +20,7 @@ namespace Core::Memory {
class Memory;
}
-namespace Kernel { class KProcess; }
-
namespace Tegra {
-struct NativeMacroContext;
namespace Control {
struct ChannelState;
}
@@ -63,12 +58,9 @@ public:
void OnClose(DeviceFD fd) override;
Kernel::KEvent* QueryEvent(u32 event_id) override;
- NvResult BindToTsg(DeviceFD group, Kernel::KProcess* process, std::shared_ptr<Tegra::NativeMacroContext> macros);
- void UnbindFromTsg(DeviceFD group);
private:
friend class nvhost_as_gpu;
- bool UsesNativeAbi() const;
enum class CtxClasses : u32_le {
Ctx2D = 0x902D,
Ctx3D = 0xB197,
@@ -226,9 +218,6 @@ private:
NvCore::NvMap& nvmap;
std::shared_ptr<Tegra::Control::ChannelState> channel_state;
::Common::unordered_map<DeviceFD, NvCore::SessionId> sessions;
- std::mutex tsg_mutex;
- std::optional<DeviceFD> tsg_group;
- u32 native_submit_logs{};
u32 channel_syncpoint;
std::mutex channel_mutex;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.cpp
deleted file mode 100644
index ae9d2a50f5..0000000000
--- a/src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.cpp
+++ /dev/null
@@ -1,85 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#include <algorithm>
-#include <array>
-#include <cstring>
-#include "common/logging.h"
-#include "core/core.h"
-#include "video_core/macro.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/service/nvdrv/nvdrv.h"
-#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
-#include "core/hle/service/nvdrv/devices/nvhost_tsg_gpu.h"
-
-namespace Service::Nvidia::Devices {
-
-nvhost_tsg_gpu::nvhost_tsg_gpu(Core::System& system, Module& module_, NvCore::Container& core_)
- : nvdevice{system, Type::GpuTsg}, native_macros{std::make_shared<Tegra::NativeMacroContext>()}, module{module_}, core{core_} { native_macros->engine.native_turing = true; native_macros->compute_engine.native_turing = true; }
-
-nvhost_tsg_gpu::~nvhost_tsg_gpu() { OnClose(0); }
-
-void nvhost_tsg_gpu::OnOpen(NvCore::SessionId id, DeviceFD fd) {
- group_fd = fd;
- if (const auto* session = core.GetSession(id)) {
- process = session->process;
- process->Open(system.Kernel());
- }
-}
-
-void nvhost_tsg_gpu::OnClose(DeviceFD fd) {
- for (const auto& [channel_fd, channel] : channels) { channel->UnbindFromTsg(group_fd); }
- channels.clear();
- if (process) {
- process->Close(system.Kernel());
- process = nullptr;
- }
-}
-
-
-NvResult nvhost_tsg_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
- std::span<u8> output) {
- std::array<u32, 8> words{};
- if (!input.empty()) { std::memcpy(words.data(), input.data(), std::min(input.size(), sizeof(words))); }
- LOG_DEBUG(Service_NVDRV, "native TSG ioctl={:#x}, input={}, output={}, words={:#x},{:#x},{:#x},{:#x},{:#x},{:#x},{:#x},{:#x}",
- command.raw, input.size(), output.size(), words[0], words[1], words[2], words[3],
- words[4], words[5], words[6], words[7]);
- if (command.raw != 0xc0045401 && command.raw != 0xc0045402 && command.raw != 0xc018540b) { return NvResult::NotImplemented; }
- const size_t packet_size = command.raw == 0xc018540b ? 24 : 4;
- if (!process || input.size() != packet_size || output.size() != packet_size) {
- return NvResult::BadParameter;
- }
- if (packet_size == 24 && (words[1] >= 64 || words[2] || words[3] || words[4] || words[5])) {
- return NvResult::BadParameter;
- }
- const DeviceFD channel_fd = static_cast<s32>(words[0]);
- if (command.cmd == 1 || command.cmd == 11) {
- if (channels.contains(channel_fd)) { return NvResult::Busy; }
- if (channels.size() >= 64) { return NvResult::InsufficientMemory; }
- const auto device = module.GetDevice<nvdevice>(channel_fd);
- if (!device || device->GetType() != Type::GpuChannel) { return NvResult::BadParameter; }
- const auto channel = std::static_pointer_cast<nvhost_gpu>(device);
- const auto result = channel->BindToTsg(fd, process, native_macros);
- if (result != NvResult::Success) { return result; }
- channels.emplace(channel_fd, channel);
- } else {
- const auto it = channels.find(channel_fd);
- if (it == channels.end()) { return NvResult::BadParameter; }
- it->second->UnbindFromTsg(fd);
- channels.erase(it);
- }
- std::copy(input.begin(), input.end(), output.begin());
- return NvResult::Success;
-}
-
-NvResult nvhost_tsg_gpu::Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
- std::span<const u8> inline_input, std::span<u8> output) {
- return NvResult::NotImplemented;
-}
-
-NvResult nvhost_tsg_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
- std::span<u8> output, std::span<u8> inline_output) {
- return NvResult::NotImplemented;
-}
-
-} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.h
deleted file mode 100644
index d64c5df3e0..0000000000
--- a/src/core/hle/service/nvdrv/devices/nvhost_tsg_gpu.h
+++ /dev/null
@@ -1,38 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
-// SPDX-License-Identifier: GPL-3.0-or-later
-
-#pragma once
-
-#include <map>
-#include <memory>
-#include "core/hle/service/nvdrv/devices/nvdevice.h"
-
-namespace Tegra { struct NativeMacroContext; }
-namespace Kernel { class KProcess; }
-namespace Service::Nvidia { class Module; }
-
-namespace Service::Nvidia::Devices {
-class nvhost_gpu;
-
-class nvhost_tsg_gpu final : public nvdevice {
-public:
- nvhost_tsg_gpu(Core::System& system, Module& module, NvCore::Container& core);
- ~nvhost_tsg_gpu() override;
- NvResult Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> input,
- std::span<u8> output) override;
- NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
- std::span<const u8> inline_input, std::span<u8> output) override;
- NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
- std::span<u8> output, std::span<u8> inline_output) override;
- void OnOpen(NvCore::SessionId session, DeviceFD fd) override;
- void OnClose(DeviceFD fd) override;
-private:
- std::shared_ptr<Tegra::NativeMacroContext> native_macros;
- Module& module;
- NvCore::Container& core;
- Kernel::KProcess* process{};
- DeviceFD group_fd{-1};
- std::map<DeviceFD, std::shared_ptr<nvhost_gpu>> channels;
-};
-
-} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 9873d07c24..b252a2efa5 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -18,8 +18,6 @@
#include "core/hle/service/nvdrv/devices/nvhost_ctrl.h"
#include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h"
#include "core/hle/service/nvdrv/devices/nvhost_gpu.h"
-#include "core/hle/service/nvdrv/devices/nvhost_tsg_gpu.h"
-#include "core/hle/kernel/k_process.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvjpg.h"
@@ -135,10 +133,6 @@ Module::Module(Core::System& system)
auto device = std::make_shared<Devices::nvhost_gpu>(system, events_interface, container);
return open_files.emplace(fd, std::move(device)).first;
};
- builders["/dev/nvhost-tsg-gpu"] = [this, &system](DeviceFD fd) {
- auto device = std::make_shared<Devices::nvhost_tsg_gpu>(system, *this, container);
- return open_files.emplace(fd, std::move(device)).first;
- };
builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) {
auto device = std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface);
return open_files.emplace(fd, std::move(device)).first;
@@ -169,12 +163,7 @@ Module::Module(Core::System& system)
};
}
-Module::~Module() {
- // Devices (including TSG-retained channels) release events and core state.
- // Destroy them while those module members are still alive.
- for (const auto& [fd, device] : open_files) { device->OnClose(fd); }
- open_files.clear();
-}
+Module::~Module() {}
NvResult Module::VerifyFD(DeviceFD fd) const {
if (fd < 0) {
@@ -191,12 +180,6 @@ NvResult Module::VerifyFD(DeviceFD fd) const {
}
DeviceFD Module::Open(const std::string& device_name, NvCore::SessionId session_id) {
- if (device_name == "/dev/nvhost-tsg-gpu") {
- const auto* session = container.GetSession(session_id);
- if (!session || !session->process || !session->process->UsesPAuthReturns()) {
- return INVALID_NVDRV_FD;
- }
- }
auto it = builders.find(device_name);
if (it == builders.end()) {
LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.cpp b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
index 3f81720a39..5fae68adbb 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.cpp
@@ -72,10 +72,6 @@ void NVDRV::Ioctl1(HLERequestContext& ctx) {
const auto input_buffer = ctx.ReadBuffer(0);
const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
- if (nv_result != NvResult::Success && ctx.GetThread().GetOwnerProcess()->UsesPAuthReturns()) {
- LOG_DEBUG(Service_NVDRV, "native ioctl failure fd={}, ioctl={:#x}, result={}, caller={:#x}",
- fd, command.raw, static_cast<u32>(nv_result), ctx.GetThread().GetContext().lr);
- }
if (command.is_out != 0) {
ctx.WriteBuffer(output_buffer);
}
@@ -103,10 +99,6 @@ void NVDRV::Ioctl2(HLERequestContext& ctx) {
const auto nv_result =
nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
- if (nv_result != NvResult::Success && ctx.GetThread().GetOwnerProcess()->UsesPAuthReturns()) {
- LOG_DEBUG(Service_NVDRV, "native ioctl failure fd={}, ioctl={:#x}, result={}, caller={:#x}",
- fd, command.raw, static_cast<u32>(nv_result), ctx.GetThread().GetContext().lr);
- }
if (command.is_out != 0) {
ctx.WriteBuffer(output_buffer);
}
@@ -134,11 +126,6 @@ void NVDRV::Ioctl3(HLERequestContext& ctx) {
const auto nv_result =
nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, inline_output_buffer);
- if (command.raw == 0xc0e04705) {
- LOG_DEBUG(Service_NVDRV, "native characteristics input={}, output={}, inline={}, result={}",
- input_buffer.size(), output_buffer.size(), inline_output_buffer.size(),
- static_cast<u32>(nv_result));
- }
if (command.is_out != 0) {
ctx.WriteBuffer(output_buffer, 0);
ctx.WriteBuffer(inline_output_buffer, 1);
@@ -198,10 +185,6 @@ void NVDRV::QueryEvent(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto fd = rp.Pop<DeviceFD>();
const auto event_id = rp.Pop<u32>();
- if (ctx.GetThread().GetOwnerProcess()->UsesPAuthReturns()) {
- LOG_DEBUG(Service_NVDRV, "native QueryEvent fd={}, id={}, caller={:#x}", fd, event_id,
- ctx.GetThread().GetContext().lr);
- }
if (!is_initialized) {
ServiceError(ctx, NvResult::NotInitialized);
@@ -282,14 +265,6 @@ NVDRV::NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char*
RegisterHandlers(functions);
}
-NVDRV::NVDRV(Core::System& system, std::shared_ptr<Module> module, const char* name,
- Kernel::KProcess* process, u64 aruid)
- : NVDRV{system, std::move(module), name} {
- session_id = nvdrv->GetContainer().OpenSession(process);
- pid = aruid;
- is_initialized = true;
-}
-
NVDRV::~NVDRV() {
if (is_initialized) {
auto& container = nvdrv->GetContainer();
diff --git a/src/core/hle/service/nvdrv/nvdrv_interface.h b/src/core/hle/service/nvdrv/nvdrv_interface.h
index d6fe4c18f5..f628fca7df 100644
--- a/src/core/hle/service/nvdrv/nvdrv_interface.h
+++ b/src/core/hle/service/nvdrv/nvdrv_interface.h
@@ -17,8 +17,6 @@ namespace Service::Nvidia {
class NVDRV final : public ServiceFramework<NVDRV> {
public:
explicit NVDRV(Core::System& system_, std::shared_ptr<Module> nvdrv_, const char* name);
- explicit NVDRV(Core::System& system, std::shared_ptr<Module> module, const char* name,
- Kernel::KProcess* process, u64 aruid);
~NVDRV() override;
std::shared_ptr<Module> GetModule() const {
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
index 9de8abaeb6..c3eb2796e3 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.cpp
@@ -393,15 +393,6 @@ Status BufferQueueProducer::DetachNextBuffer(std::shared_ptr<GraphicBuffer>* out
return Status::NoError;
}
-std::optional<Fence> BufferQueueProducer::GetReleasedBufferFence(s32 slot) {
- const std::scoped_lock lock{core->mutex};
- if (slot < 0 || static_cast<size_t>(slot) >= slots.size() ||
- slots[slot].buffer_state != BufferState::Free) {
- return std::nullopt;
- }
- return slots[slot].fence;
-}
-
Status BufferQueueProducer::AttachBuffer(s32* out_slot,
const std::shared_ptr<GraphicBuffer>& buffer) {
if (out_slot == nullptr) {
diff --git a/src/core/hle/service/nvnflinger/buffer_queue_producer.h b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
index bf815eb8d8..697de0ac9b 100644
--- a/src/core/hle/service/nvnflinger/buffer_queue_producer.h
+++ b/src/core/hle/service/nvnflinger/buffer_queue_producer.h
@@ -12,7 +12,6 @@
#include <condition_variable>
#include <memory>
#include <mutex>
-#include <optional>
#include "common/common_funcs.h"
#include "common/cpu_features.h"
@@ -58,7 +57,6 @@ public:
Kernel::KReadableEvent* GetNativeHandle(u32 type_id) override;
public:
- std::optional<Fence> GetReleasedBufferFence(s32 slot);
Status RequestBuffer(s32 slot, std::shared_ptr<GraphicBuffer>* buf);
Status SetBufferCount(s32 buffer_count);
Status DequeueBuffer(s32* out_slot, android::Fence* out_fence, bool async, u32 width,
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a7e7e10199..b4fe2b3ed5 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -4,16 +4,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <chrono>
-#include <limits>
#include <fmt/ranges.h>
#include "common/assert.h"
#include "common/logging.h"
#include "common/settings.h"
#include "core/core.h"
#include "core/hle/ipc.h"
-#include "core/hle/kernel/k_process.h"
-#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/kernel.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/service.h"
@@ -71,26 +67,6 @@ void ServiceFrameworkBase::ReportUnimplementedFunction(HLERequestContext& ctx,
fmt::format_to(std::back_inserter(buf), ", [{}]={:#x}", i, cmd_buf[i]);
buf.push_back('}');
- if (ctx.GetThread().GetOwnerProcess()->UsesPAuthReturns()) {
- const auto& context = ctx.GetThread().GetContext();
- LOG_DEBUG(Service, "Unsupported IPC caller pc={:#x}, lr={:#x}, sp={:#x}, fp={:#x}",
- context.pc, context.lr, context.sp, context.fp);
- u64 frame = context.fp;
- for (u32 depth = 0; depth < 8 && frame != 0; ++depth) {
- if (frame > (std::numeric_limits<u64>::max)() - 15 ||
- !ctx.GetMemory().IsValidVirtualAddress(frame) ||
- !ctx.GetMemory().IsValidVirtualAddress(frame + 15)) {
- break;
- }
- const u64 next = ctx.GetMemory().Read64(frame);
- LOG_DEBUG(Service, "Unsupported IPC frame {}: return={:#x}", depth,
- ctx.GetMemory().Read64(frame + 8));
- if (next <= frame) {
- break;
- }
- frame = next;
- }
- }
system.GetReporter().SaveUnimplementedFunctionReport(ctx, ctx.GetCommand(), function_name, service_name);
UNIMPLEMENTED_MSG("Unknown / unimplemented {}", fmt::to_string(buf));
if (Settings::values.use_auto_stub) {
@@ -106,7 +82,7 @@ void ServiceFrameworkBase::InvokeRequest(HLERequestContext& ctx) {
if (info == nullptr || info->handler_callback == nullptr)
return ReportUnimplementedFunction(ctx, info);
- LOG_DEBUG(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
+ LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
handler_invoker(this, info->handler_callback, ctx);
}
@@ -116,7 +92,7 @@ void ServiceFrameworkBase::InvokeRequestTipc(HLERequestContext& ctx) {
if (info == nullptr || info->handler_callback == nullptr)
return ReportUnimplementedFunction(ctx, info);
- LOG_DEBUG(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
+ LOG_TRACE(Service, "{}", MakeFunctionString(info->name, GetServiceName(), ctx.CommandBuffer()));
handler_invoker(this, info->handler_callback, ctx);
}
diff --git a/src/core/launch_params.cpp b/src/core/launch_params.cpp
index 814a2cb553..a0483226ec 100644
--- a/src/core/launch_params.cpp
+++ b/src/core/launch_params.cpp
@@ -94,7 +94,7 @@ LaunchParams ParseLaunchParams(Core::System& system, int argc, char *argv[], wch
break;
case 'u': {
// Launch game with a specific user
- bool argument_ok = isdigit(static_cast<unsigned char>(optarg[0])) != 0;
+ bool argument_ok = isdigit(optarg[0]);
p.selected_user = atoi(optarg);
if (!argument_ok) {
// try to look it up by username, only finds the first username that matches.
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp
index 1dce245f7f..5e2ec7e0b9 100644
--- a/src/core/loader/deconstructed_rom_directory.cpp
+++ b/src/core/loader/deconstructed_rom_directory.cpp
@@ -13,7 +13,6 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/romfs_factory.h"
-#include "core/file_sys/romfs.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/filesystem/filesystem.h"
@@ -130,14 +129,10 @@ AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(
: AppLoader(directory->GetFile("main"))
, dir(std::move(directory))
, override_update(override_update_)
- , standalone(false)
{}
FileType AppLoader_DeconstructedRomDirectory::IdentifyType(const FileSys::VirtualFile& dir_file) {
- const auto directory = dir_file->GetContainingDirectory();
- if (dir_file->GetName() == "main" && directory &&
- AppLoader_NSO::IdentifyType(dir_file) == FileType::NSO &&
- FileSys::IsDirectoryExeFS(directory)) {
+ if (FileSys::IsDirectoryExeFS(dir_file->GetContainingDirectory())) {
return FileType::DeconstructedRomDirectory;
}
@@ -187,11 +182,11 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
}
metadata.Print();
- // Extended ACID programs currently require the Dynarmic compatibility path.
+ // Enable NCE only for applications with 39-bit address space.
const bool is_39bit =
metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit;
const bool is_application = metadata.GetPoolPartition() == FileSys::PoolPartition::Application;
- Settings::SetNceEnabled(is_39bit && !metadata.UsesExtendedAcid());
+ Settings::SetNceEnabled(is_39bit);
const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2",
"subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7",
@@ -272,39 +267,11 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
}
is_loaded = true;
- if (standalone) {
- title_id = metadata.GetTitleID();
- system.GetFileSystemController().RegisterProcess(
- process.GetProcessId(), {},
- std::make_shared<FileSys::RomFSFactory>(*this, system.GetContentProvider(),
- system.GetFileSystemController()));
- }
return {ResultStatus::Success,
LoadParameters{metadata.GetMainThreadPriority(), metadata.GetMainThreadStackSize()}};
}
ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile& out_dir) {
- if (romfs == nullptr && standalone) {
- const auto directory = file->GetContainingDirectory();
- for (const auto& entry : directory->GetFiles()) {
- if (entry->GetExtension() == "romfs") {
- romfs = entry;
- break;
- }
- }
- if (romfs == nullptr) {
- auto loose = directory->GetSubdirectory("romfs");
- if (!loose && directory->GetName() == "exefs") {
- const auto parent = directory->GetParentDirectory();
- if (parent) {
- loose = parent->GetSubdirectory("romfs");
- }
- }
- if (loose) {
- romfs = FileSys::CreateRomFS(std::move(loose));
- }
- }
- }
if (romfs == nullptr) {
return ResultStatus::ErrorNoRomFS;
}
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h
index aba89935a3..7283db0662 100644
--- a/src/core/loader/deconstructed_rom_directory.h
+++ b/src/core/loader/deconstructed_rom_directory.h
@@ -62,7 +62,6 @@ private:
std::string name;
u64 title_id{};
bool override_update;
- bool standalone{true};
Modules modules;
};
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp
index d802d15e9f..92e2e2f602 100644
--- a/src/core/loader/loader.cpp
+++ b/src/core/loader/loader.cpp
@@ -125,10 +125,6 @@ bool HasApplicationProgramContent(const std::shared_ptr<FileSys::NSP>& nsp) {
} // namespace
FileType IdentifyFile(FileSys::VirtualFile file) {
- if (const auto romdir_type =
- IdentifyFileLoader<AppLoader_DeconstructedRomDirectory>(file)) {
- return *romdir_type;
- }
if (const auto nsp_type = IdentifyFileLoader<AppLoader_NSP>(file)) {
return *nsp_type;
} else if (const auto xci_type = IdentifyFileLoader<AppLoader_XCI>(file)) {
@@ -143,6 +139,9 @@ FileType IdentifyFile(FileSys::VirtualFile file) {
return *kip_type;
} else if (const auto nso_type = IdentifyFileLoader<AppLoader_NSO>(file)) {
return *nso_type;
+ } else if (const auto romdir_type =
+ IdentifyFileLoader<AppLoader_DeconstructedRomDirectory>(file)) {
+ return *romdir_type;
} else {
return FileType::Unknown;
}