early-access version 4136

main
pineappleEA 2024-02-13 04:52:59 +01:00
parent 765c7bb93a
commit 42df655225
102 changed files with 5712 additions and 926 deletions

View File

@ -1,7 +1,7 @@
yuzu emulator early access
=============
This is the source code for early-access 4134.
This is the source code for early-access 4136.
## Legal Notice

View File

@ -49,9 +49,7 @@
#include "core/frontend/applets/profile_select.h"
#include "core/frontend/applets/software_keyboard.h"
#include "core/frontend/applets/web_browser.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/loader/loader.h"

View File

@ -417,74 +417,72 @@ add_library(core STATIC
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.h
hle/service/am/applet_ae.cpp
hle/service/am/applet_ae.h
hle/service/am/applet_manager.cpp
hle/service/am/applet_data_broker.cpp
hle/service/am/applet_data_broker.h
hle/service/am/applet_manager.h
hle/service/am/applet_oe.cpp
hle/service/am/applet_oe.h
hle/service/am/applet_common_functions.cpp
hle/service/am/applet_common_functions.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/application_creator.cpp
hle/service/am/application_creator.h
hle/service/am/application_functions.cpp
hle/service/am/application_functions.h
hle/service/am/application_proxy.cpp
hle/service/am/application_proxy.h
hle/service/am/audio_controller.cpp
hle/service/am/audio_controller.h
hle/service/am/common_state_getter.cpp
hle/service/am/common_state_getter.h
hle/service/am/debug_functions.cpp
hle/service/am/debug_functions.h
hle/service/am/display_controller.cpp
hle/service/am/display_controller.h
hle/service/am/global_state_controller.cpp
hle/service/am/global_state_controller.h
hle/service/am/hid_registration.cpp
hle/service/am/hid_registration.h
hle/service/am/home_menu_functions.cpp
hle/service/am/home_menu_functions.h
hle/service/am/idle.cpp
hle/service/am/idle.h
hle/service/am/library_applet_accessor.cpp
hle/service/am/library_applet_accessor.h
hle/service/am/library_applet_creator.cpp
hle/service/am/library_applet_creator.h
hle/service/am/library_applet_proxy.cpp
hle/service/am/library_applet_proxy.h
hle/service/am/library_applet_self_accessor.cpp
hle/service/am/library_applet_self_accessor.h
hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h
hle/service/am/lock_accessor.cpp
hle/service/am/lock_accessor.h
hle/service/am/managed_layer_holder.cpp
hle/service/am/managed_layer_holder.h
hle/service/am/omm.cpp
hle/service/am/omm.h
hle/service/am/process_winding_controller.cpp
hle/service/am/process_winding_controller.h
hle/service/am/process.cpp
hle/service/am/process.h
hle/service/am/self_controller.cpp
hle/service/am/self_controller.h
hle/service/am/system_applet_proxy.cpp
hle/service/am/system_applet_proxy.h
hle/service/am/service/all_system_applet_proxies_service.cpp
hle/service/am/service/all_system_applet_proxies_service.h
hle/service/am/service/applet_common_functions.cpp
hle/service/am/service/applet_common_functions.h
hle/service/am/service/application_accessor.cpp
hle/service/am/service/application_accessor.h
hle/service/am/service/application_creator.cpp
hle/service/am/service/application_creator.h
hle/service/am/service/application_functions.cpp
hle/service/am/service/application_functions.h
hle/service/am/service/application_proxy_service.cpp
hle/service/am/service/application_proxy_service.h
hle/service/am/service/application_proxy.cpp
hle/service/am/service/application_proxy.h
hle/service/am/service/audio_controller.cpp
hle/service/am/service/audio_controller.h
hle/service/am/service/common_state_getter.cpp
hle/service/am/service/common_state_getter.h
hle/service/am/service/cradle_firmware_updater.cpp
hle/service/am/service/cradle_firmware_updater.h
hle/service/am/service/debug_functions.cpp
hle/service/am/service/debug_functions.h
hle/service/am/service/display_controller.cpp
hle/service/am/service/display_controller.h
hle/service/am/service/global_state_controller.cpp
hle/service/am/service/global_state_controller.h
hle/service/am/service/home_menu_functions.cpp
hle/service/am/service/home_menu_functions.h
hle/service/am/service/library_applet_accessor.cpp
hle/service/am/service/library_applet_accessor.h
hle/service/am/service/library_applet_creator.cpp
hle/service/am/service/library_applet_creator.h
hle/service/am/service/library_applet_proxy.cpp
hle/service/am/service/library_applet_proxy.h
hle/service/am/service/library_applet_self_accessor.cpp
hle/service/am/service/library_applet_self_accessor.h
hle/service/am/service/lock_accessor.cpp
hle/service/am/service/lock_accessor.h
hle/service/am/service/process_winding_controller.cpp
hle/service/am/service/process_winding_controller.h
hle/service/am/service/self_controller.cpp
hle/service/am/service/self_controller.h
hle/service/am/service/storage_accessor.cpp
hle/service/am/service/storage_accessor.h
hle/service/am/service/storage.cpp
hle/service/am/service/storage.h
hle/service/am/service/system_applet_proxy.cpp
hle/service/am/service/system_applet_proxy.h
hle/service/am/service/window_controller.cpp
hle/service/am/service/window_controller.h
hle/service/am/system_buffer_manager.cpp
hle/service/am/system_buffer_manager.h
hle/service/am/spsm.cpp
hle/service/am/spsm.h
hle/service/am/storage_accessor.cpp
hle/service/am/storage_accessor.h
hle/service/am/storage.cpp
hle/service/am/storage.h
hle/service/am/window_controller.cpp
hle/service/am/window_controller.h
hle/service/aoc/aoc_u.cpp
hle/service/aoc/aoc_u.h
hle/service/apm/apm.cpp
@ -668,6 +666,18 @@ add_library(core STATIC
hle/service/ldn/ldn.h
hle/service/ldn/ldn_results.h
hle/service/ldn/ldn_types.h
hle/service/ldn/monitor_service.cpp
hle/service/ldn/monitor_service.h
hle/service/ldn/sf_monitor_service.cpp
hle/service/ldn/sf_monitor_service.h
hle/service/ldn/sf_service.cpp
hle/service/ldn/sf_service.h
hle/service/ldn/sf_service_monitor.cpp
hle/service/ldn/sf_service_monitor.h
hle/service/ldn/system_local_communication_service.cpp
hle/service/ldn/system_local_communication_service.h
hle/service/ldn/user_local_communication_service.cpp
hle/service/ldn/user_local_communication_service.h
hle/service/ldr/ldr.cpp
hle/service/ldr/ldr.h
hle/service/lm/lm.cpp
@ -811,6 +821,14 @@ add_library(core STATIC
hle/service/nvnflinger/window.h
hle/service/olsc/olsc.cpp
hle/service/olsc/olsc.h
hle/service/omm/omm.cpp
hle/service/omm/omm.h
hle/service/omm/operation_mode_manager.cpp
hle/service/omm/operation_mode_manager.h
hle/service/omm/policy_manager_system.cpp
hle/service/omm/policy_manager_system.h
hle/service/omm/power_state_interface.cpp
hle/service/omm/power_state_interface.h
hle/service/os/event.cpp
hle/service/os/event.h
hle/service/os/multi_wait_holder.cpp

View File

@ -522,13 +522,17 @@ void DeviceMemoryManager<Traits>::UpdatePagesCachedCount(DAddr addr, size_t size
auto* memory_device_inter = registered_processes[asid.id];
const auto release_pending = [&] {
if (uncache_bytes > 0) {
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
if (memory_device_inter != nullptr) {
MarkRegionCaching(memory_device_inter, uncache_begin << Memory::YUZU_PAGEBITS,
uncache_bytes, false);
}
uncache_bytes = 0;
}
if (cache_bytes > 0) {
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
cache_bytes, true);
if (memory_device_inter != nullptr) {
MarkRegionCaching(memory_device_inter, cache_begin << Memory::YUZU_PAGEBITS,
cache_bytes, true);
}
cache_bytes = 0;
}
};

View File

@ -2,11 +2,8 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/idle.h"
#include "core/hle/service/am/omm.h"
#include "core/hle/service/am/spsm.h"
#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
#include "core/hle/service/am/service/application_proxy_service.h"
#include "core/hle/service/server_manager.h"
namespace Service::AM {
@ -14,13 +11,10 @@ namespace Service::AM {
void LoopProcess(Nvnflinger::Nvnflinger& nvnflinger, Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("appletAE",
std::make_shared<AppletAE>(nvnflinger, system));
server_manager->RegisterNamedService("appletOE",
std::make_shared<AppletOE>(nvnflinger, system));
server_manager->RegisterNamedService("idle:sys", std::make_shared<IdleSys>(system));
server_manager->RegisterNamedService("omm", std::make_shared<OMM>(system));
server_manager->RegisterNamedService("spsm", std::make_shared<SPSM>(system));
server_manager->RegisterNamedService(
"appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, nvnflinger));
server_manager->RegisterNamedService(
"appletOE", std::make_shared<IApplicationProxyService>(system, nvnflinger));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -18,7 +18,7 @@ enum class AppletType {
SystemApplet,
};
enum class GameplayRecordingState : u32 {
enum class GamePlayRecordingState : u32 {
Disabled,
Enabled,
};
@ -67,10 +67,9 @@ enum class ScreenshotPermission : u32 {
};
struct FocusHandlingMode {
bool unknown0;
bool unknown1;
bool unknown2;
bool unknown3;
bool notify;
bool background;
bool suspend;
};
enum class IdleTimeDetectionExtension : u32 {
@ -128,6 +127,40 @@ enum class AppletProgramId : u64 {
MaxProgramId = 0x0100000000001FFFull,
};
// This is nn::am::AppletMessage
enum class AppletMessage : u32 {
None = 0,
ChangeIntoForeground = 1,
ChangeIntoBackground = 2,
Exit = 4,
ApplicationExited = 6,
FocusStateChanged = 15,
Resume = 16,
DetectShortPressingHomeButton = 20,
DetectLongPressingHomeButton = 21,
DetectShortPressingPowerButton = 22,
DetectMiddlePressingPowerButton = 23,
DetectLongPressingPowerButton = 24,
RequestToPrepareSleep = 25,
FinishedSleepSequence = 26,
SleepRequiredByHighTemperature = 27,
SleepRequiredByLowBattery = 28,
AutoPowerDown = 29,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
DetectReceivingCecSystemStandby = 32,
SdCardRemoved = 33,
LaunchApplicationRequested = 50,
RequestToDisplay = 51,
ShowApplicationLogo = 55,
HideApplicationLogo = 56,
ForceHideApplicationLogo = 57,
FloatingApplicationDetected = 60,
DetectShortPressingCaptureButton = 90,
AlbumScreenShotTaken = 92,
AlbumRecordingSaved = 93,
};
enum class LibraryAppletMode : u32 {
AllForeground = 0,
PartialForeground = 1,
@ -136,6 +169,11 @@ enum class LibraryAppletMode : u32 {
AllForegroundInitiallyHidden = 4,
};
enum class LaunchParameterKind : u32 {
UserChannel = 1,
AccountPreselectedUser = 2,
};
enum class CommonArgumentVersion : u32 {
Version0,
Version1,
@ -152,6 +190,22 @@ enum class ThemeColor : u32 {
BasicBlack = 3,
};
enum class InputDetectionPolicy : u32 {
Unknown0 = 0,
Unknown1 = 1,
};
enum class WindowOriginMode : u32 {
LowerLeft = 0,
UpperLeft = 1,
};
enum class ProgramSpecifyKind : u32 {
ExecuteProgram = 0,
JumpToSubApplicationProgramForDevelopment = 1,
RestartProgram = 2,
};
struct CommonArguments {
CommonArgumentVersion arguments_version;
CommonArgumentSize size;
@ -169,6 +223,27 @@ struct AppletIdentityInfo {
};
static_assert(sizeof(AppletIdentityInfo) == 0x10, "AppletIdentityInfo has incorrect size.");
struct AppletAttribute {
u8 flag;
INSERT_PADDING_BYTES_NOINIT(0x7F);
};
static_assert(sizeof(AppletAttribute) == 0x80, "AppletAttribute has incorrect size.");
// This is nn::oe::DisplayVersion
struct DisplayVersion {
std::array<char, 0x10> string;
};
static_assert(sizeof(DisplayVersion) == 0x10, "DisplayVersion has incorrect size.");
// This is nn::pdm::ApplicationPlayStatistics
struct ApplicationPlayStatistics {
u64 application_id;
u64 play_time_ns;
u64 launch_count;
};
static_assert(sizeof(ApplicationPlayStatistics) == 0x18,
"ApplicationPlayStatistics has incorrect size.");
using AppletResourceUserId = u64;
using ProgramId = u64;

View File

@ -3,7 +3,6 @@
#pragma once
#include <list>
#include <mutex>
#include "common/math_util.h"
@ -18,7 +17,6 @@
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/managed_layer_holder.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/system_buffer_manager.h"
namespace Service::AM {
@ -76,8 +74,8 @@ struct Applet {
u32 application_core_usage_mode{};
// Application functions
bool gameplay_recording_supported{};
GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled};
bool game_play_recording_supported{};
GamePlayRecordingState game_play_recording_state{GamePlayRecordingState::Disabled};
bool jit_service_launched{};
bool is_running{};
bool application_crash_report_enabled{};

View File

@ -12,6 +12,7 @@
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/frontend/applet_mii_edit_types.h"
#include "core/hle/service/am/frontend/applet_software_keyboard_types.h"
#include "core/hle/service/am/service/storage.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
@ -303,8 +304,8 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters(
}
// Applet was started by frontend, so it is foreground.
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged);
applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessage::FocusStateChanged);
applet->focus_state = FocusState::InFocus;
this->InsertApplet(std::move(applet));

View File

@ -33,7 +33,7 @@ void AppletMessageQueue::PushMessage(AppletMessage msg) {
on_new_message->Signal();
}
AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() {
AppletMessage AppletMessageQueue::PopMessage() {
std::scoped_lock lk{lock};
if (messages.empty()) {
on_new_message->Clear();

View File

@ -5,6 +5,7 @@
#include <queue>
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
@ -16,40 +17,6 @@ namespace Service::AM {
class AppletMessageQueue {
public:
// This is nn::am::AppletMessage
enum class AppletMessage : u32 {
None = 0,
ChangeIntoForeground = 1,
ChangeIntoBackground = 2,
Exit = 4,
ApplicationExited = 6,
FocusStateChanged = 15,
Resume = 16,
DetectShortPressingHomeButton = 20,
DetectLongPressingHomeButton = 21,
DetectShortPressingPowerButton = 22,
DetectMiddlePressingPowerButton = 23,
DetectLongPressingPowerButton = 24,
RequestToPrepareSleep = 25,
FinishedSleepSequence = 26,
SleepRequiredByHighTemperature = 27,
SleepRequiredByLowBattery = 28,
AutoPowerDown = 29,
OperationModeChanged = 30,
PerformanceModeChanged = 31,
DetectReceivingCecSystemStandby = 32,
SdCardRemoved = 33,
LaunchApplicationRequested = 50,
RequestToDisplay = 51,
ShowApplicationLogo = 55,
HideApplicationLogo = 56,
ForceHideApplicationLogo = 57,
FloatingApplicationDetected = 60,
DetectShortPressingCaptureButton = 90,
AlbumScreenShotTaken = 92,
AlbumRecordingSaved = 93,
};
explicit AppletMessageQueue(Core::System& system);
~AppletMessageQueue();

View File

@ -9,7 +9,7 @@
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_cabinet.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfc/common/device.h"
#include "hid_core/hid_core.h"

View File

@ -12,7 +12,7 @@
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"

View File

@ -10,7 +10,7 @@
#include "core/frontend/applets/error.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_error.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/reporter.h"
namespace Service::AM::Frontend {

View File

@ -10,7 +10,7 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/frontend/applet_general.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/reporter.h"
namespace Service::AM::Frontend {

View File

@ -7,7 +7,7 @@
#include "core/frontend/applets/mii_edit.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_mii_edit.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/mii/mii.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/sm/sm.h"

View File

@ -10,7 +10,7 @@
#include "core/hle/service/acc/errors.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_profile_select.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
namespace Service::AM::Frontend {

View File

@ -6,7 +6,7 @@
#include "core/frontend/applets/software_keyboard.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_software_keyboard.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
namespace Service::AM::Frontend {

View File

@ -20,7 +20,7 @@
#include "core/hle/result.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ns/iplatform_service_manager.h"
#include "core/loader/loader.h"

View File

@ -15,11 +15,8 @@
#include "core/frontend/applets/web_browser.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/frontend/applet_cabinet.h"
#include "core/hle/service/am/frontend/applet_controller.h"
#include "core/hle/service/am/frontend/applet_error.h"
@ -29,7 +26,7 @@
#include "core/hle/service/am/frontend/applet_software_keyboard.h"
#include "core/hle/service/am/frontend/applet_web_browser.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM::Frontend {

View File

@ -0,0 +1,80 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/all_system_applet_proxies_service.h"
#include "core/hle/service/am/service/library_applet_proxy.h"
#include "core/hle/service/am/service/system_applet_proxy.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "appletAE"}, m_nvnflinger{nvnflinger} {
// clang-format off
static const FunctionInfo functions[] = {
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
{200, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld>, "OpenLibraryAppletProxyOld"},
{201, D<&IAllSystemAppletProxiesService::OpenLibraryAppletProxy>, "OpenLibraryAppletProxy"},
{300, nullptr, "OpenOverlayAppletProxy"},
{350, nullptr, "OpenSystemApplicationProxy"},
{400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
{410, nullptr, "GetSystemAppletControllerForDebug"},
{1000, nullptr, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
IAllSystemAppletProxiesService::~IAllSystemAppletProxiesService() = default;
Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
system, applet, process_handle.Get(), m_nvnflinger);
R_SUCCEED();
} else {
UNIMPLEMENTED();
R_THROW(ResultUnknown);
}
}
Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid); applet) {
*out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
system, applet, process_handle.Get(), m_nvnflinger);
R_SUCCEED();
} else {
UNIMPLEMENTED();
R_THROW(ResultUnknown);
}
}
Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld(
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle) {
LOG_DEBUG(Service_AM, "called");
AppletAttribute attribute{};
R_RETURN(
this->OpenLibraryAppletProxy(out_library_applet_proxy, pid, process_handle, attribute));
}
std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
ProcessId process_id) {
return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
}
} // namespace Service::AM

View File

@ -0,0 +1,47 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service {
namespace Nvnflinger {
class Nvnflinger;
}
namespace AM {
struct Applet;
struct AppletAttribute;
class ILibraryAppletProxy;
class ISystemAppletProxy;
class IAllSystemAppletProxiesService final
: public ServiceFramework<IAllSystemAppletProxiesService> {
public:
explicit IAllSystemAppletProxiesService(Core::System& system_,
Nvnflinger::Nvnflinger& nvnflinger);
~IAllSystemAppletProxiesService() override;
private:
Result OpenSystemAppletProxy(Out<SharedPointer<ISystemAppletProxy>> out_system_applet_proxy,
ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle);
Result OpenLibraryAppletProxy(Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy,
ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle,
InLargeData<AppletAttribute, BufferAttr_HipcMapAlias> attribute);
Result OpenLibraryAppletProxyOld(
Out<SharedPointer<ILibraryAppletProxy>> out_library_applet_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle);
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
Nvnflinger::Nvnflinger& m_nvnflinger;
};
} // namespace AM
} // namespace Service

View File

@ -0,0 +1,63 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "IAppletCommonFunctions"}, applet{std::move(applet_)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "SetTerminateResult"},
{10, nullptr, "ReadThemeStorage"},
{11, nullptr, "WriteThemeStorage"},
{20, nullptr, "PushToAppletBoundChannel"},
{21, nullptr, "TryPopFromAppletBoundChannel"},
{40, nullptr, "GetDisplayLogicalResolution"},
{42, nullptr, "SetDisplayMagnification"},
{50, nullptr, "SetHomeButtonDoubleClickEnabled"},
{51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
{60, nullptr, "IsVrModeCurtainRequired"},
{61, nullptr, "IsSleepRequiredByHighTemperature"},
{62, nullptr, "IsSleepRequiredByLowBattery"},
{70, D<&IAppletCommonFunctions::SetCpuBoostRequestPriority>, "SetCpuBoostRequestPriority"},
{80, nullptr, "SetHandlingCaptureButtonShortPressedMessageEnabledForApplet"},
{81, nullptr, "SetHandlingCaptureButtonLongPressedMessageEnabledForApplet"},
{90, nullptr, "OpenNamedChannelAsParent"},
{91, nullptr, "OpenNamedChannelAsChild"},
{100, nullptr, "SetApplicationCoreUsageMode"},
{300, D<&IAppletCommonFunctions::GetCurrentApplicationId>, "GetCurrentApplicationId"},
};
// clang-format on
RegisterHandlers(functions);
}
IAppletCommonFunctions::~IAppletCommonFunctions() = default;
Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
Out<bool> out_home_button_double_click_enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_home_button_double_click_enabled = false;
R_SUCCEED();
}
Result IAppletCommonFunctions::SetCpuBoostRequestPriority(s32 priority) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{applet->lock};
applet->cpu_boost_request_priority = priority;
R_SUCCEED();
}
Result IAppletCommonFunctions::GetCurrentApplicationId(Out<u64> out_application_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_application_id = system.GetApplicationProcessProgramID() & ~0xFFFULL;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IAppletCommonFunctions final : public ServiceFramework<IAppletCommonFunctions> {
public:
explicit IAppletCommonFunctions(Core::System& system_, std::shared_ptr<Applet> applet_);
~IAppletCommonFunctions() override;
private:
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
Result SetCpuBoostRequestPriority(s32 priority);
Result GetCurrentApplicationId(Out<u64> out_application_id);
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,138 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/result.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_data_broker.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/application_accessor.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationAccessor"}, m_applet(std::move(applet)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
{1, nullptr, "IsCompleted"},
{10, D<&IApplicationAccessor::Start>, "Start"},
{20, D<&IApplicationAccessor::RequestExit>, "RequestExit"},
{25, D<&IApplicationAccessor::Terminate>, "Terminate"},
{30, D<&IApplicationAccessor::GetResult>, "GetResult"},
{101, D<&IApplicationAccessor::RequestForApplicationToGetForeground>, "RequestForApplicationToGetForeground"},
{110, nullptr, "TerminateAllLibraryApplets"},
{111, nullptr, "AreAnyLibraryAppletsLeft"},
{112, D<&IApplicationAccessor::GetCurrentLibraryApplet>, "GetCurrentLibraryApplet"},
{120, nullptr, "GetApplicationId"},
{121, D<&IApplicationAccessor::PushLaunchParameter>, "PushLaunchParameter"},
{122, D<&IApplicationAccessor::GetApplicationControlProperty>, "GetApplicationControlProperty"},
{123, nullptr, "GetApplicationLaunchProperty"},
{124, nullptr, "GetApplicationLaunchRequestInfo"},
{130, D<&IApplicationAccessor::SetUsers>, "SetUsers"},
{131, D<&IApplicationAccessor::CheckRightsEnvironmentAvailable>, "CheckRightsEnvironmentAvailable"},
{132, D<&IApplicationAccessor::GetNsRightsEnvironmentHandle>, "GetNsRightsEnvironmentHandle"},
{140, nullptr, "GetDesirableUids"},
{150, D<&IApplicationAccessor::ReportApplicationExitTimeout>, "ReportApplicationExitTimeout"},
{160, nullptr, "SetApplicationAttribute"},
{170, nullptr, "HasSaveDataAccessPermission"},
{180, nullptr, "PushToFriendInvitationStorageChannel"},
{190, nullptr, "PushToNotificationStorageChannel"},
{200, nullptr, "RequestApplicationSoftReset"},
{201, nullptr, "RestartApplicationTimer"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationAccessor::~IApplicationAccessor() = default;
Result IApplicationAccessor::Start() {
LOG_INFO(Service_AM, "called");
m_applet->process->Run();
R_SUCCEED();
}
Result IApplicationAccessor::RequestExit() {
LOG_INFO(Service_AM, "called");
m_applet->message_queue.RequestExit();
R_SUCCEED();
}
Result IApplicationAccessor::Terminate() {
LOG_INFO(Service_AM, "called");
m_applet->process->Terminate();
R_SUCCEED();
}
Result IApplicationAccessor::GetResult() {
LOG_INFO(Service_AM, "called");
R_SUCCEED();
}
Result IApplicationAccessor::GetAppletStateChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_applet->caller_applet_broker->GetStateChangedEvent().GetHandle();
R_SUCCEED();
}
Result IApplicationAccessor::PushLaunchParameter(LaunchParameterKind kind,
SharedPointer<IStorage> storage) {
LOG_INFO(Service_AM, "called, kind={}", kind);
switch (kind) {
case LaunchParameterKind::AccountPreselectedUser:
m_applet->preselected_user_launch_parameter.push_back(storage->GetData());
R_SUCCEED();
default:
R_THROW(ResultUnknown);
}
}
Result IApplicationAccessor::GetApplicationControlProperty(
OutBuffer<BufferAttr_HipcMapAlias> out_control_property) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_THROW(ResultUnknown);
}
Result IApplicationAccessor::SetUsers(bool enable,
InArray<Common::UUID, BufferAttr_HipcMapAlias> user_ids) {
LOG_INFO(Service_AM, "called, enable={} user_id_count={}", enable, user_ids.size());
R_SUCCEED();
}
Result IApplicationAccessor::GetCurrentLibraryApplet(
Out<SharedPointer<ILibraryAppletAccessor>> out_accessor) {
LOG_INFO(Service_AM, "(STUBBED) called");
*out_accessor = nullptr;
R_SUCCEED();
}
Result IApplicationAccessor::RequestForApplicationToGetForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_THROW(ResultUnknown);
}
Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_is_available = true;
R_SUCCEED();
}
Result IApplicationAccessor::GetNsRightsEnvironmentHandle(Out<u64> out_handle) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_handle = 0xdeadbeef;
R_SUCCEED();
}
Result IApplicationAccessor::ReportApplicationExitTimeout() {
LOG_ERROR(Service_AM, "called");
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/uuid.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IStorage;
class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> {
public:
explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
~IApplicationAccessor() override;
private:
Result Start();
Result RequestExit();
Result Terminate();
Result GetResult();
Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result PushLaunchParameter(LaunchParameterKind kind, SharedPointer<IStorage> storage);
Result GetApplicationControlProperty(OutBuffer<BufferAttr_HipcMapAlias> out_control_property);
Result SetUsers(bool enable, InArray<Common::UUID, BufferAttr_HipcMapAlias> user_ids);
Result GetCurrentLibraryApplet(Out<SharedPointer<ILibraryAppletAccessor>> out_accessor);
Result RequestForApplicationToGetForeground();
Result CheckRightsEnvironmentAvailable(Out<bool> out_is_available);
Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
Result ReportApplicationExitTimeout();
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/application_accessor.h"
#include "core/hle/service/am/service/application_creator.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IApplicationCreator::IApplicationCreator(Core::System& system_)
: ServiceFramework{system_, "IApplicationCreator"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
{1, nullptr, "PopLaunchRequestedApplication"},
{10, nullptr, "CreateSystemApplication"},
{100, nullptr, "PopFloatingApplicationForDevelopment"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationCreator::~IApplicationCreator() = default;
Result IApplicationCreator::CreateApplication(
Out<SharedPointer<IApplicationAccessor>> out_application_accessor, u64 application_id) {
LOG_ERROR(Service_NS, "called, application_id={:x}", application_id);
R_THROW(ResultUnknown);
}
} // namespace Service::AM

View File

@ -0,0 +1,23 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class IApplicationAccessor;
struct Applet;
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public:
explicit IApplicationCreator(Core::System& system_);
~IApplicationCreator() override;
private:
Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
};
} // namespace Service::AM

View File

@ -0,0 +1,465 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "common/uuid.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/savedata_factory.h"
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/application_functions.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/filesystem/save_data_controller.h"
#include "core/hle/service/ns/ns.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
IApplicationFunctions::IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationFunctions"}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{1, D<&IApplicationFunctions::PopLaunchParameter>, "PopLaunchParameter"},
{10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
{11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
{12, nullptr, "CreateApplicationAndRequestToStart"},
{13, nullptr, "CreateApplicationAndRequestToStartForQuest"},
{14, nullptr, "CreateApplicationWithAttributeAndPushAndRequestToStartForQuest"},
{15, nullptr, "CreateApplicationWithAttributeAndRequestToStartForQuest"},
{20, D<&IApplicationFunctions::EnsureSaveData>, "EnsureSaveData"},
{21, D<&IApplicationFunctions::GetDesiredLanguage>, "GetDesiredLanguage"},
{22, D<&IApplicationFunctions::SetTerminateResult>, "SetTerminateResult"},
{23, D<&IApplicationFunctions::GetDisplayVersion>, "GetDisplayVersion"},
{24, nullptr, "GetLaunchStorageInfoForDebug"},
{25, D<&IApplicationFunctions::ExtendSaveData>, "ExtendSaveData"},
{26, D<&IApplicationFunctions::GetSaveDataSize>, "GetSaveDataSize"},
{27, D<&IApplicationFunctions::CreateCacheStorage>, "CreateCacheStorage"},
{28, D<&IApplicationFunctions::GetSaveDataSizeMax>, "GetSaveDataSizeMax"},
{29, nullptr, "GetCacheStorageMax"},
{30, D<&IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed>, "BeginBlockingHomeButtonShortAndLongPressed"},
{31, D<&IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed>, "EndBlockingHomeButtonShortAndLongPressed"},
{32, D<&IApplicationFunctions::BeginBlockingHomeButton>, "BeginBlockingHomeButton"},
{33, D<&IApplicationFunctions::EndBlockingHomeButton>, "EndBlockingHomeButton"},
{34, nullptr, "SelectApplicationLicense"},
{35, nullptr, "GetDeviceSaveDataSizeMax"},
{36, nullptr, "GetLimitedApplicationLicense"},
{37, nullptr, "GetLimitedApplicationLicenseUpgradableEvent"},
{40, D<&IApplicationFunctions::NotifyRunning>, "NotifyRunning"},
{50, D<&IApplicationFunctions::GetPseudoDeviceId>, "GetPseudoDeviceId"},
{60, nullptr, "SetMediaPlaybackStateForApplication"},
{65, D<&IApplicationFunctions::IsGamePlayRecordingSupported>, "IsGamePlayRecordingSupported"},
{66, D<&IApplicationFunctions::InitializeGamePlayRecording>, "InitializeGamePlayRecording"},
{67, D<&IApplicationFunctions::SetGamePlayRecordingState>, "SetGamePlayRecordingState"},
{68, nullptr, "RequestFlushGamePlayingMovieForDebug"},
{70, nullptr, "RequestToShutdown"},
{71, nullptr, "RequestToReboot"},
{72, nullptr, "RequestToSleep"},
{80, nullptr, "ExitAndRequestToShowThanksMessage"},
{90, D<&IApplicationFunctions::EnableApplicationCrashReport>, "EnableApplicationCrashReport"},
{100, D<&IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer>, "InitializeApplicationCopyrightFrameBuffer"},
{101, D<&IApplicationFunctions::SetApplicationCopyrightImage>, "SetApplicationCopyrightImage"},
{102, D<&IApplicationFunctions::SetApplicationCopyrightVisibility>, "SetApplicationCopyrightVisibility"},
{110, D<&IApplicationFunctions::QueryApplicationPlayStatistics>, "QueryApplicationPlayStatistics"},
{111, D<&IApplicationFunctions::QueryApplicationPlayStatisticsByUid>, "QueryApplicationPlayStatisticsByUid"},
{120, D<&IApplicationFunctions::ExecuteProgram>, "ExecuteProgram"},
{121, D<&IApplicationFunctions::ClearUserChannel>, "ClearUserChannel"},
{122, D<&IApplicationFunctions::UnpopToUserChannel>, "UnpopToUserChannel"},
{123, D<&IApplicationFunctions::GetPreviousProgramIndex>, "GetPreviousProgramIndex"},
{124, nullptr, "EnableApplicationAllThreadDumpOnCrash"},
{130, D<&IApplicationFunctions::GetGpuErrorDetectedSystemEvent>, "GetGpuErrorDetectedSystemEvent"},
{131, nullptr, "SetDelayTimeToAbortOnGpuError"},
{140, D<&IApplicationFunctions::GetFriendInvitationStorageChannelEvent>, "GetFriendInvitationStorageChannelEvent"},
{141, D<&IApplicationFunctions::TryPopFromFriendInvitationStorageChannel>, "TryPopFromFriendInvitationStorageChannel"},
{150, D<&IApplicationFunctions::GetNotificationStorageChannelEvent>, "GetNotificationStorageChannelEvent"},
{151, nullptr, "TryPopFromNotificationStorageChannel"},
{160, D<&IApplicationFunctions::GetHealthWarningDisappearedSystemEvent>, "GetHealthWarningDisappearedSystemEvent"},
{170, nullptr, "SetHdcpAuthenticationActivated"},
{180, nullptr, "GetLaunchRequiredVersion"},
{181, nullptr, "UpgradeLaunchRequiredVersion"},
{190, nullptr, "SendServerMaintenanceOverlayNotification"},
{200, nullptr, "GetLastApplicationExitReason"},
{500, nullptr, "StartContinuousRecordingFlushForDebug"},
{1000, nullptr, "CreateMovieMaker"},
{1001, D<&IApplicationFunctions::PrepareForJit>, "PrepareForJit"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationFunctions::~IApplicationFunctions() = default;
Result IApplicationFunctions::PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage,
LaunchParameterKind launch_parameter_kind) {
LOG_INFO(Service_AM, "called, kind={}", launch_parameter_kind);
std::scoped_lock lk{m_applet->lock};
auto& channel = launch_parameter_kind == LaunchParameterKind::UserChannel
? m_applet->user_channel_launch_parameter
: m_applet->preselected_user_launch_parameter;
if (channel.empty()) {
LOG_WARNING(Service_AM, "Attempted to pop parameter {} but none was found!",
launch_parameter_kind);
R_THROW(AM::ResultNoDataInChannel);
}
auto data = channel.back();
channel.pop_back();
*out_storage = std::make_shared<IStorage>(system, std::move(data));
R_SUCCEED();
}
Result IApplicationFunctions::EnsureSaveData(Out<u64> out_size, Common::UUID user_id) {
LOG_INFO(Service_AM, "called, uid={}", user_id.FormattedString());
FileSys::SaveDataAttribute attribute{};
attribute.title_id = m_applet->program_id;
attribute.user_id = user_id.AsU128();
attribute.type = FileSys::SaveDataType::SaveData;
FileSys::VirtualDir save_data{};
R_TRY(system.GetFileSystemController().OpenSaveDataController()->CreateSaveData(
&save_data, FileSys::SaveDataSpaceId::NandUser, attribute));
*out_size = 0;
R_SUCCEED();
}
Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
// FIXME: all of this stuff belongs to ns
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = [this] {
const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
u8 desired_language{};
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
// Convert to settings language code.
R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(out_language_code, desired_language));
LOG_DEBUG(Service_AM, "got desired_language={:016X}", *out_language_code);
R_SUCCEED();
}
Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(),
static_cast<u32>(terminate_result.GetModule()) + 2000,
terminate_result.GetDescription());
std::scoped_lock lk{m_applet->lock};
m_applet->terminate_result = terminate_result;
R_SUCCEED();
}
Result IApplicationFunctions::GetDisplayVersion(Out<DisplayVersion> out_display_version) {
LOG_DEBUG(Service_AM, "called");
const auto res = [this] {
const FileSys::PatchManager pm{m_applet->program_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(m_applet->program_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
const auto& version = res.first->GetVersionString();
std::memcpy(out_display_version->string.data(), version.data(),
std::min(version.size(), out_display_version->string.size()));
} else {
static constexpr char default_version[]{"1.0.0"};
std::memcpy(out_display_version->string.data(), default_version, sizeof(default_version));
}
out_display_version->string[out_display_version->string.size() - 1] = '\0';
R_SUCCEED();
}
Result IApplicationFunctions::ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type,
Common::UUID user_id, u64 normal_size,
u64 journal_size) {
LOG_DEBUG(Service_AM, "called with type={} user_id={} normal={:#x} journal={:#x}",
static_cast<u8>(type), user_id.FormattedString(), normal_size, journal_size);
system.GetFileSystemController().OpenSaveDataController()->WriteSaveDataSize(
type, m_applet->program_id, user_id.AsU128(), {normal_size, journal_size});
// The following value is used to indicate the amount of space remaining on failure
// due to running out of space. Since we always succeed, this should be 0.
*out_required_size = 0;
R_SUCCEED();
}
Result IApplicationFunctions::GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size,
FileSys::SaveDataType type, Common::UUID user_id) {
LOG_DEBUG(Service_AM, "called with type={} user_id={}", type, user_id.FormattedString());
const auto size = system.GetFileSystemController().OpenSaveDataController()->ReadSaveDataSize(
type, m_applet->program_id, user_id.AsU128());
*out_normal_size = size.normal;
*out_journal_size = size.journal;
R_SUCCEED();
}
Result IApplicationFunctions::CreateCacheStorage(Out<u32> out_target_media,
Out<u64> out_required_size, u16 index,
u64 normal_size, u64 journal_size) {
LOG_WARNING(Service_AM, "(STUBBED) called with index={} size={:#x} journal_size={:#x}", index,
normal_size, journal_size);
*out_target_media = 1; // Nand
*out_required_size = 0;
R_SUCCEED();
}
Result IApplicationFunctions::GetSaveDataSizeMax(Out<u64> out_max_normal_size,
Out<u64> out_max_journal_size) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_max_normal_size = 0xFFFFFFF;
*out_max_journal_size = 0xFFFFFFF;
R_SUCCEED();
}
Result IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed(s64 unused) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_long_pressed_blocked = true;
m_applet->home_button_short_pressed_blocked = true;
R_SUCCEED();
}
Result IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed() {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_long_pressed_blocked = false;
m_applet->home_button_short_pressed_blocked = false;
R_SUCCEED();
}
Result IApplicationFunctions::BeginBlockingHomeButton(s64 timeout_ns) {
LOG_WARNING(Service_AM, "(STUBBED) called, timeout_ns={}", timeout_ns);
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_long_pressed_blocked = true;
m_applet->home_button_short_pressed_blocked = true;
m_applet->home_button_double_click_enabled = true;
R_SUCCEED();
}
Result IApplicationFunctions::EndBlockingHomeButton() {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->home_button_long_pressed_blocked = false;
m_applet->home_button_short_pressed_blocked = false;
m_applet->home_button_double_click_enabled = false;
R_SUCCEED();
}
Result IApplicationFunctions::NotifyRunning(Out<bool> out_became_running) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_became_running = true;
R_SUCCEED();
}
Result IApplicationFunctions::GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_pseudo_device_id = {};
R_SUCCEED();
}
Result IApplicationFunctions::IsGamePlayRecordingSupported(
Out<bool> out_is_game_play_recording_supported) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_is_game_play_recording_supported = m_applet->game_play_recording_supported;
R_SUCCEED();
}
Result IApplicationFunctions::InitializeGamePlayRecording(
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IApplicationFunctions::SetGamePlayRecordingState(
GamePlayRecordingState game_play_recording_state) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->game_play_recording_state = game_play_recording_state;
R_SUCCEED();
}
Result IApplicationFunctions::EnableApplicationCrashReport(bool enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->application_crash_report_enabled = enabled;
R_SUCCEED();
}
Result IApplicationFunctions::InitializeApplicationCopyrightFrameBuffer(
s32 width, s32 height, u64 transfer_memory_size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IApplicationFunctions::SetApplicationCopyrightImage(
s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode,
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IApplicationFunctions::SetApplicationCopyrightVisibility(bool visible) {
LOG_WARNING(Service_AM, "(STUBBED) called, is_visible={}", visible);
R_SUCCEED();
}
Result IApplicationFunctions::QueryApplicationPlayStatistics(
Out<s32> out_entries,
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_entries = 0;
R_SUCCEED();
}
Result IApplicationFunctions::QueryApplicationPlayStatisticsByUid(
Out<s32> out_entries,
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_entries = 0;
R_SUCCEED();
}
Result IApplicationFunctions::ExecuteProgram(ProgramSpecifyKind kind, u64 value) {
LOG_WARNING(Service_AM, "(STUBBED) called, kind={}, value={}", kind, value);
ASSERT(kind == ProgramSpecifyKind::ExecuteProgram ||
kind == ProgramSpecifyKind::RestartProgram);
// Copy user channel ownership into the system so that it will be preserved
system.GetUserChannel() = m_applet->user_channel_launch_parameter;
system.ExecuteProgram(value);
R_SUCCEED();
}
Result IApplicationFunctions::ClearUserChannel() {
LOG_DEBUG(Service_AM, "called");
m_applet->user_channel_launch_parameter.clear();
R_SUCCEED();
}
Result IApplicationFunctions::UnpopToUserChannel(SharedPointer<IStorage> storage) {
LOG_DEBUG(Service_AM, "called");
m_applet->user_channel_launch_parameter.push_back(storage->GetData());
R_SUCCEED();
}
Result IApplicationFunctions::GetPreviousProgramIndex(Out<s32> out_previous_program_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_previous_program_index = m_applet->previous_program_index;
R_SUCCEED();
}
Result IApplicationFunctions::GetGpuErrorDetectedSystemEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_event = m_applet->gpu_error_detected_event.GetHandle();
R_SUCCEED();
}
Result IApplicationFunctions::GetFriendInvitationStorageChannelEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_applet->friend_invitation_storage_channel_event.GetHandle();
R_SUCCEED();
}
Result IApplicationFunctions::TryPopFromFriendInvitationStorageChannel(
Out<SharedPointer<IStorage>> out_storage) {
LOG_INFO(Service_AM, "(STUBBED) called");
R_THROW(AM::ResultNoDataInChannel);
}
Result IApplicationFunctions::GetNotificationStorageChannelEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_applet->notification_storage_channel_event.GetHandle();
R_SUCCEED();
}
Result IApplicationFunctions::GetHealthWarningDisappearedSystemEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_applet->health_warning_disappeared_system_event.GetHandle();
R_SUCCEED();
}
Result IApplicationFunctions::PrepareForJit() {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->jit_service_launched = true;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/uuid.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace FileSys {
enum class SaveDataType : u8;
}
namespace Kernel {
class KReadableEvent;
}
namespace Service::AM {
struct Applet;
class IStorage;
class IApplicationFunctions final : public ServiceFramework<IApplicationFunctions> {
public:
explicit IApplicationFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
~IApplicationFunctions() override;
private:
Result PopLaunchParameter(Out<SharedPointer<IStorage>> out_storage,
LaunchParameterKind launch_parameter_kind);
Result EnsureSaveData(Out<u64> out_size, Common::UUID user_id);
Result GetDesiredLanguage(Out<u64> out_language_code);
Result SetTerminateResult(Result terminate_result);
Result GetDisplayVersion(Out<DisplayVersion> out_display_version);
Result ExtendSaveData(Out<u64> out_required_size, FileSys::SaveDataType type,
Common::UUID user_id, u64 normal_size, u64 journal_size);
Result GetSaveDataSize(Out<u64> out_normal_size, Out<u64> out_journal_size,
FileSys::SaveDataType type, Common::UUID user_id);
Result CreateCacheStorage(Out<u32> out_target_media, Out<u64> out_required_size, u16 index,
u64 normal_size, u64 journal_size);
Result GetSaveDataSizeMax(Out<u64> out_max_normal_size, Out<u64> out_max_journal_size);
Result BeginBlockingHomeButtonShortAndLongPressed(s64 unused);
Result EndBlockingHomeButtonShortAndLongPressed();
Result BeginBlockingHomeButton(s64 timeout_ns);
Result EndBlockingHomeButton();
Result NotifyRunning(Out<bool> out_became_running);
Result GetPseudoDeviceId(Out<Common::UUID> out_pseudo_device_id);
Result IsGamePlayRecordingSupported(Out<bool> out_is_game_play_recording_supported);
Result InitializeGamePlayRecording(
u64 transfer_memory_size, InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
Result SetGamePlayRecordingState(GamePlayRecordingState game_play_recording_state);
Result EnableApplicationCrashReport(bool enabled);
Result InitializeApplicationCopyrightFrameBuffer(
s32 width, s32 height, u64 transfer_memory_size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
Result SetApplicationCopyrightImage(
s32 x, s32 y, s32 width, s32 height, WindowOriginMode window_origin_mode,
InBuffer<BufferAttr_HipcMapTransferAllowsNonSecure | BufferAttr_HipcMapAlias> image_data);
Result SetApplicationCopyrightVisibility(bool visible);
Result QueryApplicationPlayStatistics(
Out<s32> out_entries,
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result QueryApplicationPlayStatisticsByUid(
Out<s32> out_entries,
OutArray<ApplicationPlayStatistics, BufferAttr_HipcMapAlias> out_play_statistics,
Common::UUID user_id, InArray<u64, BufferAttr_HipcMapAlias> application_ids);
Result ExecuteProgram(ProgramSpecifyKind kind, u64 value);
Result ClearUserChannel();
Result UnpopToUserChannel(SharedPointer<IStorage> storage);
Result GetPreviousProgramIndex(Out<s32> out_previous_program_index);
Result GetGpuErrorDetectedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetFriendInvitationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result TryPopFromFriendInvitationStorageChannel(Out<SharedPointer<IStorage>> out_storage);
Result GetNotificationStorageChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetHealthWarningDisappearedSystemEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result PrepareForJit();
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,106 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/am/service/application_functions.h"
#include "core/hle/service/am/service/application_proxy.h"
#include "core/hle/service/am/service/audio_controller.h"
#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/library_applet_creator.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"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "IApplicationProxy"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
{1, D<&IApplicationProxy::GetSelfController>, "GetSelfController"},
{2, D<&IApplicationProxy::GetWindowController>, "GetWindowController"},
{3, D<&IApplicationProxy::GetAudioController>, "GetAudioController"},
{4, D<&IApplicationProxy::GetDisplayController>, "GetDisplayController"},
{10, D<&IApplicationProxy::GetProcessWindingController>, "GetProcessWindingController"},
{11, D<&IApplicationProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
{20, D<&IApplicationProxy::GetApplicationFunctions>, "GetApplicationFunctions"},
{1000, D<&IApplicationProxy::GetDebugFunctions>, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
IApplicationProxy::~IApplicationProxy() = default;
Result IApplicationProxy::GetAudioController(
Out<SharedPointer<IAudioController>> out_audio_controller) {
LOG_DEBUG(Service_AM, "called");
*out_audio_controller = std::make_shared<IAudioController>(system);
R_SUCCEED();
}
Result IApplicationProxy::GetDisplayController(
Out<SharedPointer<IDisplayController>> out_display_controller) {
LOG_DEBUG(Service_AM, "called");
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
R_SUCCEED();
}
Result IApplicationProxy::GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
LOG_DEBUG(Service_AM, "called");
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
R_SUCCEED();
}
Result IApplicationProxy::GetDebugFunctions(
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
LOG_DEBUG(Service_AM, "called");
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
R_SUCCEED();
}
Result IApplicationProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
R_SUCCEED();
}
Result IApplicationProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller =
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
R_SUCCEED();
}
Result IApplicationProxy::GetCommonStateGetter(
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
LOG_DEBUG(Service_AM, "called");
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
R_SUCCEED();
}
Result IApplicationProxy::GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
LOG_DEBUG(Service_AM, "called");
*out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
R_SUCCEED();
}
Result IApplicationProxy::GetApplicationFunctions(
Out<SharedPointer<IApplicationFunctions>> out_application_functions) {
LOG_DEBUG(Service_AM, "called");
*out_application_functions = std::make_shared<IApplicationFunctions>(system, m_applet);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IAudioController;
class IApplicationFunctions;
class ICommonStateGetter;
class IDebugFunctions;
class IDisplayController;
class ILibraryAppletCreator;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
~IApplicationProxy();
private:
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
Result GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
Result GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
Result GetApplicationFunctions(
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
private:
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/application_proxy.h"
#include "core/hle/service/am/service/application_proxy_service.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "appletOE"}, m_nvnflinger{nvnflinger} {
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
};
RegisterHandlers(functions);
}
IApplicationProxyService::~IApplicationProxyService() = default;
Result IApplicationProxyService::OpenApplicationProxy(
Out<SharedPointer<IApplicationProxy>> out_application_proxy, ClientProcessId pid,
InCopyHandle<Kernel::KProcess> process_handle) {
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid)) {
*out_application_proxy =
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get(), m_nvnflinger);
R_SUCCEED();
} else {
UNIMPLEMENTED();
R_THROW(ResultUnknown);
}
}
std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
}
} // namespace Service::AM

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service {
namespace Nvnflinger {
class Nvnflinger;
}
namespace AM {
struct Applet;
class IApplicationProxy;
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
public:
explicit IApplicationProxyService(Core::System& system_, Nvnflinger::Nvnflinger& nvnflinger);
~IApplicationProxyService() override;
private:
Result OpenApplicationProxy(Out<SharedPointer<IApplicationProxy>> out_application_proxy,
ClientProcessId pid, InCopyHandle<Kernel::KProcess> process_handle);
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
Nvnflinger::Nvnflinger& m_nvnflinger;
};
} // namespace AM
} // namespace Service

