Compare commits

...

8 Commits

Author SHA1 Message Date
yuzubot
c49529c542 Android 270 2024-02-26 15:41:31 +00:00
yuzubot
979176beae Merge yuzu-emu#13159 2024-02-26 15:41:30 +00:00
yuzubot
4c0763fecd Merge yuzu-emu#13135 2024-02-26 15:41:30 +00:00
yuzubot
f2e0148ab7 Merge yuzu-emu#13122 2024-02-26 15:41:30 +00:00
yuzubot
e49cb41451 Merge yuzu-emu#13096 2024-02-26 15:41:30 +00:00
yuzubot
3308458406 Merge yuzu-emu#13018 2024-02-26 15:41:30 +00:00
yuzubot
a6f38d918a Merge yuzu-emu#12749 2024-02-26 15:41:30 +00:00
yuzubot
fc59da23e3 Merge yuzu-emu#12461 2024-02-26 15:41:30 +00:00
143 changed files with 16344 additions and 3971 deletions

View File

@ -1,3 +1,18 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12461](https://github.com/yuzu-emu/yuzu//pull/12461) | [`a84e8e26f`](https://github.com/yuzu-emu/yuzu//pull/12461/files) | Rework Nvdec and VIC to fix out-of-order videos, and speed up decoding. | [Kelebek1](https://github.com/Kelebek1/) | Yes |
| [12749](https://github.com/yuzu-emu/yuzu//pull/12749) | [`aad4b0d6f`](https://github.com/yuzu-emu/yuzu//pull/12749/files) | general: workarounds for SMMU syncing issues | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13018](https://github.com/yuzu-emu/yuzu//pull/13018) | [`fffec12d3`](https://github.com/yuzu-emu/yuzu//pull/13018/files) | am: rewrite part 2 | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13096](https://github.com/yuzu-emu/yuzu//pull/13096) | [`0a8759057`](https://github.com/yuzu-emu/yuzu//pull/13096/files) | texture_cache: use two-pass collection for costly load resources | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13122](https://github.com/yuzu-emu/yuzu//pull/13122) | [`5dc08c7fe`](https://github.com/yuzu-emu/yuzu//pull/13122/files) | vk_rasterizer: flip scissor y on lower left origin mode | [liamwhite](https://github.com/liamwhite/) | Yes |
| [13135](https://github.com/yuzu-emu/yuzu//pull/13135) | [`fc6a87bba`](https://github.com/yuzu-emu/yuzu//pull/13135/files) | service: hid: Migrate HidServer to new IPC | [german77](https://github.com/german77/) | Yes |
| [13159](https://github.com/yuzu-emu/yuzu//pull/13159) | [`dc50b95a4`](https://github.com/yuzu-emu/yuzu//pull/13159/files) | core: enable error applet, add stubs for web applet | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later

View File

@ -314,3 +314,10 @@ endif()
if (NOT TARGET SimpleIni::SimpleIni)
add_subdirectory(simpleini)
endif()
# sse2neon
if (ARCHITECTURE_arm64 AND NOT TARGET sse2neon)
add_library(sse2neon INTERFACE)
target_include_directories(sse2neon INTERFACE sse2neon)
endif()

9285
externals/sse2neon/sse2neon.h vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@ -165,6 +165,7 @@ else()
if (MINGW)
add_definitions(-DMINGW_HAS_SECURE_API)
add_compile_options("-msse4.1")
if (MINGW_STATIC_BUILD)
add_definitions(-DQT_STATICPLUGIN)

View File

@ -140,7 +140,7 @@ struct Values {
Category::LibraryApplet};
Setting<AppletMode> data_erase_applet_mode{linkage, AppletMode::HLE, "data_erase_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> error_applet_mode{linkage, AppletMode::HLE, "error_applet_mode",
Setting<AppletMode> error_applet_mode{linkage, AppletMode::LLE, "error_applet_mode",
Category::LibraryApplet};
Setting<AppletMode> net_connect_applet_mode{linkage, AppletMode::HLE, "net_connect_applet_mode",
Category::LibraryApplet};

View File

@ -401,14 +401,16 @@ add_library(core STATIC
hle/service/am/am_types.h
hle/service/am/applet.cpp
hle/service/am/applet.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.cpp
hle/service/am/applet_manager.h
hle/service/am/applet_message_queue.cpp
hle/service/am/applet_message_queue.h
hle/service/am/button_poller.cpp
hle/service/am/button_poller.h
hle/service/am/display_layer_manager.cpp
hle/service/am/display_layer_manager.h
hle/service/am/event_observer.cpp
hle/service/am/event_observer.h
hle/service/am/frontend/applet_cabinet.cpp
hle/service/am/frontend/applet_cabinet.h
hle/service/am/frontend/applet_controller.cpp
@ -434,8 +436,12 @@ add_library(core STATIC
hle/service/am/hid_registration.h
hle/service/am/library_applet_storage.cpp
hle/service/am/library_applet_storage.h
hle/service/am/process.cpp
hle/service/am/process.h
hle/service/am/lifecycle_manager.cpp
hle/service/am/lifecycle_manager.h
hle/service/am/process_creation.cpp
hle/service/am/process_creation.h
hle/service/am/process_holder.cpp
hle/service/am/process_holder.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
@ -486,6 +492,8 @@ add_library(core STATIC
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/window_system.cpp
hle/service/am/window_system.h
hle/service/aoc/addon_content_manager.cpp
hle/service/aoc/addon_content_manager.h
hle/service/aoc/purchase_event_manager.cpp
@ -668,6 +676,10 @@ add_library(core STATIC
hle/service/glue/time/worker.h
hle/service/grc/grc.cpp
hle/service/grc/grc.h
hle/service/hid/active_vibration_device_list.cpp
hle/service/hid/active_vibration_device_list.h
hle/service/hid/applet_resource.cpp
hle/service/hid/applet_resource.h
hle/service/hid/hid.cpp
hle/service/hid/hid.h
hle/service/hid/hid_debug_server.cpp
@ -914,6 +926,8 @@ add_library(core STATIC
hle/service/os/multi_wait_utils.h
hle/service/os/mutex.cpp
hle/service/os/mutex.h
hle/service/os/process.cpp
hle/service/os/process.h
hle/service/pcie/pcie.cpp
hle/service/pcie/pcie.h
hle/service/pctl/parental_control_service_factory.cpp
@ -1047,9 +1061,12 @@ add_library(core STATIC
hle/service/spl/spl_module.h
hle/service/spl/spl_results.h
hle/service/spl/spl_types.h
hle/service/ssl/cert_store.cpp
hle/service/ssl/cert_store.h
hle/service/ssl/ssl.cpp
hle/service/ssl/ssl.h
hle/service/ssl/ssl_backend.h
hle/service/ssl/ssl_types.h
hle/service/usb/usb.cpp
hle/service/usb/usb.h
hle/service/vi/application_display_service.cpp

View File

@ -3,7 +3,6 @@
#include <array>
#include <atomic>
#include <exception>
#include <memory>
#include <utility>
@ -20,7 +19,6 @@
#include "core/cpu_manager.h"
#include "core/debugger/debugger.h"
#include "core/device_memory.h"
#include "core/file_sys/bis_factory.h"
#include "core/file_sys/fs_filesystem.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
@ -38,6 +36,7 @@
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/frontend/applets.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/apm/apm_controller.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/glue/glue_manager.h"
@ -72,30 +71,6 @@ MICROPROFILE_DEFINE(ARM_CPU3, "ARM", "CPU 3", MP_RGB(255, 64, 64));
namespace Core {
namespace {
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
}
switch (*slot) {
case FileSys::ContentProviderUnionSlot::UserNAND:
return FileSys::StorageId::NandUser;
case FileSys::ContentProviderUnionSlot::SysNAND:
return FileSys::StorageId::NandSystem;
case FileSys::ContentProviderUnionSlot::SDMC:
return FileSys::StorageId::SdCard;
case FileSys::ContentProviderUnionSlot::FrontendManual:
return FileSys::StorageId::Host;
default:
return FileSys::StorageId::None;
}
}
} // Anonymous namespace
FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
const std::string& path) {
// To account for split 00+01+etc files.
@ -297,9 +272,6 @@ struct System::Impl {
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
/// Reset all glue registrations
arp_manager.ResetAll();
telemetry_session = std::make_unique<Core::TelemetrySession>();
host1x_core = std::make_unique<Tegra::Host1x::Host1x>(system);
@ -335,33 +307,17 @@ struct System::Impl {
SystemResultStatus Load(System& system, Frontend::EmuWindow& emu_window,
const std::string& filepath,
Service::AM::FrontendAppletParameters& params) {
app_loader = Loader::GetLoader(system, GetGameFileFromPath(virtual_filesystem, filepath),
params.program_id, params.program_index);
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return SystemResultStatus::ErrorGetLoader;
}
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find title id for ROM!");
}
std::string name = "Unknown program";
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to read title for ROM!");
}
LOG_INFO(Core, "Loading {} ({})", name, params.program_id);
InitializeKernel(system);
// Create the application process.
auto main_process = Kernel::KProcess::Create(system.Kernel());
Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.AppendNewProcess(main_process);
kernel.MakeApplicationProcess(main_process);
const auto [load_result, load_parameters] = app_loader->Load(*main_process, system);
const auto file = GetGameFileFromPath(virtual_filesystem, filepath);
// Create the application process
Loader::ResultStatus load_result{};
std::vector<u8> control;
auto process =
Service::AM::CreateApplicationProcess(control, app_loader, load_result, system, file,
params.program_id, params.program_index);
if (load_result != Loader::ResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to load ROM (Error {})!", load_result);
ShutdownMainProcess();
@ -370,6 +326,25 @@ struct System::Impl {
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
}
if (!app_loader) {
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
return SystemResultStatus::ErrorGetLoader;
}
if (app_loader->ReadProgramId(params.program_id) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to find program id for ROM!");
}
std::string name = "Unknown program";
if (app_loader->ReadTitle(name) != Loader::ResultStatus::Success) {
LOG_ERROR(Core, "Failed to read title for ROM!");
}
LOG_INFO(Core, "Loading {} ({:016X}) ...", name, params.program_id);
// Make the process created be the application
kernel.MakeApplicationProcess(process->GetHandle());
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
@ -379,7 +354,6 @@ struct System::Impl {
return init_result;
}
AddGlueRegistrationForProcess(*app_loader, *main_process);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Initialize cheat engine
@ -387,14 +361,9 @@ struct System::Impl {
cheat_engine->Initialize();
}
// Register with applet manager.
applet_manager.CreateAndInsertByFrontendAppletParameters(main_process->GetProcessId(),
params);
// All threads are started, begin main process execution, now that we're in the clear.
main_process->Run(load_parameters->main_thread_priority,
load_parameters->main_thread_stack_size);
main_process->Close();
// Register with applet manager
// All threads are started, begin main process execution, now that we're in the clear
applet_manager.CreateAndInsertByFrontendAppletParameters(std::move(process), params);
if (Settings::values.gamecard_inserted) {
if (Settings::values.gamecard_current_game) {
@ -466,7 +435,6 @@ struct System::Impl {
kernel.SuspendEmulation(true);
kernel.CloseServices();
kernel.ShutdownCores();
applet_manager.Reset();
services.reset();
service_manager.reset();
fs_controller.Reset();
@ -492,6 +460,9 @@ struct System::Impl {
// Workarounds
Settings::values.renderer_amdvlk_depth_bias_workaround = false;
// Reset all glue registrations
arp_manager.ResetAll();
LOG_DEBUG(Core, "Shutdown OK");
}
@ -509,31 +480,6 @@ struct System::Impl {
return app_loader->ReadTitle(out);
}
void AddGlueRegistrationForProcess(Loader::AppLoader& loader, Kernel::KProcess& process) {
std::vector<u8> nacp_data;
FileSys::NACP nacp;
if (loader.ReadControlData(nacp) == Loader::ResultStatus::Success) {
nacp_data = nacp.GetRawBytes();
} else {
nacp_data.resize(sizeof(FileSys::RawNACP));
}
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process.GetProgramId();
FileSys::PatchManager pm{launch.title_id, fs_controller, *content_provider};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(content_provider->GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
arp_manager.Register(launch.title_id, launch, std::move(nacp_data));
}
void SetStatus(SystemResultStatus new_status, const char* details = nullptr) {
status = new_status;
if (details) {

View File

@ -43,6 +43,8 @@ public:
DeviceMemoryManager(const DeviceMemory& device_memory);
~DeviceMemoryManager();
static constexpr bool HAS_FLUSH_INVALIDATION = true;
void BindInterface(DeviceInterface* device_inter);
DAddr Allocate(size_t size);

View File

@ -44,15 +44,32 @@ public:
GuestMemory() = delete;
explicit GuestMemory(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: m_memory{memory}, m_addr{addr}, m_size{size} {
: m_memory{&memory}, m_addr{addr}, m_size{size} {
static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write);
if constexpr (FLAGS & GuestMemoryFlags::Read) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
backup->resize_destructive(this->size());
m_data_span = *backup;
m_span_valid = true;
m_is_data_copy = true;
} else {
m_data_copy.resize(this->size());
m_data_span = std::span(m_data_copy);
m_span_valid = true;
m_is_data_copy = true;
}
}
} else if constexpr (FLAGS & GuestMemoryFlags::Read) {
Read(addr, size, backup);
}
}
~GuestMemory() = default;
GuestMemory(GuestMemory&& rhs) = default;
GuestMemory& operator=(GuestMemory&& rhs) = default;
T* data() noexcept {
return m_data_span.data();
}
@ -109,8 +126,8 @@ public:
}
if (this->TrySetSpan()) {
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.FlushRegion(m_addr, this->size_bytes());
if constexpr (FLAGS & GuestMemoryFlags::Safe && M::HAS_FLUSH_INVALIDATION) {
m_memory->FlushRegion(m_addr, this->size_bytes());
}
} else {
if (backup) {
@ -123,9 +140,9 @@ public:
m_is_data_copy = true;
m_span_valid = true;
if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.ReadBlock(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlock(m_addr, this->data(), this->size_bytes());
} else {
m_memory.ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
m_memory->ReadBlockUnsafe(m_addr, this->data(), this->size_bytes());
}
}
return m_data_span;
@ -133,18 +150,19 @@ public:
void Write(std::span<T> write_data) noexcept {
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
m_memory.WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockCached(m_addr, write_data.data(), this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
m_memory.WriteBlock(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlock(m_addr, write_data.data(), this->size_bytes());
} else {
m_memory.WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
m_memory->WriteBlockUnsafe(m_addr, write_data.data(), this->size_bytes());
}
}
bool TrySetSpan() noexcept {
if (u8* ptr = m_memory.GetSpan(m_addr, this->size_bytes()); ptr) {
if (u8* ptr = m_memory->GetSpan(m_addr, this->size_bytes()); ptr) {
m_data_span = {reinterpret_cast<T*>(ptr), this->size()};
m_span_valid = true;
m_is_data_copy = false;
return true;
}
return false;
@ -159,7 +177,7 @@ protected:
return m_addr_changed;
}
M& m_memory;
M* m_memory;
u64 m_addr{};
size_t m_size{};
std::span<T> m_data_span{};
@ -175,17 +193,7 @@ public:
GuestMemoryScoped() = delete;
explicit GuestMemoryScoped(M& memory, u64 addr, std::size_t size,
Common::ScratchBuffer<T>* backup = nullptr)
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {
if constexpr (!(FLAGS & GuestMemoryFlags::Read)) {
if (!this->TrySetSpan()) {
if (backup) {
this->m_data_span = *backup;
this->m_span_valid = true;
this->m_is_data_copy = true;
}
}
}
}
: GuestMemory<M, T, FLAGS>(memory, addr, size, backup) {}
~GuestMemoryScoped() {
if constexpr (FLAGS & GuestMemoryFlags::Write) {
@ -196,15 +204,17 @@ public:
if (this->AddressChanged() || this->IsDataCopy()) {
ASSERT(this->m_span_valid);
if constexpr (FLAGS & GuestMemoryFlags::Cached) {
this->m_memory.WriteBlockCached(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockCached(this->m_addr, this->data(),
this->size_bytes());
} else if constexpr (FLAGS & GuestMemoryFlags::Safe) {
this->m_memory.WriteBlock(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlock(this->m_addr, this->data(), this->size_bytes());
} else {
this->m_memory.WriteBlockUnsafe(this->m_addr, this->data(), this->size_bytes());
this->m_memory->WriteBlockUnsafe(this->m_addr, this->data(),
this->size_bytes());
}
} else if constexpr ((FLAGS & GuestMemoryFlags::Safe) ||
(FLAGS & GuestMemoryFlags::Cached)) {
this->m_memory.InvalidateRegion(this->m_addr, this->size_bytes());
this->m_memory->InvalidateRegion(this->m_addr, this->size_bytes());
}
}
}

View File

@ -1170,6 +1170,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// Determine if we are an application.
if (pool == KMemoryManager::Pool::Application) {
flag |= Svc::CreateProcessFlag::IsApplication;
m_is_application = true;
}
// If we are 64-bit, create as such.

View File

@ -25,8 +25,8 @@
#include "core/hle/service/acc/async_context.h"
#include "core/hle/service/acc/errors.h"
#include "core/hle/service/acc/profile_manager.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/loader/loader.h"
@ -74,12 +74,12 @@ static void SanitizeJPEGImageSize(std::vector<u8>& image) {
class IManagerForSystemService final : public ServiceFramework<IManagerForSystemService> {
public:
explicit IManagerForSystemService(Core::System& system_, Common::UUID)
: ServiceFramework{system_, "IManagerForSystemService"} {
explicit IManagerForSystemService(Core::System& system_, Common::UUID uuid)
: ServiceFramework{system_, "IManagerForSystemService"}, account_id{uuid} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &IManagerForSystemService::CheckAvailability, "CheckAvailability"},
{1, nullptr, "GetAccountId"},
{0, D<&IManagerForSystemService::CheckAvailability>, "CheckAvailability"},
{1, D<&IManagerForSystemService::GetAccountId>, "GetAccountId"},
{2, nullptr, "EnsureIdTokenCacheAsync"},
{3, nullptr, "LoadIdTokenCache"},
{100, nullptr, "SetSystemProgramIdentification"},
@ -109,11 +109,18 @@ public:
}
private:
void CheckAvailability(HLERequestContext& ctx) {
Result CheckAvailability() {
LOG_WARNING(Service_ACC, "(STUBBED) called");
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
R_SUCCEED();
}
Result GetAccountId(Out<u64> out_account_id) {
LOG_WARNING(Service_ACC, "(STUBBED) called");
*out_account_id = account_id.Hash();
R_SUCCEED();
}
Common::UUID account_id;
};
// 3.0.0+

View File

@ -23,7 +23,7 @@ ACC_U1::ACC_U1(std::shared_ptr<Module> module_, std::shared_ptr<ProfileManager>
{99, nullptr, "DebugActivateOpenContextRetention"},
{100, nullptr, "GetUserRegistrationNotifier"},
{101, nullptr, "GetUserStateChangeNotifier"},
{102, nullptr, "GetBaasAccountManagerForSystemService"},
{102, &ACC_U1::GetBaasAccountManagerForSystemService, "GetBaasAccountManagerForSystemService"},
{103, nullptr, "GetBaasUserAvailabilityChangeNotifier"},
{104, nullptr, "GetProfileUpdateNotifier"},
{105, nullptr, "CheckNetworkServiceAvailabilityAsync"},

View File

@ -2,19 +2,26 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/button_poller.h"
#include "core/hle/service/am/event_observer.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/am/window_system.h"
#include "core/hle/service/server_manager.h"
namespace Service::AM {
void LoopProcess(Core::System& system) {
WindowSystem window_system(system);
ButtonPoller button_poller(system, window_system);
EventObserver event_observer(system, window_system);
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("appletAE",
std::make_shared<IAllSystemAppletProxiesService>(system));
server_manager->RegisterNamedService("appletOE",
std::make_shared<IApplicationProxyService>(system));
server_manager->RegisterNamedService(
"appletAE", std::make_shared<IAllSystemAppletProxiesService>(system, window_system));
server_manager->RegisterNamedService(
"appletOE", std::make_shared<IApplicationProxyService>(system, window_system));
ServerManager::RunServer(std::move(server_manager));
}

View File

@ -9,6 +9,7 @@ namespace Service::AM {
constexpr Result ResultNoDataInChannel{ErrorModule::AM, 2};
constexpr Result ResultNoMessages{ErrorModule::AM, 3};
constexpr Result ResultLibraryAppletTerminated{ErrorModule::AM, 22};
constexpr Result ResultInvalidOffset{ErrorModule::AM, 503};
constexpr Result ResultInvalidStorageType{ErrorModule::AM, 511};
constexpr Result ResultFatalSectionCountImbalance{ErrorModule::AM, 512};

View File

@ -48,11 +48,6 @@ enum class SystemButtonType {
CaptureButtonLongPressing,
};
enum class SysPlatformRegion : s32 {
Global = 1,
Terra = 2,
};
struct AppletProcessLaunchReason {
u8 flag;
INSERT_PADDING_BYTES(3);
@ -66,12 +61,6 @@ enum class ScreenshotPermission : u32 {
Disable = 2,
};
struct FocusHandlingMode {
bool notify;
bool background;
bool suspend;
};
enum class IdleTimeDetectionExtension : u32 {
Disabled = 0,
Extended = 1,
@ -244,7 +233,6 @@ struct ApplicationPlayStatistics {
static_assert(sizeof(ApplicationPlayStatistics) == 0x18,
"ApplicationPlayStatistics has incorrect size.");
using AppletResourceUserId = u64;
using ProgramId = u64;
struct Applet;

View File

@ -1,27 +1,71 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/scope_exit.h"
#include "core/core.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
namespace Service::AM {
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) {
Applet::Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_application)
: context(system, "Applet"), lifecycle_manager(system, context, is_application),
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), state_changed_event(context) {
aruid = process->GetProcessId();
aruid.pid = process->GetProcessId();
program_id = process->GetProgramId();
}
Applet::~Applet() = default;
void Applet::UpdateSuspensionStateLocked(bool force_message) {
// Remove any forced resumption.
lifecycle_manager.RemoveForceResumeIfPossible();
// Check if we're runnable.
const bool curr_activity_runnable = lifecycle_manager.IsRunnable();
const bool prev_activity_runnable = is_activity_runnable;
const bool was_changed = curr_activity_runnable != prev_activity_runnable;
if (was_changed) {
if (curr_activity_runnable) {
process->Suspend(false);
} else {
process->Suspend(true);
lifecycle_manager.RequestResumeNotification();
}
is_activity_runnable = curr_activity_runnable;
}
if (lifecycle_manager.GetForcedSuspend()) {
// TODO: why is this allowed?
return;
}
// Signal if the focus state was changed or the process state was changed.
if (lifecycle_manager.UpdateRequestedFocusState() || was_changed || force_message) {
lifecycle_manager.SignalSystemEventIfNeeded();
}
}
void Applet::SetInteractibleLocked(bool interactible) {
if (is_interactible == interactible) {
return;
}
is_interactible = interactible;
hid_registration.EnableAppletToGetInput(interactible && !lifecycle_manager.GetExitRequested());
}
void Applet::OnProcessTerminatedLocked() {
is_completed = true;
state_changed_event.Signal();
}
} // namespace Service::AM

View File

@ -3,25 +3,28 @@
#pragma once
#include <deque>
#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/cmif_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/os/process.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/display_layer_manager.h"
#include "core/hle/service/am/hid_registration.h"
#include "core/hle/service/am/process.h"
#include "core/hle/service/am/lifecycle_manager.h"
#include "core/hle/service/am/process_holder.h"
namespace Service::AM {
struct Applet {
explicit Applet(Core::System& system, std::unique_ptr<Process> process_);
explicit Applet(Core::System& system, std::unique_ptr<Process> process_, bool is_application);
~Applet();
// Lock
@ -30,11 +33,13 @@ struct Applet {
// Event creation helper
KernelHelpers::ServiceContext context;
// Applet message queue
AppletMessageQueue message_queue;
// Lifecycle manager
LifecycleManager lifecycle_manager;
// Process
std::unique_ptr<Process> process;
std::optional<ProcessHolder> process_holder;
bool is_process_running{};
// Creation state
AppletId applet_id{};
@ -75,11 +80,9 @@ struct Applet {
bool game_play_recording_supported{};
GamePlayRecordingState game_play_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{};
@ -93,15 +96,12 @@ struct Applet {
// Caller applet
std::weak_ptr<Applet> caller_applet{};
std::shared_ptr<AppletDataBroker> caller_applet_broker{};
std::list<std::shared_ptr<Applet>> child_applets{};
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{};
@ -110,6 +110,9 @@ struct Applet {
u64 suspended_ticks{};
bool album_image_taken_notification_enabled{};
bool record_volume_muted{};
bool is_activity_runnable{};
bool is_interactible{true};
bool window_visible{true};
// Events
Event gpu_error_detected_event;
@ -121,9 +124,15 @@ struct Applet {
Event library_applet_launchable_event;
Event accumulated_suspended_tick_changed_event;
Event sleep_lock_event;
Event state_changed_event;
// Frontend state
std::shared_ptr<Frontend::FrontendApplet> frontend{};
// Process state management
void UpdateSuspensionStateLocked(bool force_message);
void SetInteractibleLocked(bool interactible);
void OnProcessTerminatedLocked();
};
} // namespace Service::AM

View File

@ -44,24 +44,8 @@ Kernel::KReadableEvent* AppletStorageChannel::GetEvent() {
AppletDataBroker::AppletDataBroker(Core::System& system_)
: system(system_), context(system_, "AppletDataBroker"), in_data(context),
interactive_in_data(context), out_data(context), interactive_out_data(context),
state_changed_event(context), is_completed(false) {}
interactive_in_data(context), out_data(context), interactive_out_data(context) {}
AppletDataBroker::~AppletDataBroker() = default;
void AppletDataBroker::SignalCompletion() {
{
std::scoped_lock lk{lock};
if (is_completed) {
return;
}
is_completed = true;
state_changed_event.Signal();
}
system.GetAppletManager().FocusStateChanged();
}
} // namespace Service::AM

View File

@ -53,16 +53,6 @@ public:
return interactive_out_data;
}
Event& GetStateChangedEvent() {
return state_changed_event;
}
bool IsCompleted() const {
return is_completed;
}
void SignalCompletion();
private:
Core::System& system;
KernelHelpers::ServiceContext context;
@ -71,10 +61,6 @@ private:
AppletStorageChannel interactive_in_data;
AppletStorageChannel out_data;
AppletStorageChannel interactive_out_data;
Event state_changed_event;
std::mutex lock;
bool is_completed;
};
} // namespace Service::AM

View File

@ -13,6 +13,7 @@
#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 "core/hle/service/am/window_system.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
@ -225,49 +226,46 @@ void PushInShowSoftwareKeyboard(Core::System& system, AppletStorageChannel& chan
} // 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;
bool should_stop = false;
{
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);
should_stop = m_applets.empty();
}
// Terminate process.
applet->process->Terminate();
// If there were no applets left, stop emulation.
if (should_stop) {
m_system.Exit();
}
}
AppletManager::~AppletManager() = default;
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));
std::unique_ptr<Process> process, const FrontendAppletParameters& params) {
{
std::scoped_lock lk{m_lock};
m_pending_process = std::move(process);
m_pending_parameters = params;
}
m_cv.notify_all();
}
void AppletManager::RequestExit() {
std::scoped_lock lk{m_lock};
if (m_window_system) {
m_window_system->OnExitRequested();
}
}
void AppletManager::OperationModeChanged() {
std::scoped_lock lk{m_lock};
if (m_window_system) {
m_window_system->OnOperationModeChanged();
}
}
void AppletManager::SetWindowSystem(WindowSystem* window_system) {
std::unique_lock lk{m_lock};
m_window_system = window_system;
if (!m_window_system) {
return;
}
m_cv.wait(lk, [&] { return m_pending_process != nullptr; });
const auto& params = m_pending_parameters;
auto applet = std::make_shared<Applet>(m_system, std::move(m_pending_process),
params.applet_id == AppletId::Application);
applet->aruid = aruid;
applet->program_id = params.program_id;
applet->applet_id = params.applet_id;
applet->type = params.applet_type;
@ -322,59 +320,19 @@ void AppletManager::CreateAndInsertByFrontendAppletParameters(
}
// Applet was started by frontend, so it is foreground.
applet->message_queue.PushMessage(AppletMessage::ChangeIntoForeground);
applet->message_queue.PushMessage(AppletMessage::FocusStateChanged);
applet->focus_state = FocusState::InFocus;
applet->lifecycle_manager.SetFocusState(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;
if (applet->applet_id == AppletId::QLaunch) {
applet->lifecycle_manager.SetFocusHandlingMode(false);
applet->lifecycle_manager.SetOutOfFocusSuspendingEnabled(false);
m_window_system->TrackApplet(applet, false);
m_window_system->RequestHomeMenuToGetForeground();
} else {
m_window_system->TrackApplet(applet, true);
m_window_system->RequestApplicationToGetForeground();
}
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();
}
applet->process->Run();
}
} // namespace Service::AM

View File

@ -3,17 +3,23 @@
#pragma once
#include <map>
#include <condition_variable>
#include <mutex>
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/am_types.h"
namespace Core {
class System;
}
namespace Service {
class Process;
}
namespace Service::AM {
class WindowSystem;
enum class LaunchType {
FrontendInitiated,
ApplicationInitiated,
@ -33,27 +39,24 @@ public:
explicit AppletManager(Core::System& system);
~AppletManager();
void InsertApplet(std::shared_ptr<Applet> applet);
void TerminateAndRemoveApplet(AppletResourceUserId aruid);
void CreateAndInsertByFrontendAppletParameters(AppletResourceUserId aruid,
void CreateAndInsertByFrontendAppletParameters(std::unique_ptr<Process> process,
const FrontendAppletParameters& params);
std::shared_ptr<Applet> GetByAppletResourceUserId(AppletResourceUserId aruid) const;
void Reset();
void RequestExit();
void RequestResume();
void OperationModeChanged();
void FocusStateChanged();
public:
void SetWindowSystem(WindowSystem* window_system);
private:
Core::System& m_system;
mutable std::mutex m_lock{};
std::map<AppletResourceUserId, std::shared_ptr<Applet>> m_applets{};
std::mutex m_lock;
std::condition_variable m_cv;
// AudioController state goes here
WindowSystem* m_window_system{};
FrontendAppletParameters m_pending_parameters{};
std::unique_ptr<Process> m_pending_process{};
};
} // namespace Service::AM

View File

@ -1,73 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/service/am/applet_message_queue.h"
#include "core/hle/service/ipc_helpers.h"
namespace Service::AM {
AppletMessageQueue::AppletMessageQueue(Core::System& system)
: service_context{system, "AppletMessageQueue"} {
on_new_message = service_context.CreateEvent("AMMessageQueue:OnMessageReceived");
on_operation_mode_changed = service_context.CreateEvent("AMMessageQueue:OperationModeChanged");
}
AppletMessageQueue::~AppletMessageQueue() {
service_context.CloseEvent(on_new_message);
service_context.CloseEvent(on_operation_mode_changed);
}
Kernel::KReadableEvent& AppletMessageQueue::GetMessageReceiveEvent() {
return on_new_message->GetReadableEvent();
}
Kernel::KReadableEvent& AppletMessageQueue::GetOperationModeChangedEvent() {
return on_operation_mode_changed->GetReadableEvent();
}
void AppletMessageQueue::PushMessage(AppletMessage msg) {
{
std::scoped_lock lk{lock};
messages.push(msg);
}
on_new_message->Signal();
}
AppletMessage AppletMessageQueue::PopMessage() {
std::scoped_lock lk{lock};
if (messages.empty()) {
on_new_message->Clear();
return AppletMessage::None;
}
auto msg = messages.front();
messages.pop();
if (messages.empty()) {
on_new_message->Clear();
}
return msg;
}
std::size_t AppletMessageQueue::GetMessageCount() const {
std::scoped_lock lk{lock};
return messages.size();
}
void AppletMessageQueue::RequestExit() {
PushMessage(AppletMessage::Exit);
}
void AppletMessageQueue::RequestResume() {
PushMessage(AppletMessage::Resume);
}
void AppletMessageQueue::FocusStateChanged() {
PushMessage(AppletMessage::FocusStateChanged);
}
void AppletMessageQueue::OperationModeChanged() {
PushMessage(AppletMessage::OperationModeChanged);
PushMessage(AppletMessage::PerformanceModeChanged);
on_operation_mode_changed->Signal();
}
} // namespace Service::AM

View File

@ -1,43 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <queue>
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
namespace Kernel {
class KReadableEvent;
} // namespace Kernel
namespace Service::AM {
class AppletMessageQueue {
public:
explicit AppletMessageQueue(Core::System& system);
~AppletMessageQueue();
Kernel::KReadableEvent& GetMessageReceiveEvent();
Kernel::KReadableEvent& GetOperationModeChangedEvent();
void PushMessage(AppletMessage msg);
AppletMessage PopMessage();
std::size_t GetMessageCount() const;
void RequestExit();
void RequestResume();
void FocusStateChanged();
void OperationModeChanged();
private:
KernelHelpers::ServiceContext service_context;
Kernel::KEvent* on_new_message;
Kernel::KEvent* on_operation_mode_changed;
mutable std::mutex lock;
std::queue<AppletMessage> messages;
};
} // namespace Service::AM

View File

@ -0,0 +1,89 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/button_poller.h"
#include "core/hle/service/am/window_system.h"
#include "hid_core/frontend/emulated_controller.h"
#include "hid_core/hid_core.h"
#include "hid_core/hid_types.h"
namespace Service::AM {
namespace {
ButtonPressDuration ClassifyPressDuration(std::chrono::steady_clock::time_point start) {
using namespace std::chrono_literals;
const auto dur = std::chrono::steady_clock::now() - start;
// TODO: determine actual thresholds
// TODO: these are likely different for each button
if (dur < 500ms) {
return ButtonPressDuration::ShortPressing;
} else if (dur < 1000ms) {
return ButtonPressDuration::MiddlePressing;
} else {
return ButtonPressDuration::LongPressing;
}
}
} // namespace
ButtonPoller::ButtonPoller(Core::System& system, WindowSystem& window_system)
: m_window_system(window_system) {
// TODO: am reads this from the home button state in hid, which is controller-agnostic.
Core::HID::ControllerUpdateCallback engine_callback{
.on_change =
[this](Core::HID::ControllerTriggerType type) {
if (type == Core::HID::ControllerTriggerType::Button) {
this->OnButtonStateChanged();
}
},
.is_npad_service = true,
};
m_handheld = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Handheld);
m_handheld_key = m_handheld->SetCallback(engine_callback);
m_player1 = system.HIDCore().GetEmulatedController(Core::HID::NpadIdType::Player1);
m_player1_key = m_player1->SetCallback(engine_callback);
}
ButtonPoller::~ButtonPoller() {
m_handheld->DeleteCallback(m_handheld_key);
m_player1->DeleteCallback(m_player1_key);
}
void ButtonPoller::OnButtonStateChanged() {
const bool home_button =
m_handheld->GetHomeButtons().home.Value() || m_player1->GetHomeButtons().home.Value();
const bool capture_button = m_handheld->GetCaptureButtons().capture.Value() ||
m_player1->GetCaptureButtons().capture.Value();
// Buttons pressed which were not previously pressed
if (home_button && !m_home_button_press_start) {
m_home_button_press_start = std::chrono::steady_clock::now();
}
if (capture_button && !m_capture_button_press_start) {
m_capture_button_press_start = std::chrono::steady_clock::now();
}
// if (power_button && !m_power_button_press_start) {
// m_power_button_press_start = std::chrono::steady_clock::now();
// }
// Buttons released which were previously held
if (!home_button && m_home_button_press_start) {
m_window_system.OnHomeButtonPressed(ClassifyPressDuration(*m_home_button_press_start));
m_home_button_press_start = std::nullopt;
}
if (!capture_button && m_capture_button_press_start) {
// TODO
m_capture_button_press_start = std::nullopt;
}
// if (!power_button && m_power_button_press_start) {
// // TODO
// m_power_button_press_start = std::nullopt;
// }
}
} // namespace Service::AM

View File

@ -0,0 +1,43 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <chrono>
#include <optional>
#include "hid_core/frontend/emulated_controller.h"
namespace Core {
namespace HID {
class EmulatedController;
}
class System;
} // namespace Core
namespace Service::AM {
class WindowSystem;
class ButtonPoller {
public:
explicit ButtonPoller(Core::System& system, WindowSystem& window_system);
~ButtonPoller();
private:
void OnButtonStateChanged();
private:
WindowSystem& m_window_system;
Core::HID::EmulatedController* m_handheld{};
int m_handheld_key{};
Core::HID::EmulatedController* m_player1{};
int m_player1_key{};
std::optional<std::chrono::steady_clock::time_point> m_home_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_capture_button_press_start{};
std::optional<std::chrono::steady_clock::time_point> m_power_button_press_start{};
};
} // namespace Service::AM

View File

@ -0,0 +1,162 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/event_observer.h"
#include "core/hle/service/am/window_system.h"
namespace Service::AM {
enum class UserDataTag : u32 {
WakeupEvent,
AppletProcess,
};
EventObserver::EventObserver(Core::System& system, WindowSystem& window_system)
: m_system(system), m_context(system, "am:EventObserver"), m_window_system(window_system),
m_wakeup_event(m_context), m_wakeup_holder(m_wakeup_event.GetHandle()) {
m_window_system.SetEventObserver(this);
m_wakeup_holder.SetUserData(static_cast<uintptr_t>(UserDataTag::WakeupEvent));
m_wakeup_holder.LinkToMultiWait(std::addressof(m_multi_wait));
m_thread = std::thread([&] { this->ThreadFunc(); });
}
EventObserver::~EventObserver() {
// Signal thread and wait for processing to finish.
m_stop_source.request_stop();
m_wakeup_event.Signal();
m_thread.join();
// Free remaining owned sessions.
auto it = m_process_holder_list.begin();
while (it != m_process_holder_list.end()) {
// Get the holder.
auto* const holder = std::addressof(*it);
// Remove from the list.
it = m_process_holder_list.erase(it);
// Free the holder.
delete holder;
}
}
void EventObserver::TrackAppletProcess(Applet& applet) {
// Don't observe dummy processes.
if (!applet.process->IsInitialized()) {
return;
}
// Allocate new holder.
auto* holder = new ProcessHolder(applet, *applet.process);
holder->SetUserData(static_cast<uintptr_t>(UserDataTag::AppletProcess));
// Insert into list.
{
std::scoped_lock lk{m_lock};
m_process_holder_list.push_back(*holder);
holder->LinkToMultiWait(std::addressof(m_deferred_wait_list));
}
// Signal wakeup.
m_wakeup_event.Signal();
}
void EventObserver::RequestUpdate() {
m_wakeup_event.Signal();
}
void EventObserver::LinkDeferred() {
std::scoped_lock lk{m_lock};
m_multi_wait.MoveAll(std::addressof(m_deferred_wait_list));
}
MultiWaitHolder* EventObserver::WaitSignaled() {
while (true) {
this->LinkDeferred();
// If we're done, return before we start waiting.
if (m_stop_source.stop_requested()) {
return nullptr;
}
auto* selected = m_multi_wait.WaitAny(m_system.Kernel());
if (selected != std::addressof(m_wakeup_holder)) {
// Unlink the process.
selected->UnlinkFromMultiWait();
}
return selected;
}
}
void EventObserver::Process(MultiWaitHolder* holder) {
switch (static_cast<UserDataTag>(holder->GetUserData())) {
case UserDataTag::WakeupEvent:
this->OnWakeupEvent(holder);
break;
case UserDataTag::AppletProcess:
this->OnProcessEvent(static_cast<ProcessHolder*>(holder));
break;
default:
UNREACHABLE();
}
}
void EventObserver::OnWakeupEvent(MultiWaitHolder* holder) {
m_wakeup_event.Clear();
// Perform recalculation.
m_window_system.Update();
}
void EventObserver::OnProcessEvent(ProcessHolder* holder) {
// Check process state.
auto& applet = holder->GetApplet();
auto& process = holder->GetProcess();
{
std::scoped_lock lk{m_lock, applet.lock};
if (process.IsTerminated()) {
// Destroy the holder.
this->DestroyAppletProcessHolderLocked(holder);
} else {
// Reset signaled state.
process.ResetSignal();
// Relink wakeup event.
holder->LinkToMultiWait(std::addressof(m_deferred_wait_list));
}
// Set running.
applet.is_process_running = process.IsRunning();
}
// Perform recalculation.
m_window_system.Update();
}
void EventObserver::DestroyAppletProcessHolderLocked(ProcessHolder* holder) {
// Remove from owned list.
m_process_holder_list.erase(m_process_holder_list.iterator_to(*holder));
// Destroy and free.
delete holder;
}
void EventObserver::ThreadFunc() {
Common::SetCurrentThreadName("am:EventObserver");
while (true) {
auto* signaled_holder = this->WaitSignaled();
if (!signaled_holder) {
break;
}
this->Process(signaled_holder);
}
}
} // namespace Service::AM

View File

@ -0,0 +1,74 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/polyfill_thread.h"
#include "common/thread.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/os/event.h"
#include "core/hle/service/os/multi_wait.h"
namespace Core {
class System;
}
namespace Service::AM {
struct Applet;
class ProcessHolder;
class WindowSystem;
class EventObserver {
public:
explicit EventObserver(Core::System& system, WindowSystem& window_system);
~EventObserver();
void TrackAppletProcess(Applet& applet);
void RequestUpdate();
private:
void LinkDeferred();
MultiWaitHolder* WaitSignaled();
void Process(MultiWaitHolder* holder);
bool WaitAndProcessImpl();
void LoopProcess();
private:
void OnWakeupEvent(MultiWaitHolder* holder);
void OnProcessEvent(ProcessHolder* holder);
private:
void DestroyAppletProcessHolderLocked(ProcessHolder* holder);
private:
void ThreadFunc();
private:
// System reference and context.
Core::System& m_system;
KernelHelpers::ServiceContext m_context;
// Window manager.
WindowSystem& m_window_system;
// Guest event handle to wake up the event loop processor.
Event m_wakeup_event;
MultiWaitHolder m_wakeup_holder;
// Mutex to protect remaining members.
std::mutex m_lock{};
// List of owned process holders.
Common::IntrusiveListBaseTraits<ProcessHolder>::ListType m_process_holder_list;
// Multi-wait objects for new tasks.
MultiWait m_multi_wait;
MultiWait m_deferred_wait_list;
// Processing thread.
std::thread m_thread{};
std::stop_source m_stop_source{};
};
} // namespace Service::AM

View File

@ -69,7 +69,11 @@ void FrontendApplet::PushInteractiveOutData(std::shared_ptr<IStorage> storage) {
}
void FrontendApplet::Exit() {
applet.lock()->caller_applet_broker->SignalCompletion();
auto applet_ = applet.lock();
std::scoped_lock lk{applet_->lock};
applet_->is_completed = true;
applet_->state_changed_event.Signal();
}
FrontendAppletSet::FrontendAppletSet() = default;

View File

@ -3,24 +3,28 @@
#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/os/process.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");
m_hid_server = system.ServiceManager().GetService<HID::IHidServer>("hid", true);
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->RegisterAppletResourceUserId(m_process.GetProcessId(),
true);
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
true);
}
}
HidRegistration::~HidRegistration() {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
false);
m_hid_server->GetResourceManager()->UnregisterAppletResourceUserId(
m_process.GetProcessId());
}
@ -28,6 +32,8 @@ HidRegistration::~HidRegistration() {
void HidRegistration::EnableAppletToGetInput(bool enable) {
if (m_process.IsInitialized()) {
m_hid_server->GetResourceManager()->SetAruidValidForVibration(m_process.GetProcessId(),
enable);
m_hid_server->GetResourceManager()->EnableInput(m_process.GetProcessId(), enable);
}
}

View File

@ -13,9 +13,11 @@ namespace Service::HID {
class IHidServer;
}
namespace Service::AM {
namespace Service {
class Process;
}
namespace Service::AM {
class HidRegistration {
public:

View File

@ -0,0 +1,379 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "core/hle/service/am/lifecycle_manager.h"
namespace Service::AM {
LifecycleManager::LifecycleManager(Core::System& system, KernelHelpers::ServiceContext& context,
bool is_application)
: m_system_event(context), m_operation_mode_changed_system_event(context),
m_is_application(is_application) {}
LifecycleManager::~LifecycleManager() = default;
Event& LifecycleManager::GetSystemEvent() {
return m_system_event;
}
Event& LifecycleManager::GetOperationModeChangedSystemEvent() {
return m_operation_mode_changed_system_event;
}
void LifecycleManager::PushUnorderedMessage(AppletMessage message) {
m_unordered_messages.push_back(message);
this->SignalSystemEventIfNeeded();
}
AppletMessage LifecycleManager::PopMessageInOrderOfPriority() {
if (m_has_resume) {
m_has_resume = false;
return AppletMessage::Resume;
}
if (m_has_acknowledged_exit != m_has_requested_exit) {
m_has_acknowledged_exit = m_has_requested_exit;
return AppletMessage::Exit;
}
if (m_focus_state_changed_notification_enabled) {
if (!m_is_application) {
if (m_requested_focus_state != m_acknowledged_focus_state) {
m_acknowledged_focus_state = m_requested_focus_state;
switch (m_requested_focus_state) {
case FocusState::InFocus:
return AppletMessage::ChangeIntoForeground;
case FocusState::NotInFocus:
return AppletMessage::ChangeIntoBackground;
default:
ASSERT(false);
}
}
} else if (m_has_focus_state_changed) {
m_has_focus_state_changed = false;
return AppletMessage::FocusStateChanged;
}
}
if (m_has_requested_request_to_prepare_sleep != m_has_acknowledged_request_to_prepare_sleep) {
m_has_acknowledged_request_to_prepare_sleep = true;
return AppletMessage::RequestToPrepareSleep;
}
if (m_requested_request_to_display_state != m_acknowledged_request_to_display_state) {
m_acknowledged_request_to_display_state = m_requested_request_to_display_state;
return AppletMessage::RequestToDisplay;
}
if (m_has_operation_mode_changed) {
m_has_operation_mode_changed = false;
return AppletMessage::OperationModeChanged;
}
if (m_has_performance_mode_changed) {
m_has_performance_mode_changed = false;
return AppletMessage::PerformanceModeChanged;
}
if (m_has_sd_card_removed) {
m_has_sd_card_removed = false;
return AppletMessage::SdCardRemoved;
}
if (m_has_sleep_required_by_high_temperature) {
m_has_sleep_required_by_high_temperature = false;
return AppletMessage::SleepRequiredByHighTemperature;
}
if (m_has_sleep_required_by_low_battery) {
m_has_sleep_required_by_low_battery = false;
return AppletMessage::SleepRequiredByLowBattery;
}
if (m_has_auto_power_down) {
m_has_auto_power_down = false;
return AppletMessage::AutoPowerDown;
}
if (m_has_album_screen_shot_taken) {
m_has_album_screen_shot_taken = false;
return AppletMessage::AlbumScreenShotTaken;
}
if (m_has_album_recording_saved) {
m_has_album_recording_saved = false;
return AppletMessage::AlbumRecordingSaved;
}
if (!m_unordered_messages.empty()) {
const auto message = m_unordered_messages.front();
m_unordered_messages.pop_front();
return message;
}
return AppletMessage::None;
}
bool LifecycleManager::ShouldSignalSystemEvent() {
if (m_focus_state_changed_notification_enabled) {
if (!m_is_application) {
if (m_requested_focus_state != m_acknowledged_focus_state) {
return true;
}
} else if (m_has_focus_state_changed) {
return true;
}
}
return !m_unordered_messages.empty() || m_has_resume ||
(m_has_requested_exit != m_has_acknowledged_exit) ||
(m_has_requested_request_to_prepare_sleep !=
m_has_acknowledged_request_to_prepare_sleep) ||
m_has_operation_mode_changed || m_has_performance_mode_changed ||
m_has_sd_card_removed || m_has_sleep_required_by_high_temperature ||
m_has_sleep_required_by_low_battery || m_has_auto_power_down ||
(m_requested_request_to_display_state != m_acknowledged_request_to_display_state) ||
m_has_album_screen_shot_taken || m_has_album_recording_saved;
}
void LifecycleManager::OnOperationAndPerformanceModeChanged() {
if (m_operation_mode_changed_notification_enabled) {
m_has_operation_mode_changed = true;
}
if (m_performance_mode_changed_notification_enabled) {
m_has_performance_mode_changed = true;
}
m_operation_mode_changed_system_event.Signal();
this->SignalSystemEventIfNeeded();
}
void LifecycleManager::SignalSystemEventIfNeeded() {
// Check our cached value for the system event.
const bool applet_message_available = m_applet_message_available;
// If it's not current, we need to do an update, either clearing or signaling.
if (applet_message_available != this->ShouldSignalSystemEvent()) {
if (!applet_message_available) {
m_system_event.Signal();
m_applet_message_available = true;
} else {
m_system_event.Clear();
m_applet_message_available = false;
}
}
}
bool LifecycleManager::PopMessage(AppletMessage* out_message) {
const auto message = this->PopMessageInOrderOfPriority();
this->SignalSystemEventIfNeeded();
*out_message = message;
return message != AppletMessage::None;
}
void LifecycleManager::SetFocusHandlingMode(bool suspend) {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
case FocusHandlingMode::SuspendHomeSleep:
if (!suspend) {
// Disallow suspension.
m_focus_handling_mode = FocusHandlingMode::NoSuspend;
}
break;
case FocusHandlingMode::NoSuspend:
if (suspend) {
// Allow suspension temporally.
m_focus_handling_mode = FocusHandlingMode::SuspendHomeSleep;
}
break;
}
}
void LifecycleManager::SetOutOfFocusSuspendingEnabled(bool enabled) {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
if (!enabled) {
// Allow suspension temporally.
m_focus_handling_mode = FocusHandlingMode::SuspendHomeSleep;
}
break;
case FocusHandlingMode::SuspendHomeSleep:
case FocusHandlingMode::NoSuspend:
if (enabled) {
// Allow suspension.
m_focus_handling_mode = FocusHandlingMode::AlwaysSuspend;
}
break;
}
}
void LifecycleManager::RemoveForceResumeIfPossible() {
// If resume is not forced, we have nothing to do.
if (m_suspend_mode != SuspendMode::ForceResume) {
return;
}
// Check activity state.
// If we are already resumed, we can remove the forced state.
switch (m_activity_state) {
case ActivityState::ForegroundVisible:
case ActivityState::ForegroundObscured:
m_suspend_mode = SuspendMode::NoOverride;
return;
default:
break;
}
// Check focus handling mode.
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
case FocusHandlingMode::SuspendHomeSleep:
// If the applet allows suspension, we can remove the forced state.
m_suspend_mode = SuspendMode::NoOverride;
break;
case FocusHandlingMode::NoSuspend:
// If the applet is not an application, we can remove the forced state.
// Only applications can be forced to resume.
if (!m_is_application) {
m_suspend_mode = SuspendMode::NoOverride;
}
}
}
bool LifecycleManager::IsRunnable() const {
// If suspend is forced, return that.
if (m_forced_suspend) {
return false;
}
// Check suspend mode override.
switch (m_suspend_mode) {
case SuspendMode::NoOverride:
// Continue processing.
break;
case SuspendMode::ForceResume:
// The applet is runnable during forced resumption when its exit is requested.
return m_has_requested_exit;
case SuspendMode::ForceSuspend:
// The applet is never runnable during forced suspension.
return false;
}
// Always run if exit is requested.
if (m_has_requested_exit) {
return true;
}
if (m_activity_state == ActivityState::ForegroundVisible) {
// The applet is runnable now.
return true;
}
if (m_activity_state == ActivityState::ForegroundObscured) {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
// The applet is not runnable while running the applet.
return false;
case FocusHandlingMode::SuspendHomeSleep:
// The applet is runnable while running the applet.
return true;
case FocusHandlingMode::NoSuspend:
// The applet is always runnable.
return true;
}
}
// The activity is a suspended one.
// The applet should be suspended unless it has disabled suspension.
return m_focus_handling_mode == FocusHandlingMode::NoSuspend;
}
FocusState LifecycleManager::GetFocusStateWhileForegroundObscured() const {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
// The applet never learns it has lost focus.
return FocusState::InFocus;
case FocusHandlingMode::SuspendHomeSleep:
// The applet learns it has lost focus when launching a child applet.
return FocusState::NotInFocus;
case FocusHandlingMode::NoSuspend:
// The applet always learns it has lost focus.
return FocusState::NotInFocus;
default:
UNREACHABLE();
}
}
FocusState LifecycleManager::GetFocusStateWhileBackground(bool is_obscured) const {
switch (m_focus_handling_mode) {
case FocusHandlingMode::AlwaysSuspend:
// The applet never learns it has lost focus.
return FocusState::InFocus;
case FocusHandlingMode::SuspendHomeSleep:
// The applet learns it has lost focus when launching a child applet.
return is_obscured ? FocusState::NotInFocus : FocusState::InFocus;
case FocusHandlingMode::NoSuspend:
// The applet always learns it has lost focus.
return m_is_application ? FocusState::Background : FocusState::NotInFocus;
default:
UNREACHABLE();
}
}
bool LifecycleManager::UpdateRequestedFocusState() {
FocusState new_state{};
if (m_suspend_mode == SuspendMode::NoOverride) {
// With no forced suspend or resume, we take the focus state designated
// by the combination of the activity flag and the focus handling mode.
switch (m_activity_state) {
case ActivityState::ForegroundVisible:
new_state = FocusState::InFocus;
break;
case ActivityState::ForegroundObscured:
new_state = this->GetFocusStateWhileForegroundObscured();
break;
case ActivityState::BackgroundVisible:
new_state = this->GetFocusStateWhileBackground(false);
break;
case ActivityState::BackgroundObscured:
new_state = this->GetFocusStateWhileBackground(true);
break;
default:
UNREACHABLE();
}
} else {
// With forced suspend or resume, the applet is guaranteed to be background.
new_state = this->GetFocusStateWhileBackground(false);
}
if (new_state != m_requested_focus_state) {
// Mark the focus state as ready for update.
m_requested_focus_state = new_state;
// We changed the focus state.
return true;
}
// We didn't change the focus state.
return false;
}
} // namespace Service::AM

View File

@ -0,0 +1,183 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <list>
#include "core/hle/service/am/am_types.h"
#include "core/hle/service/os/event.h"
namespace Core {
class System;
}
namespace Service::AM {
enum class ActivityState : u32 {
ForegroundVisible = 0,
ForegroundObscured = 1,
BackgroundVisible = 2,
BackgroundObscured = 3,
};
enum class FocusHandlingMode : u32 {
AlwaysSuspend = 0,
SuspendHomeSleep = 1,
NoSuspend = 2,
};
enum class SuspendMode : u32 {
NoOverride = 0,
ForceResume = 1,
ForceSuspend = 2,
};
class LifecycleManager {
public:
explicit LifecycleManager(Core::System& system, KernelHelpers::ServiceContext& context,
bool is_application);
~LifecycleManager();
public:
Event& GetSystemEvent();
Event& GetOperationModeChangedSystemEvent();
public:
bool IsApplication() {
return m_is_application;
}
bool GetForcedSuspend() {
return m_forced_suspend;
}
bool GetExitRequested() {
return m_has_requested_exit;
}
ActivityState GetActivityState() {
return m_activity_state;
}
FocusState GetAndClearFocusState() {
m_acknowledged_focus_state = m_requested_focus_state;
return m_acknowledged_focus_state;
}
void SetFocusState(FocusState state) {
if (m_requested_focus_state != state) {
m_has_focus_state_changed = true;
}
m_requested_focus_state = state;
this->SignalSystemEventIfNeeded();
}
void RequestExit() {
m_has_requested_exit = true;
this->SignalSystemEventIfNeeded();
}
void RequestResumeNotification() {
// NOTE: this appears to be a bug in am.
// If an applet makes a concurrent request to receive resume notifications
// while it is being suspended, the first resume notification will be lost.
// This is not the case with other notification types.
if (m_resume_notification_enabled) {
m_has_resume = true;
}
}
void OnOperationAndPerformanceModeChanged();
public:
void SetFocusStateChangedNotificationEnabled(bool enabled) {
m_focus_state_changed_notification_enabled = enabled;
this->SignalSystemEventIfNeeded();
}
void SetOperationModeChangedNotificationEnabled(bool enabled) {
m_operation_mode_changed_notification_enabled = enabled;
this->SignalSystemEventIfNeeded();
}
void SetPerformanceModeChangedNotificationEnabled(bool enabled) {
m_performance_mode_changed_notification_enabled = enabled;
this->SignalSystemEventIfNeeded();
}
void SetResumeNotificationEnabled(bool enabled) {
m_resume_notification_enabled = enabled;
}
void SetActivityState(ActivityState state) {
m_activity_state = state;
}
void SetSuspendMode(SuspendMode mode) {
m_suspend_mode = mode;
}
void SetForcedSuspend(bool enabled) {
m_forced_suspend = enabled;
}
public:
void SetFocusHandlingMode(bool suspend);
void SetOutOfFocusSuspendingEnabled(bool enabled);
void RemoveForceResumeIfPossible();
bool IsRunnable() const;
bool UpdateRequestedFocusState();
void SignalSystemEventIfNeeded();
public:
void PushUnorderedMessage(AppletMessage message);
bool PopMessage(AppletMessage* out_message);
private:
FocusState GetFocusStateWhileForegroundObscured() const;
FocusState GetFocusStateWhileBackground(bool is_obscured) const;
private:
AppletMessage PopMessageInOrderOfPriority();
bool ShouldSignalSystemEvent();
private:
Event m_system_event;
Event m_operation_mode_changed_system_event;
std::list<AppletMessage> m_unordered_messages{};
bool m_is_application{};
bool m_focus_state_changed_notification_enabled{true};
bool m_operation_mode_changed_notification_enabled{true};
bool m_performance_mode_changed_notification_enabled{true};
bool m_resume_notification_enabled{};
bool m_requested_request_to_display_state{};
bool m_acknowledged_request_to_display_state{};
bool m_has_resume{};
bool m_has_focus_state_changed{true};
bool m_has_album_recording_saved{};
bool m_has_album_screen_shot_taken{};
bool m_has_auto_power_down{};
bool m_has_sleep_required_by_low_battery{};
bool m_has_sleep_required_by_high_temperature{};
bool m_has_sd_card_removed{};
bool m_has_performance_mode_changed{};
bool m_has_operation_mode_changed{};
bool m_has_requested_request_to_prepare_sleep{};
bool m_has_acknowledged_request_to_prepare_sleep{};
bool m_has_requested_exit{};
bool m_has_acknowledged_exit{};
bool m_applet_message_available{};
bool m_forced_suspend{};
FocusHandlingMode m_focus_handling_mode{FocusHandlingMode::SuspendHomeSleep};
ActivityState m_activity_state{ActivityState::ForegroundVisible};
SuspendMode m_suspend_mode{SuspendMode::NoOverride};
FocusState m_requested_focus_state{};
FocusState m_acknowledged_focus_state{};
};
} // namespace Service::AM

View File

@ -0,0 +1,130 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/patch_manager.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs_factory.h"
#include "core/hle/service/am/process_creation.h"
#include "core/hle/service/glue/glue_manager.h"
#include "core/hle/service/os/process.h"
#include "core/loader/loader.h"
namespace Service::AM {
namespace {
FileSys::StorageId GetStorageIdForFrontendSlot(
std::optional<FileSys::ContentProviderUnionSlot> slot) {
if (!slot.has_value()) {
return FileSys::StorageId::None;
}
switch (*slot) {
case FileSys::ContentProviderUnionSlot::UserNAND:
return FileSys::StorageId::NandUser;
case FileSys::ContentProviderUnionSlot::SysNAND:
return FileSys::StorageId::NandSystem;
case FileSys::ContentProviderUnionSlot::SDMC:
return FileSys::StorageId::SdCard;
case FileSys::ContentProviderUnionSlot::FrontendManual:
return FileSys::StorageId::Host;
default:
return FileSys::StorageId::None;
}
}
std::unique_ptr<Process> CreateProcessImpl(std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
// Get the appropriate loader to parse this NCA.
out_loader = Loader::GetLoader(system, file, program_id, program_index);
// Ensure we have a loader which can parse the NCA.
if (!out_loader) {
return nullptr;
}
// Try to load the process.
auto process = std::make_unique<Process>(system);
if (process->Initialize(*out_loader, out_load_result)) {
return process;
}
return nullptr;
}
} // Anonymous namespace
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation) {
// Attempt to load program NCA.
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
auto& storage = system.GetContentProviderUnion();
nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
// Ensure we retrieved a program NCA.
if (!nca_raw) {
return nullptr;
}
// Ensure we have a suitable version.
if (minimum_key_generation > 0) {
FileSys::NCA nca(nca_raw);
if (nca.GetStatus() == Loader::ResultStatus::Success &&
(nca.GetKeyGeneration() < minimum_key_generation ||
nca.GetKeyGeneration() > maximum_key_generation)) {
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
nca.GetKeyGeneration());
return nullptr;
}
}
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus status;
return CreateProcessImpl(loader, status, system, nca_raw, program_id, 0);
}
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index) {
auto process =
CreateProcessImpl(out_loader, out_load_result, system, file, program_id, program_index);
if (!process) {
return nullptr;
}
FileSys::NACP nacp;
if (out_loader->ReadControlData(nacp) == Loader::ResultStatus::Success) {
out_control = nacp.GetRawBytes();
} else {
out_control.resize(sizeof(FileSys::RawNACP));
}
auto& storage = system.GetContentProviderUnion();
Service::Glue::ApplicationLaunchProperty launch{};
launch.title_id = process->GetProgramId();
FileSys::PatchManager pm{launch.title_id, system.GetFileSystemController(), storage};
launch.version = pm.GetGameVersion().value_or(0);
// TODO(DarkLordZach): When FSController/Game Card Support is added, if
// current_process_game_card use correct StorageId
launch.base_game_storage_id = GetStorageIdForFrontendSlot(
storage.GetSlotForEntry(launch.title_id, FileSys::ContentRecordType::Program));
launch.update_storage_id = GetStorageIdForFrontendSlot(storage.GetSlotForEntry(
FileSys::GetUpdateTitleID(launch.title_id), FileSys::ContentRecordType::Program));
system.GetARPManager().Register(launch.title_id, launch, out_control);
return process;
}
} // 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 <memory>
#include <vector>
#include "common/common_types.h"
#include "core/file_sys/vfs/vfs_types.h"
namespace Core {
class System;
}
namespace Loader {
class AppLoader;
enum class ResultStatus : u16;
} // namespace Loader
namespace Service {
class Process;
}
namespace Service::AM {
std::unique_ptr<Process> CreateProcess(Core::System& system, u64 program_id,
u8 minimum_key_generation, u8 maximum_key_generation);
std::unique_ptr<Process> CreateApplicationProcess(std::vector<u8>& out_control,
std::unique_ptr<Loader::AppLoader>& out_loader,
Loader::ResultStatus& out_load_result,
Core::System& system, FileSys::VirtualFile file,
u64 program_id, u64 program_index);
} // namespace Service::AM

View File

@ -0,0 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_process.h"
#include "core/hle/service/am/process_holder.h"
#include "core/hle/service/os/process.h"
namespace Service::AM {
ProcessHolder::ProcessHolder(Applet& applet, Process& process)
: MultiWaitHolder(process.GetHandle()), m_applet(applet), m_process(process) {}
ProcessHolder::~ProcessHolder() = default;
} // 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/os/multi_wait_holder.h"
namespace Service {
class Process;
}
namespace Service::AM {
struct Applet;
class ProcessHolder : public MultiWaitHolder, public Common::IntrusiveListBaseNode<ProcessHolder> {
public:
explicit ProcessHolder(Applet& applet, Process& process);
~ProcessHolder();
Applet& GetApplet() const {
return m_applet;
}
Process& GetProcess() const {
return m_process;
}
private:
Applet& m_applet;
Process& m_process;
};
} // namespace Service::AM

View File

@ -6,12 +6,14 @@
#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/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_)
: ServiceFramework{system_, "appletAE"} {
IAllSystemAppletProxiesService::IAllSystemAppletProxiesService(Core::System& system_,
WindowSystem& window_system)
: ServiceFramework{system_, "appletAE"}, m_window_system{window_system} {
// clang-format off
static const FunctionInfo functions[] = {
{100, D<&IAllSystemAppletProxiesService::OpenSystemAppletProxy>, "OpenSystemAppletProxy"},
@ -36,8 +38,8 @@ Result IAllSystemAppletProxiesService::OpenSystemAppletProxy(
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());
*out_system_applet_proxy = std::make_shared<ISystemAppletProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -52,8 +54,8 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxy(
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());
*out_library_applet_proxy = std::make_shared<ILibraryAppletProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -73,7 +75,7 @@ Result IAllSystemAppletProxiesService::OpenLibraryAppletProxyOld(
std::shared_ptr<Applet> IAllSystemAppletProxiesService::GetAppletFromProcessId(
ProcessId process_id) {
return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
return m_window_system.GetByAppletResourceUserId(process_id.pid);
}
} // namespace Service::AM

View File

@ -14,11 +14,12 @@ struct Applet;
struct AppletAttribute;
class ILibraryAppletProxy;
class ISystemAppletProxy;
class WindowSystem;
class IAllSystemAppletProxiesService final
: public ServiceFramework<IAllSystemAppletProxiesService> {
public:
explicit IAllSystemAppletProxiesService(Core::System& system_);
explicit IAllSystemAppletProxiesService(Core::System& system_, WindowSystem& window_system);
~IAllSystemAppletProxiesService() override;
private:
@ -35,6 +36,8 @@ private:
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
WindowSystem& m_window_system;
};
} // namespace AM

View File

@ -19,7 +19,7 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
{21, nullptr, "TryPopFromAppletBoundChannel"},
{40, nullptr, "GetDisplayLogicalResolution"},
{42, nullptr, "SetDisplayMagnification"},
{50, nullptr, "SetHomeButtonDoubleClickEnabled"},
{50, D<&IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled>, "SetHomeButtonDoubleClickEnabled"},
{51, D<&IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled>, "GetHomeButtonDoubleClickEnabled"},
{52, nullptr, "IsHomeButtonShortPressedBlocked"},
{60, nullptr, "IsVrModeCurtainRequired"},
@ -40,6 +40,13 @@ IAppletCommonFunctions::IAppletCommonFunctions(Core::System& system_,
IAppletCommonFunctions::~IAppletCommonFunctions() = default;
Result IAppletCommonFunctions::SetHomeButtonDoubleClickEnabled(
bool home_button_double_click_enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called, home_button_double_click_enabled={}",
home_button_double_click_enabled);
R_SUCCEED();
}
Result IAppletCommonFunctions::GetHomeButtonDoubleClickEnabled(
Out<bool> out_home_button_double_click_enabled) {
LOG_WARNING(Service_AM, "(STUBBED) called");

View File

@ -16,6 +16,7 @@ public:
~IAppletCommonFunctions() override;
private:
Result SetHomeButtonDoubleClickEnabled(bool home_button_double_click_enabled);
Result GetHomeButtonDoubleClickEnabled(Out<bool> out_home_button_double_click_enabled);
Result SetCpuBoostRequestPriority(s32 priority);
Result GetCurrentApplicationId(Out<u64> out_application_id);

View File

@ -9,12 +9,16 @@
#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/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/glue/glue_manager.h"
namespace Service::AM {
IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet)
: ServiceFramework{system_, "IApplicationAccessor"}, m_applet(std::move(applet)) {
IApplicationAccessor::IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "IApplicationAccessor"}, m_window_system(window_system),
m_applet(std::move(applet)) {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationAccessor::GetAppletStateChangedEvent>, "GetAppletStateChangedEvent"},
@ -59,7 +63,15 @@ Result IApplicationAccessor::Start() {
Result IApplicationAccessor::RequestExit() {
LOG_INFO(Service_AM, "called");
m_applet->message_queue.RequestExit();
std::scoped_lock lk{m_applet->lock};
if (m_applet->exit_locked) {
m_applet->lifecycle_manager.RequestExit();
m_applet->UpdateSuspensionStateLocked(true);
} else {
m_applet->process->Terminate();
}
R_SUCCEED();
}
@ -71,13 +83,14 @@ Result IApplicationAccessor::Terminate() {
Result IApplicationAccessor::GetResult() {
LOG_INFO(Service_AM, "called");
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->terminate_result);
}
Result IApplicationAccessor::GetAppletStateChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_INFO(Service_AM, "called");
*out_event = m_applet->caller_applet_broker->GetStateChangedEvent().GetHandle();
*out_event = m_applet->state_changed_event.GetHandle();
R_SUCCEED();
}
@ -96,8 +109,15 @@ Result IApplicationAccessor::PushLaunchParameter(LaunchParameterKind kind,
Result IApplicationAccessor::GetApplicationControlProperty(
OutBuffer<BufferAttr_HipcMapAlias> out_control_property) {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_THROW(ResultUnknown);
LOG_INFO(Service_AM, "called");
std::vector<u8> nacp;
R_TRY(system.GetARPManager().GetControlProperty(&nacp, m_applet->program_id));
std::memcpy(out_control_property.data(), nacp.data(),
std::min(out_control_property.size(), nacp.size()));
R_SUCCEED();
}
Result IApplicationAccessor::SetUsers(bool enable,
@ -114,8 +134,9 @@ Result IApplicationAccessor::GetCurrentLibraryApplet(
}
Result IApplicationAccessor::RequestForApplicationToGetForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
R_THROW(ResultUnknown);
LOG_INFO(Service_AM, "called");
m_window_system.RequestApplicationToGetForeground();
R_SUCCEED();
}
Result IApplicationAccessor::CheckRightsEnvironmentAvailable(Out<bool> out_is_available) {

View File

@ -13,10 +13,12 @@ namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IStorage;
class WindowSystem;
class IApplicationAccessor final : public ServiceFramework<IApplicationAccessor> {
public:
explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet);
explicit IApplicationAccessor(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~IApplicationAccessor() override;
private:
@ -34,6 +36,7 @@ private:
Result GetNsRightsEnvironmentHandle(Out<u64> out_handle);
Result ReportApplicationExitTimeout();
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -1,17 +1,57 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#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/process_creation.h"
#include "core/hle/service/am/service/application_accessor.h"
#include "core/hle/service/am/service/application_creator.h"
#include "core/hle/service/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/loader/loader.h"
namespace Service::AM {
IApplicationCreator::IApplicationCreator(Core::System& system_)
: ServiceFramework{system_, "IApplicationCreator"} {
namespace {
Result CreateGuestApplication(SharedPointer<IApplicationAccessor>* out_application_accessor,
Core::System& system, WindowSystem& window_system, u64 program_id) {
FileSys::VirtualFile nca_raw{};
// Get the program NCA from storage.
auto& storage = system.GetContentProviderUnion();
nca_raw = storage.GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
// Ensure we retrieved a program NCA.
R_UNLESS(nca_raw != nullptr, ResultUnknown);
std::vector<u8> control;
std::unique_ptr<Loader::AppLoader> loader;
Loader::ResultStatus result;
auto process =
CreateApplicationProcess(control, loader, result, system, nca_raw, program_id, 0);
R_UNLESS(process != nullptr, ResultUnknown);
const auto applet = std::make_shared<Applet>(system, std::move(process), true);
applet->program_id = program_id;
applet->applet_id = AppletId::Application;
applet->type = AppletType::Application;
applet->library_applet_mode = LibraryAppletMode::AllForeground;
window_system.TrackApplet(applet, true);
*out_application_accessor =
std::make_shared<IApplicationAccessor>(system, applet, window_system);
R_SUCCEED();
}
} // namespace
IApplicationCreator::IApplicationCreator(Core::System& system_, WindowSystem& window_system)
: ServiceFramework{system_, "IApplicationCreator"}, m_window_system{window_system} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationCreator::CreateApplication>, "CreateApplication"},
@ -28,8 +68,9 @@ 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);
LOG_INFO(Service_NS, "called, application_id={:016X}", application_id);
R_RETURN(
CreateGuestApplication(out_application_accessor, system, m_window_system, application_id));
}
} // namespace Service::AM

View File

@ -10,14 +10,17 @@ namespace Service::AM {
class IApplicationAccessor;
struct Applet;
class WindowSystem;
class IApplicationCreator final : public ServiceFramework<IApplicationCreator> {
public:
explicit IApplicationCreator(Core::System& system_);
explicit IApplicationCreator(Core::System& system_, WindowSystem& window_system);
~IApplicationCreator() override;
private:
Result CreateApplication(Out<SharedPointer<IApplicationAccessor>>, u64 application_id);
WindowSystem& m_window_system;
};
} // namespace Service::AM

View File

@ -181,7 +181,8 @@ Result IApplicationFunctions::GetDesiredLanguage(Out<u64> out_language_code) {
}
Result IApplicationFunctions::SetTerminateResult(Result terminate_result) {
LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({}-{})", terminate_result.GetInnerValue(),
LOG_INFO(Service_AM, "(STUBBED) called, result={:#x} ({:04}-{:04})",
terminate_result.GetInnerValue(),
static_cast<u32>(terminate_result.GetModule()) + 2000,
terminate_result.GetDescription());

View File

@ -17,9 +17,9 @@
namespace Service::AM {
IApplicationProxy::IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process)
: ServiceFramework{system_, "IApplicationProxy"}, m_process{process}, m_applet{
std::move(applet)} {
Kernel::KProcess* process, WindowSystem& window_system)
: ServiceFramework{system_, "IApplicationProxy"},
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -70,7 +70,7 @@ Result IApplicationProxy::GetDebugFunctions(
Result IApplicationProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
R_SUCCEED();
}
@ -91,7 +91,8 @@ Result IApplicationProxy::GetCommonStateGetter(
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);
*out_library_applet_creator =
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
R_SUCCEED();
}

View File

@ -18,11 +18,12 @@ class ILibraryAppletCreator;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class WindowSystem;
class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
public:
explicit IApplicationProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process);
Kernel::KProcess* process, WindowSystem& window_system);
~IApplicationProxy();
private:
@ -40,6 +41,7 @@ private:
Out<SharedPointer<IApplicationFunctions>> out_application_functions);
private:
WindowSystem& m_window_system;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -6,12 +6,14 @@
#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/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
namespace Service::AM {
IApplicationProxyService::IApplicationProxyService(Core::System& system_)
: ServiceFramework{system_, "appletOE"} {
IApplicationProxyService::IApplicationProxyService(Core::System& system_,
WindowSystem& window_system)
: ServiceFramework{system_, "appletOE"}, m_window_system{window_system} {
static const FunctionInfo functions[] = {
{0, D<&IApplicationProxyService::OpenApplicationProxy>, "OpenApplicationProxy"},
};
@ -26,8 +28,8 @@ Result IApplicationProxyService::OpenApplicationProxy(
LOG_DEBUG(Service_AM, "called");
if (const auto applet = this->GetAppletFromProcessId(pid)) {
*out_application_proxy =
std::make_shared<IApplicationProxy>(system, applet, process_handle.Get());
*out_application_proxy = std::make_shared<IApplicationProxy>(
system, applet, process_handle.Get(), m_window_system);
R_SUCCEED();
} else {
UNIMPLEMENTED();
@ -36,7 +38,7 @@ Result IApplicationProxyService::OpenApplicationProxy(
}
std::shared_ptr<Applet> IApplicationProxyService::GetAppletFromProcessId(ProcessId process_id) {
return system.GetAppletManager().GetByAppletResourceUserId(process_id.pid);
return m_window_system.GetByAppletResourceUserId(process_id.pid);
}
} // namespace Service::AM

View File

@ -12,10 +12,11 @@ namespace AM {
struct Applet;
class IApplicationProxy;
class WindowSystem;
class IApplicationProxyService final : public ServiceFramework<IApplicationProxyService> {
public:
explicit IApplicationProxyService(Core::System& system_);
explicit IApplicationProxyService(Core::System& system_, WindowSystem& window_system);
~IApplicationProxyService() override;
private:
@ -24,6 +25,8 @@ private:
private:
std::shared_ptr<Applet> GetAppletFromProcessId(ProcessId pid);
WindowSystem& m_window_system;
};
} // namespace AM

View File

@ -80,15 +80,14 @@ ICommonStateGetter::~ICommonStateGetter() = default;
Result ICommonStateGetter::GetEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = &m_applet->message_queue.GetMessageReceiveEvent();
*out_event = m_applet->lifecycle_manager.GetSystemEvent().GetHandle();
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) {
if (!m_applet->lifecycle_manager.PopMessage(out_applet_message)) {
LOG_ERROR(Service_AM, "Tried to pop message but none was available!");
R_THROW(AM::ResultNoMessages);
}
@ -100,7 +99,7 @@ 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;
*out_focus_state = m_applet->lifecycle_manager.GetAndClearFocusState();
R_SUCCEED();
}
@ -137,7 +136,7 @@ Result ICommonStateGetter::GetWriterLockAccessorEx(
Result ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = &m_applet->message_queue.GetOperationModeChangedEvent();
*out_event = m_applet->lifecycle_manager.GetOperationModeChangedSystemEvent().GetHandle();
R_SUCCEED();
}
@ -260,9 +259,9 @@ Result ICommonStateGetter::GetAppletLaunchedHistory(
}
Result ICommonStateGetter::GetSettingsPlatformRegion(
Out<SysPlatformRegion> out_settings_platform_region) {
Out<Set::PlatformRegion> out_settings_platform_region) {
LOG_INFO(Service_AM, "called");
*out_settings_platform_region = SysPlatformRegion::Global;
*out_settings_platform_region = Set::PlatformRegion::Global;
R_SUCCEED();
}

View File

@ -8,6 +8,7 @@
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/pm/pm.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings_types.h"
namespace Kernel {
class KReadableEvent;
@ -50,7 +51,7 @@ private:
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 GetSettingsPlatformRegion(Out<Set::PlatformRegion> out_settings_platform_region);
Result SetRequestExitToLibraryAppletAtExecuteNextProgramEnabled();
void SetCpuBoostMode(HLERequestContext& ctx);

View File

@ -4,13 +4,16 @@
#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/am/window_system.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} {
IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "IHomeMenuFunctions"}, m_window_system{window_system},
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"},
@ -37,17 +40,20 @@ IHomeMenuFunctions::IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Ap
IHomeMenuFunctions::~IHomeMenuFunctions() = default;
Result IHomeMenuFunctions::RequestToGetForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
m_window_system.RequestHomeMenuToGetForeground();
R_SUCCEED();
}
Result IHomeMenuFunctions::LockForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
m_window_system.RequestLockHomeMenuIntoForeground();
R_SUCCEED();
}
Result IHomeMenuFunctions::UnlockForeground() {
LOG_WARNING(Service_AM, "(STUBBED) called");
LOG_INFO(Service_AM, "called");
m_window_system.RequestUnlockHomeMenuIntoForeground();
R_SUCCEED();
}

View File

@ -11,10 +11,12 @@
namespace Service::AM {
struct Applet;
class WindowSystem;
class IHomeMenuFunctions final : public ServiceFramework<IHomeMenuFunctions> {
public:
explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet);
explicit IHomeMenuFunctions(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~IHomeMenuFunctions() override;
private:
@ -26,6 +28,7 @@ private:
Result IsForceTerminateApplicationDisabledForDebug(
Out<bool> out_is_force_terminate_application_disabled_for_debug);
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
KernelHelpers::ServiceContext m_context;
Event m_pop_from_general_channel_event;

View File

@ -47,20 +47,21 @@ ILibraryAppletAccessor::~ILibraryAppletAccessor() = default;
Result ILibraryAppletAccessor::GetAppletStateChangedEvent(
OutCopyHandle<Kernel::KReadableEvent> out_event) {
LOG_DEBUG(Service_AM, "called");
*out_event = m_broker->GetStateChangedEvent().GetHandle();
*out_event = m_applet->state_changed_event.GetHandle();
R_SUCCEED();
}
Result ILibraryAppletAccessor::IsCompleted(Out<bool> out_is_completed) {
LOG_DEBUG(Service_AM, "called");
*out_is_completed = m_broker->IsCompleted();
std::scoped_lock lk{m_applet->lock};
*out_is_completed = m_applet->is_completed;
R_SUCCEED();
}
Result ILibraryAppletAccessor::GetResult(Out<Result> out_result) {
Result ILibraryAppletAccessor::GetResult() {
LOG_DEBUG(Service_AM, "called");
*out_result = m_applet->terminate_result;
R_SUCCEED();
std::scoped_lock lk{m_applet->lock};
R_RETURN(m_applet->terminate_result);
}
Result ILibraryAppletAccessor::PresetLibraryAppletGpuTimeSliceZero() {
@ -77,7 +78,10 @@ Result ILibraryAppletAccessor::Start() {
Result ILibraryAppletAccessor::RequestExit() {
LOG_DEBUG(Service_AM, "called");
m_applet->message_queue.RequestExit();
{
std::scoped_lock lk{m_applet->lock};
m_applet->lifecycle_manager.RequestExit();
}
FrontendRequestExit();
R_SUCCEED();
}

View File

@ -21,7 +21,7 @@ public:
private:
Result GetAppletStateChangedEvent(OutCopyHandle<Kernel::KReadableEvent> out_event);
Result IsCompleted(Out<bool> out_is_completed);
Result GetResult(Out<Result> out_result);
Result GetResult();
Result PresetLibraryAppletGpuTimeSliceZero();
Result Start();
Result RequestExit();

View File

@ -7,9 +7,11 @@
#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/process_creation.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/am/window_system.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/sm/sm.h"
@ -93,6 +95,7 @@ AppletProgramId AppletIdToProgramId(AppletId applet_id) {
}
std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
WindowSystem& window_system,
std::shared_ptr<Applet> caller_applet,
AppletId applet_id,
LibraryAppletMode mode) {
@ -110,53 +113,38 @@ std::shared_ptr<ILibraryAppletAccessor> CreateGuestApplet(Core::System& system,
Firmware1700 = 17,
};
auto process = std::make_unique<Process>(system);
if (!process->Initialize(program_id, Firmware1400, Firmware1700)) {
auto process = CreateProcess(system, program_id, Firmware1400, Firmware1700);
if (!process) {
// Couldn't initialize the guest process
return {};
}
const auto applet = std::make_shared<Applet>(system, std::move(process));
const auto applet = std::make_shared<Applet>(system, std::move(process), false);
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->display_layer_manager.SetWindowVisibility(false);
applet->message_queue.PushMessage(AppletMessage::ChangeIntoBackground);
break;
}
applet->window_visible = mode != LibraryAppletMode::AllForegroundInitiallyHidden;
auto broker = std::make_shared<AppletDataBroker>(system);
applet->caller_applet = caller_applet;
applet->caller_applet_broker = broker;
caller_applet->child_applets.push_back(applet);
system.GetAppletManager().InsertApplet(applet);
window_system.TrackApplet(applet, false);
return std::make_shared<ILibraryAppletAccessor>(system, broker, applet);
}
std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& system,
WindowSystem& window_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));
auto applet = std::make_shared<Applet>(system, std::move(process), false);
applet->program_id = program_id;
applet->applet_id = applet_id;
applet->type = AppletType::LibraryApplet;
@ -166,14 +154,19 @@ std::shared_ptr<ILibraryAppletAccessor> CreateFrontendApplet(Core::System& syste
applet->caller_applet = caller_applet;
applet->caller_applet_broker = storage;
applet->frontend = system.GetFrontendAppletHolder().GetApplet(applet, applet_id, mode);
caller_applet->child_applets.push_back(applet);
window_system.TrackApplet(applet, false);
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)} {
ILibraryAppletCreator::ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "ILibraryAppletCreator"},
m_window_system{window_system}, m_applet{std::move(applet)} {
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletCreator::CreateLibraryApplet>, "CreateLibraryApplet"},
{1, nullptr, "TerminateAllLibraryApplets"},
@ -195,10 +188,12 @@ Result ILibraryAppletCreator::CreateLibraryApplet(
std::shared_ptr<ILibraryAppletAccessor> library_applet;
if (ShouldCreateGuestApplet(applet_id)) {
library_applet = CreateGuestApplet(system, m_applet, applet_id, library_applet_mode);
library_applet =
CreateGuestApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
library_applet = CreateFrontendApplet(system, m_applet, applet_id, library_applet_mode);
library_applet =
CreateFrontendApplet(system, m_window_system, m_applet, applet_id, library_applet_mode);
}
if (!library_applet) {
LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", applet_id);

View File

@ -12,10 +12,12 @@ namespace Service::AM {
struct Applet;
class ILibraryAppletAccessor;
class IStorage;
class WindowSystem;
class ILibraryAppletCreator final : public ServiceFramework<ILibraryAppletCreator> {
public:
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet);
explicit ILibraryAppletCreator(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~ILibraryAppletCreator() override;
private:
@ -29,6 +31,7 @@ private:
Result CreateHandleStorage(Out<SharedPointer<IStorage>> out_storage, s64 size,
InCopyHandle<Kernel::KTransferMemory> transfer_memory_handle);
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -19,9 +19,9 @@
namespace Service::AM {
ILibraryAppletProxy::ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process)
: ServiceFramework{system_, "ILibraryAppletProxy"}, m_process{process}, m_applet{
std::move(applet)} {
Kernel::KProcess* process, WindowSystem& window_system)
: ServiceFramework{system_, "ILibraryAppletProxy"},
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ILibraryAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -75,7 +75,7 @@ Result ILibraryAppletProxy::GetDebugFunctions(
Result ILibraryAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
R_SUCCEED();
}
@ -96,7 +96,8 @@ Result ILibraryAppletProxy::GetCommonStateGetter(
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);
*out_library_applet_creator =
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
R_SUCCEED();
}
@ -118,7 +119,8 @@ Result ILibraryAppletProxy::GetAppletCommonFunctions(
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);
*out_home_menu_functions =
std::make_shared<IHomeMenuFunctions>(system, m_applet, m_window_system);
R_SUCCEED();
}

View File

@ -21,11 +21,12 @@ class ILibraryAppletSelfAccessor;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class WindowSystem;
class ILibraryAppletProxy final : public ServiceFramework<ILibraryAppletProxy> {
public:
explicit ILibraryAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process);
Kernel::KProcess* process, WindowSystem& window_system);
~ILibraryAppletProxy();
private:
@ -47,6 +48,7 @@ private:
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
WindowSystem& m_window_system;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -176,8 +176,7 @@ Result ILibraryAppletSelfAccessor::GetMainAppletStorageId(Out<FileSys::StorageId
Result ILibraryAppletSelfAccessor::ExitProcessAndReturn() {
LOG_INFO(Service_AM, "called");
system.GetAppletManager().TerminateAndRemoveApplet(m_applet->aruid);
m_broker->SignalCompletion();
m_applet->process->Terminate();
R_SUCCEED();
}

View File

@ -86,8 +86,7 @@ ISelfController::~ISelfController() {
Result ISelfController::Exit() {
LOG_DEBUG(Service_AM, "called");
// TODO
system.Exit();
m_applet->process->Terminate();
R_SUCCEED();
}
@ -95,7 +94,16 @@ Result ISelfController::Exit() {
Result ISelfController::LockExit() {
LOG_DEBUG(Service_AM, "called");
system.SetExitLocked(true);
std::scoped_lock lk{m_applet->lock};
if (m_applet->lifecycle_manager.GetExitRequested()) {
// With exit already requested, ignore and terminate immediately.
m_applet->process->Terminate();
} else {
// Otherwise, set exit lock state.
m_applet->exit_locked = true;
system.SetExitLocked(true);
}
R_SUCCEED();
}
@ -103,10 +111,13 @@ Result ISelfController::LockExit() {
Result ISelfController::UnlockExit() {
LOG_DEBUG(Service_AM, "called");
std::scoped_lock lk{m_applet->lock};
m_applet->exit_locked = false;
system.SetExitLocked(false);
if (system.GetExitRequested()) {
system.Exit();
if (m_applet->lifecycle_manager.GetExitRequested()) {
m_applet->process->Terminate();
}
R_SUCCEED();
@ -155,7 +166,7 @@ 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;
m_applet->lifecycle_manager.SetOperationModeChangedNotificationEnabled(enabled);
R_SUCCEED();
}
@ -164,17 +175,18 @@ 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;
m_applet->lifecycle_manager.SetPerformanceModeChangedNotificationEnabled(enabled);
R_SUCCEED();
}
Result ISelfController::SetFocusHandlingMode(bool notify, bool background, bool suspend) {
LOG_WARNING(Service_AM, "(STUBBED) called, notify={} background={} suspend={}", notify,
background, suspend);
LOG_INFO(Service_AM, "called, notify={} background={} suspend={}", notify, background, suspend);
std::scoped_lock lk{m_applet->lock};
m_applet->focus_handling_mode = {notify, background, suspend};
m_applet->lifecycle_manager.SetFocusStateChangedNotificationEnabled(notify);
m_applet->lifecycle_manager.SetFocusHandlingMode(suspend);
m_applet->UpdateSuspensionStateLocked(true);
R_SUCCEED();
}
@ -183,7 +195,7 @@ 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;
m_applet->lifecycle_manager.SetResumeNotificationEnabled(enabled);
R_SUCCEED();
}
@ -202,7 +214,8 @@ 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;
m_applet->lifecycle_manager.SetOutOfFocusSuspendingEnabled(enabled);
m_applet->UpdateSuspensionStateLocked(false);
R_SUCCEED();
}

View File

@ -19,9 +19,9 @@
namespace Service::AM {
ISystemAppletProxy::ISystemAppletProxy(Core::System& system_, std::shared_ptr<Applet> applet,
Kernel::KProcess* process)
: ServiceFramework{system_, "ISystemAppletProxy"}, m_process{process}, m_applet{
std::move(applet)} {
Kernel::KProcess* process, WindowSystem& window_system)
: ServiceFramework{system_, "ISystemAppletProxy"},
m_window_system{window_system}, m_process{process}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, D<&ISystemAppletProxy::GetCommonStateGetter>, "GetCommonStateGetter"},
@ -75,7 +75,7 @@ Result ISystemAppletProxy::GetDebugFunctions(
Result ISystemAppletProxy::GetWindowController(
Out<SharedPointer<IWindowController>> out_window_controller) {
LOG_DEBUG(Service_AM, "called");
*out_window_controller = std::make_shared<IWindowController>(system, m_applet);
*out_window_controller = std::make_shared<IWindowController>(system, m_applet, m_window_system);
R_SUCCEED();
}
@ -96,14 +96,15 @@ Result ISystemAppletProxy::GetCommonStateGetter(
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);
*out_library_applet_creator =
std::make_shared<ILibraryAppletCreator>(system, m_applet, m_window_system);
R_SUCCEED();
}
Result ISystemAppletProxy::GetApplicationCreator(
Out<SharedPointer<IApplicationCreator>> out_application_creator) {
LOG_DEBUG(Service_AM, "called");
*out_application_creator = std::make_shared<IApplicationCreator>(system);
*out_application_creator = std::make_shared<IApplicationCreator>(system, m_window_system);
R_SUCCEED();
}
@ -117,7 +118,8 @@ Result ISystemAppletProxy::GetAppletCommonFunctions(
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);
*out_home_menu_functions =
std::make_shared<IHomeMenuFunctions>(system, m_applet, m_window_system);
R_SUCCEED();
}

View File

@ -21,11 +21,12 @@ class ILibraryAppletCreator;
class IProcessWindingController;
class ISelfController;
class IWindowController;
class WindowSystem;
class ISystemAppletProxy final : public ServiceFramework<ISystemAppletProxy> {
public:
explicit ISystemAppletProxy(Core::System& system, std::shared_ptr<Applet> applet,
Kernel::KProcess* process);
Kernel::KProcess* process, WindowSystem& window_system);
~ISystemAppletProxy();
private:
@ -46,6 +47,7 @@ private:
Result GetGlobalStateController(
Out<SharedPointer<IGlobalStateController>> out_global_state_controller);
WindowSystem& m_window_system;
Kernel::KProcess* const m_process;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -4,12 +4,15 @@
#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/am/window_system.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)} {
IWindowController::IWindowController(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system)
: ServiceFramework{system_, "IWindowController"},
m_window_system{window_system}, m_applet{std::move(applet)} {
// clang-format off
static const FunctionInfo functions[] = {
{0, nullptr, "CreateWindow"},
@ -63,17 +66,9 @@ Result IWindowController::RejectToChangeIntoBackground() {
}
Result IWindowController::SetAppletWindowVisibility(bool visible) {
m_applet->display_layer_manager.SetWindowVisibility(visible);
m_applet->hid_registration.EnableAppletToGetInput(visible);
LOG_INFO(Service_AM, "called");
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);
m_window_system.RequestAppletVisibilityState(*m_applet, visible);
R_SUCCEED();
}

View File

@ -9,10 +9,12 @@
namespace Service::AM {
struct Applet;
class WindowSystem;
class IWindowController final : public ServiceFramework<IWindowController> {
public:
explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet);
explicit IWindowController(Core::System& system_, std::shared_ptr<Applet> applet,
WindowSystem& window_system);
~IWindowController() override;
private:
@ -24,6 +26,7 @@ private:
Result SetAppletWindowVisibility(bool visible);
Result SetAppletGpuTimeSlice(s64 time_slice);
WindowSystem& m_window_system;
const std::shared_ptr<Applet> m_applet;
};

View File

@ -0,0 +1,315 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/core.h"
#include "core/hle/service/am/am_results.h"
#include "core/hle/service/am/applet.h"
#include "core/hle/service/am/applet_manager.h"
#include "core/hle/service/am/event_observer.h"
#include "core/hle/service/am/window_system.h"
namespace Service::AM {
WindowSystem::WindowSystem(Core::System& system) : m_system(system) {}
WindowSystem::~WindowSystem() {
m_system.GetAppletManager().SetWindowSystem(nullptr);
}
void WindowSystem::SetEventObserver(EventObserver* observer) {
m_event_observer = observer;
m_system.GetAppletManager().SetWindowSystem(this);
}
void WindowSystem::Update() {
std::scoped_lock lk{m_lock};
// Loop through all applets and remove terminated applets.
this->PruneTerminatedAppletsLocked();
// If the home menu is being locked into the foreground, handle that.
if (this->LockHomeMenuIntoForegroundLocked()) {
return;
}
// Recursively update each applet root.
this->UpdateAppletStateLocked(m_home_menu, m_foreground_requested_applet == m_home_menu);
this->UpdateAppletStateLocked(m_application, m_foreground_requested_applet == m_application);
}
void WindowSystem::TrackApplet(std::shared_ptr<Applet> applet, bool is_application) {
std::scoped_lock lk{m_lock};
if (applet->applet_id == AppletId::QLaunch) {
ASSERT(m_home_menu == nullptr);
m_home_menu = applet.get();
} else if (is_application) {
ASSERT(m_application == nullptr);
m_application = applet.get();
}
m_event_observer->TrackAppletProcess(*applet);
m_applets.emplace(applet->aruid.pid, std::move(applet));
}
std::shared_ptr<Applet> WindowSystem::GetByAppletResourceUserId(u64 aruid) {
std::scoped_lock lk{m_lock};
const auto it = m_applets.find(aruid);
if (it == m_applets.end()) {
return nullptr;
}
return it->second;
}
std::shared_ptr<Applet> WindowSystem::GetMainApplet() {
std::scoped_lock lk{m_lock};
if (m_application) {
return m_applets.at(m_application->aruid.pid);
}
return nullptr;
}
void WindowSystem::RequestHomeMenuToGetForeground() {
{
std::scoped_lock lk{m_lock};
m_foreground_requested_applet = m_home_menu;
}
m_event_observer->RequestUpdate();
}
void WindowSystem::RequestApplicationToGetForeground() {
{
std::scoped_lock lk{m_lock};
m_foreground_requested_applet = m_application;
}
m_event_observer->RequestUpdate();
}
void WindowSystem::RequestLockHomeMenuIntoForeground() {
{
std::scoped_lock lk{m_lock};
m_home_menu_foreground_locked = true;
}
m_event_observer->RequestUpdate();
}
void WindowSystem::RequestUnlockHomeMenuIntoForeground() {
{
std::scoped_lock lk{m_lock};
m_home_menu_foreground_locked = false;
}
m_event_observer->RequestUpdate();
}
void WindowSystem::RequestAppletVisibilityState(Applet& applet, bool visible) {
{
std::scoped_lock lk{applet.lock};
applet.window_visible = visible;
}
m_event_observer->RequestUpdate();
}
void WindowSystem::OnOperationModeChanged() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
std::scoped_lock lk2{applet->lock};
applet->lifecycle_manager.OnOperationAndPerformanceModeChanged();
}
}
void WindowSystem::OnExitRequested() {
std::scoped_lock lk{m_lock};
for (const auto& [aruid, applet] : m_applets) {
std::scoped_lock lk2{applet->lock};
applet->lifecycle_manager.RequestExit();
}
}
void WindowSystem::OnHomeButtonPressed(ButtonPressDuration type) {
std::scoped_lock lk{m_lock};
// If we don't have a home menu, nothing to do.
if (!m_home_menu) {
return;
}
// Lock.
std::scoped_lock lk2{m_home_menu->lock};
// Send home button press event to home menu.
if (type == ButtonPressDuration::ShortPressing) {
m_home_menu->lifecycle_manager.PushUnorderedMessage(
AppletMessage::DetectShortPressingHomeButton);
}
}
void WindowSystem::PruneTerminatedAppletsLocked() {
for (auto it = m_applets.begin(); it != m_applets.end(); /* ... */) {
const auto& [aruid, applet] = *it;
std::scoped_lock lk{applet->lock};
if (!applet->process->IsTerminated()) {
// Not terminated.
it = std::next(it);
continue;
}
// Terminated, so ensure all child applets are terminated.
if (!applet->child_applets.empty()) {
this->TerminateChildAppletsLocked(applet.get());
// Not ready to unlink until all child applets are terminated.
it = std::next(it);
continue;
}
// Erase from caller applet's list of children.
if (auto caller_applet = applet->caller_applet.lock(); caller_applet) {
std::scoped_lock lk2{caller_applet->lock};
std::erase(caller_applet->child_applets, applet);
applet->caller_applet.reset();
// We don't need to update the activity state of the caller applet yet.
// It will be recalculated once we fall out of the termination handling path.
}
// If this applet was foreground, it no longer is.
if (applet.get() == m_foreground_requested_applet) {
m_foreground_requested_applet = nullptr;
}
// If this was the home menu, we should clean up.
if (applet.get() == m_home_menu) {
m_home_menu = nullptr;
m_foreground_requested_applet = m_application;
}
// If this was the application, we should try to switch to the home menu.
if (applet.get() == m_application) {
m_application = nullptr;
m_foreground_requested_applet = m_home_menu;
// If we have a home menu, send it the application exited message.
if (m_home_menu) {
m_home_menu->lifecycle_manager.PushUnorderedMessage(
AppletMessage::ApplicationExited);
}
}
// Finalize applet.
applet->OnProcessTerminatedLocked();
// Request update to ensure quiescence.
m_event_observer->RequestUpdate();
// Unlink and advance.
it = m_applets.erase(it);
}
// If the last applet has exited, exit the system.
if (m_applets.empty()) {
m_system.Exit();
}
}
bool WindowSystem::LockHomeMenuIntoForegroundLocked() {
// If the home menu is not locked into foreground, then there's nothing to do.
if (m_home_menu == nullptr || !m_home_menu_foreground_locked) {
m_home_menu_foreground_locked = false;
return false;
}
// Terminate any direct child applets of the home menu.
std::scoped_lock lk{m_home_menu->lock};
this->TerminateChildAppletsLocked(m_home_menu);
// When there are zero child applets left, we can proceed with the update.
if (m_home_menu->child_applets.empty()) {
m_home_menu->window_visible = true;
m_foreground_requested_applet = m_home_menu;
return false;
}
return true;
}
void WindowSystem::TerminateChildAppletsLocked(Applet* applet) {
auto child_applets = applet->child_applets;
applet->lock.unlock();
for (const auto& child_applet : child_applets) {
std::scoped_lock lk{child_applet->lock};
child_applet->process->Terminate();
child_applet->terminate_result = AM::ResultLibraryAppletTerminated;
}
applet->lock.lock();
}
void WindowSystem::UpdateAppletStateLocked(Applet* applet, bool is_foreground) {
// With no applet, we don't have anything to do.
if (!applet) {
return;
}
std::scoped_lock lk{applet->lock};
const bool inherited_foreground = applet->is_process_running && is_foreground;
const auto visible_state =
inherited_foreground ? ActivityState::ForegroundVisible : ActivityState::BackgroundVisible;
const auto obscured_state = inherited_foreground ? ActivityState::ForegroundObscured
: ActivityState::BackgroundObscured;
const bool has_obscuring_child_applets = [&] {
for (const auto& child_applet : applet->child_applets) {
std::scoped_lock lk2{child_applet->lock};
const auto mode = child_applet->library_applet_mode;
if (child_applet->is_process_running && child_applet->window_visible &&
(mode == LibraryAppletMode::AllForeground ||
mode == LibraryAppletMode::AllForegroundInitiallyHidden)) {
return true;
}
}
return false;
}();
// Update visibility state.
applet->display_layer_manager.SetWindowVisibility(is_foreground && applet->window_visible);
// Update interactibility state.
applet->SetInteractibleLocked(is_foreground && applet->window_visible);
// Update focus state and suspension.
const bool is_obscured = has_obscuring_child_applets || !applet->window_visible;
const auto state = applet->lifecycle_manager.GetActivityState();
if (is_obscured && state != obscured_state) {
// Set obscured state.
applet->lifecycle_manager.SetActivityState(obscured_state);
applet->UpdateSuspensionStateLocked(true);
} else if (!is_obscured && state != visible_state) {
// Set visible state.
applet->lifecycle_manager.SetActivityState(visible_state);
applet->UpdateSuspensionStateLocked(true);
}
// Recurse into child applets.
for (const auto& child_applet : applet->child_applets) {
this->UpdateAppletStateLocked(child_applet.get(), is_foreground);
}
}
} // 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 <map>
#include <memory>
#include <mutex>
#include "common/common_types.h"
namespace Core {
class System;
}
namespace Service::AM {
struct Applet;
class EventObserver;
enum class ButtonPressDuration {
ShortPressing,
MiddlePressing,
LongPressing,
};
class WindowSystem {
public:
explicit WindowSystem(Core::System& system);
~WindowSystem();
public:
void SetEventObserver(EventObserver* event_observer);
void Update();
public:
void TrackApplet(std::shared_ptr<Applet> applet, bool is_application);
std::shared_ptr<Applet> GetByAppletResourceUserId(u64 aruid);
std::shared_ptr<Applet> GetMainApplet();
public:
void RequestHomeMenuToGetForeground();
void RequestApplicationToGetForeground();
void RequestLockHomeMenuIntoForeground();
void RequestUnlockHomeMenuIntoForeground();
void RequestAppletVisibilityState(Applet& applet, bool visible);
public:
void OnOperationModeChanged();
void OnExitRequested();
void OnHomeButtonPressed(ButtonPressDuration type);
void OnCaptureButtonPressed(ButtonPressDuration type) {}
void OnPowerButtonPressed(ButtonPressDuration type) {}
private:
void PruneTerminatedAppletsLocked();
bool LockHomeMenuIntoForegroundLocked();
void TerminateChildAppletsLocked(Applet* applet);
void UpdateAppletStateLocked(Applet* applet, bool is_foreground);
private:
// System reference.
Core::System& m_system;
// Event observer.
EventObserver* m_event_observer{};
// Lock.
std::mutex m_lock{};
// Home menu state.
bool m_home_menu_foreground_locked{};
Applet* m_foreground_requested_applet{};
// Foreground roots.
Applet* m_home_menu{};
Applet* m_application{};
// Applet map by aruid.
std::map<u64, std::shared_ptr<Applet>> m_applets{};
};
} // namespace Service::AM

View File

@ -18,7 +18,7 @@ public:
// clang-format off
static const FunctionInfo functions[] = {
{0, C<&ErrorReportContext::SubmitContext>, "SubmitContext"},
{1, nullptr, "CreateReportV0"},
{1, C<&ErrorReportContext::CreateReportV0>, "CreateReportV0"},
{2, nullptr, "SetInitialLaunchSettingsCompletionTime"},
{3, nullptr, "ClearInitialLaunchSettingsCompletionTime"},
{4, nullptr, "UpdatePowerOnTime"},
@ -28,7 +28,8 @@ public:
{8, nullptr, "ClearApplicationLaunchTime"},
{9, nullptr, "SubmitAttachment"},
{10, nullptr, "CreateReportWithAttachments"},
{11, nullptr, "CreateReport"},
{11, C<&ErrorReportContext::CreateReportV1>, "CreateReportV1"},
{12, C<&ErrorReportContext::CreateReport>, "CreateReport"},
{20, nullptr, "RegisterRunningApplet"},
{21, nullptr, "UnregisterRunningApplet"},
{22, nullptr, "UpdateAppletSuspendedDuration"},
@ -40,10 +41,37 @@ public:
}
private:
Result SubmitContext(InBuffer<BufferAttr_HipcMapAlias> buffer_a,
InBuffer<BufferAttr_HipcMapAlias> buffer_b) {
LOG_WARNING(Service_SET, "(STUBBED) called, buffer_a_size={}, buffer_b_size={}",
buffer_a.size(), buffer_b.size());
Result SubmitContext(InBuffer<BufferAttr_HipcMapAlias> context_entry,
InBuffer<BufferAttr_HipcMapAlias> field_list) {
LOG_WARNING(Service_SET, "(STUBBED) called, context_entry_size={}, field_list_size={}",
context_entry.size(), field_list.size());
R_SUCCEED();
}
Result CreateReportV0(u32 report_type, InBuffer<BufferAttr_HipcMapAlias> context_entry,
InBuffer<BufferAttr_HipcMapAlias> report_list,
InBuffer<BufferAttr_HipcMapAlias> report_meta_data) {
LOG_WARNING(Service_SET, "(STUBBED) called, report_type={:#x}", report_type);
R_SUCCEED();
}
Result CreateReportV1(u32 report_type, u32 unknown,
InBuffer<BufferAttr_HipcMapAlias> context_entry,
InBuffer<BufferAttr_HipcMapAlias> report_list,
InBuffer<BufferAttr_HipcMapAlias> report_meta_data) {
LOG_WARNING(Service_SET, "(STUBBED) called, report_type={:#x}, unknown={:#x}", report_type,
unknown);
R_SUCCEED();
}
Result CreateReport(u32 report_type, u32 unknown, u32 create_report_option_flag,
InBuffer<BufferAttr_HipcMapAlias> context_entry,
InBuffer<BufferAttr_HipcMapAlias> report_list,
InBuffer<BufferAttr_HipcMapAlias> report_meta_data) {
LOG_WARNING(
Service_SET,
"(STUBBED) called, report_type={:#x}, unknown={:#x}, create_report_option_flag={:#x}",
report_type, unknown, create_report_option_flag);
R_SUCCEED();
}
};

View File

@ -71,7 +71,7 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{28, nullptr, "DeleteSaveDataFileSystemBySaveDataAttribute"},
{30, nullptr, "OpenGameCardStorage"},
{31, nullptr, "OpenGameCardFileSystem"},
{32, nullptr, "ExtendSaveDataFileSystem"},
{32, D<&FSP_SRV::ExtendSaveDataFileSystem>, "ExtendSaveDataFileSystem"},
{33, nullptr, "DeleteCacheStorage"},
{34, D<&FSP_SRV::GetCacheStorageSize>, "GetCacheStorageSize"},
{35, nullptr, "CreateSaveDataFileSystemByHashSalt"},
@ -79,9 +79,9 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{51, D<&FSP_SRV::OpenSaveDataFileSystem>, "OpenSaveDataFileSystem"},
{52, D<&FSP_SRV::OpenSaveDataFileSystemBySystemSaveDataId>, "OpenSaveDataFileSystemBySystemSaveDataId"},
{53, D<&FSP_SRV::OpenReadOnlySaveDataFileSystem>, "OpenReadOnlySaveDataFileSystem"},
{57, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
{58, nullptr, "ReadSaveDataFileSystemExtraData"},
{59, nullptr, "WriteSaveDataFileSystemExtraData"},
{57, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataBySaveDataSpaceId>, "ReadSaveDataFileSystemExtraDataBySaveDataSpaceId"},
{58, D<&FSP_SRV::ReadSaveDataFileSystemExtraData>, "ReadSaveDataFileSystemExtraData"},
{59, D<&FSP_SRV::WriteSaveDataFileSystemExtraData>, "WriteSaveDataFileSystemExtraData"},
{60, nullptr, "OpenSaveDataInfoReader"},
{61, D<&FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId>, "OpenSaveDataInfoReaderBySaveDataSpaceId"},
{62, D<&FSP_SRV::OpenSaveDataInfoReaderOnlyCacheStorage>, "OpenSaveDataInfoReaderOnlyCacheStorage"},
@ -90,8 +90,8 @@ FSP_SRV::FSP_SRV(Core::System& system_)
{66, nullptr, "WriteSaveDataFileSystemExtraData2"},
{67, D<&FSP_SRV::FindSaveDataWithFilter>, "FindSaveDataWithFilter"},
{68, nullptr, "OpenSaveDataInfoReaderBySaveDataFilter"},
{69, nullptr, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
{70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataBySaveDataAttribute"},
{69, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataBySaveDataAttribute"},
{70, D<&FSP_SRV::WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
{71, D<&FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute>, "ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute"},
{80, nullptr, "OpenSaveDataMetaFile"},
{81, nullptr, "OpenSaveDataTransferManager"},
@ -317,9 +317,23 @@ Result FSP_SRV::FindSaveDataWithFilter(Out<s64> out_count,
R_THROW(FileSys::ResultTargetNotFound);
}
Result FSP_SRV::WriteSaveDataFileSystemExtraDataBySaveDataAttribute() {
LOG_WARNING(Service_FS, "(STUBBED) called.");
Result FSP_SRV::WriteSaveDataFileSystemExtraData(InBuffer<BufferAttr_HipcMapAlias> buffer,
FileSys::SaveDataSpaceId space_id,
u64 save_data_id) {
LOG_WARNING(Service_FS, "(STUBBED) called, space_id={}, save_data_id={:016X}", space_id,
save_data_id);
R_SUCCEED();
}
Result FSP_SRV::WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
InBuffer<BufferAttr_HipcMapAlias> buffer, InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute) {
LOG_WARNING(Service_FS,
"(STUBBED) called, space_id={}, attribute.program_id={:016X}\n"
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
"attribute.type={}, attribute.rank={}, attribute.index={}",
space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
R_SUCCEED();
}
@ -341,6 +355,38 @@ Result FSP_SRV::ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
R_SUCCEED();
}
Result FSP_SRV::ReadSaveDataFileSystemExtraData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
u64 save_data_id) {
// Stub, backend needs an impl to read/write the SaveDataExtraData
LOG_WARNING(Service_FS, "(STUBBED) called, save_data_id={:016X}", save_data_id);
std::memset(out_buffer.data(), 0, out_buffer.size());
R_SUCCEED();
}
Result FSP_SRV::ReadSaveDataFileSystemExtraDataBySaveDataAttribute(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, FileSys::SaveDataSpaceId space_id,
FileSys::SaveDataAttribute attribute) {
// Stub, backend needs an impl to read/write the SaveDataExtraData
LOG_WARNING(Service_FS,
"(STUBBED) called, space_id={}, attribute.program_id={:016X}\n"
"attribute.user_id={:016X}{:016X}, attribute.save_id={:016X}\n"
"attribute.type={}, attribute.rank={}, attribute.index={}",
space_id, attribute.program_id, attribute.user_id[1], attribute.user_id[0],
attribute.system_save_data_id, attribute.type, attribute.rank, attribute.index);
std::memset(out_buffer.data(), 0, out_buffer.size());
R_SUCCEED();
}
Result FSP_SRV::ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, FileSys::SaveDataSpaceId space_id,
u64 save_data_id) {
// Stub, backend needs an impl to read/write the SaveDataExtraData
LOG_WARNING(Service_FS, "(STUBBED) called, space_id={}, save_data_id={:016X}", space_id,
save_data_id);
std::memset(out_buffer.data(), 0, out_buffer.size());
R_SUCCEED();
}
Result FSP_SRV::OpenSaveDataTransferProhibiter(
OutInterface<ISaveDataTransferProhibiter> out_prohibiter, u64 id) {
LOG_WARNING(Service_FS, "(STUBBED) called, id={:016X}", id);
@ -476,6 +522,16 @@ Result FSP_SRV::FlushAccessLogOnSdCard() {
R_SUCCEED();
}
Result FSP_SRV::ExtendSaveDataFileSystem(FileSys::SaveDataSpaceId space_id, u64 save_data_id,
s64 available_size, s64 journal_size) {
// We don't have an index of save data ids, so we can't implement this.
LOG_WARNING(Service_FS,
"(STUBBED) called, space_id={}, save_data_id={:016X}, available_size={:#x}, "
"journal_size={:#x}",
space_id, save_data_id, available_size, journal_size);
R_SUCCEED();
}
Result FSP_SRV::GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size) {
LOG_WARNING(Service_FS, "(STUBBED) called with index={}", index);

View File

@ -70,7 +70,19 @@ private:
Result FindSaveDataWithFilter(Out<s64> out_count, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
FileSys::SaveDataSpaceId space_id,
FileSys::SaveDataFilter filter);
Result WriteSaveDataFileSystemExtraDataBySaveDataAttribute();
Result WriteSaveDataFileSystemExtraData(InBuffer<BufferAttr_HipcMapAlias> buffer,
FileSys::SaveDataSpaceId space_id, u64 save_data_id);
Result WriteSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
InBuffer<BufferAttr_HipcMapAlias> buffer, InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute);
Result ReadSaveDataFileSystemExtraData(OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
u64 save_data_id);
Result ReadSaveDataFileSystemExtraDataBySaveDataAttribute(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, FileSys::SaveDataSpaceId space_id,
FileSys::SaveDataAttribute attribute);
Result ReadSaveDataFileSystemExtraDataBySaveDataSpaceId(
OutBuffer<BufferAttr_HipcMapAlias> out_buffer, FileSys::SaveDataSpaceId space_id,
u64 save_data_id);
Result ReadSaveDataFileSystemExtraDataWithMaskBySaveDataAttribute(
FileSys::SaveDataSpaceId space_id, FileSys::SaveDataAttribute attribute,
InBuffer<BufferAttr_HipcMapAlias> mask_buffer,
@ -91,6 +103,8 @@ private:
Result GetProgramIndexForAccessLog(Out<AccessLogVersion> out_access_log_version,
Out<u32> out_access_log_program_index);
Result OpenMultiCommitManager(OutInterface<IMultiCommitManager> out_interface);
Result ExtendSaveDataFileSystem(FileSys::SaveDataSpaceId space_id, u64 save_data_id,
s64 available_size, s64 journal_size);
Result GetCacheStorageSize(s32 index, Out<s64> out_data_size, Out<s64> out_journal_size);
FileSystemController& fsc;

View File

@ -0,0 +1,53 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common/logging/log.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/hid/active_vibration_device_list.h"
#include "hid_core/hid_result.h"
#include "hid_core/hid_util.h"
#include "hid_core/resource_manager.h"
#include "hid_core/resources/vibration/vibration_device.h"
namespace Service::HID {
IActiveVibrationDeviceList::IActiveVibrationDeviceList(Core::System& system_,
std::shared_ptr<ResourceManager> resource)
: ServiceFramework{system_, "IActiveVibrationDeviceList"}, resource_manager(resource) {
// clang-format off
static const FunctionInfo functions[] = {
{0, C<&IActiveVibrationDeviceList::ActivateVibrationDevice>, "ActivateVibrationDevice"},
};
// clang-format on
RegisterHandlers(functions);
}
IActiveVibrationDeviceList::~IActiveVibrationDeviceList() = default;
Result IActiveVibrationDeviceList::ActivateVibrationDevice(
Core::HID::VibrationDeviceHandle vibration_device_handle) {
LOG_DEBUG(Service_HID, "called, npad_type={}, npad_id={}, device_index={}",
vibration_device_handle.npad_type, vibration_device_handle.npad_id,
vibration_device_handle.device_index);
std::scoped_lock lock{mutex};
R_TRY(IsVibrationHandleValid(vibration_device_handle));
for (std::size_t i = 0; i < list_size; i++) {
if (vibration_device_handle.device_index == vibration_device_list[i].device_index &&
vibration_device_handle.npad_id == vibration_device_list[i].npad_id &&
vibration_device_handle.npad_type == vibration_device_list[i].npad_type) {
R_SUCCEED();
}
}
R_UNLESS(list_size < MaxVibrationDevicesHandles, ResultVibrationDeviceIndexOutOfRange);
R_TRY(resource_manager->GetVibrationDevice(vibration_device_handle)->Activate());
vibration_device_list[list_size++] = vibration_device_handle;
R_SUCCEED();
}
} // namespace Service::HID

View File

@ -0,0 +1,39 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <array>
#include <memory>
#include <mutex>
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
namespace Core {
class System;
}
namespace Service::HID {
class ResourceManager;
class IActiveVibrationDeviceList final : public ServiceFramework<IActiveVibrationDeviceList> {
public:
explicit IActiveVibrationDeviceList(Core::System& system_,
std::shared_ptr<ResourceManager> resource);
~IActiveVibrationDeviceList() override;
private:
static constexpr std::size_t MaxVibrationDevicesHandles{0x100};
Result ActivateVibrationDevice(Core::HID::VibrationDeviceHandle vibration_device_handle);
mutable std::mutex mutex;
std::size_t list_size{};
std::array<Core::HID::VibrationDeviceHandle, MaxVibrationDevicesHandles>
vibration_device_list{};
std::shared_ptr<ResourceManager> resource_manager;
};
} // namespace Service::HID

View File

@ -0,0 +1,34 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#include "common/logging/log.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/hid/applet_resource.h"
#include "hid_core/resource_manager.h"
namespace Service::HID {
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
u64 applet_resource_user_id)
: ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id},
resource_manager{resource} {
static const FunctionInfo functions[] = {
{0, C<&IAppletResource::GetSharedMemoryHandle>, "GetSharedMemoryHandle"},
};
RegisterHandlers(functions);
}
IAppletResource::~IAppletResource() {
resource_manager->FreeAppletResourceId(aruid);
}
Result IAppletResource::GetSharedMemoryHandle(
OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_handle) {
const auto result = resource_manager->GetSharedMemoryHandle(out_shared_memory_handle, aruid);
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw);
R_RETURN(result);
}
} // namespace Service::HID

View File

@ -0,0 +1,36 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-3.0-or-later
#pragma once
#include <memory>
#include "common/common_types.h"
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
namespace Core {
class System;
}
namespace Kernel {
class KSharedMemory;
}
namespace Service::HID {
class ResourceManager;
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
u64 applet_resource_user_id);
~IAppletResource() override;
private:
Result GetSharedMemoryHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_handle);
u64 aruid{};
std::shared_ptr<ResourceManager> resource_manager;
};
} // namespace Service::HID

View File

@ -23,11 +23,7 @@ void LoopProcess(Core::System& system) {
std::shared_ptr<ResourceManager> resource_manager =
std::make_shared<ResourceManager>(system, firmware_settings);
// TODO: Remove this hack when am is emulated properly.
resource_manager->Initialize();
resource_manager->RegisterAppletResourceUserId(system.ApplicationProcess()->GetProcessId(),
true);
resource_manager->SetAruidValidForVibration(system.ApplicationProcess()->GetProcessId(), true);
server_manager->RegisterNamedService(
"hid", std::make_shared<IHidServer>(system, resource_manager, firmware_settings));

File diff suppressed because it is too large Load Diff

View File

@ -6,12 +6,20 @@
#include "core/hle/service/cmif_types.h"
#include "core/hle/service/service.h"
#include "hid_core/hid_types.h"
#include "hid_core/resources/npad/npad_types.h"
#include "hid_core/resources/palma/palma.h"
namespace Core {
class System;
}
namespace Kernel {
class KReadableEvent;
}
namespace Service::HID {
class IActiveVibrationDeviceList;
class IAppletResource;
class ResourceManager;
class HidFirmwareSettings;
@ -24,128 +32,232 @@ public:
std::shared_ptr<ResourceManager> GetResourceManager();
private:
void CreateAppletResource(HLERequestContext& ctx);
void ActivateDebugPad(HLERequestContext& ctx);
void ActivateTouchScreen(HLERequestContext& ctx);
void ActivateMouse(HLERequestContext& ctx);
void ActivateKeyboard(HLERequestContext& ctx);
void SendKeyboardLockKeyEvent(HLERequestContext& ctx);
void AcquireXpadIdEventHandle(HLERequestContext& ctx);
void ReleaseXpadIdEventHandle(HLERequestContext& ctx);
void ActivateXpad(HLERequestContext& ctx);
void GetXpadIds(HLERequestContext& ctx);
void ActivateJoyXpad(HLERequestContext& ctx);
void GetJoyXpadLifoHandle(HLERequestContext& ctx);
void GetJoyXpadIds(HLERequestContext& ctx);
void ActivateSixAxisSensor(HLERequestContext& ctx);
void DeactivateSixAxisSensor(HLERequestContext& ctx);
void GetSixAxisSensorLifoHandle(HLERequestContext& ctx);
void ActivateJoySixAxisSensor(HLERequestContext& ctx);
void DeactivateJoySixAxisSensor(HLERequestContext& ctx);
void GetJoySixAxisSensorLifoHandle(HLERequestContext& ctx);
void StartSixAxisSensor(HLERequestContext& ctx);
void StopSixAxisSensor(HLERequestContext& ctx);
void IsSixAxisSensorFusionEnabled(HLERequestContext& ctx);
void EnableSixAxisSensorFusion(HLERequestContext& ctx);
void SetSixAxisSensorFusionParameters(HLERequestContext& ctx);
void GetSixAxisSensorFusionParameters(HLERequestContext& ctx);
void ResetSixAxisSensorFusionParameters(HLERequestContext& ctx);
void SetGyroscopeZeroDriftMode(HLERequestContext& ctx);
void GetGyroscopeZeroDriftMode(HLERequestContext& ctx);
void ResetGyroscopeZeroDriftMode(HLERequestContext& ctx);
void IsSixAxisSensorAtRest(HLERequestContext& ctx);
void IsFirmwareUpdateAvailableForSixAxisSensor(HLERequestContext& ctx);
void EnableSixAxisSensorUnalteredPassthrough(HLERequestContext& ctx);
void IsSixAxisSensorUnalteredPassthroughEnabled(HLERequestContext& ctx);
void LoadSixAxisSensorCalibrationParameter(HLERequestContext& ctx);
void GetSixAxisSensorIcInformation(HLERequestContext& ctx);
void ResetIsSixAxisSensorDeviceNewlyAssigned(HLERequestContext& ctx);
void ActivateGesture(HLERequestContext& ctx);
void SetSupportedNpadStyleSet(HLERequestContext& ctx);
void GetSupportedNpadStyleSet(HLERequestContext& ctx);
void SetSupportedNpadIdType(HLERequestContext& ctx);
void ActivateNpad(HLERequestContext& ctx);
void DeactivateNpad(HLERequestContext& ctx);
void AcquireNpadStyleSetUpdateEventHandle(HLERequestContext& ctx);
void DisconnectNpad(HLERequestContext& ctx);
Result CreateAppletResource(OutInterface<IAppletResource> out_applet_resource,
ClientAppletResourceUserId aruid);
Result ActivateDebugPad(ClientAppletResourceUserId aruid);
Result ActivateTouchScreen(ClientAppletResourceUserId aruid);
Result ActivateMouse(ClientAppletResourceUserId aruid);
Result ActivateKeyboard(ClientAppletResourceUserId aruid);
Result SendKeyboardLockKeyEvent(u32 flags);
Result AcquireXpadIdEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event,
ClientAppletResourceUserId aruid);
Result ReleaseXpadIdEventHandle(ClientAppletResourceUserId aruid);
Result ActivateXpad(u32 basic_xpad_id, ClientAppletResourceUserId aruid);
Result GetXpadIds(Out<u64> out_count, OutArray<u32, BufferAttr_HipcPointer> out_basic_pad_ids);
Result ActivateJoyXpad(u32 joy_xpad_id);
Result GetJoyXpadLifoHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_handle,
u32 joy_xpad_id);
Result GetJoyXpadIds(Out<s64> out_basic_xpad_id_count);
Result ActivateSixAxisSensor(u32 joy_xpad_id);
Result DeactivateSixAxisSensor(u32 joy_xpad_id);
Result GetSixAxisSensorLifoHandle(OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_handle,
u32 joy_xpad_id);
Result ActivateJoySixAxisSensor(u32 joy_xpad_id);
Result DeactivateJoySixAxisSensor(u32 joy_xpad_id);
Result GetJoySixAxisSensorLifoHandle(
OutCopyHandle<Kernel::KSharedMemory> out_shared_memory_handle, u32 joy_xpad_id);
Result StartSixAxisSensor(Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result StopSixAxisSensor(Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result IsSixAxisSensorFusionEnabled(Out<bool> out_is_enabled,
Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result EnableSixAxisSensorFusion(bool is_enabled, Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result SetSixAxisSensorFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle,
Core::HID::SixAxisSensorFusionParameters sixaxis_fusion,
ClientAppletResourceUserId aruid);
Result GetSixAxisSensorFusionParameters(
Out<Core::HID::SixAxisSensorFusionParameters> out_fusion_parameters,
Core::HID::SixAxisSensorHandle sixaxis_handle, ClientAppletResourceUserId aruid);
Result ResetSixAxisSensorFusionParameters(Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
Core::HID::GyroscopeZeroDriftMode drift_mode,
ClientAppletResourceUserId aruid);
Result GetGyroscopeZeroDriftMode(Out<Core::HID::GyroscopeZeroDriftMode> out_drift_mode,
Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result ResetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result IsSixAxisSensorAtRest(Out<bool> out_is_at_rest,
Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result IsFirmwareUpdateAvailableForSixAxisSensor(Out<bool> out_is_firmware_available,
Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result EnableSixAxisSensorUnalteredPassthrough(bool is_enabled,
Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result IsSixAxisSensorUnalteredPassthroughEnabled(Out<bool> out_is_enabled,
Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result LoadSixAxisSensorCalibrationParameter(
OutLargeData<Core::HID::SixAxisSensorCalibrationParameter, BufferAttr_HipcMapAlias>
out_calibration,
Core::HID::SixAxisSensorHandle sixaxis_handle, ClientAppletResourceUserId aruid);
Result GetSixAxisSensorIcInformation(
OutLargeData<Core::HID::SixAxisSensorIcInformation, BufferAttr_HipcPointer>
out_ic_information,
Core::HID::SixAxisSensorHandle sixaxis_handle, ClientAppletResourceUserId aruid);
Result ResetIsSixAxisSensorDeviceNewlyAssigned(Core::HID::SixAxisSensorHandle sixaxis_handle,
ClientAppletResourceUserId aruid);
Result ActivateGesture(u32 basic_gesture_id, ClientAppletResourceUserId aruid);
Result SetSupportedNpadStyleSet(Core::HID::NpadStyleSet supported_style_set,
ClientAppletResourceUserId aruid);
Result GetSupportedNpadStyleSet(Out<Core::HID::NpadStyleSet> out_supported_style_set,
ClientAppletResourceUserId aruid);
Result SetSupportedNpadIdType(
ClientAppletResourceUserId aruid,
InArray<Core::HID::NpadIdType, BufferAttr_HipcPointer> supported_npad_list);
Result ActivateNpad(ClientAppletResourceUserId aruid);
Result DeactivateNpad(ClientAppletResourceUserId aruid);
Result AcquireNpadStyleSetUpdateEventHandle(OutCopyHandle<Kernel::KReadableEvent> out_event,
Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid, u64 unknown);
Result DisconnectNpad(Core::HID::NpadIdType npad_id, ClientAppletResourceUserId aruid);
Result GetPlayerLedPattern(Out<Core::HID::LedPattern> out_led_pattern,
Core::HID::NpadIdType npad_id);
void ActivateNpadWithRevision(HLERequestContext& ctx);
void SetNpadJoyHoldType(HLERequestContext& ctx);
void GetNpadJoyHoldType(HLERequestContext& ctx);
void SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx);
void SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx);
void SetNpadJoyAssignmentModeDual(HLERequestContext& ctx);
void MergeSingleJoyAsDualJoy(HLERequestContext& ctx);
void StartLrAssignmentMode(HLERequestContext& ctx);
void StopLrAssignmentMode(HLERequestContext& ctx);
void SetNpadHandheldActivationMode(HLERequestContext& ctx);
void GetNpadHandheldActivationMode(HLERequestContext& ctx);
void SwapNpadAssignment(HLERequestContext& ctx);
void IsUnintendedHomeButtonInputProtectionEnabled(HLERequestContext& ctx);
void EnableUnintendedHomeButtonInputProtection(HLERequestContext& ctx);
void SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext& ctx);
void SetNpadAnalogStickUseCenterClamp(HLERequestContext& ctx);
void SetNpadCaptureButtonAssignment(HLERequestContext& ctx);
void ClearNpadCaptureButtonAssignment(HLERequestContext& ctx);
void GetVibrationDeviceInfo(HLERequestContext& ctx);
void SendVibrationValue(HLERequestContext& ctx);
void GetActualVibrationValue(HLERequestContext& ctx);
void CreateActiveVibrationDeviceList(HLERequestContext& ctx);
void PermitVibration(HLERequestContext& ctx);
void IsVibrationPermitted(HLERequestContext& ctx);
void SendVibrationValues(HLERequestContext& ctx);
void SendVibrationGcErmCommand(HLERequestContext& ctx);
void GetActualVibrationGcErmCommand(HLERequestContext& ctx);
void BeginPermitVibrationSession(HLERequestContext& ctx);
void EndPermitVibrationSession(HLERequestContext& ctx);
void IsVibrationDeviceMounted(HLERequestContext& ctx);
void SendVibrationValueInBool(HLERequestContext& ctx);
void ActivateConsoleSixAxisSensor(HLERequestContext& ctx);
void StartConsoleSixAxisSensor(HLERequestContext& ctx);
void StopConsoleSixAxisSensor(HLERequestContext& ctx);
void ActivateSevenSixAxisSensor(HLERequestContext& ctx);
void StartSevenSixAxisSensor(HLERequestContext& ctx);
void StopSevenSixAxisSensor(HLERequestContext& ctx);
void InitializeSevenSixAxisSensor(HLERequestContext& ctx);
void FinalizeSevenSixAxisSensor(HLERequestContext& ctx);
void ResetSevenSixAxisSensorTimestamp(HLERequestContext& ctx);
void IsUsbFullKeyControllerEnabled(HLERequestContext& ctx);
void GetPalmaConnectionHandle(HLERequestContext& ctx);
void InitializePalma(HLERequestContext& ctx);
void AcquirePalmaOperationCompleteEvent(HLERequestContext& ctx);
void GetPalmaOperationInfo(HLERequestContext& ctx);
void PlayPalmaActivity(HLERequestContext& ctx);
void SetPalmaFrModeType(HLERequestContext& ctx);
void ReadPalmaStep(HLERequestContext& ctx);
void EnablePalmaStep(HLERequestContext& ctx);
void ResetPalmaStep(HLERequestContext& ctx);
void ReadPalmaApplicationSection(HLERequestContext& ctx);
void WritePalmaApplicationSection(HLERequestContext& ctx);
void ReadPalmaUniqueCode(HLERequestContext& ctx);
void SetPalmaUniqueCodeInvalid(HLERequestContext& ctx);
void WritePalmaActivityEntry(HLERequestContext& ctx);
void WritePalmaRgbLedPatternEntry(HLERequestContext& ctx);
void WritePalmaWaveEntry(HLERequestContext& ctx);
void SetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
void GetPalmaDataBaseIdentificationVersion(HLERequestContext& ctx);
void SuspendPalmaFeature(HLERequestContext& ctx);
void GetPalmaOperationResult(HLERequestContext& ctx);
void ReadPalmaPlayLog(HLERequestContext& ctx);
void ResetPalmaPlayLog(HLERequestContext& ctx);
void SetIsPalmaAllConnectable(HLERequestContext& ctx);
void SetIsPalmaPairedConnectable(HLERequestContext& ctx);
void PairPalma(HLERequestContext& ctx);
void SetPalmaBoostMode(HLERequestContext& ctx);
void CancelWritePalmaWaveEntry(HLERequestContext& ctx);
void EnablePalmaBoostMode(HLERequestContext& ctx);
void GetPalmaBluetoothAddress(HLERequestContext& ctx);
void SetDisallowedPalmaConnection(HLERequestContext& ctx);
void SetNpadCommunicationMode(HLERequestContext& ctx);
void GetNpadCommunicationMode(HLERequestContext& ctx);
void SetTouchScreenConfiguration(HLERequestContext& ctx);
void IsFirmwareUpdateNeededForNotification(HLERequestContext& ctx);
void SetTouchScreenResolution(HLERequestContext& ctx);
Result ActivateNpadWithRevision(NpadRevision revision, ClientAppletResourceUserId aruid);
Result SetNpadJoyHoldType(ClientAppletResourceUserId aruid, NpadJoyHoldType hold_type);
Result GetNpadJoyHoldType(Out<NpadJoyHoldType> out_hold_type, ClientAppletResourceUserId aruid);
Result SetNpadJoyAssignmentModeSingleByDefault(Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid);
Result SetNpadJoyAssignmentModeSingle(Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid,
NpadJoyDeviceType npad_joy_device_type);
Result SetNpadJoyAssignmentModeDual(Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid);
Result MergeSingleJoyAsDualJoy(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2,
ClientAppletResourceUserId aruid);
Result StartLrAssignmentMode(ClientAppletResourceUserId aruid);
Result StopLrAssignmentMode(ClientAppletResourceUserId aruid);
Result SetNpadHandheldActivationMode(ClientAppletResourceUserId aruid,
NpadHandheldActivationMode activation_mode);
Result GetNpadHandheldActivationMode(Out<NpadHandheldActivationMode> out_activation_mode,
ClientAppletResourceUserId aruid);
Result SwapNpadAssignment(Core::HID::NpadIdType npad_id_1, Core::HID::NpadIdType npad_id_2,
ClientAppletResourceUserId aruid);
Result IsUnintendedHomeButtonInputProtectionEnabled(Out<bool> out_is_enabled,
Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid);
Result EnableUnintendedHomeButtonInputProtection(bool is_enabled, Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid);
Result SetNpadJoyAssignmentModeSingleWithDestination(Out<bool> out_is_reassigned,
Out<Core::HID::NpadIdType> out_new_npad_id,
Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid,
NpadJoyDeviceType npad_joy_device_type);
Result SetNpadAnalogStickUseCenterClamp(bool use_center_clamp,
ClientAppletResourceUserId aruid);
Result SetNpadCaptureButtonAssignment(Core::HID::NpadStyleSet npad_styleset,
ClientAppletResourceUserId aruid,
Core::HID::NpadButton button);
Result ClearNpadCaptureButtonAssignment(ClientAppletResourceUserId aruid);
Result GetVibrationDeviceInfo(Out<Core::HID::VibrationDeviceInfo> out_vibration_device_info,
Core::HID::VibrationDeviceHandle vibration_device_handle);
Result SendVibrationValue(Core::HID::VibrationDeviceHandle vibration_device_handle,
Core::HID::VibrationValue vibration_value,
ClientAppletResourceUserId aruid);
Result GetActualVibrationValue(Out<Core::HID::VibrationValue> out_vibration_value,
Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid);
Result CreateActiveVibrationDeviceList(OutInterface<IActiveVibrationDeviceList> out_interface);
Result PermitVibration(bool can_vibrate);
Result IsVibrationPermitted(Out<bool> out_is_permitted);
Result SendVibrationValues(
ClientAppletResourceUserId aruid,
InArray<Core::HID::VibrationDeviceHandle, BufferAttr_HipcPointer> vibration_handles,
InArray<Core::HID::VibrationValue, BufferAttr_HipcPointer> vibration_values);
Result SendVibrationGcErmCommand(Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid,
Core::HID::VibrationGcErmCommand gc_erm_command);
Result GetActualVibrationGcErmCommand(Out<Core::HID::VibrationGcErmCommand> out_gc_erm_command,
Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid);
Result BeginPermitVibrationSession(ClientAppletResourceUserId aruid);
Result EndPermitVibrationSession(ClientAppletResourceUserId aruid);
Result IsVibrationDeviceMounted(Out<bool> out_is_mounted,
Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid);
Result SendVibrationValueInBool(bool is_vibrating,
Core::HID::VibrationDeviceHandle vibration_device_handle,
ClientAppletResourceUserId aruid);
Result ActivateConsoleSixAxisSensor(ClientAppletResourceUserId aruid);
Result StartConsoleSixAxisSensor(Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle,
ClientAppletResourceUserId aruid);
Result StopConsoleSixAxisSensor(Core::HID::ConsoleSixAxisSensorHandle console_sixaxis_handle,
ClientAppletResourceUserId aruid);
Result ActivateSevenSixAxisSensor(ClientAppletResourceUserId aruid);
Result StartSevenSixAxisSensor(ClientAppletResourceUserId aruid);
Result StopSevenSixAxisSensor(ClientAppletResourceUserId aruid);
Result InitializeSevenSixAxisSensor(ClientAppletResourceUserId aruid, u64 t_mem_1_size,
u64 t_mem_2_size,
InCopyHandle<Kernel::KTransferMemory> t_mem_1,
InCopyHandle<Kernel::KTransferMemory> t_mem_2);
Result FinalizeSevenSixAxisSensor(ClientAppletResourceUserId aruid);
Result ResetSevenSixAxisSensorTimestamp(ClientAppletResourceUserId aruid);
Result IsUsbFullKeyControllerEnabled(Out<bool> out_is_enabled,
ClientAppletResourceUserId aruid);
Result GetPalmaConnectionHandle(Out<Palma::PalmaConnectionHandle> out_handle,
Core::HID::NpadIdType npad_id,
ClientAppletResourceUserId aruid);
Result InitializePalma(Palma::PalmaConnectionHandle connection_handle);
Result AcquirePalmaOperationCompleteEvent(OutCopyHandle<Kernel::KReadableEvent> out_event,
Palma::PalmaConnectionHandle connection_handle);
Result GetPalmaOperationInfo(Out<Palma::PalmaOperationType> out_operation_type,
Palma::PalmaConnectionHandle connection_handle,
OutBuffer<BufferAttr_HipcMapAlias> out_data);
Result PlayPalmaActivity(Palma::PalmaConnectionHandle connection_handle, u64 palma_activity);
Result SetPalmaFrModeType(Palma::PalmaConnectionHandle connection_handle,
Palma::PalmaFrModeType fr_mode);
Result ReadPalmaStep(Palma::PalmaConnectionHandle connection_handle);
Result EnablePalmaStep(bool is_enabled, Palma::PalmaConnectionHandle connection_handle);
Result ResetPalmaStep(Palma::PalmaConnectionHandle connection_handle);
Result ReadPalmaApplicationSection(Palma::PalmaConnectionHandle connection_handle, u64 offset,
u64 size);
Result WritePalmaApplicationSection(
Palma::PalmaConnectionHandle connection_handle, u64 offset, u64 size,
InLargeData<Palma::PalmaApplicationSection, BufferAttr_HipcPointer> data);
Result ReadPalmaUniqueCode(Palma::PalmaConnectionHandle connection_handle);
Result SetPalmaUniqueCodeInvalid(Palma::PalmaConnectionHandle connection_handle);
Result WritePalmaActivityEntry(Palma::PalmaConnectionHandle connection_handle,
Palma::PalmaActivityEntry activity_entry);
Result WritePalmaRgbLedPatternEntry(Palma::PalmaConnectionHandle connection_handle, u64 unknown,
InBuffer<BufferAttr_HipcMapAlias> led_pattern);
Result WritePalmaWaveEntry(Palma::PalmaConnectionHandle connection_handle,
Palma::PalmaWaveSet wave_set, u64 unknown, u64 t_mem_size, u64 size,
InCopyHandle<Kernel::KTransferMemory> t_mem);
Result SetPalmaDataBaseIdentificationVersion(s32 database_id_version,
Palma::PalmaConnectionHandle connection_handle);
Result GetPalmaDataBaseIdentificationVersion(Palma::PalmaConnectionHandle connection_handle);
Result SuspendPalmaFeature(Palma::PalmaFeature feature,
Palma::PalmaConnectionHandle connection_handle);
Result GetPalmaOperationResult(Palma::PalmaConnectionHandle connection_handle);
Result ReadPalmaPlayLog(u16 unknown, Palma::PalmaConnectionHandle connection_handle);
Result ResetPalmaPlayLog(u16 unknown, Palma::PalmaConnectionHandle connection_handle);
Result SetIsPalmaAllConnectable(bool is_palma_all_connectable, ClientAppletResourceUserId arui);
Result SetIsPalmaPairedConnectable(bool is_palma_paired_connectable,
ClientAppletResourceUserId aruid);
Result PairPalma(Palma::PalmaConnectionHandle connection_handle);
Result SetPalmaBoostMode(bool is_enabled);
Result CancelWritePalmaWaveEntry(Palma::PalmaConnectionHandle connection_handle);
Result EnablePalmaBoostMode(bool is_enabled, ClientAppletResourceUserId aruid);
Result GetPalmaBluetoothAddress(Out<Palma::Address> out_bt_address,
Palma::PalmaConnectionHandle connection_handle);
Result SetDisallowedPalmaConnection(
ClientAppletResourceUserId aruid,
InArray<Palma::Address, BufferAttr_HipcPointer> disallowed_address);
Result SetNpadCommunicationMode(ClientAppletResourceUserId aruid,
NpadCommunicationMode communication_mode);
Result GetNpadCommunicationMode(Out<NpadCommunicationMode> out_communication_mode,
ClientAppletResourceUserId aruid);
Result SetTouchScreenConfiguration(Core::HID::TouchScreenConfigurationForNx touchscreen_config,
ClientAppletResourceUserId aruid);
Result IsFirmwareUpdateNeededForNotification(Out<bool> out_is_firmware_update_needed,
s32 unknown, ClientAppletResourceUserId aruid);
Result SetTouchScreenResolution(u32 width, u32 height, ClientAppletResourceUserId aruid);
std::shared_ptr<ResourceManager> resource_manager;
std::shared_ptr<HidFirmwareSettings> firmware_settings;

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-3.0-or-later
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ldn/ldn_results.h"
#include "core/hle/service/ldn/monitor_service.h"
namespace Service::LDN {
@ -17,7 +18,7 @@ IMonitorService::IMonitorService(Core::System& system_)
{4, nullptr, "GetSecurityParameterForMonitor"},
{5, nullptr, "GetNetworkConfigForMonitor"},
{100, C<&IMonitorService::InitializeMonitor>, "InitializeMonitor"},
{101, nullptr, "FinalizeMonitor"},
{101, C<&IMonitorService::FinalizeMonitor>, "FinalizeMonitor"},
};
// clang-format on
@ -27,16 +28,18 @@ IMonitorService::IMonitorService(Core::System& system_)
IMonitorService::~IMonitorService() = default;
Result IMonitorService::GetStateForMonitor(Out<State> out_state) {
LOG_INFO(Service_LDN, "called");
*out_state = state;
LOG_WARNING(Service_LDN, "(STUBBED) called");
*out_state = State::None;
R_SUCCEED();
}
Result IMonitorService::InitializeMonitor() {
LOG_INFO(Service_LDN, "called");
R_SUCCEED();
}
state = State::Initialized;
Result IMonitorService::FinalizeMonitor() {
LOG_INFO(Service_LDN, "called");
R_SUCCEED();
}

View File

@ -21,6 +21,7 @@ public:
private:
Result GetStateForMonitor(Out<State> out_state);
Result InitializeMonitor();
Result FinalizeMonitor();
State state{State::None};
};

View File

@ -68,10 +68,7 @@ public:
const SyncpointManager& GetSyncpointManager() const;
struct Host1xDeviceFileData {
std::unordered_map<DeviceFD, u32> fd_to_id{};
std::deque<u32> syncpts_accumulated{};
u32 nvdec_next_id{};
u32 vic_next_id{};
};
Host1xDeviceFileData& Host1xDeviceFile();

View File

@ -8,6 +8,7 @@
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
@ -21,13 +22,8 @@ NvResult nvhost_nvdec::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> in
switch (command.group) {
case 0x0:
switch (command.cmd) {
case 0x1: {
auto& host1x_file = core.Host1xDeviceFile();
if (!host1x_file.fd_to_id.contains(fd)) {
host1x_file.fd_to_id[fd] = host1x_file.nvdec_next_id++;
}
case 0x1:
return WrapFixedVariable(this, &nvhost_nvdec::Submit, input, output, fd);
}
case 0x2:
return WrapFixed(this, &nvhost_nvdec::GetSyncpoint, input, output);
case 0x3:
@ -72,15 +68,12 @@ void nvhost_nvdec::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream started");
system.SetNVDECActive(true);
sessions[fd] = session_id;
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::NvDec, channel_syncpoint);
}
void nvhost_nvdec::OnClose(DeviceFD fd) {
LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
auto& host1x_file = core.Host1xDeviceFile();
const auto iter = host1x_file.fd_to_id.find(fd);
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::NvDec);
system.SetNVDECActive(false);
auto it = sessions.find(fd);
if (it != sessions.end()) {

View File

@ -55,8 +55,9 @@ std::size_t WriteVectors(std::span<u8> dst, const std::vector<T>& src, std::size
nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system_, NvCore::Container& core_,
NvCore::ChannelType channel_type_)
: nvdevice{system_}, core{core_}, syncpoint_manager{core.GetSyncpointManager()},
nvmap{core.GetNvMapFile()}, channel_type{channel_type_} {
: nvdevice{system_}, host1x{system_.Host1x()}, core{core_},
syncpoint_manager{core.GetSyncpointManager()}, nvmap{core.GetNvMapFile()},
channel_type{channel_type_} {
auto& syncpts_accumulated = core.Host1xDeviceFile().syncpts_accumulated;
if (syncpts_accumulated.empty()) {
channel_syncpoint = syncpoint_manager.AllocateSyncpoint(false);
@ -95,24 +96,24 @@ NvResult nvhost_nvdec_common::Submit(IoctlSubmit& params, std::span<u8> data, De
offset += SliceVectors(data, syncpt_increments, params.syncpoint_count, offset);
offset += SliceVectors(data, fence_thresholds, params.fence_count, offset);
auto& gpu = system.GPU();
auto* session = core.GetSession(sessions[fd]);
if (gpu.UseNvdec()) {
for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i];
fence_thresholds[i] =
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
}
for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
const SyncptIncr& syncpt_incr = syncpt_increments[i];
fence_thresholds[i] =
syncpoint_manager.IncrementSyncpointMaxExt(syncpt_incr.id, syncpt_incr.increments);
}
for (const auto& cmd_buffer : command_buffers) {
const auto object = nvmap.GetHandle(cmd_buffer.memory_id);
ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
session->process->GetMemory().ReadBlock(object->address + cmd_buffer.offset, cmdlist.data(),
cmdlist.size() * sizeof(u32));
gpu.PushCommandBuffer(core.Host1xDeviceFile().fd_to_id[fd], cmdlist);
Core::Memory::CpuGuestMemory<Tegra::ChCommandHeader,
Core::Memory::GuestMemoryFlags::SafeRead>
cmdlist(session->process->GetMemory(), object->address + cmd_buffer.offset,
cmd_buffer.word_count);
host1x.PushEntries(fd, std::move(cmdlist));
}
// Some games expect command_buffers to be written back
offset = 0;
offset += WriteVectors(data, command_buffers, offset);

View File

@ -119,6 +119,7 @@ protected:
Kernel::KEvent* QueryEvent(u32 event_id) override;
Tegra::Host1x::Host1x& host1x;
u32 channel_syncpoint;
s32_le nvmap_fd{};
u32_le submit_timeout{};

View File

@ -7,6 +7,7 @@
#include "core/hle/service/nvdrv/core/container.h"
#include "core/hle/service/nvdrv/devices/ioctl_serialization.h"
#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
#include "video_core/host1x/host1x.h"
#include "video_core/renderer_base.h"
namespace Service::Nvidia::Devices {
@ -21,13 +22,8 @@ NvResult nvhost_vic::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8> inpu
switch (command.group) {
case 0x0:
switch (command.cmd) {
case 0x1: {
auto& host1x_file = core.Host1xDeviceFile();
if (!host1x_file.fd_to_id.contains(fd)) {
host1x_file.fd_to_id[fd] = host1x_file.vic_next_id++;
}
case 0x1:
return WrapFixedVariable(this, &nvhost_vic::Submit, input, output, fd);
}
case 0x2:
return WrapFixed(this, &nvhost_vic::GetSyncpoint, input, output);
case 0x3:
@ -70,14 +66,11 @@ NvResult nvhost_vic::Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> inpu
void nvhost_vic::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {
sessions[fd] = session_id;
host1x.StartDevice(fd, Tegra::Host1x::ChannelType::VIC, channel_syncpoint);
}
void nvhost_vic::OnClose(DeviceFD fd) {
auto& host1x_file = core.Host1xDeviceFile();
const auto iter = host1x_file.fd_to_id.find(fd);
if (iter != host1x_file.fd_to_id.end()) {
system.GPU().ClearCdmaInstance(iter->second);
}
host1x.StopDevice(fd, Tegra::Host1x::ChannelType::VIC);
sessions.erase(fd);
}

View File

@ -3,66 +3,25 @@
#include "common/scope_exit.h"
#include "core/file_sys/content_archive.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/hle/kernel/svc_types.h"
#include "core/hle/service/os/process.h"
#include "core/loader/loader.h"
namespace Service::AM {
namespace Service {
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() {}
m_process_started() {}
Process::~Process() {
this->Finalize();
}
bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation) {
bool Process::Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result) {
// 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_raw{};
// Get the program NCA from built-in storage.
bis_system = fsc.GetSystemNANDContents();
if (bis_system) {
nca_raw = bis_system->GetEntryRaw(program_id, FileSys::ContentRecordType::Program);
}
// Ensure we retrieved a program NCA.
if (!nca_raw) {
return false;
}
// Ensure we have a suitable version.
if (minimum_key_generation > 0) {
FileSys::NCA nca(nca_raw);
if (nca.GetStatus() == Loader::ResultStatus::Success &&
(nca.GetKeyGeneration() < minimum_key_generation ||
nca.GetKeyGeneration() > maximum_key_generation)) {
LOG_WARNING(Service_LDR, "Skipping program {:016X} with generation {}", program_id,
nca.GetKeyGeneration());
return false;
}
}
// Get the appropriate loader to parse this NCA.
auto app_loader = Loader::GetLoader(m_system, nca_raw, 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);
@ -73,7 +32,8 @@ bool Process::Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_k
};
// Insert process modules into memory.
const auto [load_result, load_parameters] = app_loader->Load(*process, m_system);
const auto [load_result, load_parameters] = loader.Load(*process, m_system);
out_load_result = load_result;
// Ensure loading was successful.
if (load_result != Loader::ResultStatus::Success) {
@ -114,7 +74,6 @@ void Process::Finalize() {
m_process = nullptr;
m_main_thread_priority = 0;
m_main_thread_stack_size = 0;
m_program_id = 0;
m_process_started = false;
}
@ -142,6 +101,31 @@ void Process::Terminate() {
}
}
void Process::ResetSignal() {
if (m_process) {
m_process->Reset();
}
}
bool Process::IsRunning() const {
if (m_process) {
const auto state = m_process->GetState();
return state == Kernel::KProcess::State::Running ||
state == Kernel::KProcess::State::RunningAttached ||
state == Kernel::KProcess::State::DebugBreak;
}
return false;
}
bool Process::IsTerminated() const {
if (m_process) {
return m_process->IsTerminated();
}
return false;
}
u64 Process::GetProcessId() const {
if (m_process) {
return m_process->GetProcessId();
@ -150,4 +134,19 @@ u64 Process::GetProcessId() const {
return 0;
}
} // namespace Service::AM
u64 Process::GetProgramId() const {
if (m_process) {
return m_process->GetProgramId();
}
return 0;
}
void Process::Suspend(bool suspended) {
if (m_process) {
m_process->SetActivity(suspended ? Kernel::Svc::ProcessActivity::Paused
: Kernel::Svc::ProcessActivity::Runnable);
}
}
} // namespace Service

View File

@ -3,38 +3,47 @@
#pragma once
#include "common/common_funcs.h"
#include "common/common_types.h"
namespace Kernel {
class KProcess;
}
namespace Core {
class System;
}
namespace Service::AM {
namespace Loader {
class AppLoader;
enum class ResultStatus : u16;
} // namespace Loader
namespace Kernel {
class KProcess;
}
namespace Service {
class Process {
public:
explicit Process(Core::System& system);
~Process();
bool Initialize(u64 program_id, u8 minimum_key_generation, u8 maximum_key_generation);
bool Initialize(Loader::AppLoader& loader, Loader::ResultStatus& out_load_result);
void Finalize();
bool Run();
void Terminate();
void Suspend(bool suspended);
void ResetSignal();
bool IsInitialized() const {
return m_process != nullptr;
}
bool IsRunning() const;
bool IsTerminated() const;
u64 GetProcessId() const;
u64 GetProgramId() const {
return m_program_id;
}
Kernel::KProcess* GetProcess() const {
u64 GetProgramId() const;
Kernel::KProcess* GetHandle() const {
return m_process;
}
@ -43,8 +52,7 @@ private:
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
} // namespace Service

View File

@ -243,6 +243,11 @@ enum class TvResolution : u32 {
Resolution480p,
};
enum class PlatformRegion : s32 {
Global = 1,
Terra = 2,
};
constexpr std::array<LanguageCode, 18> available_language_codes = {{
LanguageCode::JA,
LanguageCode::EN_US,

View File

@ -272,8 +272,8 @@ ISystemSettingsServer::ISystemSettingsServer(Core::System& system_)
{180, nullptr, "SetZoomFlag"},
{181, nullptr, "GetT"},
{182, nullptr, "SetT"},
{183, nullptr, "GetPlatformRegion"},
{184, nullptr, "SetPlatformRegion"},
{183, C<&ISystemSettingsServer::GetPlatformRegion>, "GetPlatformRegion"},
{184, C<&ISystemSettingsServer::SetPlatformRegion>, "SetPlatformRegion"},
{185, C<&ISystemSettingsServer::GetHomeMenuSchemeModel>, "GetHomeMenuSchemeModel"},
{186, nullptr, "GetMemoryUsageRateFlag"},
{187, C<&ISystemSettingsServer::GetTouchScreenMode>, "GetTouchScreenMode"},
@ -1250,6 +1250,18 @@ Result ISystemSettingsServer::GetHomeMenuScheme(Out<HomeMenuScheme> out_home_men
R_SUCCEED();
}
Result ISystemSettingsServer::GetPlatformRegion(Out<PlatformRegion> out_platform_region) {
LOG_WARNING(Service_SET, "(STUBBED) called");
*out_platform_region = PlatformRegion::Global;
R_SUCCEED();
}
Result ISystemSettingsServer::SetPlatformRegion(PlatformRegion platform_region) {
LOG_WARNING(Service_SET, "(STUBBED) called");
R_SUCCEED();
}
Result ISystemSettingsServer::GetHomeMenuSchemeModel(Out<u32> out_home_menu_scheme_model) {
LOG_WARNING(Service_SET, "(STUBBED) called");

View File

@ -149,6 +149,8 @@ public:
Result GetHomeMenuScheme(Out<HomeMenuScheme> out_home_menu_scheme);
Result GetHomeMenuSchemeModel(Out<u32> out_home_menu_scheme_model);
Result GetTouchScreenMode(Out<TouchScreenMode> out_touch_screen_mode);
Result GetPlatformRegion(Out<PlatformRegion> out_platform_region);
Result SetPlatformRegion(PlatformRegion platform_region);
Result SetTouchScreenMode(TouchScreenMode touch_screen_mode);
Result GetFieldTestingFlag(Out<bool> out_field_testing_flag);
Result GetPanelCrcMode(Out<s32> out_panel_crc_mode);

View File

@ -0,0 +1,156 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/alignment.h"
#include "core/core.h"
#include "core/file_sys/content_archive.h"
#include "core/file_sys/nca_metadata.h"
#include "core/file_sys/registered_cache.h"
#include "core/file_sys/romfs.h"
#include "core/hle/service/filesystem/filesystem.h"
#include "core/hle/service/ssl/cert_store.h"
namespace Service::SSL {
// https://switchbrew.org/wiki/SSL_services#CertStore
CertStore::CertStore(Core::System& system) {
constexpr u64 CertStoreDataId = 0x0100000000000800ULL;
auto& fsc = system.GetFileSystemController();
// Attempt to load certificate data from storage
const auto nca =
fsc.GetSystemNANDContents()->GetEntry(CertStoreDataId, FileSys::ContentRecordType::Data);
if (!nca) {
return;
}
const auto romfs = nca->GetRomFS();
if (!romfs) {
return;
}
const auto extracted = FileSys::ExtractRomFS(romfs);
if (!extracted) {
LOG_ERROR(Service_SSL, "CertStore could not be extracted, corrupt RomFS?");
return;
}
const auto cert_store_file = extracted->GetFile("ssl_TrustedCerts.bdf");
if (!cert_store_file) {
LOG_ERROR(Service_SSL, "Failed to find trusted certificates in CertStore");
return;
}
// Read and verify the header.
CertStoreHeader header;
cert_store_file->ReadObject(std::addressof(header));
if (header.magic != Common::MakeMagic('s', 's', 'l', 'T')) {
LOG_ERROR(Service_SSL, "Invalid certificate store magic");
return;
}
// Ensure the file can contains the number of entries it says it does.
const u64 expected_size = sizeof(header) + sizeof(CertStoreEntry) * header.num_entries;
const u64 actual_size = cert_store_file->GetSize();
if (actual_size < expected_size) {
LOG_ERROR(Service_SSL, "Size mismatch, expected at least {} bytes, got {}", expected_size,
actual_size);
return;
}
// Read entries.
std::vector<CertStoreEntry> entries(header.num_entries);
cert_store_file->ReadArray(entries.data(), header.num_entries, sizeof(header));
// Insert into memory store.
for (const auto& entry : entries) {
m_certs.emplace(entry.certificate_id,
Certificate{
.status = entry.certificate_status,
.der_data = cert_store_file->ReadBytes(
entry.der_size, entry.der_offset + sizeof(header)),
});
}
}
CertStore::~CertStore() = default;
template <typename F>
void CertStore::ForEachCertificate(std::span<const CaCertificateId> certificate_ids, F&& f) {
if (certificate_ids.size() == 1 && certificate_ids.front() == CaCertificateId::All) {
for (const auto& entry : m_certs) {
f(entry);
}
} else {
for (const auto certificate_id : certificate_ids) {
const auto entry = m_certs.find(certificate_id);
if (entry == m_certs.end()) {
continue;
}
f(*entry);
}
}
}
Result CertStore::GetCertificates(u32* out_num_entries, std::span<u8> out_data,
std::span<const CaCertificateId> certificate_ids) {
// Ensure the buffer is large enough to hold the output.
u32 required_size;
R_TRY(this->GetCertificateBufSize(std::addressof(required_size), out_num_entries,
certificate_ids));
R_UNLESS(out_data.size_bytes() >= required_size, ResultUnknown);
// Make parallel arrays.
std::vector<BuiltInCertificateInfo> cert_infos;
std::vector<u8> der_datas;
const u32 der_data_offset = (*out_num_entries + 1) * sizeof(BuiltInCertificateInfo);
u32 cur_der_offset = der_data_offset;
// Fill output.
this->ForEachCertificate(certificate_ids, [&](auto& entry) {
const auto& [status, cur_der_data] = entry.second;
BuiltInCertificateInfo cert_info{
.cert_id = entry.first,
.status = status,
.der_size = cur_der_data.size(),
.der_offset = cur_der_offset,
};
cert_infos.push_back(cert_info);
der_datas.insert(der_datas.end(), cur_der_data.begin(), cur_der_data.end());
cur_der_offset += static_cast<u32>(cur_der_data.size());
});
// Append terminator entry.
cert_infos.push_back(BuiltInCertificateInfo{
.cert_id = CaCertificateId::All,
.status = TrustedCertStatus::Invalid,
.der_size = 0,
.der_offset = 0,
});
// Write to output span.
std::memcpy(out_data.data(), cert_infos.data(),
cert_infos.size() * sizeof(BuiltInCertificateInfo));
std::memcpy(out_data.data() + der_data_offset, der_datas.data(), der_datas.size());
R_SUCCEED();
}
Result CertStore::GetCertificateBufSize(u32* out_size, u32* out_num_entries,
std::span<const CaCertificateId> certificate_ids) {
// Output size is at least the size of the terminator entry.
*out_size = sizeof(BuiltInCertificateInfo);
*out_num_entries = 0;
this->ForEachCertificate(certificate_ids, [&](auto& entry) {
*out_size += sizeof(BuiltInCertificateInfo);
*out_size += Common::AlignUp(static_cast<u32>(entry.second.der_data.size()), 4);
(*out_num_entries)++;
});
R_SUCCEED();
}
} // namespace Service::SSL

View File

@ -0,0 +1,42 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <map>
#include <span>
#include <vector>
#include "core/hle/result.h"
#include "core/hle/service/ssl/ssl_types.h"
namespace Core {
class System;
}
namespace Service::SSL {
class CertStore {
public:
explicit CertStore(Core::System& system);
~CertStore();
Result GetCertificates(u32* out_num_entries, std::span<u8> out_data,
std::span<const CaCertificateId> certificate_ids);
Result GetCertificateBufSize(u32* out_size, u32* out_num_entries,
std::span<const CaCertificateId> certificate_ids);
private:
template <typename F>
void ForEachCertificate(std::span<const CaCertificateId> certs, F&& f);
private:
struct Certificate {
TrustedCertStatus status;
std::vector<u8> der_data;
};
std::map<CaCertificateId, Certificate> m_certs;
};
} // namespace Service::SSL

View File

@ -5,11 +5,13 @@
#include "core/core.h"
#include "core/hle/result.h"
#include "core/hle/service/cmif_serialization.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
#include "core/hle/service/sm/sm.h"
#include "core/hle/service/sockets/bsd.h"
#include "core/hle/service/ssl/cert_store.h"
#include "core/hle/service/ssl/ssl.h"
#include "core/hle/service/ssl/ssl_backend.h"
#include "core/internal_network/network.h"
@ -492,13 +494,14 @@ private:
class ISslService final : public ServiceFramework<ISslService> {
public:
explicit ISslService(Core::System& system_) : ServiceFramework{system_, "ssl"} {
explicit ISslService(Core::System& system_)
: ServiceFramework{system_, "ssl"}, cert_store{system} {
// clang-format off
static const FunctionInfo functions[] = {
{0, &ISslService::CreateContext, "CreateContext"},
{1, nullptr, "GetContextCount"},
{2, nullptr, "GetCertificates"},
{3, nullptr, "GetCertificateBufSize"},
{2, D<&ISslService::GetCertificates>, "GetCertificates"},
{3, D<&ISslService::GetCertificateBufSize>, "GetCertificateBufSize"},
{4, nullptr, "DebugIoctl"},
{5, &ISslService::SetInterfaceVersion, "SetInterfaceVersion"},
{6, nullptr, "FlushSessionCache"},
@ -540,6 +543,22 @@ private:
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
Result GetCertificateBufSize(
Out<u32> out_size, InArray<CaCertificateId, BufferAttr_HipcMapAlias> certificate_ids) {
LOG_INFO(Service_SSL, "called");
u32 num_entries;
R_RETURN(cert_store.GetCertificateBufSize(out_size, &num_entries, certificate_ids));
}
Result GetCertificates(Out<u32> out_num_entries, OutBuffer<BufferAttr_HipcMapAlias> out_buffer,
InArray<CaCertificateId, BufferAttr_HipcMapAlias> certificate_ids) {
LOG_INFO(Service_SSL, "called");
R_RETURN(cert_store.GetCertificates(out_num_entries, out_buffer, certificate_ids));
}
private:
CertStore cert_store;
};
void LoopProcess(Core::System& system) {

View File

@ -0,0 +1,107 @@
// SPDX-FileCopyrightText: Copyright 2024 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/common_types.h"
namespace Service::SSL {
enum class CaCertificateId : s32 {
All = -1,
NintendoCAG3 = 1,
NintendoClass2CAG3 = 2,
NintendoRootCAG4 = 3,
AmazonRootCA1 = 1000,
StarfieldServicesRootCertificateAuthorityG2 = 1001,
AddTrustExternalCARoot = 1002,
COMODOCertificationAuthority = 1003,
UTNDATACorpSGC = 1004,
UTNUSERFirstHardware = 1005,
BaltimoreCyberTrustRoot = 1006,
CybertrustGlobalRoot = 1007,
VerizonGlobalRootCA = 1008,
DigiCertAssuredIDRootCA = 1009,
DigiCertAssuredIDRootG2 = 1010,
DigiCertGlobalRootCA = 1011,
DigiCertGlobalRootG2 = 1012,
DigiCertHighAssuranceEVRootCA = 1013,
EntrustnetCertificationAuthority2048 = 1014,
EntrustRootCertificationAuthority = 1015,
EntrustRootCertificationAuthorityG2 = 1016,
GeoTrustGlobalCA2 = 1017,
GeoTrustGlobalCA = 1018,
GeoTrustPrimaryCertificationAuthorityG3 = 1019,
GeoTrustPrimaryCertificationAuthority = 1020,
GlobalSignRootCA = 1021,
GlobalSignRootCAR2 = 1022,
GlobalSignRootCAR3 = 1023,
GoDaddyClass2CertificationAuthority = 1024,
GoDaddyRootCertificateAuthorityG2 = 1025,
StarfieldClass2CertificationAuthority = 1026,
StarfieldRootCertificateAuthorityG2 = 1027,
thawtePrimaryRootCAG3 = 1028,
thawtePrimaryRootCA = 1029,
VeriSignClass3PublicPrimaryCertificationAuthorityG3 = 1030,
VeriSignClass3PublicPrimaryCertificationAuthorityG5 = 1031,
VeriSignUniversalRootCertificationAuthority = 1032,
DSTRootCAX3 = 1033,
USERTrustRsaCertificationAuthority = 1034,
ISRGRootX10 = 1035,
USERTrustEccCertificationAuthority = 1036,
COMODORsaCertificationAuthority = 1037,
COMODOEccCertificationAuthority = 1038,
AmazonRootCA2 = 1039,
AmazonRootCA3 = 1040,
AmazonRootCA4 = 1041,
DigiCertAssuredIDRootG3 = 1042,
DigiCertGlobalRootG3 = 1043,
DigiCertTrustedRootG4 = 1044,
EntrustRootCertificationAuthorityEC1 = 1045,
EntrustRootCertificationAuthorityG4 = 1046,
GlobalSignECCRootCAR4 = 1047,
GlobalSignECCRootCAR5 = 1048,
GlobalSignECCRootCAR6 = 1049,
GTSRootR1 = 1050,
GTSRootR2 = 1051,
GTSRootR3 = 1052,
GTSRootR4 = 1053,
SecurityCommunicationRootCA = 1054,
GlobalSignRootE4 = 1055,
GlobalSignRootR4 = 1056,
TTeleSecGlobalRootClass2 = 1057,
DigiCertTLSECCP384RootG5 = 1058,
DigiCertTLSRSA4096RootG5 = 1059,
};
enum class TrustedCertStatus : s32 {
Invalid = -1,
Removed = 0,
EnabledTrusted = 1,
EnabledNotTrusted = 2,
Revoked = 3,
};
struct BuiltInCertificateInfo {
CaCertificateId cert_id;
TrustedCertStatus status;
u64 der_size;
u64 der_offset;
};
static_assert(sizeof(BuiltInCertificateInfo) == 0x18, "BuiltInCertificateInfo has incorrect size.");
struct CertStoreHeader {
u32 magic;
u32 num_entries;
};
static_assert(sizeof(CertStoreHeader) == 0x8, "CertStoreHeader has incorrect size.");
struct CertStoreEntry {
CaCertificateId certificate_id;
TrustedCertStatus certificate_status;
u32 der_size;
u32 der_offset;
};
static_assert(sizeof(CertStoreEntry) == 0x10, "CertStoreEntry has incorrect size.");
} // namespace Service::SSL

View File

@ -49,8 +49,7 @@ struct Memory::Impl {
void SetCurrentPageTable(Kernel::KProcess& process) {
current_page_table = &process.GetPageTable().GetImpl();
if (std::addressof(process) == system.ApplicationProcess() &&
Settings::IsFastmemEnabled()) {
if (process.IsApplication() && Settings::IsFastmemEnabled()) {
current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
} else {
current_page_table->fastmem_arena = nullptr;

View File

@ -64,6 +64,8 @@ public:
Memory(Memory&&) = default;
Memory& operator=(Memory&&) = delete;
static constexpr bool HAS_FLUSH_INVALIDATION = false;
/**
* Resets the state of the Memory system.
*/

View File

@ -565,36 +565,28 @@ static_assert(sizeof(SixAxisSensorProperties) == 1, "SixAxisSensorProperties is
// This is nn::hid::SixAxisSensorCalibrationParameter
struct SixAxisSensorCalibrationParameter {
std::array<u8, 0x744> unknown_data{};
std::array<u8, 0x744> unknown_data;
};
static_assert(sizeof(SixAxisSensorCalibrationParameter) == 0x744,
"SixAxisSensorCalibrationParameter is an invalid size");
static_assert(std::is_trivial_v<SixAxisSensorCalibrationParameter>,
"SixAxisSensorCalibrationParameter must be trivial.");
// This is nn::hid::SixAxisSensorIcInformation
struct SixAxisSensorIcInformation {
f32 angular_rate{2000.0f}; // dps
std::array<f32, 6> unknown_gyro_data1{
-10.0f, -10.0f, -10.0f, 10.0f, 10.0f, 10.0f,
}; // dps
std::array<f32, 9> unknown_gyro_data2{
0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f,
};
std::array<f32, 9> unknown_gyro_data3{
1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f,
};
f32 acceleration_range{8.0f}; // g force
std::array<f32, 6> unknown_accel_data1{
-0.0612f, -0.0612f, -0.0612f, 0.0612f, 0.0612f, 0.0612f,
}; // g force
std::array<f32, 9> unknown_accel_data2{
0.95f, -0.003f, -0.003f, -0.003f, 0.95f, -0.003f, -0.003f, -0.003f, 0.95f,
};
std::array<f32, 9> unknown_accel_data3{
1.05f, 0.003f, 0.003f, 0.003f, 1.05f, 0.003f, 0.003f, 0.003f, 1.05f,
};
f32 angular_rate; // dps
std::array<f32, 6> unknown_gyro_data1; // dps
std::array<f32, 9> unknown_gyro_data2;
std::array<f32, 9> unknown_gyro_data3;
f32 acceleration_range; // g force
std::array<f32, 6> unknown_accel_data1; // g force
std::array<f32, 9> unknown_accel_data2;
std::array<f32, 9> unknown_accel_data3;
};
static_assert(sizeof(SixAxisSensorIcInformation) == 0xC8,
"SixAxisSensorIcInformation is an invalid size");
static_assert(std::is_trivial_v<SixAxisSensorIcInformation>,
"SixAxisSensorIcInformation must be trivial.");
// This is nn::hid::SixAxisSensorAttribute
struct SixAxisSensorAttribute {

View File

@ -4,7 +4,6 @@
#include "common/logging/log.h"
#include "core/core.h"
#include "core/core_timing.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/set/system_settings_server.h"
#include "core/hle/service/sm/sm.h"
@ -501,29 +500,4 @@ void ResourceManager::UpdateMotion(std::chrono::nanoseconds ns_late) {
console_six_axis->OnUpdate(core_timing);
}
IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
u64 applet_resource_user_id)
: ServiceFramework{system_, "IAppletResource"}, aruid{applet_resource_user_id},
resource_manager{resource} {
static const FunctionInfo functions[] = {
{0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"},
};
RegisterHandlers(functions);
}
IAppletResource::~IAppletResource() {
resource_manager->FreeAppletResourceId(aruid);
}
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
Kernel::KSharedMemory* handle;
const auto result = resource_manager->GetSharedMemoryHandle(&handle, aruid);
LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}", aruid, result.raw);
IPC::ResponseBuilder rb{ctx, 2, 1};
rb.Push(result);
rb.PushCopyObjects(handle);
}
} // namespace Service::HID

View File

@ -174,17 +174,4 @@ private:
KernelHelpers::ServiceContext service_context;
};
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
u64 applet_resource_user_id);
~IAppletResource() override;
private:
void GetSharedMemoryHandle(HLERequestContext& ctx);
u64 aruid{};
std::shared_ptr<ResourceManager> resource_manager;
};
} // namespace Service::HID

View File

@ -56,12 +56,14 @@ Kernel::KReadableEvent& Palma::AcquirePalmaOperationCompleteEvent(
Result Palma::GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
PalmaOperationType& operation_type,
PalmaOperationData& data) const {
std::span<u8> out_data) const {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation_type = operation.operation;
data = operation.data;
operation_type = static_cast<PalmaOperationType>(operation.operation);
std::memcpy(out_data.data(), operation.data.data(),
std::min(out_data.size(), operation.data.size()));
return ResultSuccess;
}
@ -69,7 +71,7 @@ Result Palma::PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_a
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::PlayActivity;
operation.operation = PackedPalmaOperationType::PlayActivity;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->Signal();
@ -88,7 +90,7 @@ Result Palma::ReadPalmaStep(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::ReadStep;
operation.operation = PackedPalmaOperationType::ReadStep;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->Signal();
@ -117,7 +119,7 @@ Result Palma::ReadPalmaUniqueCode(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::ReadUniqueCode;
operation.operation = PackedPalmaOperationType::ReadUniqueCode;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->Signal();
@ -128,7 +130,7 @@ Result Palma::SetPalmaUniqueCodeInvalid(const PalmaConnectionHandle& handle) {
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::SetUniqueCodeInvalid;
operation.operation = PackedPalmaOperationType::SetUniqueCodeInvalid;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->Signal();
@ -141,7 +143,7 @@ Result Palma::WritePalmaRgbLedPatternEntry(const PalmaConnectionHandle& handle,
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::WriteRgbLedPatternEntry;
operation.operation = PackedPalmaOperationType::WriteRgbLedPatternEntry;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->Signal();
@ -153,7 +155,7 @@ Result Palma::WritePalmaWaveEntry(const PalmaConnectionHandle& handle, PalmaWave
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::WriteWaveEntry;
operation.operation = PackedPalmaOperationType::WriteWaveEntry;
operation.result = PalmaResultSuccess;
operation.data = {};
operation_complete_event->Signal();
@ -166,7 +168,7 @@ Result Palma::SetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle&
return InvalidPalmaHandle;
}
database_id_version = database_id_version_;
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
operation.operation = PackedPalmaOperationType::ReadDataBaseIdentificationVersion;
operation.result = PalmaResultSuccess;
operation.data[0] = {};
operation_complete_event->Signal();
@ -177,7 +179,7 @@ Result Palma::GetPalmaDataBaseIdentificationVersion(const PalmaConnectionHandle&
if (handle.npad_id != active_handle.npad_id) {
return InvalidPalmaHandle;
}
operation.operation = PalmaOperationType::ReadDataBaseIdentificationVersion;
operation.operation = PackedPalmaOperationType::ReadDataBaseIdentificationVersion;
operation.result = PalmaResultSuccess;
operation.data = {};
operation.data[0] = static_cast<u8>(database_id_version);

View File

@ -4,6 +4,8 @@
#pragma once
#include <array>
#include <span>
#include "common/common_funcs.h"
#include "common/typed_address.h"
#include "hid_core/hid_result.h"
@ -27,9 +29,31 @@ namespace Service::HID {
class Palma final : public ControllerBase {
public:
using PalmaOperationData = std::array<u8, 0x140>;
using PalmaApplicationSection = std::array<u8, 0x100>;
using Address = std::array<u8, 0x6>;
// This is nn::hid::PalmaOperationType
enum class PalmaOperationType {
enum class PalmaOperationType : u64 {
PlayActivity,
SetFrModeType,
ReadStep,
EnableStep,
ResetStep,
ReadApplicationSection,
WriteApplicationSection,
ReadUniqueCode,
SetUniqueCodeInvalid,
WriteActivityEntry,
WriteRgbLedPatternEntry,
WriteWaveEntry,
ReadDataBaseIdentificationVersion,
WriteDataBaseIdentificationVersion,
SuspendFeature,
ReadPlayLog,
ResetPlayLog,
};
enum class PackedPalmaOperationType : u32 {
PlayActivity,
SetFrModeType,
ReadStep,
@ -75,7 +99,7 @@ public:
// This is nn::hid::PalmaOperationInfo
struct PalmaOperationInfo {
PalmaOperationType operation{};
PackedPalmaOperationType operation{};
Result result{PalmaResultSuccess};
PalmaOperationData data{};
};
@ -92,8 +116,7 @@ public:
static_assert(sizeof(PalmaActivityEntry) == 0x20, "PalmaActivityEntry is an invalid size");
struct PalmaConnectionHandle {
Core::HID::NpadIdType npad_id;
INSERT_PADDING_BYTES(4); // Unknown
alignas(8) Core::HID::NpadIdType npad_id;
};
static_assert(sizeof(PalmaConnectionHandle) == 0x8,
"PalmaConnectionHandle has incorrect size.");
@ -115,8 +138,7 @@ public:
Kernel::KReadableEvent& AcquirePalmaOperationCompleteEvent(
const PalmaConnectionHandle& handle) const;
Result GetPalmaOperationInfo(const PalmaConnectionHandle& handle,
PalmaOperationType& operation_type,
PalmaOperationData& data) const;
PalmaOperationType& operation_type, std::span<u8> out_data) const;
Result PlayPalmaActivity(const PalmaConnectionHandle& handle, u64 palma_activity);
Result SetPalmaFrModeType(const PalmaConnectionHandle& handle, PalmaFrModeType fr_mode_);
Result ReadPalmaStep(const PalmaConnectionHandle& handle);

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