Compare commits

...

18 commits

Author SHA1 Message Date
lizzie
6b94984041 properly start some stuff? 2026-05-21 16:58:18 +00:00
lizzie
a8d6b4fe60 finalize process when requested by uMenu 2026-05-21 05:52:31 +00:00
lizzie
ea4d36ad06 try make work 2026-05-21 04:11:16 +00:00
lizzie
ea9f43d987 enumerate 2026-05-21 02:36:59 +00:00
lizzie
20f1a2ef02 ulauncher ipc emu 2026-05-21 02:36:59 +00:00
lizzie
272a71d27d license 2026-05-21 02:36:59 +00:00
lizzie
84db20b9f0 AMV + WLAN stubs 2026-05-21 02:36:59 +00:00
lizzie
12af978b3e + stubbed services 2026-05-21 02:36:59 +00:00
lizzie
aa2875e1e9 ulsf:p, proper launch of 2026-05-21 02:36:58 +00:00
lizzie
daee174a87 provide proper load params 2026-05-21 02:36:58 +00:00
lizzie
41283a8fac properly give targetinput? 2026-05-21 02:36:58 +00:00
lizzie
2f90bd6de8 NSO load NPDM and retrofit to use -ulaunch 2026-05-21 02:36:58 +00:00
lizzie
610c757592 Fix NSO loading 2026-05-21 02:36:58 +00:00
lizzie
fb4385f7ea I FORGOT LOOP PROCESS FFS 2026-05-21 02:36:58 +00:00
lizzie
5d60dc79bb register ulsf as guest process 2026-05-21 02:36:58 +00:00
lizzie
5ab562a9c0 [hle] attempt support ULaunch
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-05-21 02:36:58 +00:00
lizzie
cd38b261a4 oops, fix 2026-05-21 02:36:58 +00:00
lizzie
e2ebc37cd0 [hle/sm] implement sm:AtmosphereHasService
Signed-off-by: lizzie <lizzie@eden-emu.dev>
2026-05-21 02:36:58 +00:00
21 changed files with 570 additions and 47 deletions

View file