View File

@ -0,0 +1,69 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/audio_controller.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IAudioController::IAudioController(Core::System& system_)
: ServiceFramework{system_, "IAudioController"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IAudioController::SetExpectedMasterVolume>, "SetExpectedMasterVolume"},
{1, D<&IAudioController::GetMainAppletExpectedMasterVolume>, "GetMainAppletExpectedMasterVolume"},
{2, D<&IAudioController::GetLibraryAppletExpectedMasterVolume>, "GetLibraryAppletExpectedMasterVolume"},
{3, D<&IAudioController::ChangeMainAppletMasterVolume>, "ChangeMainAppletMasterVolume"},
{4, D<&IAudioController::SetTransparentVolumeRate>, "SetTransparentVolumeRate"},
};
// clang-format on
RegisterHandlers(functions);
}
IAudioController::~IAudioController() = default;
Result IAudioController::SetExpectedMasterVolume(f32 main_applet_volume,
f32 library_applet_volume) {
LOG_DEBUG(Service_AM, "called. main_applet_volume={}, library_applet_volume={}",
main_applet_volume, library_applet_volume);
// Ensure the volume values remain within the 0-100% range
m_main_applet_volume = std::clamp(main_applet_volume, MinAllowedVolume, MaxAllowedVolume);
m_library_applet_volume = std::clamp(library_applet_volume, MinAllowedVolume, MaxAllowedVolume);
R_SUCCEED();
}
Result IAudioController::GetMainAppletExpectedMasterVolume(Out<f32> out_main_applet_volume) {
LOG_DEBUG(Service_AM, "called. main_applet_volume={}", m_main_applet_volume);
*out_main_applet_volume = m_main_applet_volume;
R_SUCCEED();
}
Result IAudioController::GetLibraryAppletExpectedMasterVolume(Out<f32> out_library_applet_volume) {
LOG_DEBUG(Service_AM, "called. library_applet_volume={}", m_library_applet_volume);
*out_library_applet_volume = m_library_applet_volume;
R_SUCCEED();
}
Result IAudioController::ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns) {
LOG_DEBUG(Service_AM, "called. volume={}, fade_time_ns={}", volume, fade_time_ns);
m_main_applet_volume = std::clamp(volume, MinAllowedVolume, MaxAllowedVolume);
m_fade_time_ns = std::chrono::nanoseconds{fade_time_ns};
R_SUCCEED();
}
Result IAudioController::SetTransparentVolumeRate(f32 transparent_volume_rate) {
LOG_DEBUG(Service_AM, "called. transparent_volume_rate={}", transparent_volume_rate);
// Clamp volume range to 0-100%.
m_transparent_volume_rate =
std::clamp(transparent_volume_rate, MinAllowedVolume, MaxAllowedVolume);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class IAudioController final : public ServiceFramework<IAudioController> {
public:
explicit IAudioController(Core::System& system_);
~IAudioController() override;
private:
Result SetExpectedMasterVolume(f32 main_applet_volume, f32 library_applet_volume);
Result GetMainAppletExpectedMasterVolume(Out<f32> out_main_applet_volume);
Result GetLibraryAppletExpectedMasterVolume(Out<f32> out_library_applet_volume);
Result ChangeMainAppletMasterVolume(f32 volume, s64 fade_time_ns);
Result SetTransparentVolumeRate(f32 transparent_volume_rate);
static constexpr float MinAllowedVolume = 0.0f;
static constexpr float MaxAllowedVolume = 1.0f;
float m_main_applet_volume{0.25f};
float m_library_applet_volume{MaxAllowedVolume};
float m_transparent_volume_rate{MinAllowedVolume};
// Volume transition fade time in nanoseconds.
// e.g. If the main applet volume was 0% and was changed to 50%
// with a fade of 50ns, then over the course of 50ns,
// the volume will gradually fade up to 50%
std::chrono::nanoseconds m_fade_time_ns{0};
};
} // namespace Service::AM

