Browse Source

[hle, kernel] Add support for FW21 and kernel changes (#3004)

- Adapts kernel changes from atmosphere for firmware 21.0.0.
- Fixes launch error of firmware 21.0.0 applets.
- Adds new commands for `prepo` (New `SaveSystemReport` & `SaveSystemReportWithUser`).
- Adds new commands for `IReadOnlyApplicationControlDataInterface` (cmd 19; incomplete!)
- Adds `{12010, nullptr, "SetButtonConfigLeft"},` undocumented IHidServer.
- Adds new commands for `ngc:u` (`Mask2` and `Check2`)
- Adds new commands for system settings server (GetHttpAuthConfig) for webapplet
- Removes incompatible firmware popup warning.

Signed-off-by: lizzie lizzie@eden-emu.dev
Co-authored by: maufeat sahyno1996@gmail.com

Co-authored-by: crueter <crueter@eden-emu.dev>
Co-authored-by: JPikachu <jpikachu.eden@gmail.com>
Co-authored-by: Maufeat <sahyno1996@gmail.com>
Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/3004
Reviewed-by: Maufeat <sahyno1996@gmail.com>
Reviewed-by: crueter <crueter@eden-emu.dev>
Reviewed-by: MaranBr <maranbr@eden-emu.dev>
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
pull/2984/head
lizzie 3 months ago
committed by crueter
parent
commit
7d239df065
No known key found for this signature in database GPG Key ID: 425ACD2D4830EBC6
  1. 1
      src/core/file_sys/savedata_factory.cpp
  2. 12
      src/core/hle/api_version.h
  3. 4
      src/core/hle/kernel/k_auto_object.cpp
  4. 10
      src/core/hle/kernel/k_auto_object.h
  5. 25
      src/core/hle/kernel/k_condition_variable.cpp
  6. 7
      src/core/hle/kernel/k_handle_table.cpp
  7. 2
      src/core/hle/kernel/k_handle_table.h
  8. 6
      src/core/hle/kernel/k_scheduler.cpp
  9. 2156
      src/core/hle/kernel/k_thread.cpp
  10. 25
      src/core/hle/kernel/k_thread.h
  11. 9
      src/core/hle/kernel/svc/svc_event.cpp
  12. 5
      src/core/hle/service/am/service/application_functions.cpp
  13. 4
      src/core/hle/service/am/service/audio_controller.cpp
  14. 4
      src/core/hle/service/audio/audio_controller.cpp
  15. 6
      src/core/hle/service/audio/audio_device.cpp
  16. 37
      src/core/hle/service/filesystem/fsp/fsp_srv.cpp
  17. 9
      src/core/hle/service/hid/hid_debug_server.cpp
  18. 51
      src/core/hle/service/hid/hid_server.cpp
  19. 11
      src/core/hle/service/hid/hid_system_server.cpp
  20. 5
      src/core/hle/service/ngc/ngc.cpp
  21. 1
      src/core/hle/service/nifm/nifm.cpp
  22. 4
      src/core/hle/service/ns/application_manager_interface.cpp
  23. 24
      src/core/hle/service/ns/read_only_application_control_data_interface.cpp
  24. 2
      src/core/hle/service/ns/read_only_application_control_data_interface.h
  25. 39
      src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
  26. 13
      src/core/hle/service/olsc/remote_storage_controller.cpp
  27. 74
      src/core/hle/service/prepo/prepo.cpp
  28. 5
      src/core/hle/service/set/firmware_debug_settings_server.cpp
  29. 19
      src/core/hle/service/set/system_settings_server.cpp
  30. 4
      src/core/hle/service/set/system_settings_server.h
  31. 6
      src/frontend_common/firmware_manager.cpp
  32. 21
      src/frontend_common/firmware_manager.h
  33. 46
      src/qt_common/qt_string_lookup.h
  34. 32
      src/yuzu/data_dialog.cpp
  35. 28
      src/yuzu/main_window.cpp

1
src/core/file_sys/savedata_factory.cpp

@ -95,6 +95,7 @@ std::string SaveDataFactory::GetSaveDataSpaceIdPath(SaveDataSpaceId space) {
case SaveDataSpaceId::System:
return "/system/";
case SaveDataSpaceId::User:
case SaveDataSpaceId::SdUser:
return "/user/";
case SaveDataSpaceId::Temporary:
return "/temp/";

12
src/core/hle/api_version.h

@ -14,9 +14,9 @@ namespace HLE::ApiVersion {
// Horizon OS version constants.
constexpr u8 HOS_VERSION_MAJOR = 20;
constexpr u8 HOS_VERSION_MINOR = 1;
constexpr u8 HOS_VERSION_MICRO = 1;
constexpr u8 HOS_VERSION_MAJOR = 21;
constexpr u8 HOS_VERSION_MINOR = 0;
constexpr u8 HOS_VERSION_MICRO = 0;
// NintendoSDK version constants.
@ -24,9 +24,9 @@ constexpr u8 SDK_REVISION_MAJOR = 1;
constexpr u8 SDK_REVISION_MINOR = 0;
constexpr char PLATFORM_STRING[] = "NX";
constexpr char VERSION_HASH[] = "9ffad64d79dd150490201461bdf66c8db963f57d";
constexpr char DISPLAY_VERSION[] = "20.1.1";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 20.1.1-1.0";
constexpr char VERSION_HASH[] = "f6b2425b6888a66590db104fc734891696e0ecb3";
constexpr char DISPLAY_VERSION[] = "21.0.0";
constexpr char DISPLAY_TITLE[] = "NintendoSDK Firmware for NX 21.0.0-1.0";
// Atmosphere version constants.

4
src/core/hle/kernel/k_auto_object.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -8,6 +11,7 @@ namespace Kernel {
KAutoObject* KAutoObject::Create(KAutoObject* obj) {
obj->m_ref_count = 1;
obj->m_class_token = obj->GetTypeObj().GetClassToken();
return obj;
}

10
src/core/hle/kernel/k_auto_object.h

@ -74,6 +74,10 @@ protected:
return (this->GetClassToken() | rhs.GetClassToken()) == this->GetClassToken();
}
static constexpr bool IsClassTokenDerivedFrom(ClassTokenType self, ClassTokenType base) {
return (self | base) == self;
}
private:
const char* m_name;
ClassTokenType m_class_token;
@ -84,6 +88,7 @@ private:
public:
explicit KAutoObject(KernelCore& kernel) : m_kernel(kernel) {
m_class_token = GetStaticTypeObj().GetClassToken();
RegisterWithKernel();
}
virtual ~KAutoObject() = default;
@ -107,11 +112,11 @@ public:
}
bool IsDerivedFrom(const TypeObj& rhs) const {
return this->GetTypeObj().IsDerivedFrom(rhs);
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.GetClassToken());
}
bool IsDerivedFrom(const KAutoObject& rhs) const {
return this->IsDerivedFrom(rhs.GetTypeObj());
return TypeObj::IsClassTokenDerivedFrom(m_class_token, rhs.m_class_token);
}
template <typename Derived>
@ -180,6 +185,7 @@ protected:
private:
std::atomic<u32> m_ref_count{};
ClassTokenType m_class_token{};
};
class KAutoObjectWithListContainer;

