19 changed files with 1496 additions and 1 deletions
-
17src/core/CMakeLists.txt
-
171src/core/hle/service/am/am_types.h
-
63src/core/hle/service/am/applet.cpp
-
164src/core/hle/service/am/applet.h
-
352src/core/hle/service/am/applet_manager.cpp
-
59src/core/hle/service/am/applet_manager.h
-
29src/core/hle/service/am/hid_registration.cpp
-
30src/core/hle/service/am/hid_registration.h
-
140src/core/hle/service/am/library_applet_storage.cpp
-
36src/core/hle/service/am/library_applet_storage.h
-
59src/core/hle/service/am/managed_layer_holder.cpp
-
32src/core/hle/service/am/managed_layer_holder.h
-
138src/core/hle/service/am/process.cpp
-
50src/core/hle/service/am/process.h
-
49src/core/hle/service/am/system_buffer_manager.cpp
-
44src/core/hle/service/am/system_buffer_manager.h
-
31src/core/hle/service/event.cpp
-
31src/core/hle/service/event.h
-
2src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@ -0,0 +1,171 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace Service::AM { |
|||
|
|||
namespace Frontend { |
|||
class FrontendApplet; |
|||
} |
|||
|
|||
enum class AppletType { |
|||
Application, |
|||
LibraryApplet, |
|||
SystemApplet, |
|||
}; |
|||
|
|||
enum class GameplayRecordingState : u32 { |
|||
Disabled, |
|||
Enabled, |
|||
}; |
|||
|
|||
// This is nn::oe::FocusState |
|||
enum class FocusState : u8 { |
|||
InFocus = 1, |
|||
NotInFocus = 2, |
|||
Background = 3, |
|||
}; |
|||
|
|||
// This is nn::oe::OperationMode |
|||
enum class OperationMode : u8 { |
|||
Handheld = 0, |
|||
Docked = 1, |
|||
}; |
|||
|
|||
// This is nn::am::service::SystemButtonType |
|||
enum class SystemButtonType { |
|||
None, |
|||
HomeButtonShortPressing, |
|||
HomeButtonLongPressing, |
|||
PowerButtonShortPressing, |
|||
PowerButtonLongPressing, |
|||
ShutdownSystem, |
|||
CaptureButtonShortPressing, |
|||
CaptureButtonLongPressing, |
|||
}; |
|||
|
|||
enum class SysPlatformRegion : s32 { |
|||
Global = 1, |
|||
Terra = 2, |
|||
}; |
|||
|
|||
struct AppletProcessLaunchReason { |
|||
u8 flag; |
|||
INSERT_PADDING_BYTES(3); |
|||
}; |
|||
static_assert(sizeof(AppletProcessLaunchReason) == 0x4, |
|||
"AppletProcessLaunchReason is an invalid size"); |
|||
|
|||
enum class ScreenshotPermission : u32 { |
|||
Inherit = 0, |
|||
Enable = 1, |
|||
Disable = 2, |
|||
}; |
|||
|
|||
struct FocusHandlingMode { |
|||
bool unknown0; |
|||
bool unknown1; |
|||
bool unknown2; |
|||
bool unknown3; |
|||
}; |
|||
|
|||
enum class IdleTimeDetectionExtension : u32 { |
|||
Disabled = 0, |
|||
Extended = 1, |
|||
ExtendedUnsafe = 2, |
|||
}; |
|||
|
|||
enum class AppletId : u32 { |
|||
None = 0x00, |
|||
Application = 0x01, |
|||
OverlayDisplay = 0x02, |
|||
QLaunch = 0x03, |
|||
Starter = 0x04, |
|||
Auth = 0x0A, |
|||
Cabinet = 0x0B, |
|||
Controller = 0x0C, |
|||
DataErase = 0x0D, |
|||
Error = 0x0E, |
|||
NetConnect = 0x0F, |
|||
ProfileSelect = 0x10, |
|||
SoftwareKeyboard = 0x11, |
|||
MiiEdit = 0x12, |
|||
Web = 0x13, |
|||
Shop = 0x14, |
|||
PhotoViewer = 0x15, |
|||
Settings = 0x16, |
|||
OfflineWeb = 0x17, |
|||
LoginShare = 0x18, |
|||
WebAuth = 0x19, |
|||
MyPage = 0x1A, |
|||
}; |
|||
|
|||
enum class AppletProgramId : u64 { |
|||
QLaunch = 0x0100000000001000ull, |
|||
Auth = 0x0100000000001001ull, |
|||
Cabinet = 0x0100000000001002ull, |
|||
Controller = 0x0100000000001003ull, |
|||
DataErase = 0x0100000000001004ull, |
|||
Error = 0x0100000000001005ull, |
|||
NetConnect = 0x0100000000001006ull, |
|||
ProfileSelect = 0x0100000000001007ull, |
|||
SoftwareKeyboard = 0x0100000000001008ull, |
|||
MiiEdit = 0x0100000000001009ull, |
|||
Web = 0x010000000000100Aull, |
|||
Shop = 0x010000000000100Bull, |
|||
OverlayDisplay = 0x010000000000100Cull, |
|||
PhotoViewer = 0x010000000000100Dull, |
|||
Settings = 0x010000000000100Eull, |
|||
OfflineWeb = 0x010000000000100Full, |
|||
LoginShare = 0x0100000000001010ull, |
|||
WebAuth = 0x0100000000001011ull, |
|||
Starter = 0x0100000000001012ull, |
|||
MyPage = 0x0100000000001013ull, |
|||
MaxProgramId = 0x0100000000001FFFull, |
|||
}; |
|||
|
|||
enum class LibraryAppletMode : u32 { |
|||
AllForeground = 0, |
|||
Background = 1, |
|||
NoUI = 2, |
|||
BackgroundIndirectDisplay = 3, |
|||
AllForegroundInitiallyHidden = 4, |
|||
}; |
|||
|
|||
enum class CommonArgumentVersion : u32 { |
|||
Version0, |
|||
Version1, |
|||
Version2, |
|||
Version3, |
|||
}; |
|||
|
|||
enum class CommonArgumentSize : u32 { |
|||
Version3 = 0x20, |
|||
}; |
|||
|
|||
enum class ThemeColor : u32 { |
|||
BasicWhite = 0, |
|||
BasicBlack = 3, |
|||
}; |
|||
|
|||
struct CommonArguments { |
|||
CommonArgumentVersion arguments_version; |
|||
CommonArgumentSize size; |
|||
u32 library_version; |
|||
ThemeColor theme_color; |
|||
bool play_startup_sound; |
|||
u64 system_tick; |
|||
}; |
|||
static_assert(sizeof(CommonArguments) == 0x20, "CommonArguments has incorrect size."); |
|||
|
|||
using AppletResourceUserId = u64; |
|||
using ProgramId = u64; |
|||
|
|||
struct Applet; |
|||
struct AppletStorageHolder; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,63 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/scope_exit.h"
|
|||
|
|||
#include "core/hle/service/am/am_results.h"
|
|||
#include "core/hle/service/am/applet.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
AppletStorageChannel::AppletStorageChannel(KernelHelpers::ServiceContext& context) |
|||
: m_event(context) {} |
|||
AppletStorageChannel::~AppletStorageChannel() = default; |
|||
|
|||
void AppletStorageChannel::PushData(std::shared_ptr<IStorage> storage) { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
m_data.emplace_back(std::move(storage)); |
|||
m_event.Signal(); |
|||
} |
|||
|
|||
Result AppletStorageChannel::PopData(std::shared_ptr<IStorage>* out_storage) { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
SCOPE_EXIT({ |
|||
if (m_data.empty()) { |
|||
m_event.Clear(); |
|||
} |
|||
}); |
|||
|
|||
R_UNLESS(!m_data.empty(), AM::ResultNoDataInChannel); |
|||
|
|||
*out_storage = std::move(m_data.front()); |
|||
m_data.pop_front(); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Kernel::KReadableEvent* AppletStorageChannel::GetEvent() { |
|||
return m_event.GetHandle(); |
|||
} |
|||
|
|||
AppletStorageHolder::AppletStorageHolder(Core::System& system) |
|||
: context(system, "AppletStorageHolder"), in_data(context), interactive_in_data(context), |
|||
out_data(context), interactive_out_data(context), state_changed_event(context) {} |
|||
|
|||
AppletStorageHolder::~AppletStorageHolder() = default; |
|||
|
|||
Applet::Applet(Core::System& system, std::unique_ptr<Process> process_) |
|||
: context(system, "Applet"), message_queue(system), process(std::move(process_)), |
|||
hid_registration(system, *process), gpu_error_detected_event(context), |
|||
friend_invitation_storage_channel_event(context), notification_storage_channel_event(context), |
|||
health_warning_disappeared_system_event(context), acquired_sleep_lock_event(context), |
|||
pop_from_general_channel_event(context), library_applet_launchable_event(context), |
|||
accumulated_suspended_tick_changed_event(context), sleep_lock_event(context) { |
|||
|
|||
aruid = process->GetProcessId(); |
|||
program_id = process->GetProgramId(); |
|||
} |
|||
|
|||
Applet::~Applet() = default; |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,164 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <list> |
|||
#include <mutex> |
|||
|
|||
#include "common/math_util.h" |
|||
#include "core/hle/service/apm/apm_controller.h" |
|||
#include "core/hle/service/caps/caps_types.h" |
|||
#include "core/hle/service/event.h" |
|||
#include "core/hle/service/kernel_helpers.h" |
|||
#include "core/hle/service/service.h" |
|||
|
|||
#include "core/hle/service/am/am_types.h" |
|||
#include "core/hle/service/am/applet_message_queue.h" |
|||
#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::Nvnflinger { |
|||
class FbShareBufferManager; |
|||
class Nvnflinger; |
|||
} // namespace Service::Nvnflinger |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class AppletStorageChannel { |
|||
public: |
|||
explicit AppletStorageChannel(KernelHelpers::ServiceContext& ctx); |
|||
~AppletStorageChannel(); |
|||
|
|||
void PushData(std::shared_ptr<IStorage> storage); |
|||
Result PopData(std::shared_ptr<IStorage>* out_storage); |
|||
Kernel::KReadableEvent* GetEvent(); |
|||
|
|||
private: |
|||
std::mutex m_lock{}; |
|||
std::deque<std::shared_ptr<IStorage>> m_data{}; |
|||
Event m_event; |
|||
}; |
|||
|
|||
struct AppletStorageHolder { |
|||
explicit AppletStorageHolder(Core::System& system); |
|||
~AppletStorageHolder(); |
|||
|
|||
KernelHelpers::ServiceContext context; |
|||
|
|||
AppletStorageChannel in_data; |
|||
AppletStorageChannel interactive_in_data; |
|||
AppletStorageChannel out_data; |
|||
AppletStorageChannel interactive_out_data; |
|||
Event state_changed_event; |
|||
}; |
|||
|
|||
struct Applet { |
|||
explicit Applet(Core::System& system, std::unique_ptr<Process> process_); |
|||
~Applet(); |
|||
|
|||
// Lock |
|||
std::mutex lock{}; |
|||
|
|||
// Event creation helper |
|||
KernelHelpers::ServiceContext context; |
|||
|
|||
// Applet message queue |
|||
AppletMessageQueue message_queue; |
|||
|
|||
// Process |
|||
std::unique_ptr<Process> process; |
|||
|
|||
// Creation state |
|||
AppletId applet_id{}; |
|||
AppletResourceUserId aruid{}; |
|||
AppletProcessLaunchReason launch_reason{}; |
|||
AppletType type{}; |
|||
ProgramId program_id{}; |
|||
LibraryAppletMode library_applet_mode{}; |
|||
s32 previous_program_index{-1}; |
|||
ScreenshotPermission previous_screenshot_permission{ScreenshotPermission::Enable}; |
|||
|
|||
// hid state |
|||
HidRegistration hid_registration; |
|||
|
|||
// vi state |
|||
SystemBufferManager system_buffer_manager{}; |
|||
ManagedLayerHolder managed_layer_holder{}; |
|||
|
|||
// Applet common functions |
|||
Result terminate_result{}; |
|||
s32 display_logical_width{}; |
|||
s32 display_logical_height{}; |
|||
Common::Rectangle<f32> display_magnification{0, 0, 1, 1}; |
|||
bool home_button_double_click_enabled{}; |
|||
bool home_button_short_pressed_blocked{}; |
|||
bool home_button_long_pressed_blocked{}; |
|||
bool vr_mode_curtain_required{}; |
|||
bool sleep_required_by_high_temperature{}; |
|||
bool sleep_required_by_low_battery{}; |
|||
s32 cpu_boost_request_priority{-1}; |
|||
bool handling_capture_button_short_pressed_message_enabled_for_applet{}; |
|||
bool handling_capture_button_long_pressed_message_enabled_for_applet{}; |
|||
u32 application_core_usage_mode{}; |
|||
|
|||
// Application functions |
|||
bool gameplay_recording_supported{}; |
|||
GameplayRecordingState gameplay_recording_state{GameplayRecordingState::Disabled}; |
|||
bool jit_service_launched{}; |
|||
bool is_running{}; |
|||
bool application_crash_report_enabled{}; |
|||
|
|||
// Common state |
|||
FocusState focus_state{}; |
|||
bool sleep_lock_enabled{}; |
|||
bool vr_mode_enabled{}; |
|||
bool lcd_backlight_off_enabled{}; |
|||
APM::CpuBoostMode boost_mode{}; |
|||
bool request_exit_to_library_applet_at_execute_next_program_enabled{}; |
|||
|
|||
// Channels |
|||
std::deque<std::vector<u8>> user_channel_launch_parameter{}; |
|||
std::deque<std::vector<u8>> preselected_user_launch_parameter{}; |
|||
|
|||
// Caller applet |
|||
std::weak_ptr<Applet> caller_applet{}; |
|||
std::shared_ptr<AppletStorageHolder> caller_applet_storage{}; |
|||
bool is_completed{}; |
|||
|
|||
// Self state |
|||
bool exit_locked{}; |
|||
s32 fatal_section_count{}; |
|||
bool operation_mode_changed_notification_enabled{true}; |
|||
bool performance_mode_changed_notification_enabled{true}; |
|||
FocusHandlingMode focus_handling_mode{}; |
|||
bool restart_message_enabled{}; |
|||
bool out_of_focus_suspension_enabled{true}; |
|||
Capture::AlbumImageOrientation album_image_orientation{}; |
|||
bool handles_request_to_display{}; |
|||
ScreenshotPermission screenshot_permission{}; |
|||
IdleTimeDetectionExtension idle_time_detection_extension{}; |
|||
bool auto_sleep_disabled{}; |
|||
u64 suspended_ticks{}; |
|||
bool album_image_taken_notification_enabled{}; |
|||
bool record_volume_muted{}; |
|||
|
|||
// Events |
|||
Event gpu_error_detected_event; |
|||
Event friend_invitation_storage_channel_event; |
|||
Event notification_storage_channel_event; |
|||
Event health_warning_disappeared_system_event; |
|||
Event acquired_sleep_lock_event; |
|||
Event pop_from_general_channel_event; |
|||
Event library_applet_launchable_event; |
|||
Event accumulated_suspended_tick_changed_event; |
|||
Event sleep_lock_event; |
|||
|
|||
// Frontend state |
|||
std::shared_ptr<Frontend::FrontendApplet> frontend{}; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,352 @@ |
|||
// 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/core.h"
|
|||
#include "core/core_timing.h"
|
|||
#include "core/hle/service/acc/profile_manager.h"
|
|||
#include "core/hle/service/am/applet_manager.h"
|
|||
#include "core/hle/service/am/applets/applet_cabinet.h"
|
|||
#include "core/hle/service/am/applets/applet_controller.h"
|
|||
#include "core/hle/service/am/applets/applet_mii_edit_types.h"
|
|||
#include "core/hle/service/am/applets/applet_software_keyboard_types.h"
|
|||
#include "hid_core/hid_types.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
namespace { |
|||
|
|||
constexpr u32 LaunchParameterAccountPreselectedUserMagic = 0xC79497CA; |
|||
|
|||
struct LaunchParameterAccountPreselectedUser { |
|||
u32 magic; |
|||
u32 is_account_selected; |
|||
Common::UUID current_user; |
|||
INSERT_PADDING_BYTES(0x70); |
|||
}; |
|||
static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); |
|||
|
|||
AppletStorageChannel& InitializeFakeCallerApplet(Core::System& system, |
|||
std::shared_ptr<Applet>& applet) { |
|||
applet->caller_applet_storage = std::make_shared<AppletStorageHolder>(system); |
|||
return applet->caller_applet_storage->in_data; |
|||
} |
|||
|
|||
void PushInShowAlbum(Core::System& system, AppletStorageChannel& channel) { |
|||
const CommonArguments arguments{ |
|||
.arguments_version = CommonArgumentVersion::Version3, |
|||
.size = CommonArgumentSize::Version3, |
|||
.library_version = 1, |
|||
.theme_color = ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(arguments)); |
|||
std::vector<u8> settings_data{2}; |
|||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(settings_data))); |
|||
} |
|||
|
|||
void PushInShowController(Core::System& system, AppletStorageChannel& channel) { |
|||
const CommonArguments common_args = { |
|||
.arguments_version = CommonArgumentVersion::Version3, |
|||
.size = CommonArgumentSize::Version3, |
|||
.library_version = static_cast<u32>(Applets::ControllerAppletVersion::Version8), |
|||
.theme_color = ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
Applets::ControllerSupportArgNew user_args = { |
|||
.header = {.player_count_min = 1, |
|||
.player_count_max = 4, |
|||
.enable_take_over_connection = true, |
|||
.enable_left_justify = false, |
|||
.enable_permit_joy_dual = true, |
|||
.enable_single_mode = false, |
|||
.enable_identification_color = false}, |
|||
.identification_colors = {}, |
|||
.enable_explain_text = false, |
|||
.explain_text = {}, |
|||
}; |
|||
|
|||
Applets::ControllerSupportArgPrivate private_args = { |
|||
.arg_private_size = sizeof(Applets::ControllerSupportArgPrivate), |
|||
.arg_size = sizeof(Applets::ControllerSupportArgNew), |
|||
.is_home_menu = true, |
|||
.flag_1 = true, |
|||
.mode = Applets::ControllerSupportMode::ShowControllerSupport, |
|||
.caller = Applets::ControllerSupportCaller:: |
|||
Application, // switchbrew: Always zero except with
|
|||
// ShowControllerFirmwareUpdateForSystem/ShowControllerKeyRemappingForSystem,
|
|||
// which sets this to the input param
|
|||
.style_set = Core::HID::NpadStyleSet::None, |
|||
.joy_hold_type = 0, |
|||
}; |
|||
std::vector<u8> common_args_data(sizeof(common_args)); |
|||
std::vector<u8> private_args_data(sizeof(private_args)); |
|||
std::vector<u8> user_args_data(sizeof(user_args)); |
|||
|
|||
std::memcpy(common_args_data.data(), &common_args, sizeof(common_args)); |
|||
std::memcpy(private_args_data.data(), &private_args, sizeof(private_args)); |
|||
std::memcpy(user_args_data.data(), &user_args, sizeof(user_args)); |
|||
|
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(common_args_data))); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(private_args_data))); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(user_args_data))); |
|||
} |
|||
|
|||
void PushInShowCabinetData(Core::System& system, AppletStorageChannel& channel) { |
|||
const CommonArguments arguments{ |
|||
.arguments_version = CommonArgumentVersion::Version3, |
|||
.size = CommonArgumentSize::Version3, |
|||
.library_version = static_cast<u32>(Applets::CabinetAppletVersion::Version1), |
|||
.theme_color = ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
const Applets::StartParamForAmiiboSettings amiibo_settings{ |
|||
.param_1 = 0, |
|||
.applet_mode = system.GetAppletManager().GetCabinetMode(), |
|||
.flags = Applets::CabinetFlags::None, |
|||
.amiibo_settings_1 = 0, |
|||
.device_handle = 0, |
|||
.tag_info{}, |
|||
.register_info{}, |
|||
.amiibo_settings_3{}, |
|||
}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(arguments)); |
|||
std::vector<u8> settings_data(sizeof(amiibo_settings)); |
|||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); |
|||
std::memcpy(settings_data.data(), &amiibo_settings, sizeof(amiibo_settings)); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(settings_data))); |
|||
} |
|||
|
|||
void PushInShowMiiEditData(Core::System& system, AppletStorageChannel& channel) { |
|||
struct MiiEditV3 { |
|||
Applets::MiiEditAppletInputCommon common; |
|||
Applets::MiiEditAppletInputV3 input; |
|||
}; |
|||
static_assert(sizeof(MiiEditV3) == 0x100, "MiiEditV3 has incorrect size."); |
|||
|
|||
MiiEditV3 mii_arguments{ |
|||
.common = |
|||
{ |
|||
.version = Applets::MiiEditAppletVersion::Version3, |
|||
.applet_mode = Applets::MiiEditAppletMode::ShowMiiEdit, |
|||
}, |
|||
.input{}, |
|||
}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(mii_arguments)); |
|||
std::memcpy(argument_data.data(), &mii_arguments, sizeof(mii_arguments)); |
|||
|
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); |
|||
} |
|||
|
|||
void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& channel) { |
|||
const CommonArguments arguments{ |
|||
.arguments_version = CommonArgumentVersion::Version3, |
|||
.size = CommonArgumentSize::Version3, |
|||
.library_version = static_cast<u32>(Applets::SwkbdAppletVersion::Version524301), |
|||
.theme_color = ThemeColor::BasicBlack, |
|||
.play_startup_sound = true, |
|||
.system_tick = system.CoreTiming().GetClockTicks(), |
|||
}; |
|||
|
|||
std::vector<char16_t> initial_string(0); |
|||
|
|||
const Applets::SwkbdConfigCommon swkbd_config{ |
|||
.type = Applets::SwkbdType::Qwerty, |
|||
.ok_text{}, |
|||
.left_optional_symbol_key{}, |
|||
.right_optional_symbol_key{}, |
|||
.use_prediction = false, |
|||
.key_disable_flags{}, |
|||
.initial_cursor_position = Applets::SwkbdInitialCursorPosition::Start, |
|||
.header_text{}, |
|||
.sub_text{}, |
|||
.guide_text{}, |
|||
.max_text_length = 500, |
|||
.min_text_length = 0, |
|||
.password_mode = Applets::SwkbdPasswordMode::Disabled, |
|||
.text_draw_type = Applets::SwkbdTextDrawType::Box, |
|||
.enable_return_button = true, |
|||
.use_utf8 = false, |
|||
.use_blur_background = true, |
|||
.initial_string_offset{}, |
|||
.initial_string_length = static_cast<u32>(initial_string.size()), |
|||
.user_dictionary_offset{}, |
|||
.user_dictionary_entries{}, |
|||
.use_text_check = false, |
|||
}; |
|||
|
|||
Applets::SwkbdConfigNew swkbd_config_new{}; |
|||
|
|||
std::vector<u8> argument_data(sizeof(arguments)); |
|||
std::vector<u8> swkbd_data(sizeof(swkbd_config) + sizeof(swkbd_config_new)); |
|||
std::vector<u8> work_buffer(swkbd_config.initial_string_length * sizeof(char16_t)); |
|||
|
|||
std::memcpy(argument_data.data(), &arguments, sizeof(arguments)); |
|||
std::memcpy(swkbd_data.data(), &swkbd_config, sizeof(swkbd_config)); |
|||
std::memcpy(swkbd_data.data() + sizeof(swkbd_config), &swkbd_config_new, |
|||
sizeof(Applets::SwkbdConfigNew)); |
|||
std::memcpy(work_buffer.data(), initial_string.data(), |
|||
swkbd_config.initial_string_length * sizeof(char16_t)); |
|||
|
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(argument_data))); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(swkbd_data))); |
|||
channel.PushData(std::make_shared<IStorage>(system, std::move(work_buffer))); |
|||
} |
|||
|
|||
} // namespace
|
|||
|
|||
AppletManager::AppletManager(Core::System& system) : m_system(system) {} |
|||
AppletManager::~AppletManager() { |
|||
this->Reset(); |
|||
} |
|||
|
|||
void AppletManager::InsertApplet(std::shared_ptr<Applet> applet) { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
m_applets.emplace(applet->aruid, std::move(applet)); |
|||
} |
|||
|
|||
void AppletManager::TerminateAndRemoveApplet(AppletResourceUserId aruid) { |
|||
std::shared_ptr<Applet> applet; |
|||
{ |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
const auto it = m_applets.find(aruid); |
|||
if (it == m_applets.end()) { |
|||
return; |
|||
} |
|||
|
|||
applet = it->second; |
|||
m_applets.erase(it); |
|||
} |
|||
|
|||
// Terminate process.
|
|||
applet->process->Terminate(); |
|||
} |
|||
|
|||
void AppletManager::CreateAndInsertByFrontendAppletParameters( |
|||
AppletResourceUserId aruid, const FrontendAppletParameters& params) { |
|||
// TODO: this should be run inside AM so that the events will have a parent process
|
|||
// TODO: have am create the guest process
|
|||
auto applet = std::make_shared<Applet>(m_system, std::make_unique<Process>(m_system)); |
|||
|
|||
applet->aruid = aruid; |
|||
applet->program_id = params.program_id; |
|||
applet->applet_id = params.applet_id; |
|||
applet->type = params.applet_type; |
|||
applet->previous_program_index = params.previous_program_index; |
|||
|
|||
// Push UserChannel data from previous application
|
|||
if (params.launch_type == LaunchType::ApplicationInitiated) { |
|||
applet->user_channel_launch_parameter.swap(m_system.GetUserChannel()); |
|||
} |
|||
|
|||
// TODO: Read whether we need a preselected user from NACP?
|
|||
// TODO: This can be done quite easily from loader
|
|||
{ |
|||
LaunchParameterAccountPreselectedUser lp{}; |
|||
|
|||
lp.magic = LaunchParameterAccountPreselectedUserMagic; |
|||
lp.is_account_selected = 1; |
|||
|
|||
Account::ProfileManager profile_manager{}; |
|||
const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user)); |
|||
ASSERT(uuid.has_value() && uuid->IsValid()); |
|||
lp.current_user = *uuid; |
|||
|
|||
std::vector<u8> buffer(sizeof(LaunchParameterAccountPreselectedUser)); |
|||
std::memcpy(buffer.data(), &lp, buffer.size()); |
|||
|
|||
applet->preselected_user_launch_parameter.push_back(std::move(buffer)); |
|||
} |
|||
|
|||
// Starting from frontend, some applets require input data.
|
|||
switch (applet->applet_id) { |
|||
case AppletId::Cabinet: |
|||
PushInShowCabinetData(m_system, InitializeFakeCallerApplet(m_system, applet)); |
|||
break; |
|||
case AppletId::MiiEdit: |
|||
PushInShowMiiEditData(m_system, InitializeFakeCallerApplet(m_system, applet)); |
|||
break; |
|||
case AppletId::PhotoViewer: |
|||
PushInShowAlbum(m_system, InitializeFakeCallerApplet(m_system, applet)); |
|||
break; |
|||
case AppletId::SoftwareKeyboard: |
|||
PushInShowSoftwareKeyboard(m_system, InitializeFakeCallerApplet(m_system, applet)); |
|||
break; |
|||
case AppletId::Controller: |
|||
PushInShowController(m_system, InitializeFakeCallerApplet(m_system, applet)); |
|||
break; |
|||
default: |
|||
break; |
|||
} |
|||
|
|||
// Applet was started by frontend, so it is foreground.
|
|||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::FocusStateChanged); |
|||
applet->message_queue.PushMessage(AppletMessageQueue::AppletMessage::ChangeIntoForeground); |
|||
applet->focus_state = FocusState::InFocus; |
|||
|
|||
this->InsertApplet(std::move(applet)); |
|||
} |
|||
|
|||
std::shared_ptr<Applet> AppletManager::GetByAppletResourceUserId(AppletResourceUserId aruid) const { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
if (const auto it = m_applets.find(aruid); it != m_applets.end()) { |
|||
return it->second; |
|||
} |
|||
|
|||
return {}; |
|||
} |
|||
|
|||
void AppletManager::Reset() { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
m_applets.clear(); |
|||
} |
|||
|
|||
void AppletManager::RequestExit() { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
for (const auto& [aruid, applet] : m_applets) { |
|||
applet->message_queue.RequestExit(); |
|||
} |
|||
} |
|||
|
|||
void AppletManager::RequestResume() { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
for (const auto& [aruid, applet] : m_applets) { |
|||
applet->message_queue.RequestResume(); |
|||
} |
|||
} |
|||
|
|||
void AppletManager::OperationModeChanged() { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
for (const auto& [aruid, applet] : m_applets) { |
|||
applet->message_queue.OperationModeChanged(); |
|||
} |
|||
} |
|||
|
|||
void AppletManager::FocusStateChanged() { |
|||
std::scoped_lock lk{m_lock}; |
|||
|
|||
for (const auto& [aruid, applet] : m_applets) { |
|||
applet->message_queue.FocusStateChanged(); |
|||
} |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,59 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <map> |
|||
#include <mutex> |
|||
|
|||
#include "core/hle/service/am/applet.h" |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace Service::AM { |
|||
|
|||
enum class LaunchType { |
|||
FrontendInitiated, |
|||
ApplicationInitiated, |
|||
}; |
|||
|
|||
struct FrontendAppletParameters { |
|||
ProgramId program_id{}; |
|||
AppletId applet_id{}; |
|||
AppletType applet_type{}; |
|||
LaunchType launch_type{}; |
|||
s32 program_index{}; |
|||
s32 previous_program_index{-1}; |
|||
}; |
|||
|
|||
class AppletManager { |
|||
public: |
|||
explicit AppletManager(Core::System& system); |
|||
~AppletManager(); |
|||
|
|||
void InsertApplet(std::shared_ptr<Applet> applet); |
|||
void TerminateAndRemoveApplet(AppletResourceUserId aruid); |
|||
|
|||
void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid, |
|||
const FrontendAppletParameters& params); |
|||
std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const; |
|||
|
|||
void Reset(); |
|||
|
|||
void RequestExit(); |
|||
void RequestResume(); |
|||
void OperationModeChanged(); |
|||
void FocusStateChanged(); |
|||
|
|||
private: |
|||
Core::System& m_system; |
|||
|
|||
mutable std::mutex m_lock{}; |
|||
std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{}; |
|||
|
|||
// AudioController state goes here |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,29 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/core.h"
|
|||
#include "core/hle/service/am/hid_registration.h"
|
|||
#include "core/hle/service/am/process.h"
|
|||
#include "core/hle/service/hid/hid_server.h"
|
|||
#include "core/hle/service/sm/sm.h"
|
|||
#include "hid_core/resource_manager.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
HidRegistration::HidRegistration(Core::System& system, Process& process) : m_process(process) { |
|||
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid"); |
|||
|
|||
if (m_process.IsInitialized()) { |
|||
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(), |
|||
true); |
|||
} |
|||
} |
|||
|
|||
HidRegistration::~HidRegistration() { |
|||
if (m_process.IsInitialized()) { |
|||
m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId( |
|||
m_process.GetProcessId()); |
|||
} |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,30 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <memory> |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace Service::HID { |
|||
class IHidServer; |
|||
} |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class Process; |
|||
|
|||
class HidRegistration { |
|||
public: |
|||
explicit HidRegistration(Core::System& system, Process& process); |
|||
~HidRegistration(); |
|||
|
|||
private: |
|||
Process& m_process; |
|||
std::shared_ptr<Service::HID::IHidServer> m_hid_server; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,140 @@ |
|||
// 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/am_results.h"
|
|||
#include "core/hle/service/am/library_applet_storage.h"
|
|||
#include "core/memory.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
namespace { |
|||
|
|||
Result ValidateOffset(s64 offset, size_t size, size_t data_size) { |
|||
R_UNLESS(offset >= 0, AM::ResultInvalidOffset); |
|||
|
|||
const size_t begin = offset; |
|||
const size_t end = begin + size; |
|||
|
|||
R_UNLESS(begin <= end && end <= data_size, AM::ResultInvalidOffset); |
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
class BufferLibraryAppletStorage final : public LibraryAppletStorage { |
|||
public: |
|||
explicit BufferLibraryAppletStorage(std::vector<u8>&& data) : m_data(std::move(data)) {} |
|||
~BufferLibraryAppletStorage() = default; |
|||
|
|||
Result Read(s64 offset, void* buffer, size_t size) override { |
|||
R_TRY(ValidateOffset(offset, size, m_data.size())); |
|||
|
|||
std::memcpy(buffer, m_data.data() + offset, size); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result Write(s64 offset, const void* buffer, size_t size) override { |
|||
R_TRY(ValidateOffset(offset, size, m_data.size())); |
|||
|
|||
std::memcpy(m_data.data() + offset, buffer, size); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
s64 GetSize() override { |
|||
return m_data.size(); |
|||
} |
|||
|
|||
Kernel::KTransferMemory* GetHandle() override { |
|||
return nullptr; |
|||
} |
|||
|
|||
private: |
|||
std::vector<u8> m_data; |
|||
}; |
|||
|
|||
class TransferMemoryLibraryAppletStorage : public LibraryAppletStorage { |
|||
public: |
|||
explicit TransferMemoryLibraryAppletStorage(Core::Memory::Memory& memory, |
|||
Kernel::KTransferMemory* trmem, bool is_writable, |
|||
s64 size) |
|||
: m_memory(memory), m_trmem(trmem), m_is_writable(is_writable), m_size(size) { |
|||
m_trmem->Open(); |
|||
} |
|||
|
|||
~TransferMemoryLibraryAppletStorage() { |
|||
m_trmem->Close(); |
|||
m_trmem = nullptr; |
|||
} |
|||
|
|||
Result Read(s64 offset, void* buffer, size_t size) override { |
|||
R_TRY(ValidateOffset(offset, size, m_size)); |
|||
|
|||
m_memory.ReadBlock(m_trmem->GetSourceAddress(), buffer, size); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
Result Write(s64 offset, const void* buffer, size_t size) override { |
|||
R_UNLESS(m_is_writable, ResultUnknown); |
|||
R_TRY(ValidateOffset(offset, size, m_size)); |
|||
|
|||
m_memory.WriteBlock(m_trmem->GetSourceAddress(), buffer, size); |
|||
|
|||
R_SUCCEED(); |
|||
} |
|||
|
|||
s64 GetSize() override { |
|||
return m_size; |
|||
} |
|||
|
|||
Kernel::KTransferMemory* GetHandle() override { |
|||
return nullptr; |
|||
} |
|||
|
|||
protected: |
|||
Core::Memory::Memory& m_memory; |
|||
Kernel::KTransferMemory* m_trmem; |
|||
bool m_is_writable; |
|||
s64 m_size; |
|||
}; |
|||
|
|||
class HandleLibraryAppletStorage : public TransferMemoryLibraryAppletStorage { |
|||
public: |
|||
explicit HandleLibraryAppletStorage(Core::Memory::Memory& memory, |
|||
Kernel::KTransferMemory* trmem, s64 size) |
|||
: TransferMemoryLibraryAppletStorage(memory, trmem, true, size) {} |
|||
~HandleLibraryAppletStorage() = default; |
|||
|
|||
Kernel::KTransferMemory* GetHandle() override { |
|||
return m_trmem; |
|||
} |
|||
}; |
|||
|
|||
} // namespace
|
|||
|
|||
LibraryAppletStorage::~LibraryAppletStorage() = default; |
|||
|
|||
std::vector<u8> LibraryAppletStorage::GetData() { |
|||
std::vector<u8> data(this->GetSize()); |
|||
this->Read(0, data.data(), data.size()); |
|||
return data; |
|||
} |
|||
|
|||
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data) { |
|||
return std::make_shared<BufferLibraryAppletStorage>(std::move(data)); |
|||
} |
|||
|
|||
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, |
|||
Kernel::KTransferMemory* trmem, |
|||
bool is_writable, s64 size) { |
|||
return std::make_shared<TransferMemoryLibraryAppletStorage>(memory, trmem, is_writable, size); |
|||
} |
|||
|
|||
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, |
|||
Kernel::KTransferMemory* trmem, |
|||
s64 size) { |
|||
return std::make_shared<HandleLibraryAppletStorage>(memory, trmem, size); |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -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/service.h" |
|||
|
|||
namespace Core::Memory { |
|||
class Memory; |
|||
} |
|||
|
|||
namespace Kernel { |
|||
class KTransferMemory; |
|||
} |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class LibraryAppletStorage { |
|||
public: |
|||
virtual ~LibraryAppletStorage(); |
|||
virtual Result Read(s64 offset, void* buffer, size_t size) = 0; |
|||
virtual Result Write(s64 offset, const void* buffer, size_t size) = 0; |
|||
virtual s64 GetSize() = 0; |
|||
virtual Kernel::KTransferMemory* GetHandle() = 0; |
|||
|
|||
std::vector<u8> GetData(); |
|||
}; |
|||
|
|||
std::shared_ptr<LibraryAppletStorage> CreateStorage(std::vector<u8>&& data); |
|||
std::shared_ptr<LibraryAppletStorage> CreateTransferMemoryStorage(Core::Memory::Memory& memory, |
|||
Kernel::KTransferMemory* trmem, |
|||
bool is_writable, s64 size); |
|||
std::shared_ptr<LibraryAppletStorage> CreateHandleStorage(Core::Memory::Memory& memory, |
|||
Kernel::KTransferMemory* trmem, s64 size); |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,59 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/managed_layer_holder.h"
|
|||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
ManagedLayerHolder::ManagedLayerHolder() = default; |
|||
ManagedLayerHolder::~ManagedLayerHolder() { |
|||
if (!m_nvnflinger) { |
|||
return; |
|||
} |
|||
|
|||
for (const auto& layer : m_managed_display_layers) { |
|||
m_nvnflinger->DestroyLayer(layer); |
|||
} |
|||
|
|||
for (const auto& layer : m_managed_display_recording_layers) { |
|||
m_nvnflinger->DestroyLayer(layer); |
|||
} |
|||
|
|||
m_nvnflinger = nullptr; |
|||
} |
|||
|
|||
void ManagedLayerHolder::Initialize(Nvnflinger::Nvnflinger* nvnflinger) { |
|||
m_nvnflinger = nvnflinger; |
|||
} |
|||
|
|||
void ManagedLayerHolder::CreateManagedDisplayLayer(u64* out_layer) { |
|||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
|||
// create the layer in the Default display.
|
|||
const auto display_id = m_nvnflinger->OpenDisplay("Default"); |
|||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id); |
|||
|
|||
m_managed_display_layers.emplace(*layer_id); |
|||
|
|||
*out_layer = *layer_id; |
|||
} |
|||
|
|||
void ManagedLayerHolder::CreateManagedDisplaySeparableLayer(u64* out_layer, |
|||
u64* out_recording_layer) { |
|||
// TODO(Subv): Find out how AM determines the display to use, for now just
|
|||
// create the layer in the Default display.
|
|||
// This calls nn::vi::CreateRecordingLayer() which creates another layer.
|
|||
// Currently we do not support more than 1 layer per display, output 1 layer id for now.
|
|||
// Outputting 1 layer id instead of the expected 2 has not been observed to cause any adverse
|
|||
// side effects.
|
|||
// TODO: Support multiple layers
|
|||
const auto display_id = m_nvnflinger->OpenDisplay("Default"); |
|||
const auto layer_id = m_nvnflinger->CreateLayer(*display_id); |
|||
|
|||
m_managed_display_layers.emplace(*layer_id); |
|||
|
|||
*out_layer = *layer_id; |
|||
*out_recording_layer = 0; |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,32 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <set> |
|||
|
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace Service::Nvnflinger { |
|||
class Nvnflinger; |
|||
} |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class ManagedLayerHolder { |
|||
public: |
|||
ManagedLayerHolder(); |
|||
~ManagedLayerHolder(); |
|||
|
|||
void Initialize(Nvnflinger::Nvnflinger* nvnflinger); |
|||
void CreateManagedDisplayLayer(u64* out_layer); |
|||
void CreateManagedDisplaySeparableLayer(u64* out_layer, u64* out_recording_layer); |
|||
|
|||
private: |
|||
Nvnflinger::Nvnflinger* m_nvnflinger{}; |
|||
std::set<u64> m_managed_display_layers{}; |
|||
std::set<u64> m_managed_display_recording_layers{}; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,138 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "common/scope_exit.h"
|
|||
|
|||
#include "core/file_sys/nca_metadata.h"
|
|||
#include "core/file_sys/registered_cache.h"
|
|||
#include "core/hle/kernel/k_process.h"
|
|||
#include "core/hle/service/am/process.h"
|
|||
#include "core/hle/service/filesystem/filesystem.h"
|
|||
#include "core/loader/loader.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
Process::Process(Core::System& system) |
|||
: m_system(system), m_process(), m_main_thread_priority(), m_main_thread_stack_size(), |
|||
m_program_id(), m_process_started() {} |
|||
|
|||
Process::~Process() { |
|||
this->Finalize(); |
|||
} |
|||
|
|||
bool Process::Initialize(u64 program_id) { |
|||
// First, ensure we are not holding another process.
|
|||
this->Finalize(); |
|||
|
|||
// Get the filesystem controller.
|
|||
auto& fsc = m_system.GetFileSystemController(); |
|||
|
|||
// Attempt to load program NCA.
|
|||
const FileSys::RegisteredCache* bis_system{}; |
|||
FileSys::VirtualFile nca{}; |
|||
|
|||
// Get the program NCA from built-in storage.
|
|||
bis_system = fsc.GetSystemNANDContents(); |
|||
if (bis_system) { |
|||
nca = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program); |
|||
} |
|||
|
|||
// Ensure we retrieved a program NCA.
|
|||
if (!nca) { |
|||
return false; |
|||
} |
|||
|
|||
// Get the appropriate loader to parse this NCA.
|
|||
auto app_loader = Loader::GetLoader(m_system, nca, program_id, 0); |
|||
|
|||
// Ensure we have a loader which can parse the NCA.
|
|||
if (!app_loader) { |
|||
return false; |
|||
} |
|||
|
|||
// Create the process.
|
|||
auto* const process = Kernel::KProcess::Create(m_system.Kernel()); |
|||
Kernel::KProcess::Register(m_system.Kernel(), process); |
|||
|
|||
// On exit, ensure we free the additional reference to the process.
|
|||
SCOPE_EXIT({ process->Close(); }); |
|||
|
|||
// Insert process modules into memory.
|
|||
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system); |
|||
|
|||
// Ensure loading was successful.
|
|||
if (load_result != Loader::ResultStatus::Success) { |
|||
return false; |
|||
} |
|||
|
|||
// TODO: remove this, kernel already tracks this
|
|||
m_system.Kernel().AppendNewProcess(process); |
|||
|
|||
// Note the load parameters from NPDM.
|
|||
m_main_thread_priority = load_parameters->main_thread_priority; |
|||
m_main_thread_stack_size = load_parameters->main_thread_stack_size; |
|||
|
|||
// This process has not started yet.
|
|||
m_process_started = false; |
|||
|
|||
// Take ownership of the process object.
|
|||
m_process = process; |
|||
m_process->Open(); |
|||
|
|||
// We succeeded.
|
|||
return true; |
|||
} |
|||
|
|||
void Process::Finalize() { |
|||
// Terminate, if we are currently holding a process.
|
|||
this->Terminate(); |
|||
|
|||
// Close the process.
|
|||
if (m_process) { |
|||
m_process->Close(); |
|||
|
|||
// TODO: remove this, kernel already tracks this
|
|||
m_system.Kernel().RemoveProcess(m_process); |
|||
} |
|||
|
|||
// Clean up.
|
|||
m_process = nullptr; |
|||
m_main_thread_priority = 0; |
|||
m_main_thread_stack_size = 0; |
|||
m_program_id = 0; |
|||
m_process_started = false; |
|||
} |
|||
|
|||
bool Process::Run() { |
|||
// If we already started the process, don't start again.
|
|||
if (m_process_started) { |
|||
return false; |
|||
} |
|||
|
|||
// Start.
|
|||
if (m_process) { |
|||
m_process->Run(m_main_thread_priority, m_main_thread_stack_size); |
|||
} |
|||
|
|||
// Mark as started.
|
|||
m_process_started = true; |
|||
|
|||
// We succeeded.
|
|||
return true; |
|||
} |
|||
|
|||
void Process::Terminate() { |
|||
if (m_process) { |
|||
m_process->Terminate(); |
|||
} |
|||
} |
|||
|
|||
u64 Process::GetProcessId() const { |
|||
if (m_process) { |
|||
return m_process->GetProcessId(); |
|||
} |
|||
|
|||
return 0; |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,50 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
|
|||
namespace Kernel { |
|||
class KProcess; |
|||
} |
|||
|
|||
namespace Core { |
|||
class System; |
|||
} |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class Process { |
|||
public: |
|||
explicit Process(Core::System& system); |
|||
~Process(); |
|||
|
|||
bool Initialize(u64 program_id); |
|||
void Finalize(); |
|||
|
|||
bool Run(); |
|||
void Terminate(); |
|||
|
|||
bool IsInitialized() const { |
|||
return m_process != nullptr; |
|||
} |
|||
u64 GetProcessId() const; |
|||
u64 GetProgramId() const { |
|||
return m_program_id; |
|||
} |
|||
Kernel::KProcess* GetProcess() const { |
|||
return m_process; |
|||
} |
|||
|
|||
private: |
|||
Core::System& m_system; |
|||
Kernel::KProcess* m_process{}; |
|||
s32 m_main_thread_priority{}; |
|||
u64 m_main_thread_stack_size{}; |
|||
u64 m_program_id{}; |
|||
bool m_process_started{}; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,49 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/service/am/system_buffer_manager.h"
|
|||
#include "core/hle/service/nvnflinger/fb_share_buffer_manager.h"
|
|||
#include "core/hle/service/nvnflinger/nvnflinger.h"
|
|||
|
|||
namespace Service::AM { |
|||
|
|||
SystemBufferManager::SystemBufferManager() = default; |
|||
|
|||
SystemBufferManager::~SystemBufferManager() { |
|||
if (!m_nvnflinger) { |
|||
return; |
|||
} |
|||
|
|||
// Clean up shared layers.
|
|||
if (m_buffer_sharing_enabled) { |
|||
} |
|||
} |
|||
|
|||
bool SystemBufferManager::Initialize(Nvnflinger::Nvnflinger* nvnflinger, Kernel::KProcess* process, |
|||
AppletId applet_id) { |
|||
if (m_nvnflinger) { |
|||
return m_buffer_sharing_enabled; |
|||
} |
|||
|
|||
m_process = process; |
|||
m_nvnflinger = nvnflinger; |
|||
m_buffer_sharing_enabled = false; |
|||
m_system_shared_buffer_id = 0; |
|||
m_system_shared_layer_id = 0; |
|||
|
|||
if (applet_id <= AppletId::Application) { |
|||
return false; |
|||
} |
|||
|
|||
const auto display_id = m_nvnflinger->OpenDisplay("Default").value(); |
|||
const auto res = m_nvnflinger->GetSystemBufferManager().Initialize( |
|||
&m_system_shared_buffer_id, &m_system_shared_layer_id, display_id); |
|||
|
|||
if (res.IsSuccess()) { |
|||
m_buffer_sharing_enabled = true; |
|||
} |
|||
|
|||
return m_buffer_sharing_enabled; |
|||
} |
|||
|
|||
} // namespace Service::AM
|
|||
@ -0,0 +1,44 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
#include <set> |
|||
|
|||
#include "common/common_funcs.h" |
|||
#include "common/common_types.h" |
|||
|
|||
#include "core/hle/service/am/am_types.h" |
|||
|
|||
namespace Kernel { |
|||
class KProcess; |
|||
} |
|||
|
|||
namespace Service::Nvnflinger { |
|||
class Nvnflinger; |
|||
} |
|||
|
|||
namespace Service::AM { |
|||
|
|||
class SystemBufferManager { |
|||
public: |
|||
SystemBufferManager(); |
|||
~SystemBufferManager(); |
|||
|
|||
bool Initialize(Nvnflinger::Nvnflinger* flinger, Kernel::KProcess* process, AppletId applet_id); |
|||
|
|||
void GetSystemSharedLayerHandle(u64* out_system_shared_buffer_id, |
|||
u64* out_system_shared_layer_id) { |
|||
*out_system_shared_buffer_id = m_system_shared_buffer_id; |
|||
*out_system_shared_layer_id = m_system_shared_layer_id; |
|||
} |
|||
|
|||
private: |
|||
Kernel::KProcess* m_process{}; |
|||
Nvnflinger::Nvnflinger* m_nvnflinger{}; |
|||
bool m_buffer_sharing_enabled{}; |
|||
u64 m_system_shared_buffer_id{}; |
|||
u64 m_system_shared_layer_id{}; |
|||
}; |
|||
|
|||
} // namespace Service::AM |
|||
@ -0,0 +1,31 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
|||
|
|||
#include "core/hle/kernel/k_event.h"
|
|||
#include "core/hle/service/event.h"
|
|||
#include "core/hle/service/kernel_helpers.h"
|
|||
|
|||
namespace Service { |
|||
|
|||
Event::Event(KernelHelpers::ServiceContext& ctx) { |
|||
m_event = ctx.CreateEvent("Event"); |
|||
} |
|||
|
|||
Event::~Event() { |
|||
m_event->GetReadableEvent().Close(); |
|||
m_event->Close(); |
|||
} |
|||
|
|||
void Event::Signal() { |
|||
m_event->Signal(); |
|||
} |
|||
|
|||
void Event::Clear() { |
|||
m_event->Clear(); |
|||
} |
|||
|
|||
Kernel::KReadableEvent* Event::GetHandle() { |
|||
return &m_event->GetReadableEvent(); |
|||
} |
|||
|
|||
} // namespace Service
|
|||
@ -0,0 +1,31 @@ |
|||
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project |
|||
// SPDX-License-Identifier: GPL-2.0-or-later |
|||
|
|||
#pragma once |
|||
|
|||
namespace Kernel { |
|||
class KEvent; |
|||
class KReadableEvent; |
|||
} // namespace Kernel |
|||
|
|||
namespace Service { |
|||
|
|||
namespace KernelHelpers { |
|||
class ServiceContext; |
|||
} |
|||
|
|||
class Event { |
|||
public: |
|||
explicit Event(KernelHelpers::ServiceContext& ctx); |
|||
~Event(); |
|||
|
|||
void Signal(); |
|||
void Clear(); |
|||
|
|||
Kernel::KReadableEvent* GetHandle(); |
|||
|
|||
private: |
|||
Kernel::KEvent* m_event; |
|||
}; |
|||
|
|||
} // namespace Service |
|||
Write
Preview
Loading…
Cancel
Save
Reference in new issue