View File

@ -0,0 +1,277 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/common_state_getter.h"
#include "core/hle/service/am/service/lock_accessor.h"
#include "core/hle/service/apm/apm_interface.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi.h"
namespace Service::AM {
ICommonStateGetter::ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "ICommonStateGetter"}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ICommonStateGetter::GetEventHandle>, "GetEventHandle"},
{1, D<&ICommonStateGetter::ReceiveMessage>, "ReceiveMessage"},
{2, nullptr, "GetThisAppletKind"},
{3, nullptr, "AllowToEnterSleep"},
{4, nullptr, "DisallowToEnterSleep"},
{5, D<&ICommonStateGetter::GetOperationMode>, "GetOperationMode"},
{6, D<&ICommonStateGetter::GetPerformanceMode>, "GetPerformanceMode"},
{7, nullptr, "GetCradleStatus"},
{8, D<&ICommonStateGetter::GetBootMode>, "GetBootMode"},
{9, D<&ICommonStateGetter::GetCurrentFocusState>, "GetCurrentFocusState"},
{10, D<&ICommonStateGetter::RequestToAcquireSleepLock>, "RequestToAcquireSleepLock"},
{11, nullptr, "ReleaseSleepLock"},
{12, nullptr, "ReleaseSleepLockTransiently"},
{13, D<&ICommonStateGetter::GetAcquiredSleepLockEvent>, "GetAcquiredSleepLockEvent"},
{14, nullptr, "GetWakeupCount"},
{20, nullptr, "PushToGeneralChannel"},
{30, nullptr, "GetHomeButtonReaderLockAccessor"},
{31, D<&ICommonStateGetter::GetReaderLockAccessorEx>, "GetReaderLockAccessorEx"},
{32, D<&ICommonStateGetter::GetWriterLockAccessorEx>, "GetWriterLockAccessorEx"},
{40, nullptr, "GetCradleFwVersion"},
{50, D<&ICommonStateGetter::IsVrModeEnabled>, "IsVrModeEnabled"},
{51, D<&ICommonStateGetter::SetVrModeEnabled>, "SetVrModeEnabled"},
{52, D<&ICommonStateGetter::SetLcdBacklighOffEnabled>, "SetLcdBacklighOffEnabled"},
{53, D<&ICommonStateGetter::BeginVrModeEx>, "BeginVrModeEx"},
{54, D<&ICommonStateGetter::EndVrModeEx>, "EndVrModeEx"},
{55, D<&ICommonStateGetter::IsInControllerFirmwareUpdateSection>, "IsInControllerFirmwareUpdateSection"},
{59, nullptr, "SetVrPositionForDebug"},
{60, D<&ICommonStateGetter::GetDefaultDisplayResolution>, "GetDefaultDisplayResolution"},
{61, D<&ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent>, "GetDefaultDisplayResolutionChangeEvent"},
{62, nullptr, "GetHdcpAuthenticationState"},
{63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
{64, nullptr, "SetTvPowerStateMatchingMode"},
{65, nullptr, "GetApplicationIdByContentActionName"},
{66, &ICommonStateGetter::SetCpuBoostMode, "SetCpuBoostMode"},
{67, nullptr, "CancelCpuBoostMode"},
{68, D<&ICommonStateGetter::GetBuiltInDisplayType>, "GetBuiltInDisplayType"},
{80, D<&ICommonStateGetter::PerformSystemButtonPressingIfInFocus>, "PerformSystemButtonPressingIfInFocus"},
{90, nullptr, "SetPerformanceConfigurationChangedNotification"},
{91, nullptr, "GetCurrentPerformanceConfiguration"},
{100, nullptr, "SetHandlingHomeButtonShortPressedEnabled"},
{110, nullptr, "OpenMyGpuErrorHandler"},
{120, D<&ICommonStateGetter::GetAppletLaunchedHistory>, "GetAppletLaunchedHistory"},
{200, D<&ICommonStateGetter::GetOperationModeSystemInfo>, "GetOperationModeSystemInfo"},
{300, D<&ICommonStateGetter::GetSettingsPlatformRegion>, "GetSettingsPlatformRegion"},
{400, nullptr, "ActivateMigrationService"},
{401, nullptr, "DeactivateMigrationService"},
{500, nullptr, "DisableSleepTillShutdown"},
{501, nullptr, "SuppressDisablingSleepTemporarily"},
{502, nullptr, "IsSleepEnabled"},
{503, nullptr, "IsDisablingSleepSuppressed"},
{900, D<&ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled>, "SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled"},
};
// clang-format on
RegisterHandlers(functions);
}
ICommonStateGetter::~ICommonStateGetter() = default;
Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = &m_applet->message_queue.GetMessageReceiveEvent();
R_SUCCEED();
}
Result ICommonStateGetter::ReceiveMessage(Out<AppletMessage> out_applet_message) {
LOG_DEBUG(Service_AM, "called");
*out_applet_message = m_applet->message_queue.PopMessage();
if (*out_applet_message == AppletMessage::None) {
LOG_ERROR(Service_AM, "Tried to pop message but none was available!");
R_THROW(AM::ResultNoMessages);
}
R_SUCCEED();
}
Result ICommonStateGetter::GetCurrentFocusState(Out<FocusState> out_focus_state) {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
*out_focus_state = m_applet->focus_state;
R_SUCCEED();
}
Result ICommonStateGetter::RequestToAcquireSleepLock() {
LOG_WARNING(Service_AM, "(STUBBED) called");
// Sleep lock is acquired immediately.
m_applet->sleep_lock_event.Signal();
R_SUCCEED();
}
Result ICommonStateGetter::GetAcquiredSleepLockEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_AM, "called");
*out_event = m_applet->sleep_lock_event.GetHandle();
R_SUCCEED();
}
Result ICommonStateGetter::GetReaderLockAccessorEx(
Out<SharedPointer<ILockAccessor>> out_lock_accessor, u32 button_type) {
LOG_INFO(Service_AM, "called, button_type={}", button_type);
*out_lock_accessor = std::make_shared<ILockAccessor>(system);
R_SUCCEED();
}
Result ICommonStateGetter::GetWriterLockAccessorEx(
Out<SharedPointer<ILockAccessor>> out_lock_accessor, u32 button_type) {
LOG_INFO(Service_AM, "called, button_type={}", button_type);
*out_lock_accessor = std::make_shared<ILockAccessor>(system);
R_SUCCEED();
}
Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = &m_applet->message_queue.GetOperationModeChangedEvent();
R_SUCCEED();
}
Result ICommonStateGetter::GetOperationMode(Out<OperationMode> out_operation_mode) {
const bool use_docked_mode{Settings::IsDockedMode()};
LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode);
*out_operation_mode = use_docked_mode ? OperationMode::Docked : OperationMode::Handheld;
R_SUCCEED();
}
Result ICommonStateGetter::GetPerformanceMode(Out<APM::PerformanceMode> out_performance_mode) {
LOG_DEBUG(Service_AM, "called");
*out_performance_mode = system.GetAPMController().GetCurrentPerformanceMode();
R_SUCCEED();
}
Result ICommonStateGetter::GetBootMode(Out<PM::SystemBootMode> out_boot_mode) {
LOG_DEBUG(Service_AM, "called");
*out_boot_mode = Service::PM::SystemBootMode::Normal;
R_SUCCEED();
}
Result ICommonStateGetter::IsVrModeEnabled(Out<bool> out_is_vr_mode_enabled) {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
*out_is_vr_mode_enabled = m_applet->vr_mode_enabled;
R_SUCCEED();
}
Result ICommonStateGetter::SetVrModeEnabled(bool is_vr_mode_enabled) {
std::scoped_lock lk{m_applet->lock};
m_applet->vr_mode_enabled = is_vr_mode_enabled;
LOG_WARNING(Service_AM, "VR Mode is {}", m_applet->vr_mode_enabled ? "on" : "off");
R_SUCCEED();
}
Result ICommonStateGetter::SetLcdBacklighOffEnabled(bool is_lcd_backlight_off_enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called. is_lcd_backlight_off_enabled={}",
is_lcd_backlight_off_enabled);
R_SUCCEED();
}
Result ICommonStateGetter::BeginVrModeEx() {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->vr_mode_enabled = true;
R_SUCCEED();
}
Result ICommonStateGetter::EndVrModeEx() {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->vr_mode_enabled = false;
R_SUCCEED();
}
Result ICommonStateGetter::IsInControllerFirmwareUpdateSection(
Out<bool> out_is_in_controller_firmware_update_section) {
LOG_INFO(Service_AM, "called");
*out_is_in_controller_firmware_update_section = false;
R_SUCCEED();
}
Result ICommonStateGetter::GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height) {
LOG_DEBUG(Service_AM, "called");
if (Settings::IsDockedMode()) {
*out_width = static_cast<u32>(Service::VI::DisplayResolution::DockedWidth);
*out_height = static_cast<u32>(Service::VI::DisplayResolution::DockedHeight);
} else {
*out_width = static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth);
*out_height = static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight);
}
R_SUCCEED();
}
void ICommonStateGetter::SetCpuBoostMode(HLERequestContext& ctx) {
LOG_DEBUG(Service_AM, "called, forwarding to APM:SYS");
const auto& sm = system.ServiceManager();
const auto apm_sys = sm.GetService<APM::APM_Sys>("apm:sys");
ASSERT(apm_sys != nullptr);
apm_sys->SetCpuBoostMode(ctx);
}
Result ICommonStateGetter::GetBuiltInDisplayType(Out<s32> out_display_type) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_display_type = 0;
R_SUCCEED();
}
Result ICommonStateGetter::PerformSystemButtonPressingIfInFocus(SystemButtonType type) {
LOG_WARNING(Service_AM, "(STUBBED) called, type={}", type);
R_SUCCEED();
}
Result ICommonStateGetter::GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_operation_mode_system_info = 0;
R_SUCCEED();
}
Result ICommonStateGetter::GetAppletLaunchedHistory(
Out<s32> out_count, OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids) {
LOG_INFO(Service_AM, "called");
std::shared_ptr<Applet> current_applet = m_applet;
for (*out_count = 0;
*out_count < static_cast<s32>(out_applet_ids.size()) && current_applet != nullptr;
/* ... */) {
out_applet_ids[(*out_count)++] = current_applet->applet_id;
current_applet = current_applet->caller_applet.lock();
}
R_SUCCEED();
}
Result ICommonStateGetter::GetSettingsPlatformRegion(
Out<SysPlatformRegion> out_settings_platform_region) {
LOG_INFO(Service_AM, "called");
*out_settings_platform_region = SysPlatformRegion::Global;
R_SUCCEED();
}
Result ICommonStateGetter::SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled() {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->request_exit_to_library_applet_at_execute_next_program_enabled = true;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KReadableEvent;
}
namespace Service::AM {
struct Applet;
class ILockAccessor;
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
public:
explicit ICommonStateGetter(Core::System& system_, std::shared_ptr<Applet> applet_);
~ICommonStateGetter() override;
private:
Result GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result ReceiveMessage(Out<AppletMessage> out_applet_message);
Result GetCurrentFocusState(Out<FocusState> out_focus_state);
Result RequestToAcquireSleepLock();
Result GetAcquiredSleepLockEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetReaderLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor,
u32 button_type);
Result GetWriterLockAccessorEx(Out<SharedPointer<ILockAccessor>> out_lock_accessor,
u32 button_type);
Result GetDefaultDisplayResolutionChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetOperationMode(Out<OperationMode> out_operation_mode);
Result GetPerformanceMode(Out<APM::PerformanceMode> out_performance_mode);
Result GetBootMode(Out<PM::SystemBootMode> out_boot_mode);
Result IsVrModeEnabled(Out<bool> out_is_vr_mode_enabled);
Result SetVrModeEnabled(bool is_vr_mode_enabled);
Result SetLcdBacklighOffEnabled(bool is_lcd_backlight_off_enabled);
Result BeginVrModeEx();
Result EndVrModeEx();
Result IsInControllerFirmwareUpdateSection(
Out<bool> out_is_in_controller_firmware_update_section);
Result GetDefaultDisplayResolution(Out<s32> out_width, Out<s32> out_height);
Result GetBuiltInDisplayType(Out<s32> out_display_type);
Result PerformSystemButtonPressingIfInFocus(SystemButtonType type);
Result GetOperationModeSystemInfo(Out<u32> out_operation_mode_system_info);
Result GetAppletLaunchedHistory(Out<s32> out_count,
OutArray<AppletId, BufferAttr_HipcMapAlias> out_applet_ids);
Result GetSettingsPlatformRegion(Out<SysPlatformRegion> out_settings_platform_region);
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
void SetCpuBoostMode(HLERequestContext& ctx);
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,52 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/cradle_firmware_updater.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
ICradleFirmwareUpdater::ICradleFirmwareUpdater(Core::System& system_)
: ServiceFramework{system_, "ICradleFirmwareUpdater"},
m_context{system, "ICradleFirmwareUpdater"}, m_cradle_device_info_event{m_context} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ICradleFirmwareUpdater::StartUpdate>, "StartUpdate"},
{1, D<&ICradleFirmwareUpdater::FinishUpdate>, "FinishUpdate"},
{2, D<&ICradleFirmwareUpdater::GetCradleDeviceInfo>, "GetCradleDeviceInfo"},
{3, D<&ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent>, "GetCradleDeviceInfoChangeEvent"},
{4, nullptr, "GetUpdateProgressInfo"},
{5, nullptr, "GetLastInternalResult"},
};
// clang-format on
RegisterHandlers(functions);
}
ICradleFirmwareUpdater::~ICradleFirmwareUpdater() = default;
Result ICradleFirmwareUpdater::StartUpdate() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ICradleFirmwareUpdater::FinishUpdate() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ICradleFirmwareUpdater::GetCradleDeviceInfo(Out<CradleDeviceInfo> out_cradle_device_info) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_cradle_device_info = {};
R_SUCCEED();
}
Result ICradleFirmwareUpdater::GetCradleDeviceInfoChangeEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_event = m_cradle_device_info_event.GetHandle();
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct CradleDeviceInfo {
bool unknown0;
bool unknown1;
bool unknown2;
u64 unknown3;
};
static_assert(sizeof(CradleDeviceInfo) == 0x10, "CradleDeviceInfo has incorrect size");
class ICradleFirmwareUpdater final : public ServiceFramework<ICradleFirmwareUpdater> {
public:
explicit ICradleFirmwareUpdater(Core::System& system_);
~ICradleFirmwareUpdater() override;
private:
Result StartUpdate();
Result FinishUpdate();
Result GetCradleDeviceInfo(Out<CradleDeviceInfo> out_cradle_device_info);
Result GetCradleDeviceInfoChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
private:
KernelHelpers::ServiceContext m_context;
Event m_cradle_device_info_event;
};
} // namespace Service::AM

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/debug_functions.h"
namespace Service::AM {
IDebugFunctions::IDebugFunctions(Core::System& system_)
: ServiceFramework{system_, "IDebugFunctions"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "NotifyMessageToHomeMenuForDebug"},
{1, nullptr, "OpenMainApplication"},
{10, nullptr, "PerformSystemButtonPressing"},
{20, nullptr, "InvalidateTransitionLayer"},
{30, nullptr, "RequestLaunchApplicationWithUserAndArgumentForDebug"},
{31, nullptr, "RequestLaunchApplicationByApplicationLaunchInfoForDebug"},
{40, nullptr, "GetAppletResourceUsageInfo"},
{50, nullptr, "AddSystemProgramIdAndAppletIdForDebug"},
{51, nullptr, "AddOperationConfirmedLibraryAppletIdForDebug"},
{100, nullptr, "SetCpuBoostModeForApplet"},
{101, nullptr, "CancelCpuBoostModeForApplet"},
{110, nullptr, "PushToAppletBoundChannelForDebug"},
{111, nullptr, "TryPopFromAppletBoundChannelForDebug"},
{120, nullptr, "AlarmSettingNotificationEnableAppEventReserve"},
{121, nullptr, "AlarmSettingNotificationDisableAppEventReserve"},
{122, nullptr, "AlarmSettingNotificationPushAppEventNotify"},
{130, nullptr, "FriendInvitationSetApplicationParameter"},
{131, nullptr, "FriendInvitationClearApplicationParameter"},
{132, nullptr, "FriendInvitationPushApplicationParameter"},
{140, nullptr, "RestrictPowerOperationForSecureLaunchModeForDebug"},
{200, nullptr, "CreateFloatingLibraryAppletAccepterForDebug"},
{300, nullptr, "TerminateAllRunningApplicationsForDebug"},
{900, nullptr, "GetGrcProcessLaunchedSystemEvent"},
};
// clang-format on
RegisterHandlers(functions);
}
IDebugFunctions::~IDebugFunctions() = default;
} // namespace Service::AM

View File

@ -0,0 +1,16 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Service::AM {
class IDebugFunctions final : public ServiceFramework<IDebugFunctions> {
public:
explicit IDebugFunctions(Core::System& system_);
~IDebugFunctions() override;
};
} // namespace Service::AM

View File

@ -0,0 +1,105 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/result.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/service/display_controller.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IDisplayController::IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_)
: ServiceFramework{system_, "IDisplayController"}, applet(std::move(applet_)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetLastForegroundCaptureImage"},
{1, nullptr, "UpdateLastForegroundCaptureImage"},
{2, nullptr, "GetLastApplicationCaptureImage"},
{3, nullptr, "GetCallerAppletCaptureImage"},
{4, nullptr, "UpdateCallerAppletCaptureImage"},
{5, nullptr, "GetLastForegroundCaptureImageEx"},
{6, nullptr, "GetLastApplicationCaptureImageEx"},
{7, D<&IDisplayController::GetCallerAppletCaptureImageEx>, "GetCallerAppletCaptureImageEx"},
{8, D<&IDisplayController::TakeScreenShotOfOwnLayer>, "TakeScreenShotOfOwnLayer"},
{9, nullptr, "CopyBetweenCaptureBuffers"},
{10, nullptr, "AcquireLastApplicationCaptureBuffer"},
{11, nullptr, "ReleaseLastApplicationCaptureBuffer"},
{12, nullptr, "AcquireLastForegroundCaptureBuffer"},
{13, nullptr, "ReleaseLastForegroundCaptureBuffer"},
{14, nullptr, "AcquireCallerAppletCaptureBuffer"},
{15, nullptr, "ReleaseCallerAppletCaptureBuffer"},
{16, nullptr, "AcquireLastApplicationCaptureBufferEx"},
{17, nullptr, "AcquireLastForegroundCaptureBufferEx"},
{18, nullptr, "AcquireCallerAppletCaptureBufferEx"},
{20, D<&IDisplayController::ClearCaptureBuffer>, "ClearCaptureBuffer"},
{21, nullptr, "ClearAppletTransitionBuffer"},
{22, D<&IDisplayController::AcquireLastApplicationCaptureSharedBuffer>, "AcquireLastApplicationCaptureSharedBuffer"},
{23, D<&IDisplayController::ReleaseLastApplicationCaptureSharedBuffer>, "ReleaseLastApplicationCaptureSharedBuffer"},
{24, D<&IDisplayController::AcquireLastForegroundCaptureSharedBuffer>, "AcquireLastForegroundCaptureSharedBuffer"},
{25, D<&IDisplayController::ReleaseLastForegroundCaptureSharedBuffer>, "ReleaseLastForegroundCaptureSharedBuffer"},
{26, D<&IDisplayController::AcquireCallerAppletCaptureSharedBuffer>, "AcquireCallerAppletCaptureSharedBuffer"},
{27, D<&IDisplayController::ReleaseCallerAppletCaptureSharedBuffer>, "ReleaseCallerAppletCaptureSharedBuffer"},
{28, nullptr, "TakeScreenShotOfOwnLayerEx"},
};
// clang-format on
RegisterHandlers(functions);
}
IDisplayController::~IDisplayController() = default;
Result IDisplayController::GetCallerAppletCaptureImageEx(
Out<bool> out_was_written, OutBuffer<BufferAttr_HipcMapAlias> out_image_data) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_was_written = true;
R_SUCCEED();
}
Result IDisplayController::TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IDisplayController::ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color) {
LOG_WARNING(Service_AM, "(STUBBED) called, unknown0={} fbshare_layer_index={} color={:#x}",
unknown0, fbshare_layer_index, color);
R_SUCCEED();
}
Result IDisplayController::AcquireLastForegroundCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseLastForegroundCaptureSharedBuffer() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IDisplayController::AcquireCallerAppletCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseCallerAppletCaptureSharedBuffer() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IDisplayController::AcquireLastApplicationCaptureSharedBuffer(
Out<bool> out_was_written, Out<s32> out_fbshare_layer_index) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_RETURN(applet->system_buffer_manager.WriteAppletCaptureBuffer(out_was_written,
out_fbshare_layer_index));
}
Result IDisplayController::ReleaseLastApplicationCaptureSharedBuffer() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IDisplayController final : public ServiceFramework<IDisplayController> {
public:
explicit IDisplayController(Core::System& system_, std::shared_ptr<Applet> applet_);
~IDisplayController() override;
private:
Result GetCallerAppletCaptureImageEx(Out<bool> out_was_written,
OutBuffer<BufferAttr_HipcMapAlias> out_image_data);
Result TakeScreenShotOfOwnLayer(bool unknown0, s32 fbshare_layer_index);
Result ClearCaptureBuffer(bool unknown0, s32 fbshare_layer_index, u32 color);
Result AcquireLastForegroundCaptureSharedBuffer(Out<bool> out_was_written,
Out<s32> out_fbshare_layer_index);
Result ReleaseLastForegroundCaptureSharedBuffer();
Result AcquireCallerAppletCaptureSharedBuffer(Out<bool> out_was_written,
Out<s32> out_fbshare_layer_index);
Result ReleaseCallerAppletCaptureSharedBuffer();
Result AcquireLastApplicationCaptureSharedBuffer(Out<bool> out_was_written,
Out<s32> out_fbshare_layer_index);
Result ReleaseLastApplicationCaptureSharedBuffer();
const std::shared_ptr<Applet> applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/cradle_firmware_updater.h"
#include "core/hle/service/am/service/global_state_controller.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IGlobalStateController::IGlobalStateController(Core::System& system_)
: ServiceFramework{system_, "IGlobalStateController"},
m_context{system_, "IGlobalStateController"}, m_hdcp_authentication_failed_event{m_context} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "RequestToEnterSleep"},
{1, nullptr, "EnterSleep"},
{2, nullptr, "StartSleepSequence"},
{3, nullptr, "StartShutdownSequence"},
{4, nullptr, "StartRebootSequence"},
{9, nullptr, "IsAutoPowerDownRequested"},
{10, D<&IGlobalStateController::LoadAndApplyIdlePolicySettings>, "LoadAndApplyIdlePolicySettings"},
{11, nullptr, "NotifyCecSettingsChanged"},
{12, nullptr, "SetDefaultHomeButtonLongPressTime"},
{13, nullptr, "UpdateDefaultDisplayResolution"},
{14, D<&IGlobalStateController::ShouldSleepOnBoot>, "ShouldSleepOnBoot"},
{15, D<&IGlobalStateController::GetHdcpAuthenticationFailedEvent>, "GetHdcpAuthenticationFailedEvent"},
{30, D<&IGlobalStateController::OpenCradleFirmwareUpdater>, "OpenCradleFirmwareUpdater"},
};
// clang-format on
RegisterHandlers(functions);
}
IGlobalStateController::~IGlobalStateController() = default;
Result IGlobalStateController::LoadAndApplyIdlePolicySettings() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IGlobalStateController::ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot) {
LOG_INFO(Service_AM, "called");
*out_should_sleep_on_boot = false;
R_SUCCEED();
}
Result IGlobalStateController::GetHdcpAuthenticationFailedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_hdcp_authentication_failed_event.GetHandle();
R_SUCCEED();
}
Result IGlobalStateController::OpenCradleFirmwareUpdater(
Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater) {
LOG_INFO(Service_AM, "called");
*out_cradle_firmware_updater = std::make_shared<ICradleFirmwareUpdater>(system);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,31 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class ICradleFirmwareUpdater;
class IGlobalStateController final : public ServiceFramework<IGlobalStateController> {
public:
explicit IGlobalStateController(Core::System& system_);
~IGlobalStateController() override;
private:
Result LoadAndApplyIdlePolicySettings();
Result ShouldSleepOnBoot(Out<bool> out_should_sleep_on_boot);
Result GetHdcpAuthenticationFailedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result OpenCradleFirmwareUpdater(
Out<SharedPointer<ICradleFirmwareUpdater>> out_cradle_firmware_updater);
KernelHelpers::ServiceContext m_context;
Event m_hdcp_authentication_failed_event;
};
} // namespace Service::AM