25
src/core/hle/kernel/k_condition_variable.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -23,8 +26,8 @@ bool ReadFromUser(KernelCore& kernel, u32* out, KProcessAddress address) {
return true;
}
bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
GetCurrentMemory(kernel).Write32(GetInteger(address), *p);
bool WriteToUser(KernelCore& kernel, KProcessAddress address, u32 val) {
GetCurrentMemory(kernel).Write32(GetInteger(address), val);
return true;
}
@ -133,7 +136,7 @@ Result KConditionVariable::SignalToAddress(KernelCore& kernel, KProcessAddress a
// Write the value to userspace.
Result result{ResultSuccess};
if (WriteToUser(kernel, addr, std::addressof(next_value))) [[likely]] {
if (WriteToUser(kernel, addr, next_value)) {
result = ResultSuccess;
} else {
result = ResultInvalidCurrentMemory;
@ -207,13 +210,13 @@ void KConditionVariable::SignalImpl(KThread* thread) {
// TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true;
if (can_access) [[likely]] {
if (can_access) {
UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask);
}
}
if (can_access) [[likely]] {
if (can_access) {
if (prev_tag == Svc::InvalidHandle) {
// If nobody held the lock previously, we're all good.
thread->EndWait(ResultSuccess);
@ -225,7 +228,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
static_cast<Handle>(prev_tag & ~Svc::HandleWaitMask))
.ReleasePointerUnsafe();
if (owner_thread) [[likely]] {
if (owner_thread) {
// Add the thread as a waiter on the owner.
owner_thread->AddWaiter(thread);
owner_thread->Close();
@ -261,8 +264,8 @@ void KConditionVariable::Signal(u64 cv_key, s32 count) {
// If we have no waiters, clear the has waiter flag.
if (it == m_tree.end() || it->GetConditionVariableKey() != cv_key) {
const u32 has_waiter_flag{};
WriteToUser(m_kernel, cv_key, std::addressof(has_waiter_flag));
constexpr u32 HasNoWaiterFlag = 0;
WriteToUser(m_kernel, cv_key, HasNoWaiterFlag);
}
}
}
@ -305,13 +308,13 @@ Result KConditionVariable::Wait(KProcessAddress addr, u64 key, u32 value, s64 ti
// Write to the cv key.
{
const u32 has_waiter_flag = 1;
WriteToUser(m_kernel, key, std::addressof(has_waiter_flag));
constexpr u32 HasWaiterFlag = 1;
WriteToUser(m_kernel, key, HasWaiterFlag);
std::atomic_thread_fence(std::memory_order_seq_cst);
}
// Write the value to userspace.
if (!WriteToUser(m_kernel, addr, std::addressof(next_value))) {
if (!WriteToUser(m_kernel, addr, next_value)) {
slp.CancelSleep();
R_THROW(ResultInvalidCurrentMemory);
}

7
src/core/hle/kernel/k_handle_table.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -6,7 +9,7 @@
namespace Kernel {
Result KHandleTable::Finalize() {
void KHandleTable::Finalize() {
// Get the table and clear our record of it.
u16 saved_table_size = 0;
{
@ -22,8 +25,6 @@ Result KHandleTable::Finalize() {
obj->Close();
}
}
R_SUCCEED();
}
bool KHandleTable::Remove(Handle handle) {

2
src/core/hle/kernel/k_handle_table.h

@ -68,7 +68,7 @@ public:
return m_max_count;
}
Result Finalize();
void Finalize();
bool Remove(Handle handle);
template <typename T = KAutoObject>

6
src/core/hle/kernel/k_scheduler.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -381,6 +384,9 @@ void KScheduler::SwitchThread(KThread* next_thread) {
// Set the new Thread Local region.
// cpu::SwitchThreadLocalRegion(GetInteger(next_thread->GetThreadLocalRegionAddress()));
// Update the thread's cpu time differential in TLS, if relevant.
next_thread->UpdateTlsThreadCpuTime(cur_tick);
}
void KScheduler::ScheduleImpl() {

2156
src/core/hle/kernel/k_thread.cpp
File diff suppressed because it is too large
View File

25
src/core/hle/kernel/k_thread.h

@ -99,6 +99,12 @@ enum class DpcFlag : u32 {
Terminated = (1 << 1),
};
enum class ExceptionFlag : u8 {
IsCallingSvc = 1 << 0,
InExceptionHandler = 1 << 1,
};
DECLARE_ENUM_FLAG_OPERATORS(ExceptionFlag);
enum class ThreadWaitReasonForDebugging : u32 {
None, ///< Thread is not waiting
Sleep, ///< Thread is waiting due to a SleepThread SVC
@ -153,7 +159,7 @@ public:
/**
* Sets the thread's current priority.
* @param priority The new priority.
* @param value The new priority.
*/
void SetPriority(s32 value) {
m_priority = value;
@ -340,6 +346,8 @@ public:
void SetInterruptFlag();
void ClearInterruptFlag();
void UpdateTlsThreadCpuTime(s64 switch_tick);
KThread* GetLockOwner() const;
const KAffinityMask& GetAffinityMask() const {
@ -446,6 +454,7 @@ public:
bool is_pinned;
s32 disable_count;
KThread* cur_thread;
std::atomic<u8> exception_flags{0};
};
StackParameters& GetStackParameters() {
@ -456,6 +465,16 @@ public:
return m_stack_parameters;
}
void SetExceptionFlag(ExceptionFlag flag) {
GetStackParameters().exception_flags.fetch_or(static_cast<u8>(flag), std::memory_order_relaxed);
}
void ClearExceptionFlag(ExceptionFlag flag) {
GetStackParameters().exception_flags.fetch_and(static_cast<u8>(~static_cast<u8>(flag)), std::memory_order_relaxed);
}
bool IsExceptionFlagSet(ExceptionFlag flag) const {
return (GetStackParameters().exception_flags.load(std::memory_order_relaxed) & static_cast<u8>(flag)) != 0;
}
class QueueEntry {
public:
constexpr QueueEntry() = default;
@ -511,10 +530,12 @@ public:
void SetInExceptionHandler() {
this->GetStackParameters().is_in_exception_handler = true;
SetExceptionFlag(ExceptionFlag::InExceptionHandler);
}
void ClearInExceptionHandler() {
this->GetStackParameters().is_in_exception_handler = false;
ClearExceptionFlag(ExceptionFlag::InExceptionHandler);
}
bool IsInExceptionHandler() const {
@ -523,10 +544,12 @@ public:
void SetIsCallingSvc() {
this->GetStackParameters().is_calling_svc = true;
SetExceptionFlag(ExceptionFlag::IsCallingSvc);
}
void ClearIsCallingSvc() {
this->GetStackParameters().is_calling_svc = false;
ClearExceptionFlag(ExceptionFlag::IsCallingSvc);
}
bool IsCallingSvc() const {

9
src/core/hle/kernel/svc/svc_event.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -34,7 +37,8 @@ Result ClearEvent(Core::System& system, Handle event_handle) {
{
KScopedAutoObject event = handle_table.GetObject<KEvent>(event_handle);
if (event.IsNotNull()) {
R_RETURN(event->Clear());
event->Clear();
R_SUCCEED();
}
}
@ -42,7 +46,8 @@ Result ClearEvent(Core::System& system, Handle event_handle) {
{
KScopedAutoObject readable_event = handle_table.GetObject<KReadableEvent>(event_handle);
if (readable_event.IsNotNull()) {
R_RETURN(readable_event->Clear());
readable_event->Clear();
R_SUCCEED();
}
}

5
src/core/hle/service/am/service/application_functions.cpp

@ -89,6 +89,11 @@ IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
{200, nullptr, "GetLastApplicationExitReason"},
{210, D<&IApplicationFunctions::GetUnknownEvent210>, "Unknown210"},
{220, nullptr, "Unknown220"}, // [20.0.0+]
{300, nullptr, "Unknown300"}, // [20.0.0+]
{310, nullptr, "Unknown310"}, // [20.0.0+]
{320, nullptr, "Unknown320"}, // [20.0.0+]
{330, nullptr, "Unknown330"}, // [20.0.0+]
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},

4
src/core/hle/service/am/service/audio_controller.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -15,6 +18,7 @@ IAudioController::IAudioController(Core::System& system_)
{2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
{3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
{4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
{5, nullptr, "Unknown5"},
};
// clang-format on

4
src/core/hle/service/audio/audio_controller.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -68,6 +71,7 @@ IAudioController::IAudioController(Core::System& system_)
{10104, nullptr, "GetAudioOutputChannelCountForPlayReport"},
{10105, nullptr, "BindAudioOutputChannelCountUpdateEventForPlayReport"},
{10106, nullptr, "GetDefaultAudioOutputTargetForPlayReport"},
{10200, nullptr, "Unknown10200"}, // [20.0.0+]
{50000, nullptr, "SetAnalogInputBoostGainForPrototyping"},
{50001, nullptr, "OverrideDefaultTargetForDebug"},
{50003, nullptr, "SetForceOverrideExternalDeviceNameForDebug"},

6
src/core/hle/service/audio/audio_device.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -34,7 +37,8 @@ IAudioDevice::IAudioDevice(Core::System& system_, u64 applet_resource_user_id, u
{17, nullptr, "AcquireAudioOutputDeviceNotification"}, // 17.0.0+
{18, nullptr, "ReleaseAudioOutputDeviceNotification"}, // 17.0.0+
{19, nullptr, "SetAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"} // 18.0.0+
{20, nullptr, "IsAudioDeviceOutputVolumeAutoTuneEnabled"}, // 18.0.0+
{21, nullptr, "IsActiveOutputDeviceEstimatedLowLatency"} // 21.0.0+
};
RegisterHandlers(functions);

37
src/core/hle/service/filesystem/fsp/fsp_srv.cpp

@ -298,8 +298,41 @@ Result FSP_SRV::OpenSaveDataFileSystem(OutInterface<IFileSystem> out_interface,
Result FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId(OutInterface<IFileSystem> out_interface,
FileSys::SaveDataSpaceId space_id,
FileSys::SaveDataAttribute attribute) {
LOG_WARNING(Service_FS, "(STUBBED) called, delegating to 51 OpenSaveDataFilesystem");
R_RETURN(OpenSaveDataFileSystem(out_interface, space_id, attribute));
LOG_INFO(Service_FS, "called, space_id={}, {}",
space_id, attribute.DebugInfo());
R_UNLESS(attribute.system_save_data_id != FileSys::InvalidSystemSaveDataId,
FileSys::ResultInvalidArgument);
if (attribute.program_id == 0) {
attribute.program_id = program_id;
}
FileSys::VirtualDir dir{};
R_TRY(save_data_controller->OpenSaveData(&dir, space_id, attribute));
FileSys::StorageId id{};
switch (space_id) {
case FileSys::SaveDataSpaceId::User:
id = FileSys::StorageId::NandUser;
break;
case FileSys::SaveDataSpaceId::SdSystem:
case FileSys::SaveDataSpaceId::SdUser:
id = FileSys::StorageId::SdCard;
break;
case FileSys::SaveDataSpaceId::System:
id = FileSys::StorageId::NandSystem;
break;
case FileSys::SaveDataSpaceId::Temporary:
case FileSys::SaveDataSpaceId::ProperSystem:
case FileSys::SaveDataSpaceId::SafeMode:
ASSERT(false);
}
*out_interface =
std::make_shared<IFileSystem>(system, std::move(dir), SizeGetter::FromStorageId(fsc, id));
R_SUCCEED();
}
Result FSP_SRV::OpenReadOnlySaveDataFileSystem(OutInterface<IFileSystem> out_interface,

9
src/core/hle/service/hid/hid_debug_server.cpp

@ -38,6 +38,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{20, nullptr, "DeactivateMouse"},
{21, nullptr, "SetMouseAutoPilotState"},
{22, nullptr, "UnsetMouseAutoPilotState"},
{23, nullptr, "AddMouseSideWheelDelta"},
{25, nullptr, "SetDebugMouseAutoPilotState"},
{26, nullptr, "UnsetDebugMouseAutoPilotState"},
{30, nullptr, "DeactivateKeyboard"},
@ -124,6 +125,13 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{250, nullptr, "IsVirtual"},
{251, nullptr, "GetAnalogStickModuleParam"},
{253, nullptr, "ClearStorageForShipment"}, //19.0.0+
{254, nullptr, "Unknown254"},
{255, nullptr, "Unknown255"},
{256, nullptr, "Unknown256"},
{261, nullptr, "UpdateDesignInfo12"},
{262, nullptr, "GetUniquePadButtonCount"},
{267, nullptr, "Unknown267"},
{268, nullptr, "Unknown268"},
{301, nullptr, "GetAbstractedPadHandles"},
{302, nullptr, "GetAbstractedPadState"},
{303, nullptr, "GetAbstractedPadsState"},
@ -154,6 +162,7 @@ IHidDebugServer::IHidDebugServer(Core::System& system_, std::shared_ptr<Resource
{650, nullptr, "AddButtonPlayData"},
{651, nullptr, "StartButtonPlayData"},
{652, nullptr, "StopButtonPlayData"},
{700, nullptr, "Unknown700"},
{2000, nullptr, "DeactivateDigitizer"},
{2001, nullptr, "SetDigitizerAutoPilotState"},
{2002, nullptr, "UnsetDigitizerAutoPilotState"},

51
src/core/hle/service/hid/hid_server.cpp

@ -143,6 +143,8 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
{308, nullptr, "SetSevenSixAxisSensorFusionStrength"},
{309, nullptr, "GetSevenSixAxisSensorFusionStrength"},
{310, C<&IHidServer::ResetSevenSixAxisSensorTimestamp>, "ResetSevenSixAxisSensorTimestamp"},
{320, nullptr, "EnableNpadImu"}, //21.0.0+
{321, nullptr, "DisableNpadImu"}, //21.0.0+
{400, C<&IHidServer::IsUsbFullKeyControllerEnabled>, "IsUsbFullKeyControllerEnabled"},
{401, nullptr, "EnableUsbFullKeyController"},
{402, nullptr, "IsUsbFullKeyControllerConnected"},
@ -187,7 +189,56 @@ IHidServer::IHidServer(Core::System& system_, std::shared_ptr<ResourceManager> r
{1002, C<&IHidServer::SetTouchScreenConfiguration>, "SetTouchScreenConfiguration"},
{1003, C<&IHidServer::IsFirmwareUpdateNeededForNotification>, "IsFirmwareUpdateNeededForNotification"},
{1004, C<&IHidServer::SetTouchScreenResolution>, "SetTouchScreenResolution"},
{1270, nullptr, "DeleteButtonConfigStorageRight"},
{1271, nullptr, "IsUsingCustomButtonConfig"},
{1272, nullptr, "IsAnyCustomButtonConfigEnabled"},
{1273, nullptr, "SetAllCustomButtonConfigEnabled"},
{1274, nullptr, "SetDefaultButtonConfig"},
{1275, nullptr, "SetAllDefaultButtonConfig"},
{1276, nullptr, "SetHidButtonConfigEmbedded"},
{1277, nullptr, "SetHidButtonConfigFull"},
{1278, nullptr, "SetHidButtonConfigLeft"},
{1279, nullptr, "SetHidButtonConfigRight"},
{1280, nullptr, "GetHidButtonConfigEmbedded"},
{1281, nullptr, "GetHidButtonConfigFull"},
{1282, nullptr, "GetHidButtonConfigLeft"},
{1283, nullptr, "GetHidButtonConfigRight"},
{1284, nullptr, "GetButtonConfigStorageEmbedded"},
{1285, nullptr, "GetButtonConfigStorageFull"},
{1286, nullptr, "GetButtonConfigStorageLeft"},
{1287, nullptr, "GetButtonConfigStorageRight"},
{1288, nullptr, "SetButtonConfigStorageEmbedded"},
{1289, nullptr, "SetButtonConfigStorageFull"},
{1290, nullptr, "SetButtonConfigStorageLeft"},
{1291, nullptr, "SetButtonConfigStorageRight"},
{1308, nullptr, "SetButtonConfigVisible"},
{1309, nullptr, "IsButtonConfigVisible"},
{1320, nullptr, "WakeTouchScreenUp"},
{1321, nullptr, "PutTouchScreenToSleep"},
{1322, nullptr, "AcquireTouchScreenAsyncWakeCompletedEvent"},
{1323, nullptr, "StartTouchScreenAutoTuneForSystemSettings"},
{1324, nullptr, "AcquireTouchScreenAutoTuneCompletedEvent"},
{1325, nullptr, "IsTouchScreenAutoTuneRequiredForRepairProviderReplacement"},
{1420, nullptr, "GetAppletResourceProperty"},
{2000, nullptr, "ActivateDigitizer"},
{3000, nullptr, "GetDebugPadGenericPadMap"},
{3001, nullptr, "SetDebugPadGenericPadMap"},
{3002, nullptr, "ResetDebugPadGenericPadMap"},
{3003, nullptr, "GetDebugPadKeyboardMap"},
{3004, nullptr, "SetDebugPadKeyboardMap"},
{3005, nullptr, "ResetDebugPadKeyboardMap"},
{3006, nullptr, "GetFullKeyGenericPadMap"},
{3007, nullptr, "SetFullKeyGenericPadMap"},
{3008, nullptr, "ResetFullKeyGenericPadMap"},
{3009, nullptr, "GetFullKeyKeyboardMap"},
{3010, nullptr, "SetFullKeyKeyboardMap"},
{3011, nullptr, "ResetFullKeyKeyboardMap"},
{3012, nullptr, "GetDebugPadGenericPadMap"}, //21.0.0+
{3013, nullptr, "SetDebugPadGenericPadMap"}, //21.0.0+
{3014, nullptr, "GetDebugPadKeyboardMap"}, //21.0.0+
{3015, nullptr, "SetDebugPadKeyboardMap"}, //21.0.0+
{3150, nullptr, "SetMouseLibraryVersion"}, //21.0.0+
// What? -- {12010, nullptr, "SetButtonConfigLeft"},
};
// clang-format on

11
src/core/hle/service/hid/hid_system_server.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@ -96,9 +99,12 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{547, nullptr, "GetAllowedBluetoothLinksCount"},
{548, &IHidSystemServer::GetRegisteredDevices, "GetRegisteredDevices"},
{549, nullptr, "GetConnectableRegisteredDevices"},
{551, nullptr, "GetRegisteredDevicesForControllerSupport"},
{700, nullptr, "ActivateUniquePad"},
{702, &IHidSystemServer::AcquireUniquePadConnectionEventHandle, "AcquireUniquePadConnectionEventHandle"},
{703, &IHidSystemServer::GetUniquePadIds, "GetUniquePadIds"},
{711, nullptr, "AcquireUniquePadConnectionOnHandheldForNsEventHandle"}, //20.0.0+
{712, nullptr, "GetUniquePadColor12"}, //20.0.0+
{751, &IHidSystemServer::AcquireJoyDetachOnBluetoothOffEventHandle, "AcquireJoyDetachOnBluetoothOffEventHandle"},
{800, nullptr, "ListSixAxisSensorHandles"},
{801, nullptr, "IsSixAxisSensorUserCalibrationSupported"},
@ -225,6 +231,11 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{1309, nullptr, "IsButtonConfigVisible"}, // 18.0.0+
{1320, nullptr, "WakeTouchScreenUp"}, // 17.0.0+
{1321, nullptr, "PutTouchScreenToSleep"}, // 17.0.0+
{1322, nullptr, "AcquireTouchScreenAsyncWakeCompletedEvent"}, // 20.0.0+
{1323, nullptr, "StartTouchScreenAutoTuneForSystemSettings"}, // 21.0.0+
{1324, nullptr, "AcquireTouchScreenAutoTuneCompletedEvent"}, // 21.0.0+
{1325, nullptr, "IsTouchScreenAutoTuneRequiredForRepairProviderReplacement"}, // 21.0.0+
{1326, nullptr, "Unknown1326"}, // 21.0.0+
{1420, nullptr, "GetAppletResourceProperty"}, // 19.0.0+
};
// clang-format on

5
src/core/hle/service/ngc/ngc.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -61,6 +64,8 @@ public:
{1, &NgcServiceImpl::Check, "Check"},
{2, &NgcServiceImpl::Mask, "Mask"},
{3, &NgcServiceImpl::Reload, "Reload"},
{4, &NgcServiceImpl::Check, "Check2"},
{5, &NgcServiceImpl::Mask, "Mask2"},
};
// clang-format on

1
src/core/hle/service/nifm/nifm.cpp

@ -366,6 +366,7 @@ public:
{23, nullptr, "SetKeptInSleep"},
{24, nullptr, "RegisterSocketDescriptor"},
{25, nullptr, "UnregisterSocketDescriptor"},
{26, nullptr, "GetNetworkAccessStatus"}, //21.0.0+
};
RegisterHandlers(functions);

4
src/core/hle/service/ns/application_manager_interface.cpp

@ -548,8 +548,8 @@ Result IApplicationManagerInterface::GetApplicationTerminateResult(Out<Result> o
}
Result IApplicationManagerInterface::RequestDownloadApplicationControlDataInBackground(
u64 unk, u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED), app={:016X} unk={}", application_id, unk);
u64 control_source, u64 application_id) {
LOG_WARNING(Service_NS, "(STUBBED), control_source={} app={:016X}", control_source, application_id);
R_SUCCEED();
}

24
src/core/hle/service/ns/read_only_application_control_data_interface.cpp

@ -27,7 +27,8 @@ IReadOnlyApplicationControlDataInterface::IReadOnlyApplicationControlDataInterfa
{2, D<&IReadOnlyApplicationControlDataInterface::ConvertApplicationLanguageToLanguageCode>, "ConvertApplicationLanguageToLanguageCode"},
{3, nullptr, "ConvertLanguageCodeToApplicationLanguage"},
{4, nullptr, "SelectApplicationDesiredLanguage"},
{5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIconSize>, "GetApplicationControlDataWithIconSize"},
{5, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithoutIcon>, "GetApplicationControlDataWithIconSize"},
{19, D<&IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithoutIcon>, "GetApplicationControlDataWithIconSize"},
};
// clang-format on
@ -163,7 +164,7 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlData(
R_SUCCEED();
}
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIconSize(
Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithoutIcon(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_total_size,
ApplicationControlSource application_control_source,
@ -173,19 +174,11 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIc
constexpr size_t kExpectedBufferSize = 0x14000;
constexpr size_t kNACPSize = sizeof(FileSys::RawNACP);
constexpr size_t kMaxIconSize = kExpectedBufferSize - kNACPSize;
const FileSys::PatchManager pm{application_id, system.GetFileSystemController(),
system.GetContentProvider()};
const auto control = pm.GetControlMetadata();
const auto size = out_buffer.size();
if (size < kExpectedBufferSize) {
LOG_ERROR(Service_NS, "output buffer is too small! (actual={:016X}, required={:016X})", size, kExpectedBufferSize);
R_THROW(ResultUnknown);
}
// Copy NACP
if (control.first != nullptr) {
const auto bytes = control.first->GetRawBytes();
std::memcpy(out_buffer.data(), bytes.data(), bytes.size());
@ -193,17 +186,6 @@ Result IReadOnlyApplicationControlDataInterface::GetApplicationControlDataWithIc
std::memset(out_buffer.data(), 0, kNACPSize);
}
// Copy icon, pad with zeros if needed
size_t icon_size = control.second ? control.second->GetSize() : 0;
if (icon_size > kMaxIconSize) {
icon_size = kMaxIconSize; // Truncate if too large
}
if (control.second != nullptr && icon_size > 0) {
control.second->Read(out_buffer.data() + kNACPSize, icon_size);
} else {
std::memset(out_buffer.data() + kNACPSize, 0, kMaxIconSize);
}
*out_total_size = kExpectedBufferSize;
R_SUCCEED();
}

2
src/core/hle/service/ns/read_only_application_control_data_interface.h

@ -31,7 +31,7 @@ public:
Out<u32> out_actual_size,
ApplicationControlSource application_control_source,
u64 application_id);
Result GetApplicationControlDataWithIconSize(
Result GetApplicationControlDataWithoutIcon(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
Out<u64> out_total_size,
ApplicationControlSource application_control_source,

39
src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp

@ -187,7 +187,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx(IoctlAllocGpfifoEx& params, DeviceFD fd) {
params.reserved[2]);
if (channel_state->initialized) {
LOG_CRITICAL(Service_NVDRV, "Already allocated!");
LOG_DEBUG(Service_NVDRV, "Channel already initialized; AllocGPFIFOEx returning AlreadyAllocated");
return NvResult::AlreadyAllocated;
}
@ -196,6 +196,15 @@ NvResult nvhost_gpu::AllocGPFIFOEx(IoctlAllocGpfifoEx& params, DeviceFD fd) {
program_id = session->process->GetProgramId();
}
// Store program id for later lazy initialization
channel_state->program_id = program_id;
// If address space is not yet bound, defer channel initialization.
if (!channel_state->memory_manager) {
params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
return NvResult::Success;
}
system.GPU().InitChannel(*channel_state, program_id);
params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
@ -211,7 +220,7 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx& params, DeviceFD fd) {
params.reserved[2]);
if (channel_state->initialized) {
LOG_CRITICAL(Service_NVDRV, "Already allocated!");
LOG_DEBUG(Service_NVDRV, "Channel already initialized; AllocGPFIFOEx2 returning AlreadyAllocated");
return NvResult::AlreadyAllocated;
}
@ -220,6 +229,15 @@ NvResult nvhost_gpu::AllocGPFIFOEx2(IoctlAllocGpfifoEx& params, DeviceFD fd) {
program_id = session->process->GetProgramId();
}
// Store program id for later lazy initialization
channel_state->program_id = program_id;
// If address space is not yet bound, defer channel initialization.
if (!channel_state->memory_manager) {
params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
return NvResult::Success;
}
system.GPU().InitChannel(*channel_state, program_id);
params.fence_out = syncpoint_manager.GetSyncpointFence(channel_syncpoint);
@ -244,9 +262,10 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
LOG_DEBUG(Service_NVDRV, "called, class_num={:#X}, flags={:#X}, obj_id={:#X}", params.class_num,
params.flags, params.obj_id);
if (!channel_state || !channel_state->initialized) {
LOG_CRITICAL(Service_NVDRV, "No address space bound to allocate a object context!");
return NvResult::NotInitialized;
// Do not require channel initialization here: some clients allocate contexts before binding.
if (!channel_state) {
LOG_ERROR(Service_NVDRV, "No channel state available!");
return NvResult::InvalidState;
}
std::scoped_lock lk(channel_mutex);
@ -268,11 +287,12 @@ NvResult nvhost_gpu::AllocateObjectContext(IoctlAllocObjCtx& params) {
}
if (ctxObjs[ctx_class_number_index].has_value()) {
LOG_ERROR(Service_NVDRV, "Object context for class {:#X} already allocated on this channel",
params.class_num);
LOG_WARNING(Service_NVDRV, "Object context for class {:#X} already allocated on this channel",
params.class_num);
return NvResult::AlreadyAllocated;
}
// Defer actual hardware context binding until channel is initialized.
ctxObjs[ctx_class_number_index] = params;
return NvResult::Success;
@ -326,6 +346,11 @@ NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, Tegra::CommandL
std::scoped_lock lock(channel_mutex);
// Lazily initialize channel when address space is available
if (!channel_state->initialized && channel_state->memory_manager) {
system.GPU().InitChannel(*channel_state, channel_state->program_id);
}
const auto bind_id = channel_state->bind_id;
auto& flags = params.flags;

13
src/core/hle/service/olsc/remote_storage_controller.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -26,14 +29,20 @@ IRemoteStorageController::IRemoteStorageController(Core::System& system_)
{16, nullptr, "CreateCleanupToDeleteSaveDataArchiveInfoTask"},
{17, nullptr, "ListDataInfo"},
{18, nullptr, "GetDataInfo"},
{19, nullptr, "Unknown19"},
{19, nullptr, "GetDataInfoCacheUpdateNativeHandleHolder"},
{20, nullptr, "CreateSaveDataArchiveInfoCacheForSaveDataBackupUpdationTask"},
{21, nullptr, "ListSecondarySaves"},
{22, D<&IRemoteStorageController::GetSecondarySave>, "GetSecondarySave"},
{23, nullptr, "TouchSecondarySave"},
{24, nullptr, "GetSecondarySaveDataInfo"},
{25, nullptr, "RegisterDownloadSaveDataTransferTaskForAutonomyRegistration"},
{900, nullptr, "Unknown900"},
{26, nullptr, "Unknown26"}, //20.0.0+
{27, nullptr, "Unknown27"}, //20.0.0+
{28, nullptr, "Unknown28"}, //20.0.0+
{29, nullptr, "Unknown29"}, //21.0.0+
{800, nullptr, "Unknown800"}, //20.0.0+
{900, nullptr, "SetLoadedDataMissing"},
{901, nullptr, "Unknown901"}, //20.2.0+
};
// clang-format on

74
src/core/hle/service/prepo/prepo.cpp

@ -1,8 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/hex_util.h"
#include "common/logging/log.h"
#include "common/uuid.h"
#include <cstring>
#include "core/core.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/ipc_helpers.h"
@ -27,8 +33,10 @@ public:
{10200, &PlayReport::RequestImmediateTransmission, "RequestImmediateTransmission"},
{10300, &PlayReport::GetTransmissionStatus, "GetTransmissionStatus"},
{10400, &PlayReport::GetSystemSessionId, "GetSystemSessionId"},
{20100, &PlayReport::SaveSystemReport, "SaveSystemReport"},
{20101, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
{20100, &PlayReport::SaveSystemReportOld, "SaveSystemReport"},
{20101, &PlayReport::SaveSystemReportWithUserOld, "SaveSystemReportWithUser"},
{20102, &PlayReport::SaveSystemReport, "SaveSystemReport"},
{20103, &PlayReport::SaveSystemReportWithUser, "SaveSystemReportWithUser"},
{20200, nullptr, "SetOperationMode"},
{30100, nullptr, "ClearStorage"},
{30200, nullptr, "ClearStatistics"},
@ -121,7 +129,7 @@ private:
rb.Push(system_session_id);
}
void SaveSystemReport(HLERequestContext& ctx) {
void SaveSystemReportOld(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto title_id = rp.PopRaw<u64>();
@ -131,14 +139,11 @@ private:
LOG_DEBUG(Service_PREPO, "called, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
title_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data1, data2});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void SaveSystemReportWithUser(HLERequestContext& ctx) {
void SaveSystemReportWithUserOld(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto user_id = rp.PopRaw<u128>();
const auto title_id = rp.PopRaw<u64>();
@ -146,10 +151,12 @@ private:
const auto data1 = ctx.ReadBufferA(0);
const auto data2 = ctx.ReadBufferX(0);
Common::UUID uuid{};
std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID));
LOG_DEBUG(Service_PREPO,
"called, user_id={:016X}{:016X}, title_id={:016X}, data1_size={:016X}, "
"data2_size={:016X}",
user_id[1], user_id[0], title_id, data1.size(), data2.size());
"called, user_id={}, title_id={:016X}, data1_size={:016X}, data2_size={:016X}",
uuid.FormattedString(), title_id, data1.size(), data2.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data1, data2},
@ -158,6 +165,53 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
// (21.0.0+) buffers: [0x9 (X), 0x5 (A)], inbytes: 0x10
void SaveSystemReport(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto field0 = rp.PopRaw<u64>();
const auto title_id = rp.PopRaw<u64>();
const auto data_x = ctx.ReadBufferX(0);
const auto data_a = ctx.ReadBufferA(0);
LOG_DEBUG(Service_PREPO,
"called, field0={}, title_id={:016X}, data_a_size={}, data_x_size={}",
field0, title_id, data_a.size(), data_x.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data_a, data_x});
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
// (21.0.0+) buffers: [0x9 (X), 0x5 (A)], inbytes: 0x20
void SaveSystemReportWithUser(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
// 21.0.0+: field0 (u64), user_id (u128), title_id (u64)
const auto field0 = rp.PopRaw<u64>();
const auto user_id = rp.PopRaw<u128>();
const auto title_id = rp.PopRaw<u64>();
const auto data_x = ctx.ReadBufferX(0);
const auto data_a = ctx.ReadBufferA(0);
Common::UUID uuid{};
std::memcpy(uuid.uuid.data(), user_id.data(), sizeof(Common::UUID));
LOG_DEBUG(Service_PREPO,
"called, user_id={}, field0={:016X}, title_id={:016X}, data_a_size={}, data_x_size={}",
uuid.FormattedString(), field0, title_id, data_a.size(), data_x.size());
const auto& reporter{system.GetReporter()};
reporter.SavePlayReport(Core::Reporter::PlayReportType::System, title_id, {data_a, data_x},
std::nullopt, user_id);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
void LoopProcess(Core::System& system) {

5
src/core/hle/service/set/firmware_debug_settings_server.cpp

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -18,6 +21,8 @@ IFirmwareDebugSettingsServer::IFirmwareDebugSettingsServer(Core::System& system_
{21, nullptr, "SetAllowedSslHosts"},
{22, nullptr, "SetHostFsMountPoint"},
{23, nullptr, "SetMemoryUsageRateFlag"},
{24, nullptr, "CommitSettings"}, //20.0.0+
{27, nullptr, "SetHttpAuthConfigs"}, //21.0.0+
};
// clang-format on

19
src/core/hle/service/set/system_settings_server.cpp

@ -307,6 +307,19 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{222, nullptr, "SetForceMonauralOutputFlag"}, //17.0.0+
{251, nullptr, "GetAccountIdentificationSettings"}, //18.0.0+
{252, nullptr, "SetAccountIdentificationSettings"}, //18.0.0+
{263, nullptr, "AcquireVphymDirtyFlagEventHandle"}, //20.0.0+
{264, nullptr, "GetVphymDirtyFlags"}, //20.0.0+
{282, nullptr, "ConvertToProductModel"}, //20.0.0+
{283, nullptr, "ConvertToProductModelName"}, //20.0.0+
{289, nullptr, "GetDefaultAccountIdentificationFlagSet"}, //20.0.0+
{300, nullptr, "AcquirePushNotificationDirtyFlagEventHandle"}, //20.0.0+
{301, nullptr, "GetPushNotificationDirtyFlags"}, //20.0.0+
{306, nullptr, "GetPinCodeReregistrationGuideAccounts"}, //20.0.0+
{307, nullptr, "SetPinCodeReregistrationGuideAccounts"}, //20.0.0+
{315, C<&ISystemSettingsServer::GetHttpAuthConfigs>, "GetHttpAuthConfigs"}, //21.0.0+
{319, nullptr, "GetAccountUserSettings"}, //21.0.0+
{320, nullptr, "SetAccountUserSettings"}, //21.0.0+
{321, nullptr, "GetDefaultAccountUserSettings"}, //21.0.0+
};
// clang-format on
@ -1323,6 +1336,12 @@ Result ISystemSettingsServer::SetPanelCrcMode(s32 panel_crc_mode) {
R_SUCCEED();
}
Result ISystemSettingsServer::GetHttpAuthConfigs(Out<s32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_configs) {
LOG_WARNING(Service_SET, "(STUBBED) called, buffer_size={}", out_configs.size());
*out_count = 0;
R_SUCCEED();
}
void ISystemSettingsServer::SetupSettings() {
auto system_dir =
Common::FS::GetEdenPath(Common::FS::EdenPath::NANDDir) / "system/save/8000000000000050";

4
src/core/hle/service/set/system_settings_server.h

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
@ -157,6 +160,7 @@ public:
Result GetFieldTestingFlag(Out<bool> out_field_testing_flag);
Result GetPanelCrcMode(Out<s32> out_panel_crc_mode);
Result SetPanelCrcMode(s32 panel_crc_mode);
Result GetHttpAuthConfigs(Out<s32> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_configs);
private:
bool LoadSettingsFile(std::filesystem::path& path, auto&& default_func);

6
src/frontend_common/firmware_manager.cpp

@ -121,18 +121,12 @@ FirmwareManager::FirmwareCheckResult FirmwareManager::VerifyFirmware(Core::Syste
return ErrorFirmwareMissing;
} else {
const auto pair = GetFirmwareVersion(system);
const auto firmware_data = pair.first;
const auto result = pair.second;
if (result.IsError()) {
LOG_INFO(Frontend, "Unable to read firmware");
return ErrorFirmwareCorrupted;
}
// TODO: update this whenever newer firmware is properly supported
if (firmware_data.major > 20) {
return ErrorFirmwareTooNew;
}
}
return FirmwareGood;

21
src/frontend_common/firmware_manager.h

@ -53,21 +53,10 @@ inline constexpr bool GameRequiresFirmware(u64 program_id)
!= FIRMWARE_REQUIRED_GAMES.end();
}
enum FirmwareCheckResult {
FirmwareGood,
ErrorFirmwareMissing,
ErrorFirmwareCorrupted,
ErrorFirmwareTooNew,
};
static constexpr std::array<const char *, 4> FIRMWARE_CHECK_STRINGS = {
"",
"Firmware missing. Firmware is required to run certain games and use the Home Menu. "
"Eden only works with firmware 19.0.1 and earlier.",
"Firmware reported as present, but was unable to be read. Check for decryption keys and "
"redump firmware if necessary.",
"Firmware is too new or could not be read. Eden only works with firmware 19.0.1 and earlier.",
};
/**
@ -100,16 +89,6 @@ inline bool CheckFirmwarePresence(Core::System &system)
*/
FirmwareCheckResult VerifyFirmware(Core::System &system);
/**
* \brief Get a string representation of a result from CheckFirmwareVersion.
* \param result The result code.
* \return A string representation of the passed result code.
*/
inline constexpr const char *GetFirmwareCheckString(FirmwareCheckResult result)
{
return FIRMWARE_CHECK_STRINGS.at(static_cast<std::size_t>(result));
}
/**
* @brief Get the currently installed firmware version.
* @param system The system to check firmware on.

46
src/qt_common/qt_string_lookup.h

@ -11,8 +11,8 @@
/// Small helper to look up enums.
/// res = the result code
/// base = the base matching value in the StringKey table
#define LOOKUP_ENUM(res, base) StringLookup::Lookup( \
static_cast<StringLookup::StringKey>((int) res + (int) StringLookup::base))
#define LOOKUP_ENUM(res, base) QtCommon::StringLookup::Lookup( \
QtCommon::StringLookup::StringKey((int) res + (int) QtCommon::StringLookup::base))
namespace QtCommon::StringLookup {
@ -20,11 +20,11 @@ Q_NAMESPACE
// TODO(crueter): QML interface
enum StringKey {
SavesTooltip,
ShadersTooltip,
UserNandTooltip,
SysNandTooltip,
ModsTooltip,
DataManagerSavesTooltip,
DataManagerShadersTooltip,
DataManagerUserNandTooltip,
DataManagerSysNandTooltip,
DataManagerModsTooltip,
// Key install results
KeyInstallSuccess,
@ -40,6 +40,10 @@ enum StringKey {
FwInstallFailedCopy,
FwInstallFailedCorrupted,
// Firmware Check results
FwCheckErrorFirmwareMissing,
FwCheckErrorFirmwareCorrupted,
// user data migrator
MigrationPromptPrefix,
MigrationPrompt,
@ -55,18 +59,19 @@ enum StringKey {
KvdbMisaligned,
KvdbNoImens,
RyujinxNoSaveId,
};
static const constexpr frozen::map<StringKey, frozen::string, 27> strings = {
// NB: the constexpr check always succeeds (in clangd at least) if size arg < size
// always triple-check the size arg
static const constexpr frozen::map<StringKey, frozen::string, 29> strings = {
// 0-4
{SavesTooltip,
{DataManagerSavesTooltip,
QT_TR_NOOP("Contains game save data. DO NOT REMOVE UNLESS YOU KNOW WHAT YOU'RE DOING!")},
{ShadersTooltip,
{DataManagerShadersTooltip,
QT_TR_NOOP("Contains Vulkan and OpenGL pipeline caches. Generally safe to remove.")},
{UserNandTooltip, QT_TR_NOOP("Contains updates and DLC for games.")},
{SysNandTooltip, QT_TR_NOOP("Contains firmware and applet data.")},
{ModsTooltip, QT_TR_NOOP("Contains game mods, patches, and cheats.")},
{DataManagerUserNandTooltip, QT_TR_NOOP("Contains updates and DLC for games.")},
{DataManagerSysNandTooltip, QT_TR_NOOP("Contains firmware and applet data.")},
{DataManagerModsTooltip, QT_TR_NOOP("Contains game mods, patches, and cheats.")},
// Key install
// 5-9
@ -91,8 +96,17 @@ static const constexpr frozen::map<StringKey, frozen::string, 27> strings = {
"Firmware installation cancelled, firmware may be in a bad state or corrupted. Restart "
"Eden or re-install firmware.")},
{FwCheckErrorFirmwareMissing,
QT_TR_NOOP(
"Firmware missing. Firmware is required to run certain games and use the Home Menu. "
"Versions 19.0.1 or earlier are recommended, as 20.0.0+ is currently experimental.")},
{FwCheckErrorFirmwareCorrupted,
QT_TR_NOOP(
"Firmware reported as present, but was unable to be read. Check for decryption keys and "
"redump firmware if necessary.")},
// migrator
// 15-20
// 17-22
{MigrationPromptPrefix, QT_TR_NOOP("Eden has detected user data for the following emulators:")},
{MigrationPrompt,
QT_TR_NOOP("Would you like to migrate your data for use in Eden?\n"
@ -113,7 +127,7 @@ static const constexpr frozen::map<StringKey, frozen::string, 27> strings = {
"This is recommended if you want to share data between emulators.")},
// why am I writing these comments again
// 21-26
// 23-28
{KvdbNonexistent, QT_TR_NOOP("Ryujinx title database does not exist.")},
{KvdbNoHeader, QT_TR_NOOP("Invalid header on Ryujinx title database.")},
{KvdbInvalidMagic, QT_TR_NOOP("Invalid magic header on Ryujinx title database.")},

32
src/yuzu/data_dialog.cpp

@ -27,7 +27,7 @@ DataDialog::DataDialog(QWidget *parent)
// TODO: Should we make this a single widget that pulls data from a model?
#define WIDGET(label, name) \
ui->page->addWidget(new DataWidget(FrontendCommon::DataManager::DataDir::name, \
QtCommon::StringLookup::name##Tooltip, \
QtCommon::StringLookup::DataManager##name##Tooltip, \
QStringLiteral(#name), \
this)); \
ui->labels->addItem(label);
@ -80,39 +80,27 @@ DataWidget::DataWidget(FrontendCommon::DataManager::DataDir data_dir,
void DataWidget::clear()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
}
std::string user_id = selectProfile();
QtCommon::Content::ClearDataDir(m_dir, user_id);
scan();
}
void DataWidget::open()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
}
std::string user_id = selectProfile();
QDesktopServices::openUrl(QUrl::fromLocalFile(
QString::fromStdString(FrontendCommon::DataManager::GetDataDirString(m_dir, user_id))));
}
void DataWidget::upload()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
}
std::string user_id = selectProfile();
QtCommon::Content::ExportDataDir(m_dir, user_id, m_exportName);
}
void DataWidget::download()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
}
std::string user_id = selectProfile();
QtCommon::Content::ImportDataDir(m_dir, user_id, std::bind(&DataWidget::scan, this));
}
@ -131,3 +119,13 @@ void DataWidget::scan() {
watcher->setFuture(
QtConcurrent::run([this]() { return FrontendCommon::DataManager::DataDirSize(m_dir); }));
}
std::string DataWidget::selectProfile()
{
std::string user_id{};
if (m_dir == FrontendCommon::DataManager::DataDir::Saves) {
user_id = GetProfileIDString();
}
return user_id;
}

28
src/yuzu/main_window.cpp

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
// Qt on macOS doesn't define VMA shit
#include "qt_common/qt_string_lookup.h"
#if defined(QT_STATICPLUGIN) && !defined(__APPLE__)
#undef VMA_IMPLEMENTATION
#endif
@ -4058,35 +4059,18 @@ void MainWindow::OnOpenControllerMenu() {
void MainWindow::OnHomeMenu() {
auto result = FirmwareManager::VerifyFirmware(*QtCommon::system.get());
using namespace QtCommon::StringLookup;
switch (result) {
case FirmwareManager::ErrorFirmwareMissing:
QMessageBox::warning(this, tr("No firmware available"),
tr("Please install firmware to use the Home Menu."));
Lookup(FwCheckErrorFirmwareMissing));
return;
case FirmwareManager::ErrorFirmwareCorrupted:
QMessageBox::warning(this, tr("Firmware Corrupted"),
tr(FirmwareManager::GetFirmwareCheckString(result)));
Lookup(FwCheckErrorFirmwareCorrupted));
return;
case FirmwareManager::ErrorFirmwareTooNew: {
if (!UISettings::values.show_fw_warning.GetValue()) break;
QMessageBox box(QMessageBox::Warning,
tr("Firmware Too New"),
tr(FirmwareManager::GetFirmwareCheckString(result)) + tr("\nContinue anyways?"),
QMessageBox::Yes | QMessageBox::No,
this);
QCheckBox *checkbox = new QCheckBox(tr("Don't show again"));
box.setCheckBox(checkbox);
int button = box.exec();
if (checkbox->isChecked()) {
UISettings::values.show_fw_warning.SetValue(false);
}
if (button == static_cast<int>(QMessageBox::No)) return;
break;
} default:
default:
break;
}

Loading…
Cancel
Save