@ -1089,6 +1089,8 @@ add_library(core STATIC
hle/service/ssl/ssl.h
hle/service/ssl/ssl_backend.h
hle/service/ssl/ssl_types.h
hle/service/ulsf/ulsf.cpp
hle/service/ulsf/ulsf.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
hle/service/vi/application_display_service.cpp

View file

@ -83,7 +83,8 @@ constexpr size_t SlabCountKDeviceAddressSpace = 300;
constexpr size_t SlabCountKSession = 1133;
constexpr size_t SlabCountKLightSession = 100;
constexpr size_t SlabCountKObjectName = 7;
constexpr size_t SlabCountKResourceLimit = 5;
// TODO(lizzie): divergence that allows ulauncher to work
constexpr size_t SlabCountKResourceLimit = 5 + 1;
constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES;
constexpr size_t SlabCountKIoPool = 1;
constexpr size_t SlabCountKIoRegion = 6;

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -94,7 +94,9 @@ enum class AppletId : u32 {
LoginShare = 0x18,
WebAuth = 0x19,
MyPage = 0x1A,
Lhub = 0x35
Lhub = 0x35,
// Homebrew -- uses same ProgramId as qlaunch
UlauncherUmenu = 0xF000'0000,
};
enum class AppletProgramId : u64 {

View file

@ -24,6 +24,20 @@ namespace Service::AM {
namespace {
constexpr size_t NroPathSize = 512;
constexpr size_t NroArgvSize = 2048;
constexpr size_t MenuCaptionSize = 1024;
struct UloaderTargetInput {
u32 magic;
bool target_once;
bool is_auto_game_recording;
std::array<u8, 2> unused;
std::array<char, NroPathSize> nro_path;
std::array<char, NroArgvSize> nro_argv;
std::array<char, MenuCaptionSize> menu_caption;
};
static_assert(sizeof(UloaderTargetInput) == 3592);
constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA;
struct LaunchParameterAccountPreselectedUser {
@ -121,6 +135,44 @@ void PushInShowController(Core::System& system, AppletStorageChannel& channel) {
channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data)));
}
void PushInShowUlauncherUmenu(Core::System& system, AppletStorageChannel& channel) {
typedef std::array<u64, 2> AccountUid;
const CommonArguments common_args = {
.arguments_version = CommonArgumentVersion::Version3,
.size = CommonArgumentSize::Version3,
.library_version = 2,
.theme_color = ThemeColor::BasicBlack,
.play_startup_sound = true,
.system_tick = system.CoreTiming().GetClockTicks(),
};
struct UmenuInput {
AccountUid selected_user;
UloaderTargetInput suspended_hb_target_ipt; // Set if homebrew (launched as an application) is currently suspended
u64 suspended_app_id; // Set if any normal application is suspended
std::array<char, 0x301> last_menu_fs_path; //FS_MAX_PATH
std::array<char, 0x301> last_menu_path;
u32 last_menu_index;
bool reload_theme_cache;
bool warned_about_outdated_theme;
u32 last_added_app_count;
u32 last_deleted_app_count;
u32 in_verify_app_count;
} user_args = {};
static_assert(sizeof(UmenuInput) == 5176);
auto const user = system.GetProfileManager().GetUser(0);
user_args.selected_user[0] = user->uuid[0];
user_args.selected_user[1] = user->uuid[1];
user_args.warned_about_outdated_theme = true;
std::vector<u8> common_args_data(sizeof(common_args));
std::vector<u8> user_args_data(sizeof(user_args));
std::memcpy(common_args_data.data(), std::addressof(common_args), sizeof(common_args));
std::memcpy(user_args_data.data(), std::addressof(user_args), sizeof(user_args));
channel.Push(std::make_shared<IStorage>(system, std::move(common_args_data)));
channel.Push(std::make_shared<IStorage>(system, std::move(user_args_data)));
}
void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) {
const CommonArguments arguments{
.arguments_version = CommonArgumentVersion::Version3,
@ -292,8 +344,18 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
applet->previous_program_index = params.previous_program_index;
// Push UserChannel data from previous application
// Or ulaunch initialization where we push parameters willingly!
if (params.launch_type == LaunchType::ApplicationInitiated) {
applet->user_channel_launch_parameter.swap(m_system.GetUserChannel());
} else if (params.launch_type == LaunchType::FrontendUlaunchInitiated) {
UloaderTargetInput target_ipt = {};
target_ipt.magic = 0x49444C55; // "ULDI"
target_ipt.nro_path = {"sdmc:/hbmenu.nro"};
target_ipt.menu_caption = {"Loaded by uLoader v1.2.4 - uLaunch's custom hbloader replacement ;)"};
std::vector<u8> v(sizeof(target_ipt));
std::memcpy(v.data(), std::addressof(target_ipt), sizeof(target_ipt));
applet->user_channel_launch_parameter.clear();
applet->user_channel_launch_parameter.push_back(std::move(v));
}
// TODO: Read whether we need a preselected user from NACP?
@ -335,6 +397,9 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
case AppletId::Controller:
PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
case AppletId::UlauncherUmenu:
PushInShowUlauncherUmenu(m_system, InitializeFakeCallerApplet(m_system, applet));
break;
default:
break;
}
@ -342,7 +407,7 @@ void AppletManager::SetWindowSystem(WindowSystem* window_system) {
// Applet was started by frontend, so it is foreground.
applet->lifecycle_manager.SetFocusState(FocusState::InFocus);
if (applet->applet_id == AppletId::QLaunch) {
if (applet->applet_id == AppletId::QLaunch || applet->applet_id == AppletId::UlauncherUmenu) {
applet->lifecycle_manager.SetFocusHandlingMode(false);
applet->lifecycle_manager.SetOutOfFocusSuspendingEnabled(false);
m_window_system->TrackApplet(applet, false);

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -26,6 +26,9 @@ class WindowSystem;
enum class LaunchType {
FrontendInitiated,
ApplicationInitiated,
// Special masquerade for AMS + uLaunch CFW
FrontendUlaunchInitiated = 0x800,
FrontendUmenuInitiated,
};
struct FrontendAppletParameters {

View file

@ -55,6 +55,7 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
case AppletId::OverlayDisplay:
return AppletProgramId::OverlayDisplay;
case AppletId::QLaunch:
case AppletId::UlauncherUmenu: //reuses same id as Qlaunch
return AppletProgramId::QLaunch;
case AppletId::Starter:
return AppletProgramId::Starter;

View file

@ -8,18 +8,23 @@
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/hle/result.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/am/service/library_applet_self_accessor.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ns/application_manager_interface.h"
#include "core/hle/service/ns/service_getter_interface.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
#include "core/loader/loader.h"
namespace Service::AM {
@ -44,8 +49,9 @@ AppletIdentityInfo GetCallerIdentity(Applet& applet) {
ILibraryAppletSelfAccessor::ILibraryAppletSelfAccessor(Core::System& system_,
std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, m_applet{std::move(applet)},
m_broker{m_applet->caller_applet_broker} {
: ServiceFramework{system_, "ILibraryAppletSelfAccessor"}, m_applet{std::move(applet)}
, m_broker{m_applet->caller_applet_broker}
{
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletSelfAccessor::PopInData>, "PopInData"},
@ -96,9 +102,130 @@ Result ILibraryAppletSelfAccessor::PopInData(Out<SharedPointer<IStorage>> out_st
R_RETURN(m_broker->GetInData().Pop(out_storage));
}
// uLauncher emulation
static Result UloaderCreateApplication(Core::System& system, u64 program_id, std::shared_ptr<Applet> caller_applet) {
// Get the program NCA from storage.
auto& storage = system.GetContentProviderUnion();
FileSys::VirtualFile nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
// Ensure we retrieved a program NCA.
R_UNLESS(nca_raw != nullptr, ResultUnknown);
std::vector<u8> control;
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus result;
auto process = CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
R_UNLESS(process != nullptr, ResultUnknown);
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
applet->program_id = program_id;
applet->applet_id = AppletId::Application;
applet->type = AppletType::Application;
applet->library_applet_mode = LibraryAppletMode::AllForeground;
applet->caller_applet = caller_applet;
applet->caller_applet_broker = std::make_shared<AppletDataBroker>(system);
applet->frontend = caller_applet->frontend;
caller_applet->child_applets.push_back(applet);
system.GetAppletManager().GetWindowSystem()->TrackApplet(applet, true);
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::PushOutData(SharedPointer<IStorage> storage) {
LOG_INFO(Service_AM, "called");
m_broker->GetOutData().Push(storage);
if (m_applet->applet_id == AppletId::UlauncherUmenu) {
enum class SystemMessage : u32 {
Invalid,
SetSelectedUser,
LaunchApplication,
ResumeApplication,
TerminateApplication,
LaunchHomebrewLibraryApplet,
LaunchHomebrewApplication,
ChooseHomebrew,
OpenWebPage,
OpenAlbum,
RestartMenu,
ReloadConfig,
UpdateMenuPaths,
UpdateMenuIndex,
OpenUserPage,
OpenMiiEdit,
OpenAddUser,
OpenNetConnect,
ListAddedApplications,
ListDeletedApplications,
OpenCabinet,
StartVerifyApplication,
ListInVerifyApplications,
NotifyWarnedAboutOutdatedTheme,
TerminateMenu,
OpenControllerKeyRemapping
};
struct CommandCommonHeader {
u32 magic;
u32 val;
};
std::shared_ptr<IStorage> req_storage;
m_broker->GetOutData().Pop(&req_storage);
auto req_data = req_storage->GetData();
CommandCommonHeader req_cmd{};
std::memcpy(&req_cmd, req_data.data(), sizeof(req_cmd));
LOG_WARNING(Service_AM, "uLauncher:IPC {}, {}", req_cmd.magic, req_cmd.val);
switch (SystemMessage(req_cmd.val)) {
case SystemMessage::SetSelectedUser:
break;
case SystemMessage::LaunchApplication: {
// all applet proxies OpenSystemAppletProxy
// applet proxy GetApplicationCreator
// application creator CreateApplication
u64 args_value{};
std::memcpy(std::addressof(args_value), req_data.data() + sizeof(req_cmd), sizeof(args_value));
LOG_WARNING(Service_AM, "program_id={:016x}", args_value);
UloaderCreateApplication(system, args_value, m_applet);
break;
}
case SystemMessage::ResumeApplication:
case SystemMessage::TerminateApplication:
case SystemMessage::LaunchHomebrewLibraryApplet:
case SystemMessage::LaunchHomebrewApplication:
case SystemMessage::ChooseHomebrew:
case SystemMessage::OpenWebPage:
case SystemMessage::OpenAlbum:
case SystemMessage::RestartMenu:
case SystemMessage::ReloadConfig:
case SystemMessage::UpdateMenuPaths:
case SystemMessage::UpdateMenuIndex:
case SystemMessage::OpenUserPage:
case SystemMessage::OpenMiiEdit:
case SystemMessage::OpenAddUser:
case SystemMessage::OpenNetConnect:
case SystemMessage::ListAddedApplications:
case SystemMessage::ListDeletedApplications:
case SystemMessage::OpenCabinet:
case SystemMessage::StartVerifyApplication:
case SystemMessage::ListInVerifyApplications:
case SystemMessage::NotifyWarnedAboutOutdatedTheme:
break;
case SystemMessage::TerminateMenu:
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(0);
break;
case SystemMessage::OpenControllerKeyRemapping:
break;
case SystemMessage::Invalid:
break;
}
CommandCommonHeader res_cmd{};
std::vector<u8> res_data(0x8000);
res_cmd.magic = 0x21494D53;
res_cmd.val = u32(ResultSuccess.raw);
std::memcpy(res_data.data(), &res_cmd, sizeof(res_cmd));
m_broker->GetInData().Push(std::make_shared<IStorage>(system, std::move(res_data)));
}
R_SUCCEED();
}

View file

@ -59,7 +59,7 @@ void WindowSystem::Update() {
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
std::scoped_lock lk{m_lock};
if (applet->applet_id == AppletId::QLaunch) {
if (applet->applet_id == AppletId::QLaunch || applet->applet_id == AppletId::UlauncherUmenu) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (applet->applet_id == AppletId::OverlayDisplay) {

View file

@ -29,7 +29,7 @@ IBtmSystemCore::IBtmSystemCore(Core::System& system_)
{10, nullptr, "StartAudioDeviceDiscovery"},
{11, nullptr, "StopAudioDeviceDiscovery"},
{12, nullptr, "IsDiscoveryingAudioDevice"},
{13, nullptr, "GetDiscoveredAudioDevice"},
{13, C<&IBtmSystemCore::GetDiscoveredAudioDevice>, "GetDiscoveredAudioDevice"},
{14, C<&IBtmSystemCore::AcquireAudioDeviceConnectionEvent>, "AcquireAudioDeviceConnectionEvent"},
{15, nullptr, "ConnectAudioDevice"},
{16, nullptr, "IsConnectingAudioDevice"},
@ -93,6 +93,11 @@ Result IBtmSystemCore::AcquireRadioEvent(Out<bool> out_is_valid,
R_SUCCEED();
}
Result IBtmSystemCore::GetDiscoveredAudioDevice(OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices, s32 count, Out<s32> out_total) {
LOG_WARNING(Service_BTM, "(STUBBED) called");
R_SUCCEED();
}
Result IBtmSystemCore::AcquireAudioDeviceConnectionEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_BTM, "(STUBBED) called");

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
@ -34,9 +37,8 @@ private:
Result DisableRadio();
Result IsRadioEnabled(Out<bool> out_is_enabled);
Result AcquireRadioEvent(Out<bool> out_is_valid,
OutCopyHandle<Kernel::KReadableEvent> out_event);
Result AcquireRadioEvent(Out<bool> out_is_valid, OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetDiscoveredAudioDevice(OutArray<std::array<u8, 0xFF>, BufferAttr_HipcPointer> out_audio_devices, s32 count, Out<s32> out_total);
Result AcquireAudioDeviceConnectionEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetConnectedAudioDevices(

View file

@ -1,4 +1,4 @@
// SPDX-FileCopyrightText: Copyright 2025 Eden Emulator Project
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
@ -62,6 +62,7 @@
#include "core/hle/service/sockets/sockets.h"
#include "core/hle/service/spl/spl_module.h"
#include "core/hle/service/ssl/ssl.h"
#include "core/hle/service/ulsf/ulsf.h"
#include "core/hle/service/usb/usb.h"
#include "core/hle/service/vi/vi.h"
@ -144,7 +145,8 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
{"ro", &RO::LoopProcess},
{"spl", &SPL::LoopProcess},
{"ssl", &SSL::LoopProcess},
{"usb", &USB::LoopProcess}
{"usb", &USB::LoopProcess},
{"ulsf", &ULSF::LoopProcess},
})
kernel.RunOnGuestCoreProcess(std::string(e.first), [&system, f = e.second] { f(system); });
}

View file

@ -142,10 +142,10 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{22, C<&ISystemSettingsServer::SetEulaVersions>, "SetEulaVersions"},
{23, C<&ISystemSettingsServer::GetColorSetId>, "GetColorSetId"},
{24, C<&ISystemSettingsServer::SetColorSetId>, "SetColorSetId"},
{25, nullptr, "GetConsoleInformationUploadFlag"},
{26, nullptr, "SetConsoleInformationUploadFlag"},
{27, nullptr, "GetAutomaticApplicationDownloadFlag"},
{28, nullptr, "SetAutomaticApplicationDownloadFlag"},
{25, C<&ISystemSettingsServer::GetConsoleInformationUploadFlag>, "GetConsoleInformationUploadFlag"},
{26, C<&ISystemSettingsServer::SetConsoleInformationUploadFlag>, "SetConsoleInformationUploadFlag"},
{27, C<&ISystemSettingsServer::GetAutomaticApplicationDownloadFlag>, "GetAutomaticApplicationDownloadFlag"},
{28, C<&ISystemSettingsServer::SetAutomaticApplicationDownloadFlag>, "SetAutomaticApplicationDownloadFlag"},
{29, C<&ISystemSettingsServer::GetNotificationSettings>, "GetNotificationSettings"},
{30, C<&ISystemSettingsServer::SetNotificationSettings>, "SetNotificationSettings"},
{31, C<&ISystemSettingsServer::GetAccountNotificationSettings>, "GetAccountNotificationSettings"},
@ -160,8 +160,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{42, nullptr, "SetEdid"},
{43, C<&ISystemSettingsServer::GetAudioOutputMode>, "GetAudioOutputMode"},
{44, C<&ISystemSettingsServer::SetAudioOutputMode>, "SetAudioOutputMode"},
{45, C<&ISystemSettingsServer::GetSpeakerAutoMuteFlag> , "GetSpeakerAutoMuteFlag"},
{46, C<&ISystemSettingsServer::SetSpeakerAutoMuteFlag> , "SetSpeakerAutoMuteFlag"},
{45, C<&ISystemSettingsServer::GetSpeakerAutoMuteFlag>, "GetSpeakerAutoMuteFlag"},
{46, C<&ISystemSettingsServer::SetSpeakerAutoMuteFlag>, "SetSpeakerAutoMuteFlag"},
{47, C<&ISystemSettingsServer::GetQuestFlag>, "GetQuestFlag"},
{48, C<&ISystemSettingsServer::SetQuestFlag>, "SetQuestFlag"},
{49, nullptr, "GetDataDeletionSettings"},
@ -180,8 +180,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{62, C<&ISystemSettingsServer::GetDebugModeFlag>, "GetDebugModeFlag"},
{63, C<&ISystemSettingsServer::GetPrimaryAlbumStorage>, "GetPrimaryAlbumStorage"},
{64, C<&ISystemSettingsServer::SetPrimaryAlbumStorage>, "SetPrimaryAlbumStorage"},
{65, nullptr, "GetUsb30EnableFlag"},
{66, nullptr, "SetUsb30EnableFlag"},
{65, C<&ISystemSettingsServer::GetUsb30EnableFlag>, "GetUsb30EnableFlag"},
{66, C<&ISystemSettingsServer::SetUsb30EnableFlag>, "SetUsb30EnableFlag"},
{67, C<&ISystemSettingsServer::GetBatteryLot>, "GetBatteryLot"},
{68, C<&ISystemSettingsServer::GetSerialNumber>, "GetSerialNumber"},
{69, C<&ISystemSettingsServer::GetNfcEnableFlag>, "GetNfcEnableFlag"},
@ -1074,6 +1074,45 @@ Result ISystemSettingsServer::SetNfcEnableFlag(bool nfc_enable_flag) {
R_SUCCEED();
}
Result ISystemSettingsServer::GetConsoleInformationUploadFlag(Out<bool> out_flag) {
LOG_INFO(Service_SET, "called {}", m_system_settings.console_information_upload_flag);
*out_flag = m_system_settings.console_information_upload_flag;
R_SUCCEED();
}
Result ISystemSettingsServer::SetConsoleInformationUploadFlag(bool flag) {
LOG_INFO(Service_SET, "called {}", flag);
m_system_settings.usb_30_enable_flag = flag;
SetSaveNeeded();
R_SUCCEED();
}
Result ISystemSettingsServer::GetAutomaticApplicationDownloadFlag(Out<bool> out_flag) {
LOG_INFO(Service_SET, "called {}", m_system_settings.usb_30_enable_flag);
*out_flag = m_system_settings.automatic_application_download_flag;
R_SUCCEED();
}
Result ISystemSettingsServer::SetAutomaticApplicationDownloadFlag(bool flag) {
LOG_INFO(Service_SET, "called {}", flag);
m_system_settings.automatic_application_download_flag = flag;
SetSaveNeeded();
R_SUCCEED();
}
Result ISystemSettingsServer::GetUsb30EnableFlag(Out<bool> out_usb30_enable_flag) {
LOG_INFO(Service_SET, "called, usb30_enable_flag={}", m_system_settings.usb_30_enable_flag);
*out_usb30_enable_flag = m_system_settings.usb_30_enable_flag;
R_SUCCEED();
}
Result ISystemSettingsServer::SetUsb30EnableFlag(bool usb30_enable_flag) {
LOG_INFO(Service_SET, "called, usb30_enable_flag={}", usb30_enable_flag);
m_system_settings.usb_30_enable_flag = usb30_enable_flag;
SetSaveNeeded();
R_SUCCEED();
}
Result ISystemSettingsServer::GetSleepSettings(Out<SleepSettings> out_sleep_settings) {
LOG_INFO(Service_SET, "called, flags={}, handheld_sleep_plan={}, console_sleep_plan={}",
m_system_settings.sleep_settings.flags.raw,

View file

@ -109,6 +109,12 @@ public:
Result SetPrimaryAlbumStorage(PrimaryAlbumStorage primary_album_storage);
Result GetBatteryLot(Out<BatteryLot> out_battery_lot);
Result GetSerialNumber(Out<SerialNumber> out_console_serial);
Result GetConsoleInformationUploadFlag(Out<bool> out_flag);
Result SetConsoleInformationUploadFlag(bool flag);
Result GetAutomaticApplicationDownloadFlag(Out<bool> out_flag);
Result SetAutomaticApplicationDownloadFlag(bool flag);
Result GetUsb30EnableFlag(Out<bool> out_usb30_enable_flag);
Result SetUsb30EnableFlag(bool usb30_enable_flag);
Result GetNfcEnableFlag(Out<bool> out_nfc_enable_flag);
Result SetNfcEnableFlag(bool nfc_enable_flag);
Result GetSleepSettings(Out<SleepSettings> out_sleep_settings);

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@ -11,6 +14,7 @@
#include "core/hle/kernel/k_scoped_resource_reservation.h"
#include "core/hle/kernel/k_server_port.h"
#include "core/hle/result.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/sm/sm.h"
@ -250,15 +254,37 @@ void SM::UnregisterService(HLERequestContext& ctx) {
rb.Push(service_manager.UnregisterService(name));
}
void SM::AtmosphereHasService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
std::string name(PopServiceName(rp));
LOG_WARNING(Service_SM, "(stubbed) called with name={}", name);
IPC::ResponseBuilder rb{ctx, 3};
Kernel::KClientPort* out_client_port = nullptr;
rb.Push(ResultSuccess);
rb.Push<bool>(service_manager.GetServicePort(&out_client_port, name) == ResultSuccess);
}
SM::SM(ServiceManager& service_manager_, Core::System& system_)
: ServiceFramework{system_, "sm:", 4},
service_manager{service_manager_}, kernel{system_.Kernel()} {
: ServiceFramework{system_, "sm:", 4}
, service_manager{service_manager_}
, kernel{system_.Kernel()}
{
RegisterHandlers({
{0, &SM::Initialize, "Initialize"},
{1, &SM::GetServiceCmif, "GetService"},
{2, &SM::RegisterServiceCmif, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"},
// TODO: are these non-TIPC as well?
{65000, nullptr, "AtmosphereInstallMitm"},
{65001, nullptr, "AtmosphereUninstallMitm"},
{65002, nullptr, "Deprecated_AtmosphereAssociatePidTidForMitm"},
{65003, nullptr, "AtmosphereAcknowledgeMitmSession"},
{65004, nullptr, "AtmosphereHasMitm"},
{65005, nullptr, "AtmosphereWaitMitm"},
{65006, nullptr, "AtmosphereDeclareFutureMitm"},
{65100, &SM::AtmosphereHasService, "AtmosphereHasService"},
{65101, nullptr, "AtmosphereWaitService"},
});
RegisterHandlersTipc({
{0, &SM::Initialize, "Initialize"},
@ -266,6 +292,15 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
{2, &SM::RegisterServiceTipc, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"},
{65000, nullptr, "AtmosphereInstallMitm"},
{65001, nullptr, "AtmosphereUninstallMitm"},
{65002, nullptr, "Deprecated_AtmosphereAssociatePidTidForMitm"},
{65003, nullptr, "AtmosphereAcknowledgeMitmSession"},
{65004, nullptr, "AtmosphereHasMitm"},
{65005, nullptr, "AtmosphereWaitMitm"},
{65006, nullptr, "AtmosphereDeclareFutureMitm"},
{65100, &SM::AtmosphereHasService, "AtmosphereHasService"},
{65101, nullptr, "AtmosphereWaitService"},
});
}

View file

@ -47,6 +47,7 @@ private:
void RegisterServiceCmif(HLERequestContext& ctx);
void RegisterServiceTipc(HLERequestContext& ctx);
void UnregisterService(HLERequestContext& ctx);
void AtmosphereHasService(HLERequestContext& ctx);
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,

View file

@ -0,0 +1,137 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <memory>
#include "core/hle/result.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ulsf/ulsf.h"
#include "core/hle/service/server_manager.h"
namespace Service::ULSF {
ULSF_U::ULSF_U(Core::System& system_) : ServiceFramework{system_, "ulsf:u"} {
static const FunctionInfo functions[] = {
{0, &ULSF_U::GetVersion, "GetVersion"},
};
RegisterHandlers(functions);
}
ULSF_U::~ULSF_U() = default;
// Result ULSF_U::GetVersion(Out<ULauncherVersion> out_version) {
// LOG_WARNING(Service_SM, "(stubbed)");
// *out_version = {};
// R_SUCCEED();
// }
void ULSF_U::GetVersion(HLERequestContext& ctx) {
LOG_WARNING(Service_SM, "(stubbed)");
ULauncherVersion version{1, 6, 7};
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
rb.PushRaw(version);
}
enum class MenuMessage : u32 {
Invalid,
HomeRequest,
SdCardEjected,
GameCardMountFailure,
PreviousLaunchFailure,
ChosenHomebrew,
FinishedSleep,
ApplicationRecordsChanged,
ApplicationVerifyProgress,
ApplicationVerifyResult
};
struct MenuMessageContext {
MenuMessage msg;
union {
struct {
Result mount_rc;
} gc_mount_failure;
struct {
char nro_path[0x301];
} chosen_hb;
struct {
bool records_added_or_deleted;
} app_records_changed;
struct {
u64 app_id;
u64 done;
u64 total;
} app_verify_progress;
struct {
u64 app_id;
Result rc;
Result detail_rc;
} app_verify_rc;
};
};
class ULSF_P final : public ServiceFramework<ULSF_P> {
public:
explicit ULSF_P(Core::System& system_) : ServiceFramework{system_, "ulsf:p"} {
static const FunctionInfo functions[] = {
{0, C<&ULSF_P::Initialize>, "Initialize"},
{1, C<&ULSF_P::TryPopMessageContext>, "TryPopMessageContext"},
};
RegisterHandlers(functions);
}
~ULSF_P() = default;
Result Initialize(u64 pid) {
LOG_WARNING(Service_SM, "(stubbed) pid={}", pid);
R_SUCCEED();
}
Result TryPopMessageContext(OutLargeData<MenuMessageContext, BufferAttr_HipcMapAlias> out_menu_message) {
//LOG_WARNING(Service_SM, "(stubbed)");
// *out_menu_message = {};
// R_SUCCEED();
R_THROW(Kernel::ResultInvalidAddress);
}
};
class AVM final : public ServiceFramework<AVM> {
public:
explicit AVM(Core::System& system_): ServiceFramework{system_, "avm"} {
static const FunctionInfo functions[] = {
{0, &AVM::Cmd0, "Cmd0"},
};
RegisterHandlers(functions);
}
~AVM() = default;
void Cmd0(HLERequestContext& ctx) {
LOG_WARNING(Service_SM, "(stubbed)");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
class WLAN final : public ServiceFramework<WLAN> {
public:
explicit WLAN(Core::System& system_): ServiceFramework{system_, "wlan"} {
static const FunctionInfo functions[] = {
{0, &WLAN::Cmd0, "Cmd0"},
};
RegisterHandlers(functions);
}
~WLAN() = default;
void Cmd0(HLERequestContext& ctx) {
LOG_WARNING(Service_SM, "(stubbed)");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("ulsf:u", std::make_shared<ULSF_U>(system));
server_manager->RegisterNamedService("ulsf:p", std::make_shared<ULSF_P>(system));
server_manager->RegisterNamedService("avm", std::make_shared<AVM>(system));
server_manager->RegisterNamedService("wlan", std::make_shared<WLAN>(system));
ServerManager::RunServer(std::move(server_manager));
}
}

View file

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "common/common_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::ULSF {
struct ULauncherVersion {
u8 major;
u8 minor;
u8 micro;
};
class ULSF_U final : public ServiceFramework<ULSF_U> {
public:
explicit ULSF_U(Core::System& system_);
~ULSF_U();
//Result GetVersion(Out<ULauncherVersion> out_version);
void GetVersion(HLERequestContext& ctx);
};
void LoopProcess(Core::System& system);
}

View file

@ -12,6 +12,7 @@
#include "core/file_sys/content_archive.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/program_metadata.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
@ -204,7 +205,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
process, system, *module_file, code_size, should_pass_arguments, false, {},
process, system, *module_file, code_size, should_pass_arguments, false, nullptr, metadata, {},
patch_ctx.GetPatchers(), patch_ctx.GetLastIndex());
if (!tentative_next_load_addr) {
return {ResultStatus::ErrorLoadingNSO, {}};
@ -251,8 +252,9 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
const VAddr load_addr{next_load_addr};
const bool should_pass_arguments = std::strcmp(module, "rtld") == 0;
FileSys::ProgramMetadata tmp_metadata{};
const auto tentative_next_load_addr = AppLoader_NSO::LoadModule(
process, system, *module_file, load_addr, should_pass_arguments, true, pm,
process, system, *module_file, load_addr, should_pass_arguments, true, nullptr, metadata, pm,
patch_ctx.GetPatchers(), patch_ctx.GetIndex(i));
if (!tentative_next_load_addr) {
return {ResultStatus::ErrorLoadingNSO, {}};

View file

@ -17,10 +17,14 @@
#include "common/swap.h"
#include "core/core.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/romfs_factory.h"
#include "core/file_sys/vfs/vfs_types.h"
#include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_page_table.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"
#include "core/loader/nso.h"
#include "core/memory.h"
@ -66,7 +70,7 @@ FileType AppLoader_NSO::IdentifyType(const FileSys::VirtualFile& in_file) {
return FileType::NSO;
}
std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, const FileSys::VfsFile& nso_file, VAddr load_base, bool should_pass_arguments, bool load_into_process, std::optional<FileSys::PatchManager> pm, std::vector<Core::NCE::Patcher>* patches, s32 patch_index) {
std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::System& system, const FileSys::VfsFile& nso_file, const VAddr load_base, const bool should_pass_arguments, const bool load_into_process, VAddr* out_load_base, FileSys::ProgramMetadata metadata, std::optional<FileSys::PatchManager> pm, std::vector<Core::NCE::Patcher>* patches, s32 patch_index) {
if (nso_file.GetSize() < sizeof(NSOHeader))
return std::nullopt;
NSOHeader nso_header{};
@ -216,9 +220,19 @@ std::optional<VAddr> AppLoader_NSO::LoadModule(Kernel::KProcess& process, Core::
}
}
const bool is_hbl = true;
if (process
.LoadFromMetadata(metadata, image_size, 0, 0, is_hbl)
.IsError()) {
return false;
}
auto const new_load_base = process.GetEntryPoint().GetValue();
if (out_load_base)
*out_load_base = new_load_base; // no change
// Load codeset for current process
process.LoadModule(std::move(codeset), load_base);
return load_base + image_size;
process.LoadModule(std::move(codeset), new_load_base);
return new_load_base + image_size;
}
AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::System& system) {
@ -226,20 +240,34 @@ AppLoader_NSO::LoadResult AppLoader_NSO::Load(Kernel::KProcess& process, Core::S
return {ResultStatus::ErrorAlreadyLoaded, {}};
}
modules.clear();
FileSys::VirtualFile npdm_file{};
metadata = FileSys::ProgramMetadata::GetDefault();
if (auto const dir = file->GetContainingDirectory()) {
npdm_file = dir->GetFile("main.npdm");
if (npdm_file) {
metadata.Load(npdm_file);
}
}
modules.clear();
// Load module
const VAddr base_address = GetInteger(process.GetEntryPoint());
if (!LoadModule(process, system, *file, base_address, true, true)) {
VAddr base_address = GetInteger(process.GetEntryPoint());
if (!LoadModule(process, system, *file, base_address, true, true, &base_address, metadata)) {
return {ResultStatus::ErrorLoadingNSO, {}};
}
modules.insert_or_assign(base_address, file->GetName());
LOG_DEBUG(Loader, "loaded module {} @ {:#X}", file->GetName(), base_address);
if (npdm_file) {
LOG_WARNING(Loader, "creating associated rom-fs factories for likely standalone NSO");
u64 program_id{};
ReadProgramId(program_id);
system.GetFileSystemController().RegisterProcess(process.GetProcessId(), program_id, std::make_unique<FileSys::RomFSFactory>(*this, system.GetContentProvider(), system.GetFileSystemController()));
}
is_loaded = true;
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority,
Core::Memory::DEFAULT_STACK_SIZE}};
return {ResultStatus::Success, LoadParameters{Kernel::KThread::DefaultThreadPriority, Core::Memory::DEFAULT_STACK_SIZE}};
}
ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
@ -247,4 +275,18 @@ ResultStatus AppLoader_NSO::ReadNSOModules(Modules& out_modules) {
return ResultStatus::Success;
}
ResultStatus AppLoader_NSO::ReadProgramId(u64& out_program_id) {
if (metadata.GetTitleID() == 0)
return ResultStatus::ErrorNoControl;
out_program_id = metadata.GetTitleID();
return ResultStatus::Success;
}
ResultStatus AppLoader_NSO::ReadTitle(std::string& out_title) {
auto const raw_name = metadata.GetName();
out_title.resize(raw_name.size());
std::memcpy(out_title.data(), raw_name.data(), raw_name.size());
return ResultStatus::Success;
}
} // namespace Loader

View file

@ -1,3 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2026 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
@ -9,6 +12,7 @@
#include "common/common_types.h"
#include "common/swap.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/program_metadata.h"
#include "core/loader/loader.h"
namespace Core {
@ -90,18 +94,20 @@ public:
}
static std::optional<VAddr> LoadModule(Kernel::KProcess& process, Core::System& system,
const FileSys::VfsFile& nso_file, VAddr load_base,
bool should_pass_arguments, bool load_into_process,
std::optional<FileSys::PatchManager> pm = {},
std::vector<Core::NCE::Patcher>* patches = nullptr,
s32 patch_index = -1);
const FileSys::VfsFile& nso_file, const VAddr load_base,
const bool should_pass_arguments, const bool load_into_process, VAddr* out_load_base,
FileSys::ProgramMetadata metadata,
std::optional<FileSys::PatchManager> pm = {}, std::vector<Core::NCE::Patcher>* patches = nullptr, s32 patch_index = -1);
LoadResult Load(Kernel::KProcess& process, Core::System& system) override;
ResultStatus ReadNSOModules(Modules& out_modules) override;
ResultStatus ReadProgramId(u64& out_program_id) override;
ResultStatus ReadTitle(std::string& title) override;
private:
Modules modules;
FileSys::ProgramMetadata metadata;
};
} // namespace Loader

View file

@ -512,11 +512,12 @@ MainWindow::MainWindow(bool has_broken_vulkan)
return;
}
QString game_path;
QString game_path{};
bool should_launch_qlaunch = false;
bool should_launch_hlaunch = false;
bool should_launch_hlaunch_uloader = false;
bool should_launch_ulaunch = false;
bool should_launch_setup = false;
bool has_gamepath = false;
bool is_fullscreen = false;
// Preserves drag/drop functionality
@ -550,7 +551,6 @@ MainWindow::MainWindow(bool has_broken_vulkan)
} else if (args[i] == QStringLiteral("-g") && i < args.size() - 1) {
// Launch game at path
game_path = args[++i];
has_gamepath = true;
} else if (args[i] == QStringLiteral("-input-profile") && i < args.size() - 1) {
auto& players = Settings::values.players.GetValue();
players[0].profile_name = args[++i].toStdString();
@ -558,16 +558,19 @@ MainWindow::MainWindow(bool has_broken_vulkan)
should_launch_qlaunch = true;
} else if (args[i] == QStringLiteral("-hlaunch")) {
should_launch_hlaunch = true;
} else if (args[i] == QStringLiteral("-hlaunch-uloader")) {
should_launch_hlaunch_uloader = true;
} else if (args[i] == QStringLiteral("-ulaunch")) {
should_launch_ulaunch = true;
} else if (args[i] == QStringLiteral("-setup")) {
should_launch_setup = true;
} else {
game_path = args[i];
has_gamepath = true;
}
}
// Override fullscreen setting if gamepath or argument is provided
if (has_gamepath || is_fullscreen) {
if (!game_path.isEmpty() || is_fullscreen) {
ui->action_Fullscreen->setChecked(is_fullscreen);
}
@ -580,8 +583,22 @@ MainWindow::MainWindow(bool has_broken_vulkan)
LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt);
} else if (should_launch_hlaunch) {
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
auto const hbl_path = (sd_dir / "atmosphere" / "hbl.nsp").string();
BootGame(QString::fromStdString(hbl_path), ApplicationAppletParameters());
auto const path = (sd_dir / "atmosphere" / "hbl.nsp").string();
BootGame(QString::fromStdString(path), ApplicationAppletParameters());
} else if (should_launch_hlaunch_uloader) {
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
auto const path = (sd_dir / "ulaunch" / "bin" / "uLoader" / "application" / "main").string();
auto params = ApplicationAppletParameters();
params.launch_type = Service::AM::LaunchType::FrontendUlaunchInitiated;
BootGame(QString::fromStdString(path), params);
} else if (should_launch_ulaunch) {
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
auto const path = (sd_dir / "ulaunch" / "bin" / "uMenu" / "main").string();
auto const program_id = 0x010000000000FFFF;
auto const applet_id = Service::AM::AppletId::UlauncherUmenu;
auto params = LibraryAppletParameters(program_id, applet_id);
QtCommon::system->GetFrontendAppletHolder().SetCurrentAppletId(applet_id);
BootGame(QString::fromStdString(path), params);
}
}
}
@ -2779,7 +2796,7 @@ void MainWindow::OnMenuLoadFolder() {
const QDir dir{dir_path};
const QStringList matching_main = dir.entryList({QStringLiteral("main")}, QDir::Files);
if (matching_main.size() == 1) {
if (matching_main.size() > 0) {
BootGame(dir.path() + QDir::separator() + matching_main[0], ApplicationAppletParameters());
} else {
QMessageBox::warning(this, tr("Invalid Directory Selected"),