View File

@ -0,0 +1,74 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/result.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/home_menu_functions.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IHomeMenuFunctions"}, m_applet{std::move(applet)},
m_context{system, "IHomeMenuFunctions"}, m_pop_from_general_channel_event{m_context} {
// clang-format off
static const FunctionInfo functions[] = {
{10, D<&IHomeMenuFunctions::RequestToGetForeground>, "RequestToGetForeground"},
{11, D<&IHomeMenuFunctions::LockForeground>, "LockForeground"},
{12, D<&IHomeMenuFunctions::UnlockForeground>, "UnlockForeground"},
{20, nullptr, "PopFromGeneralChannel"},
{21, D<&IHomeMenuFunctions::GetPopFromGeneralChannelEvent>, "GetPopFromGeneralChannelEvent"},
{30, nullptr, "GetHomeButtonWriterLockAccessor"},
{31, nullptr, "GetWriterLockAccessorEx"},
{40, nullptr, "IsSleepEnabled"},
{41, D<&IHomeMenuFunctions::IsRebootEnabled>, "IsRebootEnabled"},
{50, nullptr, "LaunchSystemApplet"},
{51, nullptr, "LaunchStarter"},
{100, nullptr, "PopRequestLaunchApplicationForDebug"},
{110, D<&IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug>, "IsForceTerminateApplicationDisabledForDebug"},
{200, nullptr, "LaunchDevMenu"},
{1000, nullptr, "SetLastApplicationExitReason"},
};
// clang-format on
RegisterHandlers(functions);
}
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
Result IHomeMenuFunctions::RequestToGetForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IHomeMenuFunctions::LockForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IHomeMenuFunctions::UnlockForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result IHomeMenuFunctions::GetPopFromGeneralChannelEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_pop_from_general_channel_event.GetHandle();
R_SUCCEED();
}
Result IHomeMenuFunctions::IsRebootEnabled(Out<bool> out_is_reboot_enbaled) {
LOG_INFO(Service_AM, "called");
*out_is_reboot_enbaled = true;
R_SUCCEED();
}
Result IHomeMenuFunctions::IsForceTerminateApplicationDisabledForDebug(
Out<bool> out_is_force_terminate_application_disabled_for_debug) {
LOG_INFO(Service_AM, "called");
*out_is_force_terminate_application_disabled_for_debug = false;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
public:
explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
~IHomeMenuFunctions() override;
private:
Result RequestToGetForeground();
Result LockForeground();
Result UnlockForeground();
Result GetPopFromGeneralChannelEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsRebootEnabled(Out<bool> out_is_reboot_enbaled);
Result IsForceTerminateApplicationDisabledForDebug(
Out<bool> out_is_force_terminate_application_disabled_for_debug);
const std::shared_ptr<Applet> m_applet;
KernelHelpers::ServiceContext m_context;
Event m_pop_from_general_channel_event;
};
} // namespace Service::AM

View File

@ -0,0 +1,157 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#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/service/library_applet_accessor.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
ILibraryAppletAccessor::ILibraryAppletAccessor(Core::System& system_,
std::shared_ptr<AppletDataBroker> broker,
std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "ILibraryAppletAccessor"}, m_broker{std::move(broker)},
m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
{1, D<&ILibraryAppletAccessor::IsCompleted>, "IsCompleted"},
{10, D<&ILibraryAppletAccessor::Start>, "Start"},
{20, D<&ILibraryAppletAccessor::RequestExit>, "RequestExit"},
{25, D<&ILibraryAppletAccessor::Terminate>, "Terminate"},
{30, D<&ILibraryAppletAccessor::GetResult>, "GetResult"},
{50, nullptr, "SetOutOfFocusApplicationSuspendingEnabled"},
{60, D<&ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero>, "PresetLibraryAppletGpuTimeSliceZero"},
{100, D<&ILibraryAppletAccessor::PushInData>, "PushInData"},
{101, D<&ILibraryAppletAccessor::PopOutData>, "PopOutData"},
{102, nullptr, "PushExtraStorage"},
{103, D<&ILibraryAppletAccessor::PushInteractiveInData>, "PushInteractiveInData"},
{104, D<&ILibraryAppletAccessor::PopInteractiveOutData>, "PopInteractiveOutData"},
{105, D<&ILibraryAppletAccessor::GetPopOutDataEvent>, "GetPopOutDataEvent"},
{106, D<&ILibraryAppletAccessor::GetPopInteractiveOutDataEvent>, "GetPopInteractiveOutDataEvent"},
{110, nullptr, "NeedsToExitProcess"},
{120, nullptr, "GetLibraryAppletInfo"},
{150, nullptr, "RequestForAppletToGetForeground"},
{160, D<&ILibraryAppletAccessor::GetIndirectLayerConsumerHandle>, "GetIndirectLayerConsumerHandle"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
Result ILibraryAppletAccessor::GetAppletStateChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_broker->GetStateChangedEvent().GetHandle();
R_SUCCEED();
}
Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) {
LOG_DEBUG(Service_AM, "called");
*out_is_completed = m_broker->IsCompleted();
R_SUCCEED();
}
Result ILibraryAppletAccessor::GetResult(Out<Result> out_result) {
LOG_DEBUG(Service_AM, "called");
*out_result = m_applet->terminate_result;
R_SUCCEED();
}
Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() {
LOG_INFO(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ILibraryAppletAccessor::Start() {
LOG_DEBUG(Service_AM, "called");
m_applet->process->Run();
FrontendExecute();
R_SUCCEED();
}
Result ILibraryAppletAccessor::RequestExit() {
LOG_DEBUG(Service_AM, "called");
m_applet->message_queue.RequestExit();
FrontendRequestExit();
R_SUCCEED();
}
Result ILibraryAppletAccessor::Terminate() {
LOG_DEBUG(Service_AM, "called");
m_applet->process->Terminate();
FrontendRequestExit();
R_SUCCEED();
}
Result ILibraryAppletAccessor::PushInData(SharedPointer<IStorage> storage) {
LOG_DEBUG(Service_AM, "called");
m_broker->GetInData().Push(storage);
R_SUCCEED();
}
Result ILibraryAppletAccessor::PopOutData(Out<SharedPointer<IStorage>> out_storage) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(m_broker->GetOutData().Pop(out_storage.Get()));
}
Result ILibraryAppletAccessor::PushInteractiveInData(SharedPointer<IStorage> storage) {
LOG_DEBUG(Service_AM, "called");
m_broker->GetInteractiveInData().Push(storage);
FrontendExecuteInteractive();
R_SUCCEED();
}
Result ILibraryAppletAccessor::PopInteractiveOutData(Out<SharedPointer<IStorage>> out_storage) {
LOG_DEBUG(Service_AM, "called");
R_RETURN(m_broker->GetInteractiveOutData().Pop(out_storage.Get()));
}
Result ILibraryAppletAccessor::GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_broker->GetOutData().GetEvent();
R_SUCCEED();
}
Result ILibraryAppletAccessor::GetPopInteractiveOutDataEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_broker->GetInteractiveOutData().GetEvent();
R_SUCCEED();
}
Result ILibraryAppletAccessor::GetIndirectLayerConsumerHandle(Out<u64> out_handle) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// We require a non-zero handle to be valid. Using 0xdeadbeef allows us to trace if this is
// actually used anywhere
*out_handle = 0xdeadbeef;
R_SUCCEED();
}
void ILibraryAppletAccessor::FrontendExecute() {
if (m_applet->frontend) {
m_applet->frontend->Initialize();
m_applet->frontend->Execute();
}
}
void ILibraryAppletAccessor::FrontendExecuteInteractive() {
if (m_applet->frontend) {
m_applet->frontend->ExecuteInteractive();
m_applet->frontend->Execute();
}
}
void ILibraryAppletAccessor::FrontendRequestExit() {
if (m_applet->frontend) {
m_applet->frontend->RequestExit();
}
}
} // namespace Service::AM

View File

@ -0,0 +1,45 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class AppletDataBroker;
struct Applet;
class IStorage;
class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
public:
explicit ILibraryAppletAccessor(Core::System& system_, std::shared_ptr<AppletDataBroker> broker,
std::shared_ptr<Applet> applet);
~ILibraryAppletAccessor();
private:
Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsCompleted(Out<bool> out_is_completed);
Result GetResult(Out<Result> out_result);
Result PresetLibraryAppletGpuTimeSliceZero();
Result Start();
Result RequestExit();
Result Terminate();
Result PushInData(SharedPointer<IStorage> storage);
Result PopOutData(Out<SharedPointer<IStorage>> out_storage);
Result PushInteractiveInData(SharedPointer<IStorage> storage);
Result PopInteractiveOutData(Out<SharedPointer<IStorage>> out_storage);
Result GetPopOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetPopInteractiveOutDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetIndirectLayerConsumerHandle(Out<u64> out_handle);
void FrontendExecute();
void FrontendExecuteInteractive();
void FrontendRequestExit();
const std::shared_ptr<AppletDataBroker> m_broker;
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,268 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/settings.h"
#include "core/hle/kernel/k_transfer_memory.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/library_applet_storage.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/library_applet_creator.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
namespace {
bool ShouldCreateGuestApplet(AppletId applet_id) {
#define X(Name, name) \
if (applet_id == AppletId::Name && \
Settings::values.name##_applet_mode.GetValue() != Settings::AppletMode::LLE) { \
return false; \
}
X(Cabinet, cabinet)
X(Controller, controller)
X(DataErase, data_erase)
X(Error, error)
X(NetConnect, net_connect)
X(ProfileSelect, player_select)
X(SoftwareKeyboard, swkbd)
X(MiiEdit, mii_edit)
X(Web, web)
X(Shop, shop)
X(PhotoViewer, photo_viewer)
X(OfflineWeb, offline_web)
X(LoginShare, login_share)
X(WebAuth, wifi_web_auth)
X(MyPage, my_page)
#undef X
return true;
}
AppletProgramId AppletIdToProgramId(AppletId applet_id) {
switch (applet_id) {
case AppletId::OverlayDisplay:
return AppletProgramId::OverlayDisplay;
case AppletId::QLaunch:
return AppletProgramId::QLaunch;
case AppletId::Starter:
return AppletProgramId::Starter;
case AppletId::Auth:
return AppletProgramId::Auth;
case AppletId::Cabinet:
return AppletProgramId::Cabinet;
case AppletId::Controller:
return AppletProgramId::Controller;
case AppletId::DataErase:
return AppletProgramId::DataErase;
case AppletId::Error:
return AppletProgramId::Error;
case AppletId::NetConnect:
return AppletProgramId::NetConnect;
case AppletId::ProfileSelect:
return AppletProgramId::ProfileSelect;
case AppletId::SoftwareKeyboard:
return AppletProgramId::SoftwareKeyboard;
case AppletId::MiiEdit:
return AppletProgramId::MiiEdit;
case AppletId::Web:
return AppletProgramId::Web;
case AppletId::Shop:
return AppletProgramId::Shop;
case AppletId::PhotoViewer:
return AppletProgramId::PhotoViewer;
case AppletId::Settings:
return AppletProgramId::Settings;
case AppletId::OfflineWeb:
return AppletProgramId::OfflineWeb;
case AppletId::LoginShare:
return AppletProgramId::LoginShare;
case AppletId::WebAuth:
return AppletProgramId::WebAuth;
case AppletId::MyPage:
return AppletProgramId::MyPage;
default:
return static_cast<AppletProgramId>(0);
}
}
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
if (program_id == 0) {
// Unknown applet
return {};
}
// TODO: enable other versions of applets
enum : u8 {
Firmware1400 = 14,
Firmware1500 = 15,
Firmware1600 = 16,
Firmware1700 = 17,
};
auto process = std::make_unique<Process>(system);
if (!process->Initialize(program_id, Firmware1400, Firmware1700)) {
// Couldn't initialize the guest process
return {};
}
const auto applet = std::make_shared<Applet>(system, std::move(process));
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
// Set focus state
switch (mode) {
case LibraryAppletMode::AllForeground:
case LibraryAppletMode::NoUi:
case LibraryAppletMode::PartialForeground:
case LibraryAppletMode::PartialForegroundIndirectDisplay:
applet->hid_registration.EnableAppletToGetInput(true);
applet->focus_state = FocusState::InFocus;
applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
break;
case LibraryAppletMode::AllForegroundInitiallyHidden:
applet->hid_registration.EnableAppletToGetInput(false);
applet->focus_state = FocusState::NotInFocus;
applet->system_buffer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
break;
}
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
system.GetAppletManager().InsertApplet(applet);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
const auto program_id = static_cast<u64>(AppletIdToProgramId(applet_id));
auto process = std::make_unique<Process>(system);
auto applet = std::make_shared<Applet>(system, std::move(process));
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
applet->library_applet_mode = mode;
auto storage = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = storage;
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
return std::make_shared<ILibraryAppletAccessor>(system, storage, applet);
}
} // namespace
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "ILibraryAppletCreator"}, m_applet{std::move(applet)} {
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
{2, nullptr, "AreAnyLibraryAppletsLeft"},
{10, D<&ILibraryAppletCreator::CreateStorage>, "CreateStorage"},
{11, D<&ILibraryAppletCreator::CreateTransferMemoryStorage>, "CreateTransferMemoryStorage"},
{12, D<&ILibraryAppletCreator::CreateHandleStorage>, "CreateHandleStorage"},
};
RegisterHandlers(functions);
}
ILibraryAppletCreator::~ILibraryAppletCreator() = default;
Result ILibraryAppletCreator::CreateLibraryApplet(
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
LibraryAppletMode library_applet_mode) {
LOG_DEBUG(Service_AM, "called with applet_id={} applet_mode={}", applet_id,
library_applet_mode);
std::shared_ptr<ILibraryAppletAccessor> library_applet;
if (ShouldCreateGuestApplet(applet_id)) {
library_applet = CreateGuestApplet(system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
library_applet = CreateFrontendApplet(system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);
R_THROW(ResultUnknown);
}
// Applet is created, can now be launched.
m_applet->library_applet_launchable_event.Signal();
*out_library_applet_accessor = library_applet;
R_SUCCEED();
}
Result ILibraryAppletCreator::CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size) {
LOG_DEBUG(Service_AM, "called, size={}", size);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
R_THROW(ResultUnknown);
}
*out_storage = std::make_shared<IStorage>(system, AM::CreateStorage(std::vector<u8>(size)));
R_SUCCEED();
}
Result ILibraryAppletCreator::CreateTransferMemoryStorage(
Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
LOG_DEBUG(Service_AM, "called, is_writable={} size={}", is_writable, size);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
R_THROW(ResultUnknown);
}
if (!transfer_memory_handle) {
LOG_ERROR(Service_AM, "transfer_memory_handle is null");
R_THROW(ResultUnknown);
}
*out_storage = std::make_shared<IStorage>(
system, AM::CreateTransferMemoryStorage(transfer_memory_handle->GetOwner()->GetMemory(),
transfer_memory_handle.Get(), is_writable, size));
R_SUCCEED();
}
Result ILibraryAppletCreator::CreateHandleStorage(
Out<SharedPointer<IStorage>> out_storage, s64 size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle) {
LOG_DEBUG(Service_AM, "called, size={}", size);
if (size <= 0) {
LOG_ERROR(Service_AM, "size is less than or equal to 0");
R_THROW(ResultUnknown);
}
if (!transfer_memory_handle) {
LOG_ERROR(Service_AM, "transfer_memory_handle is null");
R_THROW(ResultUnknown);
}
*out_storage = std::make_shared<IStorage>(
system, AM::CreateHandleStorage(transfer_memory_handle->GetOwner()->GetMemory(),
transfer_memory_handle.Get(), size));
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IStorage;
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet);
~ILibraryAppletCreator() override;
private:
Result CreateLibraryApplet(
Out<SharedPointer<ILibraryAppletAccessor>> out_library_applet_accessor, AppletId applet_id,
LibraryAppletMode library_applet_mode);
Result CreateStorage(Out<SharedPointer<IStorage>> out_storage, s64 size);
Result CreateTransferMemoryStorage(
Out<SharedPointer<IStorage>> out_storage, bool is_writable, s64 size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,134 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/am/service/audio_controller.h"
#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/global_state_controller.h"
#include "core/hle/service/am/service/home_menu_functions.h"
#include "core/hle/service/am/service/library_applet_creator.h"
#include "core/hle/service/am/service/library_applet_proxy.h"
#include "core/hle/service/am/service/library_applet_self_accessor.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"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "ILibraryAppletProxy"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
{1, D<&ILibraryAppletProxy::GetSelfController>, "GetSelfController"},
{2, D<&ILibraryAppletProxy::GetWindowController>, "GetWindowController"},
{3, D<&ILibraryAppletProxy::GetAudioController>, "GetAudioController"},
{4, D<&ILibraryAppletProxy::GetDisplayController>, "GetDisplayController"},
{10, D<&ILibraryAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
{11, D<&ILibraryAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
{20, D<&ILibraryAppletProxy::OpenLibraryAppletSelfAccessor>, "OpenLibraryAppletSelfAccessor"},
{21, D<&ILibraryAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
{22, D<&ILibraryAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"},
{23, D<&ILibraryAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
{1000, D<&ILibraryAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletProxy::~ILibraryAppletProxy() = default;
Result ILibraryAppletProxy::GetAudioController(
Out<SharedPointer<IAudioController>> out_audio_controller) {
LOG_DEBUG(Service_AM, "called");
*out_audio_controller = std::make_shared<IAudioController>(system);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetDisplayController(
Out<SharedPointer<IDisplayController>> out_display_controller) {
LOG_DEBUG(Service_AM, "called");
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
LOG_DEBUG(Service_AM, "called");
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetDebugFunctions(
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
LOG_DEBUG(Service_AM, "called");
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller =
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetCommonStateGetter(
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
LOG_DEBUG(Service_AM, "called");
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
LOG_DEBUG(Service_AM, "called");
*out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::OpenLibraryAppletSelfAccessor(
Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor) {
LOG_DEBUG(Service_AM, "called");
*out_library_applet_self_accessor =
std::make_shared<ILibraryAppletSelfAccessor>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetAppletCommonFunctions(
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) {
LOG_DEBUG(Service_AM, "called");
*out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetHomeMenuFunctions(
Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
LOG_DEBUG(Service_AM, "called");
*out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet);
R_SUCCEED();
}
Result ILibraryAppletProxy::GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller) {
LOG_DEBUG(Service_AM, "called");
*out_global_state_controller = std::make_shared<IGlobalStateController>(system);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,55 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IAppletCommonFunctions;
class IAudioController;
class ICommonStateGetter;
class IDebugFunctions;
class IDisplayController;
class IHomeMenuFunctions;
class IGlobalStateController;
class ILibraryAppletCreator;
class ILibraryAppletSelfAccessor;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
~ILibraryAppletProxy();
private:
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
Result GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
Result GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
Result OpenLibraryAppletSelfAccessor(
Out<SharedPointer<ILibraryAppletSelfAccessor>> out_library_applet_self_accessor);
Result GetAppletCommonFunctions(
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions);
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,322 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core_timing.h"
#include "core/file_sys/control_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.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/service/library_applet_self_accessor.h"
#include "core/hle/service/am/service/storage.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/ns.h"
#include "core/hle/service/sm/sm.h"
namespace Service::AM {
namespace {
AppletIdentityInfo GetCallerIdentity(Applet& applet) {
if (const auto caller_applet = applet.caller_applet.lock(); caller_applet) {
// TODO: is this actually the application ID?
return {
.applet_id = caller_applet->applet_id,
.application_id = caller_applet->program_id,
};
} else {
return {
.applet_id = AppletId::QLaunch,
.application_id = 0x0100000000001000ull,
};
}
}
} // namespace
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} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletSelfAccessor::PopInData>, "PopInData"},
{1, D<&ILibraryAppletSelfAccessor::PushOutData>, "PushOutData"},
{2, D<&ILibraryAppletSelfAccessor::PopInteractiveInData>, "PopInteractiveInData"},
{3, D<&ILibraryAppletSelfAccessor::PushInteractiveOutData>, "PushInteractiveOutData"},
{5, D<&ILibraryAppletSelfAccessor::GetPopInDataEvent>, "GetPopInDataEvent"},
{6, D<&ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent>, "GetPopInteractiveInDataEvent"},
{10, D<&ILibraryAppletSelfAccessor::ExitProcessAndReturn>, "ExitProcessAndReturn"},
{11, D<&ILibraryAppletSelfAccessor::GetLibraryAppletInfo>, "GetLibraryAppletInfo"},
{12, D<&ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo>, "GetMainAppletIdentityInfo"},
{13, D<&ILibraryAppletSelfAccessor::CanUseApplicationCore>, "CanUseApplicationCore"},
{14, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo>, "GetCallerAppletIdentityInfo"},
{15, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty>, "GetMainAppletApplicationControlProperty"},
{16, D<&ILibraryAppletSelfAccessor::GetMainAppletStorageId>, "GetMainAppletStorageId"},
{17, D<&ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack>, "GetCallerAppletIdentityInfoStack"},
{18, nullptr, "GetNextReturnDestinationAppletIdentityInfo"},
{19, D<&ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout>, "GetDesirableKeyboardLayout"},
{20, nullptr, "PopExtraStorage"},
{25, nullptr, "GetPopExtraStorageEvent"},
{30, nullptr, "UnpopInData"},
{31, nullptr, "UnpopExtraStorage"},
{40, nullptr, "GetIndirectLayerProducerHandle"},
{50, D<&ILibraryAppletSelfAccessor::ReportVisibleError>, "ReportVisibleError"},
{51, D<&ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext>, "ReportVisibleErrorWithErrorContext"},
{60, D<&ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage>, "GetMainAppletApplicationDesiredLanguage"},
{70, D<&ILibraryAppletSelfAccessor::GetCurrentApplicationId>, "GetCurrentApplicationId"},
{80, nullptr, "RequestExitToSelf"},
{90, nullptr, "CreateApplicationAndPushAndRequestToLaunch"},
{100, nullptr, "CreateGameMovieTrimmer"},
{101, nullptr, "ReserveResourceForMovieOperation"},
{102, nullptr, "UnreserveResourceForMovieOperation"},
{110, D<&ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers>, "GetMainAppletAvailableUsers"},
{120, nullptr, "GetLaunchStorageInfoForDebug"},
{130, nullptr, "GetGpuErrorDetectedSystemEvent"},
{140, nullptr, "SetApplicationMemoryReservation"},
{150, D<&ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually>, "ShouldSetGpuTimeSliceManually"},
{160, D<&ILibraryAppletSelfAccessor::Cmd160>, "Cmd160"},
};
// clang-format on
RegisterHandlers(functions);
}
ILibraryAppletSelfAccessor::~ILibraryAppletSelfAccessor() = default;
Result ILibraryAppletSelfAccessor::PopInData(Out<SharedPointer<IStorage>> out_storage) {
LOG_INFO(Service_AM, "called");
R_RETURN(m_broker->GetInData().Pop(out_storage));
}
Result ILibraryAppletSelfAccessor::PushOutData(SharedPointer<IStorage> storage) {
LOG_INFO(Service_AM, "called");
m_broker->GetOutData().Push(storage);
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage) {
LOG_INFO(Service_AM, "called");
R_RETURN(m_broker->GetInteractiveInData().Pop(out_storage));
}
Result ILibraryAppletSelfAccessor::PushInteractiveOutData(SharedPointer<IStorage> storage) {
LOG_INFO(Service_AM, "called");
m_broker->GetInteractiveOutData().Push(storage);
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetPopInDataEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_broker->GetInData().GetEvent();
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetPopInteractiveInDataEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_broker->GetInteractiveInData().GetEvent();
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetLibraryAppletInfo(
Out<LibraryAppletInfo> out_library_applet_info) {
LOG_INFO(Service_AM, "called");
*out_library_applet_info = {
.applet_id = m_applet->applet_id,
.library_applet_mode = m_applet->library_applet_mode,
};
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetMainAppletIdentityInfo(
Out<AppletIdentityInfo> out_identity_info) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_identity_info = {
.applet_id = AppletId::QLaunch,
.application_id = 0x0100000000001000ull,
};
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::CanUseApplicationCore(Out<bool> out_can_use_application_core) {
// TODO: This appears to read the NPDM from state and check the core mask of the applet.
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_can_use_application_core = false;
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetMainAppletApplicationControlProperty(
OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// TODO: this should be the main applet, not the caller applet
const auto application = GetCallerIdentity(*m_applet);
std::vector<u8> nacp;
const auto result =
system.GetARPManager().GetControlProperty(&nacp, application.application_id);
if (R_SUCCEEDED(result)) {
std::memcpy(out_nacp->data(), nacp.data(), std::min(nacp.size(), out_nacp->size()));
}
R_RETURN(result);
}
Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id) {
LOG_INFO(Service_AM, "(STUBBED) called");
*out_storage_id = FileSys::StorageId::NandUser;
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() {
LOG_INFO(Service_AM, "called");
system.GetAppletManager().TerminateAndRemoveApplet(m_applet->aruid);
m_broker->SignalCompletion();
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfo(
Out<AppletIdentityInfo> out_identity_info) {
LOG_INFO(Service_AM, "called");
*out_identity_info = GetCallerIdentity(*m_applet);
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetCallerAppletIdentityInfoStack(
Out<s32> out_count, OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info) {
LOG_INFO(Service_AM, "called");
std::shared_ptr<Applet> applet = m_applet;
*out_count = 0;
do {
if (*out_count >= static_cast<s32>(out_identity_info.size())) {
break;
}
out_identity_info[(*out_count)++] = GetCallerIdentity(*applet);
} while ((applet = applet->caller_applet.lock()));
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetDesirableKeyboardLayout(Out<u32> out_desirable_layout) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_desirable_layout = 0;
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::ReportVisibleError(ErrorCode error_code) {
LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category,
error_code.number);
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::ReportVisibleErrorWithErrorContext(
ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context) {
LOG_WARNING(Service_AM, "(STUBBED) called, error {}-{}", error_code.category,
error_code.number);
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetMainAppletApplicationDesiredLanguage(
Out<u64> out_desired_language) {
// FIXME: this is copied from IApplicationFunctions::GetDesiredLanguage
// FIXME: all of this stuff belongs to ns
auto identity = GetCallerIdentity(*m_applet);
// TODO(bunnei): This should be configurable
LOG_DEBUG(Service_AM, "called");
// Get supported languages from NACP, if possible
// Default to 0 (all languages supported)
u32 supported_languages = 0;
const auto res = [this, identity] {
const FileSys::PatchManager pm{identity.application_id, system.GetFileSystemController(),
system.GetContentProvider()};
auto metadata = pm.GetControlMetadata();
if (metadata.first != nullptr) {
return metadata;
}
const FileSys::PatchManager pm_update{FileSys::GetUpdateTitleID(identity.application_id),
system.GetFileSystemController(),
system.GetContentProvider()};
return pm_update.GetControlMetadata();
}();
if (res.first != nullptr) {
supported_languages = res.first->GetSupportedLanguages();
}
// Call IApplicationManagerInterface implementation.
auto& service_manager = system.ServiceManager();
auto ns_am2 = service_manager.GetService<NS::NS>("ns:am2");
auto app_man = ns_am2->GetApplicationManagerInterface();
// Get desired application language
u8 desired_language{};
R_TRY(app_man->GetApplicationDesiredLanguage(&desired_language, supported_languages));
// Convert to settings language code.
u64 language_code{};
R_TRY(app_man->ConvertApplicationLanguageToLanguageCode(&language_code, desired_language));
LOG_DEBUG(Service_AM, "got desired_language={:016X}", language_code);
*out_desired_language = language_code;
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetCurrentApplicationId(Out<u64> out_application_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
// TODO: this should be the main applet, not the caller applet
const auto main_applet = GetCallerIdentity(*m_applet);
*out_application_id = main_applet.application_id;
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::GetMainAppletAvailableUsers(
Out<bool> out_no_users_available, Out<s32> out_users_count,
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users) {
const Service::Account::ProfileManager manager{};
*out_no_users_available = true;
*out_users_count = -1;
LOG_INFO(Service_AM, "called");
if (manager.GetUserCount() > 0) {
*out_no_users_available = false;
*out_users_count = static_cast<s32>(manager.GetUserCount());
const auto users = manager.GetAllUsers();
for (size_t i = 0; i < users.size() && i < out_users.size(); i++) {
out_users[i] = users[i];
}
}
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::ShouldSetGpuTimeSliceManually(
Out<bool> out_should_set_gpu_time_slice_manually) {
LOG_INFO(Service_AM, "(STUBBED) called");
*out_should_set_gpu_time_slice_manually = false;
R_SUCCEED();
}
Result ILibraryAppletSelfAccessor::Cmd160(Out<u64> out_unknown0) {
LOG_WARNING(Service_AM, "(STUBBED) called");
*out_unknown0 = 0;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,83 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/uuid.h"
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace FileSys {
enum class StorageId : u8;
}
namespace Kernel {
class KReadableEvent;
}
namespace Service::AM {
class AppletDataBroker;
struct Applet;
class IStorage;
struct LibraryAppletInfo {
AppletId applet_id;
LibraryAppletMode library_applet_mode;
};
static_assert(sizeof(LibraryAppletInfo) == 0x8, "LibraryAppletInfo has incorrect size.");
struct ErrorCode {
u32 category;
u32 number;
};
static_assert(sizeof(ErrorCode) == 0x8, "ErrorCode has incorrect size.");
struct ErrorContext {
u8 type;
INSERT_PADDING_BYTES_NOINIT(0x7);
std::array<u8, 0x1f4> data;
Result result;
};
static_assert(sizeof(ErrorContext) == 0x200, "ErrorContext has incorrect size.");
class ILibraryAppletSelfAccessor final : public ServiceFramework<ILibraryAppletSelfAccessor> {
public:
explicit ILibraryAppletSelfAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
~ILibraryAppletSelfAccessor() override;
private:
Result PopInData(Out<SharedPointer<IStorage>> out_storage);
Result PushOutData(SharedPointer<IStorage> storage);
Result PopInteractiveInData(Out<SharedPointer<IStorage>> out_storage);
Result PushInteractiveOutData(SharedPointer<IStorage> storage);
Result GetPopInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetPopInteractiveInDataEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetLibraryAppletInfo(Out<LibraryAppletInfo> out_library_applet_info);
Result GetMainAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info);
Result CanUseApplicationCore(Out<bool> out_can_use_application_core);
Result GetMainAppletApplicationControlProperty(
OutLargeData<std::array<u8, 0x4000>, BufferAttr_HipcMapAlias> out_nacp);
Result GetMainAppletStorageId(Out<FileSys::StorageId> out_storage_id);
Result ExitProcessAndReturn();
Result GetCallerAppletIdentityInfo(Out<AppletIdentityInfo> out_identity_info);
Result GetCallerAppletIdentityInfoStack(
Out<s32> out_count,
OutArray<AppletIdentityInfo, BufferAttr_HipcMapAlias> out_identity_info);
Result GetDesirableKeyboardLayout(Out<u32> out_desirable_layout);
Result ReportVisibleError(ErrorCode error_code);
Result ReportVisibleErrorWithErrorContext(
ErrorCode error_code, InLargeData<ErrorContext, BufferAttr_HipcMapAlias> error_context);
Result GetMainAppletApplicationDesiredLanguage(Out<u64> out_desired_language);
Result GetCurrentApplicationId(Out<u64> out_application_id);
Result GetMainAppletAvailableUsers(Out<bool> out_no_users_available, Out<s32> out_users_count,
OutArray<Common::UUID, BufferAttr_HipcMapAlias> out_users);
Result ShouldSetGpuTimeSliceManually(Out<bool> out_should_set_gpu_time_slice_manually);
Result Cmd160(Out<u64> out_unknown0);
const std::shared_ptr<Applet> m_applet;
const std::shared_ptr<AppletDataBroker> m_broker;
};
} // namespace Service::AM

View File

@ -0,0 +1,75 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/lock_accessor.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
ILockAccessor::ILockAccessor(Core::System& system_)
: ServiceFramework{system_, "ILockAccessor"}, m_context{system_, "ILockAccessor"},
m_event{m_context} {
// clang-format off
static const FunctionInfo functions[] = {
{1, D<&ILockAccessor::TryLock>, "TryLock"},
{2, D<&ILockAccessor::Unlock>, "Unlock"},
{3, D<&ILockAccessor::GetEvent>, "GetEvent"},
{4, D<&ILockAccessor::IsLocked>, "IsLocked"},
};
// clang-format on
RegisterHandlers(functions);
m_event.Signal();
}
ILockAccessor::~ILockAccessor() = default;
Result ILockAccessor::TryLock(Out<bool> out_is_locked,
OutCopyHandle<Kernel::KReadableEvent> out_handle,
bool return_handle) {
LOG_INFO(Service_AM, "called, return_handle={}", return_handle);
{
std::scoped_lock lk{m_mutex};
if (m_is_locked) {
*out_is_locked = false;
} else {
m_is_locked = true;
*out_is_locked = true;
}
}
if (return_handle) {
*out_handle = m_event.GetHandle();
}
R_SUCCEED();
}
Result ILockAccessor::Unlock() {
LOG_INFO(Service_AM, "called");
{
std::scoped_lock lk{m_mutex};
m_is_locked = false;
}
m_event.Signal();
R_SUCCEED();
}
Result ILockAccessor::GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle) {
LOG_INFO(Service_AM, "called");
*out_handle = m_event.GetHandle();
R_SUCCEED();
}
Result ILockAccessor::IsLocked(Out<bool> out_is_locked) {
LOG_INFO(Service_AM, "called");
std::scoped_lock lk{m_mutex};
*out_is_locked = m_is_locked;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class ILockAccessor final : public ServiceFramework<ILockAccessor> {
public:
explicit ILockAccessor(Core::System& system_);
~ILockAccessor() override;
private:
Result TryLock(Out<bool> out_is_locked, OutCopyHandle<Kernel::KReadableEvent> out_handle,
bool return_handle);
Result Unlock();
Result GetEvent(OutCopyHandle<Kernel::KReadableEvent> out_handle);
Result IsLocked(Out<bool> out_is_locked);
private:
KernelHelpers::ServiceContext m_context;
Event m_event;
std::mutex m_mutex{};
bool m_is_locked{};
};
} // namespace Service::AM

View File

@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/service/library_applet_accessor.h"
#include "core/hle/service/am/service/process_winding_controller.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IProcessWindingController::IProcessWindingController(Core::System& system_,
std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IProcessWindingController"}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IProcessWindingController::GetLaunchReason>, "GetLaunchReason"},
{11, D<&IProcessWindingController::OpenCallingLibraryApplet>, "OpenCallingLibraryApplet"},
{21, nullptr, "PushContext"},
{22, nullptr, "PopContext"},
{23, nullptr, "CancelWindingReservation"},
{30, nullptr, "WindAndDoReserved"},
{40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
{41, nullptr, "ReserveToStartAndWait"},
};
// clang-format on
RegisterHandlers(functions);
}
IProcessWindingController::~IProcessWindingController() = default;
Result IProcessWindingController::GetLaunchReason(
Out<AppletProcessLaunchReason> out_launch_reason) {
LOG_INFO(Service_AM, "called");
*out_launch_reason = m_applet->launch_reason;
R_SUCCEED();
}
Result IProcessWindingController::OpenCallingLibraryApplet(
Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet) {
LOG_INFO(Service_AM, "called");
const auto caller_applet = m_applet->caller_applet.lock();
if (caller_applet == nullptr) {
LOG_ERROR(Service_AM, "No caller applet available");
R_THROW(ResultUnknown);
}
*out_calling_library_applet = std::make_shared<ILibraryAppletAccessor>(
system, m_applet->caller_applet_broker, caller_applet);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IProcessWindingController final : public ServiceFramework<IProcessWindingController> {
public:
explicit IProcessWindingController(Core::System& system_, std::shared_ptr<Applet> applet_);
~IProcessWindingController() override;
private:
Result GetLaunchReason(Out<AppletProcessLaunchReason> out_launch_reason);
Result OpenCallingLibraryApplet(
Out<SharedPointer<ILibraryAppletAccessor>> out_calling_library_applet);
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,393 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.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/caps/caps_su.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/vi/vi_results.h"
namespace Service::AM {
ISelfController::ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "ISelfController"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ISelfController::Exit>, "Exit"},
{1, D<&ISelfController::LockExit>, "LockExit"},
{2, D<&ISelfController::UnlockExit>, "UnlockExit"},
{3, D<&ISelfController::EnterFatalSection>, "EnterFatalSection"},
{4, D<&ISelfController::LeaveFatalSection>, "LeaveFatalSection"},
{9, D<&ISelfController::GetLibraryAppletLaunchableEvent>, "GetLibraryAppletLaunchableEvent"},
{10, D<&ISelfController::SetScreenShotPermission>, "SetScreenShotPermission"},
{11, D<&ISelfController::SetOperationModeChangedNotification>, "SetOperationModeChangedNotification"},
{12, D<&ISelfController::SetPerformanceModeChangedNotification>, "SetPerformanceModeChangedNotification"},
{13, D<&ISelfController::SetFocusHandlingMode>, "SetFocusHandlingMode"},
{14, D<&ISelfController::SetRestartMessageEnabled>, "SetRestartMessageEnabled"},
{15, D<&ISelfController::SetScreenShotAppletIdentityInfo>, "SetScreenShotAppletIdentityInfo"},
{16, D<&ISelfController::SetOutOfFocusSuspendingEnabled>, "SetOutOfFocusSuspendingEnabled"},
{17, nullptr, "SetControllerFirmwareUpdateSection"},
{18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"},
{19, D<&ISelfController::SetAlbumImageOrientation>, "SetAlbumImageOrientation"},
{20, nullptr, "SetDesirableKeyboardLayout"},
{21, nullptr, "GetScreenShotProgramId"},
{40, D<&ISelfController::CreateManagedDisplayLayer>, "CreateManagedDisplayLayer"},
{41, D<&ISelfController::IsSystemBufferSharingEnabled>, "IsSystemBufferSharingEnabled"},
{42, D<&ISelfController::GetSystemSharedLayerHandle>, "GetSystemSharedLayerHandle"},
{43, D<&ISelfController::GetSystemSharedBufferHandle>, "GetSystemSharedBufferHandle"},
{44, D<&ISelfController::CreateManagedDisplaySeparableLayer>, "CreateManagedDisplaySeparableLayer"},
{45, nullptr, "SetManagedDisplayLayerSeparationMode"},
{46, nullptr, "SetRecordingLayerCompositionEnabled"},
{50, D<&ISelfController::SetHandlesRequestToDisplay>, "SetHandlesRequestToDisplay"},
{51, D<&ISelfController::ApproveToDisplay>, "ApproveToDisplay"},
{60, D<&ISelfController::OverrideAutoSleepTimeAndDimmingTime>, "OverrideAutoSleepTimeAndDimmingTime"},
{61, D<&ISelfController::SetMediaPlaybackState>, "SetMediaPlaybackState"},
{62, D<&ISelfController::SetIdleTimeDetectionExtension>, "SetIdleTimeDetectionExtension"},
{63, D<&ISelfController::GetIdleTimeDetectionExtension>, "GetIdleTimeDetectionExtension"},
{64, nullptr, "SetInputDetectionSourceSet"},
{65, D<&ISelfController::ReportUserIsActive>, "ReportUserIsActive"},
{66, nullptr, "GetCurrentIlluminance"},
{67, nullptr, "IsIlluminanceAvailable"},
{68, D<&ISelfController::SetAutoSleepDisabled>, "SetAutoSleepDisabled"},
{69, D<&ISelfController::IsAutoSleepDisabled>, "IsAutoSleepDisabled"},
{70, nullptr, "ReportMultimediaError"},
{71, nullptr, "GetCurrentIlluminanceEx"},
{72, D<&ISelfController::SetInputDetectionPolicy>, "SetInputDetectionPolicy"},
{80, nullptr, "SetWirelessPriorityMode"},
{90, D<&ISelfController::GetAccumulatedSuspendedTickValue>, "GetAccumulatedSuspendedTickValue"},
{91, D<&ISelfController::GetAccumulatedSuspendedTickChangedEvent>, "GetAccumulatedSuspendedTickChangedEvent"},
{100, D<&ISelfController::SetAlbumImageTakenNotificationEnabled>, "SetAlbumImageTakenNotificationEnabled"},
{110, nullptr, "SetApplicationAlbumUserData"},
{120, D<&ISelfController::SaveCurrentScreenshot>, "SaveCurrentScreenshot"},
{130, D<&ISelfController::SetRecordVolumeMuted>, "SetRecordVolumeMuted"},
{1000, nullptr, "GetDebugStorageChannel"},
};
// clang-format on
RegisterHandlers(functions);
}
ISelfController::~ISelfController() = default;
Result ISelfController::Exit() {
LOG_DEBUG(Service_AM, "called");
// TODO
system.Exit();
R_SUCCEED();
}
Result ISelfController::LockExit() {
LOG_DEBUG(Service_AM, "called");
system.SetExitLocked(true);
R_SUCCEED();
}
Result ISelfController::UnlockExit() {
LOG_DEBUG(Service_AM, "called");
system.SetExitLocked(false);
if (system.GetExitRequested()) {
system.Exit();
}
R_SUCCEED();
}
Result ISelfController::EnterFatalSection() {
std::scoped_lock lk{m_applet->lock};
m_applet->fatal_section_count++;
LOG_DEBUG(Service_AM, "called. Num fatal sections entered: {}", m_applet->fatal_section_count);
R_SUCCEED();
}
Result ISelfController::LeaveFatalSection() {
LOG_DEBUG(Service_AM, "called");
// Entry and exit of fatal sections must be balanced.
std::scoped_lock lk{m_applet->lock};
R_UNLESS(m_applet->fatal_section_count > 0, AM::ResultFatalSectionCountImbalance);
m_applet->fatal_section_count--;
R_SUCCEED();
}
Result ISelfController::GetLibraryAppletLaunchableEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_WARNING(Service_AM, "(STUBBED) called");
m_applet->library_applet_launchable_event.Signal();
*out_event = m_applet->library_applet_launchable_event.GetHandle();
R_SUCCEED();
}
Result ISelfController::SetScreenShotPermission(ScreenshotPermission screen_shot_permission) {
LOG_DEBUG(Service_AM, "called, permission={}", screen_shot_permission);
std::scoped_lock lk{m_applet->lock};
m_applet->screenshot_permission = screen_shot_permission;
R_SUCCEED();
}
Result ISelfController::SetOperationModeChangedNotification(bool enabled) {
LOG_INFO(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->operation_mode_changed_notification_enabled = enabled;
R_SUCCEED();
}
Result ISelfController::SetPerformanceModeChangedNotification(bool enabled) {
LOG_INFO(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->performance_mode_changed_notification_enabled = enabled;
R_SUCCEED();
}
Result ISelfController::SetFocusHandlingMode(bool notify, bool background, bool suspend) {
LOG_WARNING(Service_AM, "(STUBBED) called, notify={} background={} suspend={}", notify,
background, suspend);
std::scoped_lock lk{m_applet->lock};
m_applet->focus_handling_mode = {notify, background, suspend};
R_SUCCEED();
}
Result ISelfController::SetRestartMessageEnabled(bool enabled) {
LOG_INFO(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->restart_message_enabled = enabled;
R_SUCCEED();
}
Result ISelfController::SetScreenShotAppletIdentityInfo(
AppletIdentityInfo screen_shot_applet_identity_info) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
m_applet->screen_shot_identity = screen_shot_applet_identity_info;
R_SUCCEED();
}
Result ISelfController::SetOutOfFocusSuspendingEnabled(bool enabled) {
LOG_INFO(Service_AM, "called, enabled={}", enabled);
std::scoped_lock lk{m_applet->lock};
m_applet->out_of_focus_suspension_enabled = enabled;
R_SUCCEED();
}
Result ISelfController::SetAlbumImageOrientation(
Capture::AlbumImageOrientation album_image_orientation) {
LOG_WARNING(Service_AM, "(STUBBED) called, orientation={}", album_image_orientation);
std::scoped_lock lk{m_applet->lock};
m_applet->album_image_orientation = album_image_orientation;
R_SUCCEED();
}
Result ISelfController::IsSystemBufferSharingEnabled() {
LOG_INFO(Service_AM, "called");
R_SUCCEED_IF(m_applet->system_buffer_manager.Initialize(
&m_nvnflinger, m_process, m_applet->applet_id, m_applet->library_applet_mode));
R_THROW(VI::ResultOperationFailed);
}
Result ISelfController::GetSystemSharedBufferHandle(Out<u64> out_buffer_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_TRY(this->IsSystemBufferSharingEnabled());
u64 layer_id;
m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, &layer_id);
R_SUCCEED();
}
Result ISelfController::GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id) {
LOG_INFO(Service_AM, "(STUBBED) called");
R_TRY(this->IsSystemBufferSharingEnabled());
m_applet->system_buffer_manager.GetSystemSharedLayerHandle(out_buffer_id, out_layer_id);
R_SUCCEED();
}
Result ISelfController::CreateManagedDisplayLayer(Out<u64> out_layer_id) {
LOG_INFO(Service_AM, "called");
m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
m_applet->managed_layer_holder.CreateManagedDisplayLayer(out_layer_id);
R_SUCCEED();
}
Result ISelfController::CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
Out<u64> out_recording_layer_id) {
LOG_WARNING(Service_AM, "(STUBBED) called");
m_applet->managed_layer_holder.Initialize(&m_nvnflinger);
m_applet->managed_layer_holder.CreateManagedDisplaySeparableLayer(out_layer_id,
out_recording_layer_id);
R_SUCCEED();
}
Result ISelfController::SetHandlesRequestToDisplay(bool enable) {
LOG_WARNING(Service_AM, "(STUBBED) called, enable={}", enable);
R_SUCCEED();
}
Result ISelfController::ApproveToDisplay() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ISelfController::SetMediaPlaybackState(bool state) {
LOG_WARNING(Service_AM, "(STUBBED) called, state={}", state);
R_SUCCEED();
}
Result ISelfController::OverrideAutoSleepTimeAndDimmingTime(s32 a, s32 b, s32 c, s32 d) {
LOG_WARNING(Service_AM, "(STUBBED) called, a={}, b={}, c={}, d={}", a, b, c, d);
R_SUCCEED();
}
Result ISelfController::SetIdleTimeDetectionExtension(
IdleTimeDetectionExtension idle_time_detection_extension) {
LOG_DEBUG(Service_AM, "(STUBBED) called extension={}", idle_time_detection_extension);
std::scoped_lock lk{m_applet->lock};
m_applet->idle_time_detection_extension = idle_time_detection_extension;
R_SUCCEED();
}
Result ISelfController::GetIdleTimeDetectionExtension(
Out<IdleTimeDetectionExtension> out_idle_time_detection_extension) {
LOG_WARNING(Service_AM, "(STUBBED) called");
std::scoped_lock lk{m_applet->lock};
*out_idle_time_detection_extension = m_applet->idle_time_detection_extension;
R_SUCCEED();
}
Result ISelfController::ReportUserIsActive() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ISelfController::SetAutoSleepDisabled(bool is_auto_sleep_disabled) {
LOG_DEBUG(Service_AM, "called. is_auto_sleep_disabled={}", is_auto_sleep_disabled);
// On the system itself, if the previous state of is_auto_sleep_disabled
// differed from the current value passed in, it'd signify the internal
// window manager to update (and also increment some statistics like update counts)
//
// It'd also indicate this change to an idle handling context.
//
// However, given we're emulating this behavior, most of this can be ignored
// and it's sufficient to simply set the member variable for querying via
// IsAutoSleepDisabled().
std::scoped_lock lk{m_applet->lock};
m_applet->auto_sleep_disabled = is_auto_sleep_disabled;
R_SUCCEED();
}
Result ISelfController::IsAutoSleepDisabled(Out<bool> out_is_auto_sleep_disabled) {
LOG_DEBUG(Service_AM, "called.");
std::scoped_lock lk{m_applet->lock};
*out_is_auto_sleep_disabled = m_applet->auto_sleep_disabled;
R_SUCCEED();
}
Result ISelfController::SetInputDetectionPolicy(InputDetectionPolicy input_detection_policy) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_SUCCEED();
}
Result ISelfController::GetAccumulatedSuspendedTickValue(
Out<u64> out_accumulated_suspended_tick_value) {
LOG_DEBUG(Service_AM, "called.");
// This command returns the total number of system ticks since ISelfController creation
// where the game was suspended. Since Yuzu doesn't implement game suspension, this command
// can just always return 0 ticks.
std::scoped_lock lk{m_applet->lock};
*out_accumulated_suspended_tick_value = m_applet->suspended_ticks;
R_SUCCEED();
}
Result ISelfController::GetAccumulatedSuspendedTickChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called.");
*out_event = m_applet->accumulated_suspended_tick_changed_event.GetHandle();
R_SUCCEED();
}
Result ISelfController::SetAlbumImageTakenNotificationEnabled(bool enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called. enabled={}", enabled);
// This service call sets an internal flag whether a notification is shown when an image is
// captured. Currently we do not support capturing images via the capture button, so this can be
// stubbed for now.
std::scoped_lock lk{m_applet->lock};
m_applet->album_image_taken_notification_enabled = enabled;
R_SUCCEED();
}
Result ISelfController::SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option) {
LOG_INFO(Service_AM, "called, report_option={}", album_report_option);
const auto screenshot_service =
system.ServiceManager().GetService<Service::Capture::IScreenShotApplicationService>(
"caps:su");
if (screenshot_service) {
screenshot_service->CaptureAndSaveScreenshot(album_report_option);
}
R_SUCCEED();
}
Result ISelfController::SetRecordVolumeMuted(bool muted) {
LOG_WARNING(Service_AM, "(STUBBED) called. muted={}", muted);
std::scoped_lock lk{m_applet->lock};
m_applet->record_volume_muted = muted;
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,72 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KReadableEvent;
}
namespace Service::Capture {
enum class AlbumImageOrientation;
enum class AlbumReportOption;
} // namespace Service::Capture
namespace Service::AM {
struct Applet;
class ISelfController final : public ServiceFramework<ISelfController> {
public:
explicit ISelfController(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
~ISelfController() override;
private:
Result Exit();
Result LockExit();
Result UnlockExit();
Result EnterFatalSection();
Result LeaveFatalSection();
Result GetLibraryAppletLaunchableEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result SetScreenShotPermission(ScreenshotPermission screen_shot_permission);
Result SetOperationModeChangedNotification(bool enabled);
Result SetPerformanceModeChangedNotification(bool enabled);
Result SetFocusHandlingMode(bool notify, bool background, bool suspend);
Result SetRestartMessageEnabled(bool enabled);
Result SetScreenShotAppletIdentityInfo(AppletIdentityInfo screen_shot_applet_identity_info);
Result SetOutOfFocusSuspendingEnabled(bool enabled);
Result SetAlbumImageOrientation(Capture::AlbumImageOrientation album_image_orientation);
Result IsSystemBufferSharingEnabled();
Result GetSystemSharedBufferHandle(Out<u64> out_buffer_id);
Result GetSystemSharedLayerHandle(Out<u64> out_buffer_id, Out<u64> out_layer_id);
Result CreateManagedDisplayLayer(Out<u64> out_layer_id);
Result CreateManagedDisplaySeparableLayer(Out<u64> out_layer_id,
Out<u64> out_recording_layer_id);
Result SetHandlesRequestToDisplay(bool enable);
Result ApproveToDisplay();
Result SetMediaPlaybackState(bool state);
Result OverrideAutoSleepTimeAndDimmingTime(s32 a, s32 b, s32 c, s32 d);
Result SetIdleTimeDetectionExtension(IdleTimeDetectionExtension idle_time_detection_extension);
Result GetIdleTimeDetectionExtension(
Out<IdleTimeDetectionExtension> out_idle_time_detection_extension);
Result ReportUserIsActive();
Result SetAutoSleepDisabled(bool is_auto_sleep_disabled);
Result IsAutoSleepDisabled(Out<bool> out_is_auto_sleep_disabled);
Result SetInputDetectionPolicy(InputDetectionPolicy input_detection_policy);
Result GetAccumulatedSuspendedTickValue(Out<u64> out_accumulated_suspended_tick_value);
Result GetAccumulatedSuspendedTickChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result SetAlbumImageTakenNotificationEnabled(bool enabled);
Result SaveCurrentScreenshot(Capture::AlbumReportOption album_report_option);
Result SetRecordVolumeMuted(bool muted);
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,48 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/service/storage.h"
#include "core/hle/service/am/service/storage_accessor.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IStorage::IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl)
: ServiceFramework{system_, "IStorage"}, m_impl{std::move(impl)} {
static const FunctionInfo functions[] = {
{0, D<&IStorage::Open>, "Open"},
{1, D<&IStorage::OpenTransferStorage>, "OpenTransferStorage"},
};
RegisterHandlers(functions);
}
IStorage::IStorage(Core::System& system_, std::vector<u8>&& data)
: IStorage(system_, CreateStorage(std::move(data))) {}
IStorage::~IStorage() = default;
Result IStorage::Open(Out<SharedPointer<IStorageAccessor>> out_storage_accessor) {
LOG_DEBUG(Service_AM, "called");
R_UNLESS(m_impl->GetHandle() == nullptr, AM::ResultInvalidStorageType);
*out_storage_accessor = std::make_shared<IStorageAccessor>(system, m_impl);
R_SUCCEED();
}
Result IStorage::OpenTransferStorage(
Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor) {
R_UNLESS(m_impl->GetHandle() != nullptr, AM::ResultInvalidStorageType);
*out_transfer_storage_accessor = std::make_shared<ITransferStorageAccessor>(system, m_impl);
R_SUCCEED();
}
std::vector<u8> IStorage::GetData() const {
return m_impl->GetData();
}
} // namespace Service::AM

View File

@ -0,0 +1,35 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class LibraryAppletStorage;
class IStorageAccessor;
class ITransferStorageAccessor;
class IStorage final : public ServiceFramework<IStorage> {
public:
explicit IStorage(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl);
explicit IStorage(Core::System& system_, std::vector<u8>&& buffer);
~IStorage() override;
std::shared_ptr<LibraryAppletStorage> GetImpl() const {
return m_impl;
}
std::vector<u8> GetData() const;
private:
Result Open(Out<SharedPointer<IStorageAccessor>> out_storage_accessor);
Result OpenTransferStorage(
Out<SharedPointer<ITransferStorageAccessor>> out_transfer_storage_accessor);
const std::shared_ptr<LibraryAppletStorage> m_impl;
};
} // namespace Service::AM

View File

@ -0,0 +1,68 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_transfer_memory.h"
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/am/service/storage_accessor.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IStorageAccessor::IStorageAccessor(Core::System& system_,
std::shared_ptr<LibraryAppletStorage> impl)
: ServiceFramework{system_, "IStorageAccessor"}, m_impl{std::move(impl)} {
static const FunctionInfo functions[] = {
{0, D<&IStorageAccessor::GetSize>, "GetSize"},
{10, D<&IStorageAccessor::Write>, "Write"},
{11, D<&IStorageAccessor::Read>, "Read"},
};
RegisterHandlers(functions);
}
IStorageAccessor::~IStorageAccessor() = default;
Result IStorageAccessor::GetSize(Out<s64> out_size) {
LOG_DEBUG(Service_AM, "called");
*out_size = m_impl->GetSize();
R_SUCCEED();
}
Result IStorageAccessor::Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset) {
LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, buffer.size());
R_RETURN(m_impl->Write(offset, buffer.data(), buffer.size()));
}
Result IStorageAccessor::Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset) {
LOG_DEBUG(Service_AM, "called, offset={} size={}", offset, out_buffer.size());
R_RETURN(m_impl->Read(offset, out_buffer.data(), out_buffer.size()));
}
ITransferStorageAccessor::ITransferStorageAccessor(Core::System& system_,
std::shared_ptr<LibraryAppletStorage> impl)
: ServiceFramework{system_, "ITransferStorageAccessor"}, m_impl{std::move(impl)} {
static const FunctionInfo functions[] = {
{0, D<&ITransferStorageAccessor::GetSize>, "GetSize"},
{1, D<&ITransferStorageAccessor::GetHandle>, "GetHandle"},
};
RegisterHandlers(functions);
}
ITransferStorageAccessor::~ITransferStorageAccessor() = default;
Result ITransferStorageAccessor::GetSize(Out<s64> out_size) {
LOG_DEBUG(Service_AM, "called");
*out_size = m_impl->GetSize();
R_SUCCEED();
}
Result ITransferStorageAccessor::GetHandle(Out<s64> out_size,
OutCopyHandle<Kernel::KTransferMemory> out_handle) {
LOG_INFO(Service_AM, "called");
*out_size = m_impl->GetSize();
*out_handle = m_impl->GetHandle();
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,38 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/am/library_applet_storage.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
public:
explicit IStorageAccessor(Core::System& system_, std::shared_ptr<LibraryAppletStorage> impl);
~IStorageAccessor() override;
private:
Result GetSize(Out<s64> out_size);
Result Write(InBuffer<BufferAttr_HipcAutoSelect> buffer, s64 offset);
Result Read(OutBuffer<BufferAttr_HipcAutoSelect> out_buffer, s64 offset);
const std::shared_ptr<LibraryAppletStorage> m_impl;
};
class ITransferStorageAccessor final : public ServiceFramework<ITransferStorageAccessor> {
public:
explicit ITransferStorageAccessor(Core::System& system_,
std::shared_ptr<LibraryAppletStorage> impl);
~ITransferStorageAccessor() override;
private:
Result GetSize(Out<s64> out_size);
Result GetHandle(Out<s64> out_size, OutCopyHandle<Kernel::KTransferMemory> out_handle);
const std::shared_ptr<LibraryAppletStorage> m_impl;
};
} // namespace Service::AM

View File

@ -0,0 +1,133 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/service/applet_common_functions.h"
#include "core/hle/service/am/service/application_creator.h"
#include "core/hle/service/am/service/audio_controller.h"
#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/global_state_controller.h"
#include "core/hle/service/am/service/home_menu_functions.h"
#include "core/hle/service/am/service/library_applet_creator.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/system_applet_proxy.h"
#include "core/hle/service/am/service/window_controller.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process,
Nvnflinger::Nvnflinger& nvnflinger)
: ServiceFramework{system_, "ISystemAppletProxy"},
m_nvnflinger{nvnflinger}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
{1, D<&ISystemAppletProxy::GetSelfController>, "GetSelfController"},
{2, D<&ISystemAppletProxy::GetWindowController>, "GetWindowController"},
{3, D<&ISystemAppletProxy::GetAudioController>, "GetAudioController"},
{4, D<&ISystemAppletProxy::GetDisplayController>, "GetDisplayController"},
{10, D<&ISystemAppletProxy::GetProcessWindingController>, "GetProcessWindingController"},
{11, D<&ISystemAppletProxy::GetLibraryAppletCreator>, "GetLibraryAppletCreator"},
{20, D<&ISystemAppletProxy::GetHomeMenuFunctions>, "GetHomeMenuFunctions"},
{21, D<&ISystemAppletProxy::GetGlobalStateController>, "GetGlobalStateController"},
{22, D<&ISystemAppletProxy::GetApplicationCreator>, "GetApplicationCreator"},
{23, D<&ISystemAppletProxy::GetAppletCommonFunctions>, "GetAppletCommonFunctions"},
{1000, D<&ISystemAppletProxy::GetDebugFunctions>, "GetDebugFunctions"},
};
// clang-format on
RegisterHandlers(functions);
}
ISystemAppletProxy::~ISystemAppletProxy() = default;
Result ISystemAppletProxy::GetAudioController(
Out<SharedPointer<IAudioController>> out_audio_controller) {
LOG_DEBUG(Service_AM, "called");
*out_audio_controller = std::make_shared<IAudioController>(system);
R_SUCCEED();
}
Result ISystemAppletProxy::GetDisplayController(
Out<SharedPointer<IDisplayController>> out_display_controller) {
LOG_DEBUG(Service_AM, "called");
*out_display_controller = std::make_shared<IDisplayController>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller) {
LOG_DEBUG(Service_AM, "called");
*out_process_winding_controller = std::make_shared<IProcessWindingController>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetDebugFunctions(
Out<SharedPointer<IDebugFunctions>> out_debug_functions) {
LOG_DEBUG(Service_AM, "called");
*out_debug_functions = std::make_shared<IDebugFunctions>(system);
R_SUCCEED();
}
Result ISystemAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetSelfController(
Out<SharedPointer<ISelfController>> out_self_controller) {
LOG_DEBUG(Service_AM, "called");
*out_self_controller =
std::make_shared<ISelfController>(system, m_applet, m_process, m_nvnflinger);
R_SUCCEED();
}
Result ISystemAppletProxy::GetCommonStateGetter(
Out<SharedPointer<ICommonStateGetter>> out_common_state_getter) {
LOG_DEBUG(Service_AM, "called");
*out_common_state_getter = std::make_shared<ICommonStateGetter>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator) {
LOG_DEBUG(Service_AM, "called");
*out_library_applet_creator = std::make_shared<ILibraryAppletCreator>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetApplicationCreator(
Out<SharedPointer<IApplicationCreator>> out_application_creator) {
LOG_DEBUG(Service_AM, "called");
*out_application_creator = std::make_shared<IApplicationCreator>(system);
R_SUCCEED();
}
Result ISystemAppletProxy::GetAppletCommonFunctions(
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions) {
LOG_DEBUG(Service_AM, "called");
*out_applet_common_functions = std::make_shared<IAppletCommonFunctions>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetHomeMenuFunctions(
Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions) {
LOG_DEBUG(Service_AM, "called");
*out_home_menu_functions = std::make_shared<IHomeMenuFunctions>(system, m_applet);
R_SUCCEED();
}
Result ISystemAppletProxy::GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller) {
LOG_DEBUG(Service_AM, "called");
*out_global_state_controller = std::make_shared<IGlobalStateController>(system);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,54 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IAppletCommonFunctions;
class IApplicationCreator;
class IAudioController;
class ICommonStateGetter;
class IDebugFunctions;
class IDisplayController;
class IHomeMenuFunctions;
class IGlobalStateController;
class ILibraryAppletCreator;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
Kernel::KProcess* process, Nvnflinger::Nvnflinger& nvnflinger);
~ISystemAppletProxy();
private:
Result GetAudioController(Out<SharedPointer<IAudioController>> out_audio_controller);
Result GetDisplayController(Out<SharedPointer<IDisplayController>> out_display_controller);
Result GetProcessWindingController(
Out<SharedPointer<IProcessWindingController>> out_process_winding_controller);
Result GetDebugFunctions(Out<SharedPointer<IDebugFunctions>> out_debug_functions);
Result GetWindowController(Out<SharedPointer<IWindowController>> out_window_controller);
Result GetSelfController(Out<SharedPointer<ISelfController>> out_self_controller);
Result GetCommonStateGetter(Out<SharedPointer<ICommonStateGetter>> out_common_state_getter);
Result GetLibraryAppletCreator(
Out<SharedPointer<ILibraryAppletCreator>> out_library_applet_creator);
Result GetApplicationCreator(Out<SharedPointer<IApplicationCreator>> out_application_creator);
Result GetAppletCommonFunctions(
Out<SharedPointer<IAppletCommonFunctions>> out_applet_common_functions);
Result GetHomeMenuFunctions(Out<SharedPointer<IHomeMenuFunctions>> out_home_menu_functions);
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
Nvnflinger::Nvnflinger& m_nvnflinger;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -0,0 +1,86 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/service/window_controller.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IWindowController"}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateWindow"},
{1, D<&IWindowController::GetAppletResourceUserId>, "GetAppletResourceUserId"},
{2, D<&IWindowController::GetAppletResourceUserIdOfCallerApplet>, "GetAppletResourceUserIdOfCallerApplet"},
{10, D<&IWindowController::AcquireForegroundRights>, "AcquireForegroundRights"},
{11, D<&IWindowController::ReleaseForegroundRights>, "ReleaseForegroundRights"},
{12, D<&IWindowController::RejectToChangeIntoBackground>, "RejectToChangeIntoBackground"},
{20, D<&IWindowController::SetAppletWindowVisibility>, "SetAppletWindowVisibility"},
{21, D<&IWindowController::SetAppletGpuTimeSlice>, "SetAppletGpuTimeSlice"},
};
// clang-format on
RegisterHandlers(functions);
}
IWindowController::~IWindowController() = default;
Result IWindowController::GetAppletResourceUserId(Out<AppletResourceUserId> out_aruid) {
LOG_INFO(Service_AM, "called");
*out_aruid = m_applet->aruid;
R_SUCCEED();
}
Result IWindowController::GetAppletResourceUserIdOfCallerApplet(
Out<AppletResourceUserId> out_aruid) {
LOG_INFO(Service_AM, "called");
if (auto caller_applet = m_applet->caller_applet.lock(); caller_applet != nullptr) {
*out_aruid = caller_applet->aruid;
} else {
*out_aruid = AppletResourceUserId{};
}
R_SUCCEED();
}
Result IWindowController::AcquireForegroundRights() {
LOG_INFO(Service_AM, "called");
R_SUCCEED();
}
Result IWindowController::ReleaseForegroundRights() {
LOG_INFO(Service_AM, "called");
R_SUCCEED();
}
Result IWindowController::RejectToChangeIntoBackground() {
LOG_INFO(Service_AM, "called");
R_SUCCEED();
}
Result IWindowController::SetAppletWindowVisibility(bool visible) {
m_applet->system_buffer_manager.SetWindowVisibility(visible);
m_applet->hid_registration.EnableAppletToGetInput(visible);
if (visible) {
m_applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
m_applet->focus_state = FocusState::InFocus;
} else {
m_applet->focus_state = FocusState::NotInFocus;
}
m_applet->message_queue.PushMessage(AppletMessage::FocusStateChanged);
R_SUCCEED();
}
Result IWindowController::SetAppletGpuTimeSlice(s64 time_slice) {
LOG_WARNING(Service_AM, "(STUBBED) called, time_slice={}", time_slice);
R_SUCCEED();
}
} // namespace Service::AM

View File

@ -0,0 +1,30 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Service::AM {
struct Applet;
class IWindowController final : public ServiceFramework<IWindowController> {
public:
explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet);
~IWindowController() override;
private:
Result GetAppletResourceUserId(Out<AppletResourceUserId> out_aruid);
Result GetAppletResourceUserIdOfCallerApplet(Out<AppletResourceUserId> out_aruid);
Result AcquireForegroundRights();
Result ReleaseForegroundRights();
Result RejectToChangeIntoBackground();
Result SetAppletWindowVisibility(bool visible);
Result SetAppletGpuTimeSlice(s64 time_slice);
const std::shared_ptr<Applet> m_applet;
};
} // namespace Service::AM

View File

@ -85,15 +85,14 @@ Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network) const {
}
Result LANDiscovery::GetNetworkInfo(NetworkInfo& out_network,
std::vector<NodeLatestUpdate>& out_updates,
std::size_t buffer_count) {
if (buffer_count > NodeCountMax) {
std::span<NodeLatestUpdate> out_updates) {
if (out_updates.size() > NodeCountMax) {
return ResultInvalidBufferCount;
}
if (state == State::AccessPointCreated || state == State::StationConnected) {
std::memcpy(&out_network, &network_info, sizeof(network_info));
for (std::size_t i = 0; i < buffer_count; i++) {
for (std::size_t i = 0; i < out_updates.size(); i++) {
out_updates[i].state_change = node_changes[i].state_change;
node_changes[i].state_change = NodeStateChange::None;
}
@ -107,15 +106,8 @@ DisconnectReason LANDiscovery::GetDisconnectReason() const {
return disconnect_reason;
}
Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
Result LANDiscovery::Scan(std::span<NetworkInfo> out_networks, s16& out_count,
const ScanFilter& filter) {
if (!IsFlagSet(filter.flag, ScanFilterFlag::NetworkType) ||
filter.network_type <= NetworkType::All) {
if (!IsFlagSet(filter.flag, ScanFilterFlag::Ssid) && filter.ssid.length >= SsidLengthMax) {
return ResultBadInput;
}
}
{
std::scoped_lock lock{packet_mutex};
scan_results.clear();
@ -128,7 +120,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
std::scoped_lock lock{packet_mutex};
for (const auto& [key, info] : scan_results) {
if (count >= networks.size()) {
if (out_count >= static_cast<s16>(out_networks.size())) {
break;
}
@ -159,7 +151,7 @@ Result LANDiscovery::Scan(std::vector<NetworkInfo>& networks, u16& count,
}
}
networks[count++] = info;
out_networks[out_count++] = info;
}
return ResultSuccess;

View File

@ -54,11 +54,10 @@ public:
void SetState(State new_state);
Result GetNetworkInfo(NetworkInfo& out_network) const;
Result GetNetworkInfo(NetworkInfo& out_network, std::vector<NodeLatestUpdate>& out_updates,
std::size_t buffer_count);
Result GetNetworkInfo(NetworkInfo& out_network, std::span<NodeLatestUpdate> out_updates);
DisconnectReason GetDisconnectReason() const;
Result Scan(std::vector<NetworkInfo>& networks, u16& count, const ScanFilter& filter);
Result Scan(std::span<NetworkInfo> out_networks, s16& out_count, const ScanFilter& filter);
Result SetAdvertiseData(std::span<const u8> data);
Result OpenAccessPoint();

View File

@ -1,36 +1,24 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include <memory>
#include "core/core.h"
#include "core/hle/service/ldn/lan_discovery.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/ldn.h"
#include "core/hle/service/ldn/ldn_results.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/server_manager.h"
#include "core/internal_network/network.h"
#include "core/internal_network/network_interface.h"
#include "network/network.h"
// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
#undef CreateEvent
#include "core/hle/service/ldn/monitor_service.h"
#include "core/hle/service/ldn/sf_monitor_service.h"
#include "core/hle/service/ldn/sf_service.h"
#include "core/hle/service/ldn/sf_service_monitor.h"
#include "core/hle/service/ldn/system_local_communication_service.h"
#include "core/hle/service/ldn/user_local_communication_service.h"
namespace Service::LDN {
class IMonitorService final : public ServiceFramework<IMonitorService> {
class IMonitorServiceCreator final : public ServiceFramework<IMonitorServiceCreator> {
public:
explicit IMonitorService(Core::System& system_) : ServiceFramework{system_, "IMonitorService"} {
explicit IMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IMonitorService::GetStateForMonitor, "GetStateForMonitor"},
{1, nullptr, "GetNetworkInfoForMonitor"},
{2, nullptr, "GetIpv4AddressForMonitor"},
{3, nullptr, "GetDisconnectReasonForMonitor"},
{4, nullptr, "GetSecurityParameterForMonitor"},
{5, nullptr, "GetNetworkConfigForMonitor"},
{100, &IMonitorService::InitializeMonitor, "InitializeMonitor"},
{101, nullptr, "FinalizeMonitor"},
{0, C<&IMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"}
};
// clang-format on
@ -38,84 +26,20 @@ public:
}
private:
void GetStateForMonitor(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
void InitializeMonitor(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
state = State::Initialized;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
State state{State::None};
};
class LDNM final : public ServiceFramework<LDNM> {
public:
explicit LDNM(Core::System& system_) : ServiceFramework{system_, "ldn:m"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LDNM::CreateMonitorService, "CreateMonitorService"}
};
// clang-format on
RegisterHandlers(functions);
}
void CreateMonitorService(HLERequestContext& ctx) {
Result CreateMonitorService(OutInterface<IMonitorService> out_interface) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IMonitorService>(system);
*out_interface = std::make_shared<IMonitorService>(system);
R_SUCCEED();
}
};
class ISystemLocalCommunicationService final
: public ServiceFramework<ISystemLocalCommunicationService> {
class ISystemServiceCreator final : public ServiceFramework<ISystemServiceCreator> {
public:
explicit ISystemLocalCommunicationService(Core::System& system_)
: ServiceFramework{system_, "ISystemLocalCommunicationService"} {
explicit ISystemServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetState"},
{1, nullptr, "GetNetworkInfo"},
{2, nullptr, "GetIpv4Address"},
{3, nullptr, "GetDisconnectReason"},
{4, nullptr, "GetSecurityParameter"},
{5, nullptr, "GetNetworkConfig"},
{100, nullptr, "AttachStateChangeEvent"},
{101, nullptr, "GetNetworkInfoLatestUpdate"},
{102, nullptr, "Scan"},
{103, nullptr, "ScanPrivate"},
{104, nullptr, "SetWirelessControllerRestriction"},
{200, nullptr, "OpenAccessPoint"},
{201, nullptr, "CloseAccessPoint"},
{202, nullptr, "CreateNetwork"},
{203, nullptr, "CreateNetworkPrivate"},
{204, nullptr, "DestroyNetwork"},
{205, nullptr, "Reject"},
{206, nullptr, "SetAdvertiseData"},
{207, nullptr, "SetStationAcceptPolicy"},
{208, nullptr, "AddAcceptFilterEntry"},
{209, nullptr, "ClearAcceptFilter"},
{300, nullptr, "OpenStation"},
{301, nullptr, "CloseStation"},
{302, nullptr, "Connect"},
{303, nullptr, "ConnectPrivate"},
{304, nullptr, "Disconnect"},
{400, nullptr, "InitializeSystem"},
{401, nullptr, "FinalizeSystem"},
{402, nullptr, "SetOperationMode"},
{403, &ISystemLocalCommunicationService::InitializeSystem2, "InitializeSystem2"},
{0, C<&ISystemServiceCreator::CreateSystemLocalCommunicationService>, "CreateSystemLocalCommunicationService"},
};
// clang-format on
@ -123,651 +47,78 @@ public:
}
private:
void InitializeSystem2(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
class IUserLocalCommunicationService final
: public ServiceFramework<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_)
: ServiceFramework{system_, "IUserLocalCommunicationService"},
service_context{system, "IUserLocalCommunicationService"},
room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IUserLocalCommunicationService::GetState, "GetState"},
{1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"},
{2, &IUserLocalCommunicationService::GetIpv4Address, "GetIpv4Address"},
{3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"},
{4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"},
{5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"},
{100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"},
{101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"},
{102, &IUserLocalCommunicationService::Scan, "Scan"},
{103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"},
{104, &IUserLocalCommunicationService::SetWirelessControllerRestriction, "SetWirelessControllerRestriction"},
{200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"},
{201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"},
{202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"},
{203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"},
{204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"},
{205, nullptr, "Reject"},
{206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"},
{207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"},
{208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"},
{209, nullptr, "ClearAcceptFilter"},
{300, &IUserLocalCommunicationService::OpenStation, "OpenStation"},
{301, &IUserLocalCommunicationService::CloseStation, "CloseStation"},
{302, &IUserLocalCommunicationService::Connect, "Connect"},
{303, nullptr, "ConnectPrivate"},
{304, &IUserLocalCommunicationService::Disconnect, "Disconnect"},
{400, &IUserLocalCommunicationService::Initialize, "Initialize"},
{401, &IUserLocalCommunicationService::Finalize, "Finalize"},
{402, &IUserLocalCommunicationService::Initialize2, "Initialize2"},
};
// clang-format on
RegisterHandlers(functions);
state_change_event =
service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
}
~IUserLocalCommunicationService() {
if (is_initialized) {
if (auto room_member = room_network.GetRoomMember().lock()) {
room_member->Unbind(ldn_packet_received);
}
}
service_context.CloseEvent(state_change_event);
}
/// Callback to parse and handle a received LDN packet.
void OnLDNPacketReceived(const Network::LDNPacket& packet) {
lan_discovery.ReceivePacket(packet);
}
void OnEventFired() {
state_change_event->Signal();
}
void GetState(HLERequestContext& ctx) {
State state = State::Error;
if (is_initialized) {
state = lan_discovery.GetState();
}
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(state);
}
void GetNetworkInfo(HLERequestContext& ctx) {
const auto write_buffer_size = ctx.GetWriteBufferSize();
if (write_buffer_size != sizeof(NetworkInfo)) {
LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
NetworkInfo network_info{};
const auto rc = lan_discovery.GetNetworkInfo(network_info);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
ctx.WriteBuffer<NetworkInfo>(network_info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void GetIpv4Address(HLERequestContext& ctx) {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface) {
LOG_ERROR(Service_LDN, "No network interface available");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultNoIpAddress);
return;
}
Ipv4Address current_address{Network::TranslateIPv4(network_interface->ip_address)};
Ipv4Address subnet_mask{Network::TranslateIPv4(network_interface->subnet_mask)};
// When we're connected to a room, spoof the hosts IP address
if (auto room_member = room_network.GetRoomMember().lock()) {
if (room_member->IsConnected()) {
current_address = room_member->GetFakeIpAddress();
}
}
std::reverse(std::begin(current_address), std::end(current_address)); // ntohl
std::reverse(std::begin(subnet_mask), std::end(subnet_mask)); // ntohl
IPC::ResponseBuilder rb{ctx, 4};
rb.Push(ResultSuccess);
rb.PushRaw(current_address);
rb.PushRaw(subnet_mask);
}
void GetDisconnectReason(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.PushEnum(lan_discovery.GetDisconnectReason());
}
void GetSecurityParameter(HLERequestContext& ctx) {
SecurityParameter security_parameter{};
NetworkInfo info{};
const Result rc = lan_discovery.GetNetworkInfo(info);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
security_parameter.session_id = info.network_id.session_id;
std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(),
sizeof(SecurityParameter::data));
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(rc);
rb.PushRaw<SecurityParameter>(security_parameter);
}
void GetNetworkConfig(HLERequestContext& ctx) {
NetworkConfig config{};
NetworkInfo info{};
const Result rc = lan_discovery.GetNetworkInfo(info);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
config.intent_id = info.network_id.intent_id;
config.channel = info.common.channel;
config.node_count_max = info.ldn.node_count_max;
config.local_communication_version = info.ldn.nodes[0].local_communication_version;
IPC::ResponseBuilder rb{ctx, 10};
rb.Push(rc);
rb.PushRaw<NetworkConfig>(config);
}
void AttachStateChangeEvent(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(ResultSuccess);
rb.PushCopyObjects(state_change_event->GetReadableEvent());
}
void GetNetworkInfoLatestUpdate(HLERequestContext& ctx) {
const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0);
const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements<NodeLatestUpdate>(1);
if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) {
LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size,
node_buffer_count);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
NetworkInfo info{};
std::vector<NodeLatestUpdate> latest_update(node_buffer_count);
const auto rc = lan_discovery.GetNetworkInfo(info, latest_update, latest_update.size());
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
return;
}
ctx.WriteBuffer(info, 0);
ctx.WriteBuffer(latest_update, 1);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void Scan(HLERequestContext& ctx) {
ScanImpl(ctx);
}
void ScanPrivate(HLERequestContext& ctx) {
ScanImpl(ctx, true);
}
void ScanImpl(HLERequestContext& ctx, bool is_private = false) {
IPC::RequestParser rp{ctx};
const auto channel{rp.PopEnum<WifiChannel>()};
const auto scan_filter{rp.PopRaw<ScanFilter>()};
const std::size_t network_info_size = ctx.GetWriteBufferNumElements<NetworkInfo>();
if (network_info_size == 0) {
LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
u16 count = 0;
std::vector<NetworkInfo> network_infos(network_info_size);
Result rc = lan_discovery.Scan(network_infos, count, scan_filter);
LOG_INFO(Service_LDN,
"called, channel={}, filter_scan_flag={}, filter_network_type={}, is_private={}",
channel, scan_filter.flag, scan_filter.network_type, is_private);
ctx.WriteBuffer(network_infos);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(rc);
rb.Push<u32>(count);
}
void SetWirelessControllerRestriction(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void OpenAccessPoint(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.OpenAccessPoint());
}
void CloseAccessPoint(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.CloseAccessPoint());
}
void CreateNetwork(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
CreateNetworkImpl(ctx);
}
void CreateNetworkPrivate(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
CreateNetworkImpl(ctx, true);
}
void CreateNetworkImpl(HLERequestContext& ctx, bool is_private = false) {
IPC::RequestParser rp{ctx};
const auto security_config{rp.PopRaw<SecurityConfig>()};
[[maybe_unused]] const auto security_parameter{is_private ? rp.PopRaw<SecurityParameter>()
: SecurityParameter{}};
const auto user_config{rp.PopRaw<UserConfig>()};
rp.Pop<u32>(); // Padding
const auto network_Config{rp.PopRaw<NetworkConfig>()};
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.CreateNetwork(security_config, user_config, network_Config));
}
void DestroyNetwork(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.DestroyNetwork());
}
void SetAdvertiseData(HLERequestContext& ctx) {
const auto read_buffer = ctx.ReadBuffer();
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.SetAdvertiseData(read_buffer));
}
void SetStationAcceptPolicy(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void AddAcceptFilterEntry(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
void OpenStation(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.OpenStation());
}
void CloseStation(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.CloseStation());
}
void Connect(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
SecurityConfig security_config;
UserConfig user_config;
u32 local_communication_version;
u32 option;
};
static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size.");
const auto parameters{rp.PopRaw<Parameters>()};
LOG_INFO(Service_LDN,
"called, passphrase_size={}, security_mode={}, "
"local_communication_version={}",
parameters.security_config.passphrase_size,
parameters.security_config.security_mode, parameters.local_communication_version);
const auto read_buffer = ctx.ReadBuffer();
if (read_buffer.size() != sizeof(NetworkInfo)) {
LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultBadInput);
return;
}
NetworkInfo network_info{};
std::memcpy(&network_info, read_buffer.data(), read_buffer.size());
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.Connect(network_info, parameters.user_config,
static_cast<u16>(parameters.local_communication_version)));
}
void Disconnect(HLERequestContext& ctx) {
LOG_INFO(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.Disconnect());
}
void Initialize(HLERequestContext& ctx) {
const auto rc = InitializeImpl(ctx);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
}
void Finalize(HLERequestContext& ctx) {
if (auto room_member = room_network.GetRoomMember().lock()) {
room_member->Unbind(ldn_packet_received);
}
is_initialized = false;
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(lan_discovery.Finalize());
}
void Initialize2(HLERequestContext& ctx) {
const auto rc = InitializeImpl(ctx);
if (rc.IsError()) {
LOG_ERROR(Service_LDN, "Network isn't initialized, rc={}", rc.raw);
}
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(rc);
}
Result InitializeImpl(HLERequestContext& ctx) {
const auto network_interface = Network::GetSelectedNetworkInterface();
if (!network_interface) {
LOG_ERROR(Service_LDN, "No network interface is set");
return ResultAirplaneModeEnabled;
}
if (auto room_member = room_network.GetRoomMember().lock()) {
ldn_packet_received = room_member->BindOnLdnPacketReceived(
[this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); });
} else {
LOG_ERROR(Service_LDN, "Couldn't bind callback!");
return ResultAirplaneModeEnabled;
}
lan_discovery.Initialize([&]() { OnEventFired(); });
is_initialized = true;
return ResultSuccess;
}
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* state_change_event;
Network::RoomNetwork& room_network;
LANDiscovery lan_discovery;
// Callback identifier for the OnLDNPacketReceived event.
Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received;
bool is_initialized{};
};
class LDNS final : public ServiceFramework<LDNS> {
public:
explicit LDNS(Core::System& system_) : ServiceFramework{system_, "ldn:s"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LDNS::CreateSystemLocalCommunicationService, "CreateSystemLocalCommunicationService"},
};
// clang-format on
RegisterHandlers(functions);
}
void CreateSystemLocalCommunicationService(HLERequestContext& ctx) {
Result CreateSystemLocalCommunicationService(
OutInterface<ISystemLocalCommunicationService> out_interface) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISystemLocalCommunicationService>(system);
*out_interface = std::make_shared<ISystemLocalCommunicationService>(system);
R_SUCCEED();
}
};
class LDNU final : public ServiceFramework<LDNU> {
class IUserServiceCreator final : public ServiceFramework<IUserServiceCreator> {
public:
explicit LDNU(Core::System& system_) : ServiceFramework{system_, "ldn:u"} {
explicit IUserServiceCreator(Core::System& system_) : ServiceFramework{system_, "ldn:u"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LDNU::CreateUserLocalCommunicationService, "CreateUserLocalCommunicationService"},
{0, C<&IUserServiceCreator::CreateUserLocalCommunicationService>, "CreateUserLocalCommunicationService"},
};
// clang-format on
RegisterHandlers(functions);
}
void CreateUserLocalCommunicationService(HLERequestContext& ctx) {
private:
Result CreateUserLocalCommunicationService(
OutInterface<IUserLocalCommunicationService> out_interface) {
LOG_DEBUG(Service_LDN, "called");
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<IUserLocalCommunicationService>(system);
*out_interface = std::make_shared<IUserLocalCommunicationService>(system);
R_SUCCEED();
}
};
class INetworkService final : public ServiceFramework<INetworkService> {
class ISfServiceCreator final : public ServiceFramework<ISfServiceCreator> {
public:
explicit INetworkService(Core::System& system_) : ServiceFramework{system_, "INetworkService"} {
explicit ISfServiceCreator(Core::System& system_, bool is_system_, const char* name_)
: ServiceFramework{system_, name_}, is_system{is_system_} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Initialize"},
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
{264, nullptr, "GetNetworkInterfaceLastError"},
{272, nullptr, "GetRole"},
{280, nullptr, "GetAdvertiseData"},
{288, nullptr, "GetGroupInfo"},
{296, nullptr, "GetGroupInfo2"},
{304, nullptr, "GetGroupOwner"},
{312, nullptr, "GetIpConfig"},
{320, nullptr, "GetLinkLevel"},
{512, nullptr, "Scan"},
{768, nullptr, "CreateGroup"},
{776, nullptr, "DestroyGroup"},
{784, nullptr, "SetAdvertiseData"},
{1536, nullptr, "SendToOtherGroup"},
{1544, nullptr, "RecvFromOtherGroup"},
{1552, nullptr, "AddAcceptableGroupId"},
{1560, nullptr, "ClearAcceptableGroupId"},
};
// clang-format on
RegisterHandlers(functions);
}
};
class INetworkServiceMonitor final : public ServiceFramework<INetworkServiceMonitor> {
public:
explicit INetworkServiceMonitor(Core::System& system_)
: ServiceFramework{system_, "INetworkServiceMonitor"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &INetworkServiceMonitor::Initialize, "Initialize"},
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
{264, nullptr, "GetNetworkInterfaceLastError"},
{272, nullptr, "GetRole"},
{280, nullptr, "GetAdvertiseData"},
{281, nullptr, "GetAdvertiseData2"},
{288, nullptr, "GetGroupInfo"},
{296, nullptr, "GetGroupInfo2"},
{304, nullptr, "GetGroupOwner"},
{312, nullptr, "GetIpConfig"},
{320, nullptr, "GetLinkLevel"},
{328, nullptr, "AttachJoinEvent"},
{336, nullptr, "GetMembers"},
{0, C<&ISfServiceCreator::CreateNetworkService>, "CreateNetworkService"},
{8, C<&ISfServiceCreator::CreateNetworkServiceMonitor>, "CreateNetworkServiceMonitor"},
};
// clang-format on
RegisterHandlers(functions);
}
void Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultDisabled);
}
};
class LP2PAPP final : public ServiceFramework<LP2PAPP> {
public:
explicit LP2PAPP(Core::System& system_) : ServiceFramework{system_, "lp2p:app"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LP2PAPP::CreateMonitorService, "CreateNetworkService"},
{8, &LP2PAPP::CreateMonitorService, "CreateNetworkServiceMonitor"},
};
// clang-format on
RegisterHandlers(functions);
}
void CreateNetworkervice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
const u32 input = rp.Pop<u32>();
private:
Result CreateNetworkService(OutInterface<ISfService> out_interface, u32 input,
u64 reserved_input) {
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INetworkService>(system);
*out_interface = std::make_shared<ISfService>(system);
R_SUCCEED();
}
void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
Result CreateNetworkServiceMonitor(OutInterface<ISfServiceMonitor> out_interface,
u64 reserved_input) {
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INetworkServiceMonitor>(system);
*out_interface = std::make_shared<ISfServiceMonitor>(system);
R_SUCCEED();
}
bool is_system{};
};
class LP2PSYS final : public ServiceFramework<LP2PSYS> {
class ISfMonitorServiceCreator final : public ServiceFramework<ISfMonitorServiceCreator> {
public:
explicit LP2PSYS(Core::System& system_) : ServiceFramework{system_, "lp2p:sys"} {
explicit ISfMonitorServiceCreator(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LP2PSYS::CreateMonitorService, "CreateNetworkService"},
{8, &LP2PSYS::CreateMonitorService, "CreateNetworkServiceMonitor"},
};
// clang-format on
RegisterHandlers(functions);
}
void CreateNetworkervice(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
const u32 input = rp.Pop<u32>();
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={} input={}", reserved_input,
input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INetworkService>(system);
}
void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
LOG_WARNING(Service_LDN, "(STUBBED) called reserved_input={}", reserved_input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<INetworkServiceMonitor>(system);
}
};
class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
public:
explicit ISfMonitorService(Core::System& system_)
: ServiceFramework{system_, "ISfMonitorService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISfMonitorService::Initialize, "Initialize"},
{288, &ISfMonitorService::GetGroupInfo, "GetGroupInfo"},
{320, nullptr, "GetLinkLevel"},
{0, C<&ISfMonitorServiceCreator::CreateMonitorService>, "CreateMonitorService"},
};
// clang-format on
@ -775,64 +126,27 @@ public:
}
private:
void Initialize(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push(0);
}
void GetGroupInfo(HLERequestContext& ctx) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
struct GroupInfo {
std::array<u8, 0x200> info;
};
GroupInfo group_info{};
ctx.WriteBuffer(group_info);
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
};
class LP2PM final : public ServiceFramework<LP2PM> {
public:
explicit LP2PM(Core::System& system_) : ServiceFramework{system_, "lp2p:m"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &LP2PM::CreateMonitorService, "CreateMonitorService"},
};
// clang-format on
RegisterHandlers(functions);
}
private:
void CreateMonitorService(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const u64 reserved_input = rp.Pop<u64>();
Result CreateMonitorService(OutInterface<ISfMonitorService> out_interface, u64 reserved_input) {
LOG_INFO(Service_LDN, "called, reserved_input={}", reserved_input);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
rb.Push(ResultSuccess);
rb.PushIpcInterface<ISfMonitorService>(system);
*out_interface = std::make_shared<ISfMonitorService>(system);
R_SUCCEED();
}
};
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("ldn:m", std::make_shared<LDNM>(system));
server_manager->RegisterNamedService("ldn:s", std::make_shared<LDNS>(system));
server_manager->RegisterNamedService("ldn:u", std::make_shared<LDNU>(system));
server_manager->RegisterNamedService("ldn:m", std::make_shared<IMonitorServiceCreator>(system));
server_manager->RegisterNamedService("ldn:s", std::make_shared<ISystemServiceCreator>(system));
server_manager->RegisterNamedService("ldn:u", std::make_shared<IUserServiceCreator>(system));
server_manager->RegisterNamedService("lp2p:app", std::make_shared<LP2PAPP>(system));
server_manager->RegisterNamedService("lp2p:sys", std::make_shared<LP2PSYS>(system));
server_manager->RegisterNamedService("lp2p:m", std::make_shared<LP2PM>(system));
server_manager->RegisterNamedService(
"lp2p:app", std::make_shared<ISfServiceCreator>(system, false, "lp2p:app"));
server_manager->RegisterNamedService(
"lp2p:sys", std::make_shared<ISfServiceCreator>(system, true, "lp2p:sys"));
server_manager->RegisterNamedService("lp2p:m",
std::make_shared<ISfMonitorServiceCreator>(system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -3,12 +3,6 @@
#pragma once
#include "core/hle/kernel/k_event.h"
#include "core/hle/result.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/sm/sm.h"
namespace Core {
class System;
}

View File

@ -123,6 +123,18 @@ enum class NodeStatus : u8 {
Connected,
};
enum class WirelessControllerRestriction : u32 {
None,
Default,
};
struct ConnectOption {
union {
u32 raw;
};
};
static_assert(sizeof(ConnectOption) == 0x4, "ConnectOption is an invalid size");
struct NodeLatestUpdate {
NodeStateChange state_change;
INSERT_PADDING_BYTES(0x7); // Unknown
@ -139,9 +151,9 @@ static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size");
struct IntentId {
u64 local_communication_id;
INSERT_PADDING_BYTES(0x2); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
u16 scene_id;
INSERT_PADDING_BYTES(0x4); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x4); // Reserved
};
static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size");
@ -152,13 +164,14 @@ struct NetworkId {
static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size");
struct Ssid {
u8 length{};
std::array<char, SsidLengthMax + 1> raw{};
u8 length;
std::array<char, SsidLengthMax + 1> raw;
Ssid() = default;
constexpr explicit Ssid(std::string_view data) {
length = static_cast<u8>(std::min(data.size(), SsidLengthMax));
raw = {};
data.copy(raw.data(), length);
raw[length] = 0;
}
@ -181,7 +194,7 @@ using Ipv4Address = std::array<u8, 4>;
static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size");
struct MacAddress {
std::array<u8, 6> raw{};
std::array<u8, 6> raw;
friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default;
};
@ -211,7 +224,7 @@ struct CommonNetworkInfo {
WifiChannel channel;
LinkLevel link_level;
PackedNetworkType network_type;
INSERT_PADDING_BYTES(0x4);
INSERT_PADDING_BYTES_NOINIT(0x4);
};
static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size");
@ -221,9 +234,9 @@ struct NodeInfo {
s8 node_id;
u8 is_connected;
std::array<u8, UserNameBytesMax + 1> user_name;
INSERT_PADDING_BYTES(0x1); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x1); // Reserved
s16 local_communication_version;
INSERT_PADDING_BYTES(0x10); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x10); // Reserved
};
static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size");
@ -232,14 +245,14 @@ struct LdnNetworkInfo {
SecurityMode security_mode;
AcceptPolicy station_accept_policy;
u8 has_action_frame;
INSERT_PADDING_BYTES(0x2); // Padding
INSERT_PADDING_BYTES_NOINIT(0x2); // Padding
u8 node_count_max;
u8 node_count;
std::array<NodeInfo, NodeCountMax> nodes;
INSERT_PADDING_BYTES(0x2); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x2); // Reserved
u16 advertise_data_size;
std::array<u8, AdvertiseDataSizeMax> advertise_data;
INSERT_PADDING_BYTES(0x8C); // Reserved
INSERT_PADDING_BYTES_NOINIT(0x8C); // Reserved
u64 random_authentication_id;
};
static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size");
@ -250,6 +263,7 @@ struct NetworkInfo {
LdnNetworkInfo ldn;
};
static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size");
static_assert(std::is_trivial_v<NetworkInfo>, "NetworkInfo type must be trivially copyable.");
struct SecurityConfig {
SecurityMode security_mode;
@ -303,4 +317,36 @@ struct AddressList {
};
static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size");
struct GroupInfo {
std::array<u8, 0x200> info;
};
struct CreateNetworkConfig {
SecurityConfig security_config;
UserConfig user_config;
INSERT_PADDING_BYTES(0x4);
NetworkConfig network_config;
};
static_assert(sizeof(CreateNetworkConfig) == 0x98, "CreateNetworkConfig is an invalid size");
#pragma pack(push, 4)
struct CreateNetworkConfigPrivate {
SecurityConfig security_config;
SecurityParameter security_parameter;
UserConfig user_config;
INSERT_PADDING_BYTES(0x4);
NetworkConfig network_config;
};
#pragma pack(pop)
static_assert(sizeof(CreateNetworkConfigPrivate) == 0xB8,
"CreateNetworkConfigPrivate is an invalid size");
struct ConnectNetworkData {
SecurityConfig security_config;
UserConfig user_config;
s32 local_communication_version;
ConnectOption option;
};
static_assert(sizeof(ConnectNetworkData) == 0x7c, "ConnectNetworkData is an invalid size");
} // namespace Service::LDN

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/monitor_service.h"
namespace Service::LDN {
IMonitorService::IMonitorService(Core::System& system_)
: ServiceFramework{system_, "IMonitorService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, C<&IMonitorService::GetStateForMonitor>, "GetStateForMonitor"},
{1, nullptr, "GetNetworkInfoForMonitor"},
{2, nullptr, "GetIpv4AddressForMonitor"},
{3, nullptr, "GetDisconnectReasonForMonitor"},
{4, nullptr, "GetSecurityParameterForMonitor"},
{5, nullptr, "GetNetworkConfigForMonitor"},
{100, C<&IMonitorService::InitializeMonitor>, "InitializeMonitor"},
{101, nullptr, "FinalizeMonitor"},
};
// clang-format on
RegisterHandlers(functions);
}
IMonitorService::~IMonitorService() = default;
Result IMonitorService::GetStateForMonitor(Out<State> out_state) {
LOG_INFO(Service_LDN, "called");
*out_state = state;
R_SUCCEED();
}
Result IMonitorService::InitializeMonitor() {
LOG_INFO(Service_LDN, "called");
state = State::Initialized;
R_SUCCEED();
}
} // namespace Service::LDN

View File

@ -0,0 +1,28 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::LDN {
class IMonitorService final : public ServiceFramework<IMonitorService> {
public:
explicit IMonitorService(Core::System& system_);
~IMonitorService() override;
private:
Result GetStateForMonitor(Out<State> out_state);
Result InitializeMonitor();
State state{State::None};
};
} // namespace Service::LDN

View File

@ -0,0 +1,40 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/ldn/sf_monitor_service.h"
namespace Service::LDN {
ISfMonitorService::ISfMonitorService(Core::System& system_)
: ServiceFramework{system_, "ISfMonitorService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, C<&ISfMonitorService::Initialize>, "Initialize"},
{288, C<&ISfMonitorService::GetGroupInfo>, "GetGroupInfo"},
{320, nullptr, "GetLinkLevel"},
};
// clang-format on
RegisterHandlers(functions);
}
ISfMonitorService::~ISfMonitorService() = default;
Result ISfMonitorService::Initialize(Out<u32> out_value) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_value = 0;
R_SUCCEED();
}
Result ISfMonitorService::GetGroupInfo(
OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_group_info = GroupInfo{};
R_SUCCEED();
}
} // namespace Service::LDN

View File

@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu 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 Core {
class System;
}
namespace Service::LDN {
struct GroupInfo;
class ISfMonitorService final : public ServiceFramework<ISfMonitorService> {
public:
explicit ISfMonitorService(Core::System& system_);
~ISfMonitorService() override;
private:
Result Initialize(Out<u32> out_value);
Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
};
} // namespace Service::LDN

View File

@ -0,0 +1,37 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/ldn/sf_service.h"
namespace Service::LDN {
ISfService::ISfService(Core::System& system_) : ServiceFramework{system_, "ISfService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "Initialize"},
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
{264, nullptr, "GetNetworkInterfaceLastError"},
{272, nullptr, "GetRole"},
{280, nullptr, "GetAdvertiseData"},
{288, nullptr, "GetGroupInfo"},
{296, nullptr, "GetGroupInfo2"},
{304, nullptr, "GetGroupOwner"},
{312, nullptr, "GetIpConfig"},
{320, nullptr, "GetLinkLevel"},
{512, nullptr, "Scan"},
{768, nullptr, "CreateGroup"},
{776, nullptr, "DestroyGroup"},
{784, nullptr, "SetAdvertiseData"},
{1536, nullptr, "SendToOtherGroup"},
{1544, nullptr, "RecvFromOtherGroup"},
{1552, nullptr, "AddAcceptableGroupId"},
{1560, nullptr, "ClearAcceptableGroupId"},
};
// clang-format on
RegisterHandlers(functions);
}
ISfService::~ISfService() = default;
} // namespace Service::LDN

View File

@ -0,0 +1,21 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu 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 Core {
class System;
}
namespace Service::LDN {
class ISfService final : public ServiceFramework<ISfService> {
public:
explicit ISfService(Core::System& system_);
~ISfService() override;
};
} // namespace Service::LDN

View File

@ -0,0 +1,50 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/ldn/sf_service_monitor.h"
namespace Service::LDN {
ISfServiceMonitor::ISfServiceMonitor(Core::System& system_)
: ServiceFramework{system_, "ISfServiceMonitor"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, C<&ISfServiceMonitor::Initialize>, "Initialize"},
{256, nullptr, "AttachNetworkInterfaceStateChangeEvent"},
{264, nullptr, "GetNetworkInterfaceLastError"},
{272, nullptr, "GetRole"},
{280, nullptr, "GetAdvertiseData"},
{281, nullptr, "GetAdvertiseData2"},
{288, C<&ISfServiceMonitor::GetGroupInfo>, "GetGroupInfo"},
{296, nullptr, "GetGroupInfo2"},
{304, nullptr, "GetGroupOwner"},
{312, nullptr, "GetIpConfig"},
{320, nullptr, "GetLinkLevel"},
{328, nullptr, "AttachJoinEvent"},
{336, nullptr, "GetMembers"},
};
// clang-format on
RegisterHandlers(functions);
}
ISfServiceMonitor::~ISfServiceMonitor() = default;
Result ISfServiceMonitor::Initialize(Out<u32> out_value) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_value = 0;
R_SUCCEED();
}
Result ISfServiceMonitor::GetGroupInfo(
OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_group_info = GroupInfo{};
R_SUCCEED();
}
} // namespace Service::LDN

View File

@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu 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 Core {
class System;
}
namespace Service::LDN {
struct GroupInfo;
class ISfServiceMonitor final : public ServiceFramework<ISfServiceMonitor> {
public:
explicit ISfServiceMonitor(Core::System& system_);
~ISfServiceMonitor() override;
private:
Result Initialize(Out<u32> out_value);
Result GetGroupInfo(OutLargeData<GroupInfo, BufferAttr_HipcAutoSelect> out_group_info);
};
} // namespace Service::LDN

View File

@ -0,0 +1,56 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/system_local_communication_service.h"
namespace Service::LDN {
ISystemLocalCommunicationService::ISystemLocalCommunicationService(Core::System& system_)
: ServiceFramework{system_, "ISystemLocalCommunicationService"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetState"},
{1, nullptr, "GetNetworkInfo"},
{2, nullptr, "GetIpv4Address"},
{3, nullptr, "GetDisconnectReason"},
{4, nullptr, "GetSecurityParameter"},
{5, nullptr, "GetNetworkConfig"},
{100, nullptr, "AttachStateChangeEvent"},
{101, nullptr, "GetNetworkInfoLatestUpdate"},
{102, nullptr, "Scan"},
{103, nullptr, "ScanPrivate"},
{104, nullptr, "SetWirelessControllerRestriction"},
{200, nullptr, "OpenAccessPoint"},
{201, nullptr, "CloseAccessPoint"},
{202, nullptr, "CreateNetwork"},
{203, nullptr, "CreateNetworkPrivate"},
{204, nullptr, "DestroyNetwork"},
{205, nullptr, "Reject"},
{206, nullptr, "SetAdvertiseData"},
{207, nullptr, "SetStationAcceptPolicy"},
{208, nullptr, "AddAcceptFilterEntry"},
{209, nullptr, "ClearAcceptFilter"},
{300, nullptr, "OpenStation"},
{301, nullptr, "CloseStation"},
{302, nullptr, "Connect"},
{303, nullptr, "ConnectPrivate"},
{304, nullptr, "Disconnect"},
{400, nullptr, "InitializeSystem"},
{401, nullptr, "FinalizeSystem"},
{402, nullptr, "SetOperationMode"},
{403, C<&ISystemLocalCommunicationService::InitializeSystem2>, "InitializeSystem2"},
};
// clang-format on
RegisterHandlers(functions);
}
ISystemLocalCommunicationService::~ISystemLocalCommunicationService() = default;
Result ISystemLocalCommunicationService::InitializeSystem2() {
LOG_WARNING(Service_LDN, "(STUBBED) called");
R_SUCCEED();
}
} // namespace Service::LDN

View File

@ -0,0 +1,25 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu 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 Core {
class System;
}
namespace Service::LDN {
class ISystemLocalCommunicationService final
: public ServiceFramework<ISystemLocalCommunicationService> {
public:
explicit ISystemLocalCommunicationService(Core::System& system_);
~ISystemLocalCommunicationService() override;
private:
Result InitializeSystem2();
};
} // namespace Service::LDN

View File

@ -0,0 +1,320 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include <memory>
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/ldn_results.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/ldn/user_local_communication_service.h"
#include "core/hle/service/server_manager.h"
#include "core/internal_network/network.h"
#include "core/internal_network/network_interface.h"
#include "network/network.h"
// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent
#undef CreateEvent
namespace Service::LDN {
IUserLocalCommunicationService::IUserLocalCommunicationService(Core::System& system_)
: ServiceFramework{system_, "IUserLocalCommunicationService"},
service_context{system, "IUserLocalCommunicationService"},
room_network{system_.GetRoomNetwork()}, lan_discovery{room_network} {
// clang-format off
static const FunctionInfo functions[] = {
{0, C<&IUserLocalCommunicationService::GetState>, "GetState"},
{1, C<&IUserLocalCommunicationService::GetNetworkInfo>, "GetNetworkInfo"},
{2, C<&IUserLocalCommunicationService::GetIpv4Address>, "GetIpv4Address"},
{3, C<&IUserLocalCommunicationService::GetDisconnectReason>, "GetDisconnectReason"},
{4, C<&IUserLocalCommunicationService::GetSecurityParameter>, "GetSecurityParameter"},
{5, C<&IUserLocalCommunicationService::GetNetworkConfig>, "GetNetworkConfig"},
{100, C<&IUserLocalCommunicationService::AttachStateChangeEvent>, "AttachStateChangeEvent"},
{101, C<&IUserLocalCommunicationService::GetNetworkInfoLatestUpdate>, "GetNetworkInfoLatestUpdate"},
{102, C<&IUserLocalCommunicationService::Scan>, "Scan"},
{103, C<&IUserLocalCommunicationService::ScanPrivate>, "ScanPrivate"},
{104, C<&IUserLocalCommunicationService::SetWirelessControllerRestriction>, "SetWirelessControllerRestriction"},
{200, C<&IUserLocalCommunicationService::OpenAccessPoint>, "OpenAccessPoint"},
{201, C<&IUserLocalCommunicationService::CloseAccessPoint>, "CloseAccessPoint"},
{202, C<&IUserLocalCommunicationService::CreateNetwork>, "CreateNetwork"},
{203, C<&IUserLocalCommunicationService::CreateNetworkPrivate>, "CreateNetworkPrivate"},
{204, C<&IUserLocalCommunicationService::DestroyNetwork>, "DestroyNetwork"},
{205, nullptr, "Reject"},
{206, C<&IUserLocalCommunicationService::SetAdvertiseData>, "SetAdvertiseData"},
{207, C<&IUserLocalCommunicationService::SetStationAcceptPolicy>, "SetStationAcceptPolicy"},
{208, C<&IUserLocalCommunicationService::AddAcceptFilterEntry>, "AddAcceptFilterEntry"},
{209, nullptr, "ClearAcceptFilter"},
{300, C<&IUserLocalCommunicationService::OpenStation>, "OpenStation"},
{301, C<&IUserLocalCommunicationService::CloseStation>, "CloseStation"},
{302, C<&IUserLocalCommunicationService::Connect>, "Connect"},
{303, nullptr, "ConnectPrivate"},
{304, C<&IUserLocalCommunicationService::Disconnect>, "Disconnect"},
{400, C<&IUserLocalCommunicationService::Initialize>, "Initialize"},
{401, C<&IUserLocalCommunicationService::Finalize>, "Finalize"},
{402, C<&IUserLocalCommunicationService::Initialize2>, "Initialize2"},
};
// clang-format on
RegisterHandlers(functions);
state_change_event =
service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent");
}
IUserLocalCommunicationService::~IUserLocalCommunicationService() {
if (is_initialized) {
if (auto room_member = room_network.GetRoomMember().lock()) {
room_member->Unbind(ldn_packet_received);
}
}
service_context.CloseEvent(state_change_event);
}
Result IUserLocalCommunicationService::GetState(Out<State> out_state) {
*out_state = State::Error;
if (is_initialized) {
*out_state = lan_discovery.GetState();
}
LOG_INFO(Service_LDN, "called, state={}", *out_state);
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetNetworkInfo(
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info) {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info));
}
Result IUserLocalCommunicationService::GetIpv4Address(Out<Ipv4Address> out_current_address,
Out<Ipv4Address> out_subnet_mask) {
LOG_INFO(Service_LDN, "called");
const auto network_interface = Network::GetSelectedNetworkInterface();
R_UNLESS(network_interface.has_value(), ResultNoIpAddress);
*out_current_address = {Network::TranslateIPv4(network_interface->ip_address)};
*out_subnet_mask = {Network::TranslateIPv4(network_interface->subnet_mask)};
// When we're connected to a room, spoof the hosts IP address
if (auto room_member = room_network.GetRoomMember().lock()) {
if (room_member->IsConnected()) {
*out_current_address = room_member->GetFakeIpAddress();
}
}
std::reverse(std::begin(*out_current_address), std::end(*out_current_address)); // ntohl
std::reverse(std::begin(*out_subnet_mask), std::end(*out_subnet_mask)); // ntohl
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetDisconnectReason(
Out<DisconnectReason> out_disconnect_reason) {
LOG_INFO(Service_LDN, "called");
*out_disconnect_reason = lan_discovery.GetDisconnectReason();
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetSecurityParameter(
Out<SecurityParameter> out_security_parameter) {
LOG_INFO(Service_LDN, "called");
NetworkInfo info{};
R_TRY(lan_discovery.GetNetworkInfo(info));
out_security_parameter->session_id = info.network_id.session_id;
std::memcpy(out_security_parameter->data.data(), info.ldn.security_parameter.data(),
sizeof(SecurityParameter::data));
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetNetworkConfig(Out<NetworkConfig> out_network_config) {
LOG_INFO(Service_LDN, "called");
NetworkInfo info{};
R_TRY(lan_discovery.GetNetworkInfo(info));
out_network_config->intent_id = info.network_id.intent_id;
out_network_config->channel = info.common.channel;
out_network_config->node_count_max = info.ldn.node_count_max;
out_network_config->local_communication_version = info.ldn.nodes[0].local_communication_version;
R_SUCCEED();
}
Result IUserLocalCommunicationService::AttachStateChangeEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_LDN, "called");
*out_event = &state_change_event->GetReadableEvent();
R_SUCCEED();
}
Result IUserLocalCommunicationService::GetNetworkInfoLatestUpdate(
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update) {
LOG_INFO(Service_LDN, "called");
R_UNLESS(!out_node_latest_update.empty(), ResultBadInput);
R_RETURN(lan_discovery.GetNetworkInfo(*out_network_info, out_node_latest_update));
}
Result IUserLocalCommunicationService::Scan(
Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info) {
LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}",
channel, scan_filter.flag, scan_filter.network_type);
R_UNLESS(!out_network_info.empty(), ResultBadInput);
R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter));
}
Result IUserLocalCommunicationService::ScanPrivate(
Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info) {
LOG_INFO(Service_LDN, "called, channel={}, filter_scan_flag={}, filter_network_type={}",
channel, scan_filter.flag, scan_filter.network_type);
R_UNLESS(out_network_info.empty(), ResultBadInput);
R_RETURN(lan_discovery.Scan(out_network_info, *network_count, scan_filter));
}
Result IUserLocalCommunicationService::SetWirelessControllerRestriction(
WirelessControllerRestriction wireless_restriction) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
R_SUCCEED();
}
Result IUserLocalCommunicationService::OpenAccessPoint() {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.OpenAccessPoint());
}
Result IUserLocalCommunicationService::CloseAccessPoint() {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.CloseAccessPoint());
}
Result IUserLocalCommunicationService::CreateNetwork(const CreateNetworkConfig& create_config) {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config,
create_config.network_config));
}
Result IUserLocalCommunicationService::CreateNetworkPrivate(
const CreateNetworkConfigPrivate& create_config,
InArray<AddressEntry, BufferAttr_HipcPointer> address_list) {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.CreateNetwork(create_config.security_config, create_config.user_config,
create_config.network_config));
}
Result IUserLocalCommunicationService::DestroyNetwork() {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.DestroyNetwork());
}
Result IUserLocalCommunicationService::SetAdvertiseData(
InBuffer<BufferAttr_HipcAutoSelect> buffer_data) {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.SetAdvertiseData(buffer_data));
}
Result IUserLocalCommunicationService::SetStationAcceptPolicy(AcceptPolicy accept_policy) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
R_SUCCEED();
}
Result IUserLocalCommunicationService::AddAcceptFilterEntry(MacAddress mac_address) {
LOG_WARNING(Service_LDN, "(STUBBED) called");
R_SUCCEED();
}
Result IUserLocalCommunicationService::OpenStation() {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.OpenStation());
}
Result IUserLocalCommunicationService::CloseStation() {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.CloseStation());
}
Result IUserLocalCommunicationService::Connect(
const ConnectNetworkData& connect_data,
InLargeData<NetworkInfo, BufferAttr_HipcPointer> network_info) {
LOG_INFO(Service_LDN,
"called, passphrase_size={}, security_mode={}, "
"local_communication_version={}",
connect_data.security_config.passphrase_size,
connect_data.security_config.security_mode, connect_data.local_communication_version);
R_RETURN(lan_discovery.Connect(*network_info, connect_data.user_config,
static_cast<u16>(connect_data.local_communication_version)));
}
Result IUserLocalCommunicationService::Disconnect() {
LOG_INFO(Service_LDN, "called");
R_RETURN(lan_discovery.Disconnect());
}
Result IUserLocalCommunicationService::Initialize(ClientProcessId aruid) {
LOG_INFO(Service_LDN, "called, process_id={}", aruid.pid);
const auto network_interface = Network::GetSelectedNetworkInterface();
R_UNLESS(network_interface, ResultAirplaneModeEnabled);
if (auto room_member = room_network.GetRoomMember().lock()) {
ldn_packet_received = room_member->BindOnLdnPacketReceived(
[this](const Network::LDNPacket& packet) { OnLDNPacketReceived(packet); });
} else {
LOG_ERROR(Service_LDN, "Couldn't bind callback!");
R_RETURN(ResultAirplaneModeEnabled);
}
lan_discovery.Initialize([&]() { OnEventFired(); });
is_initialized = true;
R_SUCCEED();
}
Result IUserLocalCommunicationService::Finalize() {
LOG_INFO(Service_LDN, "called");
if (auto room_member = room_network.GetRoomMember().lock()) {
room_member->Unbind(ldn_packet_received);
}
is_initialized = false;
R_RETURN(lan_discovery.Finalize());
}
Result IUserLocalCommunicationService::Initialize2(u32 version, ClientProcessId process_id) {
LOG_INFO(Service_LDN, "called, version={}, process_id={}", version, process_id.pid);
R_RETURN(Initialize(process_id));
}
void IUserLocalCommunicationService::OnLDNPacketReceived(const Network::LDNPacket& packet) {
lan_discovery.ReceivePacket(packet);
}
void IUserLocalCommunicationService::OnEventFired() {
state_change_event->Signal();
}
} // namespace Service::LDN

View File

@ -0,0 +1,103 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/ldn/lan_discovery.h"
#include "core/hle/service/ldn/ldn_types.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Network {
class RoomNetwork;
}
namespace Service::LDN {
class IUserLocalCommunicationService final
: public ServiceFramework<IUserLocalCommunicationService> {
public:
explicit IUserLocalCommunicationService(Core::System& system_);
~IUserLocalCommunicationService() override;
private:
Result GetState(Out<State> out_state);
Result GetNetworkInfo(OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info);
Result GetIpv4Address(Out<Ipv4Address> out_current_address, Out<Ipv4Address> out_subnet_mask);
Result GetDisconnectReason(Out<DisconnectReason> out_disconnect_reason);
Result GetSecurityParameter(Out<SecurityParameter> out_security_parameter);
Result GetNetworkConfig(Out<NetworkConfig> out_network_config);
Result AttachStateChangeEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result GetNetworkInfoLatestUpdate(
OutLargeData<NetworkInfo, BufferAttr_HipcPointer> out_network_info,
OutArray<NodeLatestUpdate, BufferAttr_HipcPointer> out_node_latest_update);
Result Scan(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
Result ScanPrivate(Out<s16> network_count, WifiChannel channel, const ScanFilter& scan_filter,
OutArray<NetworkInfo, BufferAttr_HipcAutoSelect> out_network_info);
Result SetWirelessControllerRestriction(WirelessControllerRestriction wireless_restriction);
Result OpenAccessPoint();
Result CloseAccessPoint();
Result CreateNetwork(const CreateNetworkConfig& create_network_Config);
Result CreateNetworkPrivate(const CreateNetworkConfigPrivate& create_network_Config,
InArray<AddressEntry, BufferAttr_HipcPointer> address_list);
Result DestroyNetwork();
Result SetAdvertiseData(InBuffer<BufferAttr_HipcAutoSelect> buffer_data);
Result SetStationAcceptPolicy(AcceptPolicy accept_policy);
Result AddAcceptFilterEntry(MacAddress mac_address);
Result OpenStation();
Result CloseStation();
Result Connect(const ConnectNetworkData& connect_data,
InLargeData<NetworkInfo, BufferAttr_HipcPointer> network_info);
Result Disconnect();
Result Initialize(ClientProcessId aruid);
Result Finalize();
Result Initialize2(u32 version, ClientProcessId aruid);
private:
/// Callback to parse and handle a received LDN packet.
void OnLDNPacketReceived(const Network::LDNPacket& packet);
void OnEventFired();
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* state_change_event;
Network::RoomNetwork& room_network;
LANDiscovery lan_discovery;
// Callback identifier for the OnLDNPacketReceived event.
Network::RoomMember::CallbackHandle<Network::LDNPacket> ldn_packet_received;
bool is_initialized{};
};
} // namespace Service::LDN

View File

@ -0,0 +1,22 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/omm/omm.h"
#include "core/hle/service/omm/operation_mode_manager.h"
#include "core/hle/service/omm/policy_manager_system.h"
#include "core/hle/service/omm/power_state_interface.h"
#include "core/hle/service/server_manager.h"
namespace Service::OMM {
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("idle:sys",
std::make_shared<IPolicyManagerSystem>(system));
server_manager->RegisterNamedService("omm", std::make_shared<IOperationModeManager>(system));
server_manager->RegisterNamedService("spsm", std::make_shared<IPowerStateInterface>(system));
ServerManager::RunServer(std::move(server_manager));
}
} // namespace Service::OMM

14
src/core/hle/service/omm/omm.h Executable file
View File

@ -0,0 +1,14 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
namespace Core {
class System;
}
namespace Service::OMM {
void LoopProcess(Core::System& system);
} // namespace Service::OMM

View File

@ -0,0 +1,49 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/omm/operation_mode_manager.h"
namespace Service::OMM {
IOperationModeManager::IOperationModeManager(Core::System& system_)
: ServiceFramework{system_, "omm"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetOperationMode"},
{1, nullptr, "GetOperationModeChangeEvent"},
{2, nullptr, "EnableAudioVisual"},
{3, nullptr, "DisableAudioVisual"},
{4, nullptr, "EnterSleepAndWait"},
{5, nullptr, "GetCradleStatus"},
{6, nullptr, "FadeInDisplay"},
{7, nullptr, "FadeOutDisplay"},
{8, nullptr, "GetCradleFwVersion"},
{9, nullptr, "NotifyCecSettingsChanged"},
{10, nullptr, "SetOperationModePolicy"},
{11, nullptr, "GetDefaultDisplayResolution"},
{12, nullptr, "GetDefaultDisplayResolutionChangeEvent"},
{13, nullptr, "UpdateDefaultDisplayResolution"},
{14, nullptr, "ShouldSleepOnBoot"},
{15, nullptr, "NotifyHdcpApplicationExecutionStarted"},
{16, nullptr, "NotifyHdcpApplicationExecutionFinished"},
{17, nullptr, "NotifyHdcpApplicationDrawingStarted"},
{18, nullptr, "NotifyHdcpApplicationDrawingFinished"},
{19, nullptr, "GetHdcpAuthenticationFailedEvent"},
{20, nullptr, "GetHdcpAuthenticationFailedEmulationEnabled"},
{21, nullptr, "SetHdcpAuthenticationFailedEmulation"},
{22, nullptr, "GetHdcpStateChangeEvent"},
{23, nullptr, "GetHdcpState"},
{24, nullptr, "ShowCardUpdateProcessing"},
{25, nullptr, "SetApplicationCecSettingsAndNotifyChanged"},
{26, nullptr, "GetOperationModeSystemInfo"},
{27, nullptr, "GetAppletFullAwakingSystemEvent"},
{28, nullptr, "CreateCradleFirmwareUpdater"},
};
// clang-format on
RegisterHandlers(functions);
}
IOperationModeManager::~IOperationModeManager() = default;
} // namespace Service::OMM

View File

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::OMM {
class IOperationModeManager final : public ServiceFramework<IOperationModeManager> {
public:
explicit IOperationModeManager(Core::System& system_);
~IOperationModeManager() override;
};
} // namespace Service::OMM

View File

@ -0,0 +1,26 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/omm/policy_manager_system.h"
namespace Service::OMM {
IPolicyManagerSystem::IPolicyManagerSystem(Core::System& system_)
: ServiceFramework{system_, "idle:sys"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetAutoPowerDownEvent"},
{1, nullptr, "IsAutoPowerDownRequested"},
{2, nullptr, "Unknown2"},
{3, nullptr, "SetHandlingContext"},
{4, nullptr, "LoadAndApplySettings"},
{5, nullptr, "ReportUserIsActive"},
};
// clang-format on
RegisterHandlers(functions);
}
IPolicyManagerSystem::~IPolicyManagerSystem() = default;
} // namespace Service::OMM

View File

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::OMM {
class IPolicyManagerSystem final : public ServiceFramework<IPolicyManagerSystem> {
public:
explicit IPolicyManagerSystem(Core::System& system_);
~IPolicyManagerSystem() override;
};
} // namespace Service::OMM

View File

@ -0,0 +1,32 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/omm/power_state_interface.h"
namespace Service::OMM {
IPowerStateInterface::IPowerStateInterface(Core::System& system_)
: ServiceFramework{system_, "spsm"} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "GetState"},
{1, nullptr, "EnterSleep"},
{2, nullptr, "GetLastWakeReason"},
{3, nullptr, "Shutdown"},
{4, nullptr, "GetNotificationMessageEventHandle"},
{5, nullptr, "ReceiveNotificationMessage"},
{6, nullptr, "AnalyzeLogForLastSleepWakeSequence"},
{7, nullptr, "ResetEventLog"},
{8, nullptr, "AnalyzePerformanceLogForLastSleepWakeSequence"},
{9, nullptr, "ChangeHomeButtonLongPressingTime"},
{10, nullptr, "PutErrorState"},
{11, nullptr, "InvalidateCurrentHomeButtonPressing"},
};
// clang-format on
RegisterHandlers(functions);
}
IPowerStateInterface::~IPowerStateInterface() = default;
} // namespace Service::OMM

View File

@ -0,0 +1,20 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Service::OMM {
class IPowerStateInterface final : public ServiceFramework<IPowerStateInterface> {
public:
explicit IPowerStateInterface(Core::System& system_);
~IPowerStateInterface() override;
};
} // namespace Service::OMM

View File

@ -52,6 +52,7 @@
#include "core/hle/service/nvnflinger/hos_binder_driver_server.h"
#include "core/hle/service/nvnflinger/nvnflinger.h"
#include "core/hle/service/olsc/olsc.h"
#include "core/hle/service/omm/omm.h"
#include "core/hle/service/pcie/pcie.h"
#include "core/hle/service/pctl/pctl_module.h"
#include "core/hle/service/pcv/pcv.h"
@ -266,6 +267,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
kernel.RunOnGuestCoreProcess("npns", [&] { NPNS::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("ns", [&] { NS::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("olsc", [&] { OLSC::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("omm", [&] { OMM::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("pcie", [&] { PCIe::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("pctl", [&] { PCTL::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("pcv", [&] { PCV::LoopProcess(system); });

View File

@ -35,7 +35,7 @@ BufferCache<P>::BufferCache(Tegra::MaxwellDeviceMemoryManager& device_memory_, R
const s64 min_spacing_critical = device_local_memory - 512_MiB;
const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
minimum_memory = static_cast<u64>(
std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
DEFAULT_EXPECTED_MEMORY));

View File

@ -3,6 +3,7 @@
#include "common/common_types.h"
#include "common/math_util.h"
#include "common/settings.h"
#include "video_core/surface.h"
namespace VideoCore::Surface {
@ -400,11 +401,20 @@ std::pair<u32, u32> GetASTCBlockSize(PixelFormat format) {
return {DefaultBlockWidth(format), DefaultBlockHeight(format)};
}
u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format) {
u64 TranscodedAstcSize(u64 base_size, PixelFormat format) {
constexpr u64 RGBA8_PIXEL_SIZE = 4;
const u64 base_block_size = static_cast<u64>(DefaultBlockWidth(format)) *
static_cast<u64>(DefaultBlockHeight(format)) * RGBA8_PIXEL_SIZE;
return (base_size * base_block_size) / BytesPerBlock(format);
const u64 uncompressed_size = (base_size * base_block_size) / BytesPerBlock(format);
switch (Settings::values.astc_recompression.GetValue()) {
case Settings::AstcRecompression::Bc1:
return uncompressed_size / 8;
case Settings::AstcRecompression::Bc3:
return uncompressed_size / 4;
default:
return uncompressed_size;
}
}
} // namespace VideoCore::Surface

View File

@ -517,6 +517,6 @@ size_t PixelComponentSizeBitsInteger(PixelFormat format);
std::pair<u32, u32> GetASTCBlockSize(PixelFormat format);
u64 EstimatedDecompressedSize(u64 base_size, PixelFormat format);
u64 TranscodedAstcSize(u64 base_size, PixelFormat format);
} // namespace VideoCore::Surface

View File

@ -55,7 +55,7 @@ TextureCache<P>::TextureCache(Runtime& runtime_, Tegra::MaxwellDeviceMemoryManag
const s64 min_spacing_critical = device_local_memory - 512_MiB;
const s64 mem_threshold = std::min(device_local_memory, TARGET_THRESHOLD);
const s64 min_vacancy_expected = (6 * mem_threshold) / 10;
const s64 min_vacancy_critical = (3 * mem_threshold) / 10;
const s64 min_vacancy_critical = (2 * mem_threshold) / 10;
expected_memory = static_cast<u64>(
std::max(std::min(device_local_memory - min_vacancy_expected, min_spacing_expected),
DEFAULT_EXPECTED_MEMORY));
@ -1979,7 +1979,7 @@ void TextureCache<P>::RegisterImage(ImageId image_id) {
if ((IsPixelFormatASTC(image.info.format) &&
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
True(image.flags & ImageFlagBits::Converted)) {
tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory += Common::AlignUp(tentative_size, 1024);
image.lru_index = lru_cache.Insert(image_id, frame_tick);
@ -2149,7 +2149,7 @@ void TextureCache<P>::DeleteImage(ImageId image_id, bool immediate_delete) {
if ((IsPixelFormatASTC(image.info.format) &&
True(image.flags & ImageFlagBits::AcceleratedUpload)) ||
True(image.flags & ImageFlagBits::Converted)) {
tentative_size = EstimatedDecompressedSize(tentative_size, image.info.format);
tentative_size = TranscodedAstcSize(tentative_size, image.info.format);
}
total_used_memory -= Common::AlignUp(tentative_size, 1024);
const GPUVAddr gpu_addr = image.gpu_addr;

View File

@ -1290,10 +1290,6 @@ u64 Device::GetDeviceMemoryUsage() const {
}
void Device::CollectPhysicalMemoryInfo() {
// Account for resolution scaling in memory limits
const size_t normal_memory = 6_GiB;
const size_t scaler_memory = 1_GiB * Settings::values.resolution_info.ScaleUp(1);
// Calculate limits using memory budget
VkPhysicalDeviceMemoryBudgetPropertiesEXT budget{};
budget.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_MEMORY_BUDGET_PROPERTIES_EXT;
@ -1324,7 +1320,6 @@ void Device::CollectPhysicalMemoryInfo() {
if (!is_integrated) {
const u64 reserve_memory = std::min<u64>(device_access_memory / 8, 1_GiB);
device_access_memory -= reserve_memory;
device_access_memory = std::min<u64>(device_access_memory, normal_memory + scaler_memory);
return;
}
const s64 available_memory = static_cast<s64>(device_access_memory - device_initial_usage);

Some files were not shown because too many files have changed in this diff Show More