summaryrefslogtreecommitdiffstats
path: root/src/core/hle/service
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/hle/service')
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp8
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.cpp313
-rw-r--r--src/core/hle/service/hid/controllers/applet_resource.h98
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.cpp21
-rw-r--r--src/core/hle/service/hid/controllers/console_six_axis.h19
-rw-r--r--src/core/hle/service/hid/controllers/controller_base.h3
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.h48
-rw-r--r--src/core/hle/service/hid/controllers/gesture.cpp36
-rw-r--r--src/core/hle/service/hid/controllers/gesture.h90
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.cpp23
-rw-r--r--src/core/hle/service/hid/controllers/keyboard.h33
-rw-r--r--src/core/hle/service/hid/controllers/mouse.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/mouse.h16
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp28
-rw-r--r--src/core/hle/service/hid/controllers/npad.h314
-rw-r--r--src/core/hle/service/hid/controllers/palma.cpp3
-rw-r--r--src/core/hle/service/hid/controllers/palma.h3
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_format.h240
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.cpp53
-rw-r--r--src/core/hle/service/hid/controllers/shared_memory_holder.h44
-rw-r--r--src/core/hle/service/hid/controllers/six_axis.cpp25
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.cpp19
-rw-r--r--src/core/hle/service/hid/controllers/stubbed.h18
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.cpp24
-rw-r--r--src/core/hle/service/hid/controllers/touchscreen.h32
-rw-r--r--src/core/hle/service/hid/controllers/types/debug_pad_types.h31
-rw-r--r--src/core/hle/service/hid/controllers/types/gesture_types.h77
-rw-r--r--src/core/hle/service/hid/controllers/types/keyboard_types.h20
-rw-r--r--src/core/hle/service/hid/controllers/types/mouse_types.h8
-rw-r--r--src/core/hle/service/hid/controllers/types/npad_types.h254
-rw-r--r--src/core/hle/service/hid/controllers/types/touch_types.h90
-rw-r--r--src/core/hle/service/hid/controllers/xpad.cpp39
-rw-r--r--src/core/hle/service/hid/controllers/xpad.h112
-rw-r--r--src/core/hle/service/hid/errors.h8
-rw-r--r--src/core/hle/service/hid/hid.cpp8
-rw-r--r--src/core/hle/service/hid/hid_server.cpp32
-rw-r--r--src/core/hle/service/hid/hid_system_server.cpp139
-rw-r--r--src/core/hle/service/hid/hid_system_server.h6
-rw-r--r--src/core/hle/service/hid/resource_manager.cpp160
-rw-r--r--src/core/hle/service/hid/resource_manager.h44
-rw-r--r--src/core/hle/service/hle_ipc.cpp15
-rw-r--r--src/core/hle/service/hle_ipc.h15
-rw-r--r--src/core/hle/service/jit/jit.cpp6
-rw-r--r--src/core/hle/service/ldr/ldr.cpp634
-rw-r--r--src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp1
-rw-r--r--src/core/hle/service/ro/ro.cpp709
-rw-r--r--src/core/hle/service/ro/ro.h14
-rw-r--r--src/core/hle/service/ro/ro_nro_utils.cpp185
-rw-r--r--src/core/hle/service/ro/ro_nro_utils.h26
-rw-r--r--src/core/hle/service/ro/ro_results.h24
-rw-r--r--src/core/hle/service/ro/ro_types.h181
-rw-r--r--src/core/hle/service/server_manager.cpp32
-rw-r--r--src/core/hle/service/server_manager.h14
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/core/hle/service/sm/sm.cpp33
-rw-r--r--src/core/hle/service/sm/sm.h14
-rw-r--r--src/core/hle/service/ssl/ssl.cpp6
58 files changed, 2955 insertions, 1537 deletions
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp
index 126cd6ffd..b1310d6e4 100644
--- a/src/core/hle/service/filesystem/fsp_srv.cpp
+++ b/src/core/hle/service/filesystem/fsp_srv.cpp
@@ -246,7 +246,13 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec
entries.reserve(entries.size() + new_data.size());
for (const auto& new_entry : new_data) {
- entries.emplace_back(new_entry->GetName(), type,
+ auto name = new_entry->GetName();
+
+ if (type == FileSys::EntryType::File && name == FileSys::GetSaveDataSizeFileName()) {
+ continue;
+ }
+
+ entries.emplace_back(name, type,
type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize());
}
}
diff --git a/src/core/hle/service/hid/controllers/applet_resource.cpp b/src/core/hle/service/hid/controllers/applet_resource.cpp
new file mode 100644
index 000000000..c8e74c764
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/applet_resource.cpp
@@ -0,0 +1,313 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/service/hid/controllers/applet_resource.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
+#include "core/hle/service/hid/errors.h"
+
+namespace Service::HID {
+
+AppletResource::AppletResource(Core::System& system_) : system{system_} {}
+
+AppletResource::~AppletResource() = default;
+
+Result AppletResource::CreateAppletResource(u64 aruid) {
+ const u64 index = GetIndexFromAruid(aruid);
+
+ if (index >= AruidIndexMax) {
+ return ResultAruidNotRegistered;
+ }
+
+ if (data[index].flag.is_assigned) {
+ return ResultAruidAlreadyRegistered;
+ }
+
+ auto& shared_memory = shared_memory_holder[index];
+ if (!shared_memory.IsMapped()) {
+ const Result result = shared_memory.Initialize(system);
+ if (result.IsError()) {
+ return result;
+ }
+ if (shared_memory.GetAddress() == nullptr) {
+ shared_memory.Finalize();
+ return ResultSharedMemoryNotInitialized;
+ }
+ }
+
+ auto* shared_memory_format = shared_memory.GetAddress();
+ if (shared_memory_format != nullptr) {
+ shared_memory_format->Initialize();
+ }
+
+ data[index].shared_memory_format = shared_memory_format;
+ data[index].flag.is_assigned.Assign(true);
+ // TODO: InitializeSixAxisControllerConfig(false);
+ active_aruid = aruid;
+ return ResultSuccess;
+}
+
+Result AppletResource::RegisterAppletResourceUserId(u64 aruid, bool enable_input) {
+ const u64 index = GetIndexFromAruid(aruid);
+
+ if (index < AruidIndexMax) {
+ return ResultAruidAlreadyRegistered;
+ }
+
+ std::size_t data_index = AruidIndexMax;
+ for (std::size_t i = 0; i < AruidIndexMax; i++) {
+ if (!data[i].flag.is_initialized) {
+ data_index = i;
+ break;
+ }
+ }
+
+ if (data_index == AruidIndexMax) {
+ return ResultAruidNoAvailableEntries;
+ }
+
+ AruidData& aruid_data = data[data_index];
+
+ aruid_data.aruid = aruid;
+ aruid_data.flag.is_initialized.Assign(true);
+ if (enable_input) {
+ aruid_data.flag.enable_pad_input.Assign(true);
+ aruid_data.flag.enable_six_axis_sensor.Assign(true);
+ aruid_data.flag.bit_18.Assign(true);
+ aruid_data.flag.enable_touchscreen.Assign(true);
+ }
+
+ data_index = AruidIndexMax;
+ for (std::size_t i = 0; i < AruidIndexMax; i++) {
+ if (registration_list.flag[i] == RegistrationStatus::Initialized) {
+ if (registration_list.aruid[i] != aruid) {
+ continue;
+ }
+ data_index = i;
+ break;
+ }
+ if (registration_list.flag[i] == RegistrationStatus::None) {
+ data_index = i;
+ break;
+ }
+ }
+
+ if (data_index == AruidIndexMax) {
+ return ResultSuccess;
+ }
+
+ registration_list.flag[data_index] = RegistrationStatus::Initialized;
+ registration_list.aruid[data_index] = aruid;
+
+ return ResultSuccess;
+}
+
+void AppletResource::UnregisterAppletResourceUserId(u64 aruid) {
+ u64 index = GetIndexFromAruid(aruid);
+
+ if (index < AruidIndexMax) {
+ if (data[index].flag.is_assigned) {
+ data[index].shared_memory_format = nullptr;
+ data[index].flag.is_assigned.Assign(false);
+ }
+ }
+
+ index = GetIndexFromAruid(aruid);
+ if (index < AruidIndexMax) {
+ DestroySevenSixAxisTransferMemory();
+ data[index].flag.raw = 0;
+ data[index].aruid = 0;
+
+ index = GetIndexFromAruid(aruid);
+ if (index < AruidIndexMax) {
+ registration_list.flag[index] = RegistrationStatus::PendingDelete;
+ }
+ }
+}
+
+void AppletResource::FreeAppletResourceId(u64 aruid) {
+ u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ auto& aruid_data = data[index];
+ if (aruid_data.flag.is_assigned) {
+ aruid_data.shared_memory_format = nullptr;
+ aruid_data.flag.is_assigned.Assign(false);
+ }
+}
+
+u64 AppletResource::GetActiveAruid() {
+ return active_aruid;
+}
+
+Result AppletResource::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
+ u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return ResultAruidNotRegistered;
+ }
+
+ *out_handle = shared_memory_holder[index].GetHandle();
+ return ResultSuccess;
+}
+
+Result AppletResource::GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format,
+ u64 aruid) {
+ u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return ResultAruidNotRegistered;
+ }
+
+ *out_shared_memory_format = data[index].shared_memory_format;
+ return ResultSuccess;
+}
+
+u64 AppletResource::GetIndexFromAruid(u64 aruid) {
+ for (std::size_t i = 0; i < AruidIndexMax; i++) {
+ if (registration_list.flag[i] == RegistrationStatus::Initialized &&
+ registration_list.aruid[i] == aruid) {
+ return i;
+ }
+ }
+ return AruidIndexMax;
+}
+
+Result AppletResource::DestroySevenSixAxisTransferMemory() {
+ // TODO
+ return ResultSuccess;
+}
+
+void AppletResource::EnableInput(u64 aruid, bool is_enabled) {
+ const u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ data[index].flag.enable_pad_input.Assign(is_enabled);
+ data[index].flag.enable_touchscreen.Assign(is_enabled);
+}
+
+void AppletResource::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
+ const u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ data[index].flag.enable_six_axis_sensor.Assign(is_enabled);
+}
+
+void AppletResource::EnablePadInput(u64 aruid, bool is_enabled) {
+ const u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ data[index].flag.enable_pad_input.Assign(is_enabled);
+}
+
+void AppletResource::EnableTouchScreen(u64 aruid, bool is_enabled) {
+ const u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ data[index].flag.enable_touchscreen.Assign(is_enabled);
+}
+
+void AppletResource::SetIsPalmaConnectable(u64 aruid, bool is_connectable) {
+ const u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ data[index].flag.is_palma_connectable.Assign(is_connectable);
+}
+
+void AppletResource::EnablePalmaBoostMode(u64 aruid, bool is_enabled) {
+ const u64 index = GetIndexFromAruid(aruid);
+ if (index >= AruidIndexMax) {
+ return;
+ }
+
+ data[index].flag.enable_palma_boost_mode.Assign(is_enabled);
+}
+
+Result AppletResource::RegisterCoreAppletResource() {
+ if (ref_counter == std::numeric_limits<s32>::max() - 1) {
+ return ResultAppletResourceOverflow;
+ }
+ if (ref_counter == 0) {
+ const u64 index = GetIndexFromAruid(0);
+ if (index < AruidIndexMax) {
+ return ResultAruidAlreadyRegistered;
+ }
+
+ std::size_t data_index = AruidIndexMax;
+ for (std::size_t i = 0; i < AruidIndexMax; i++) {
+ if (!data[i].flag.is_initialized) {
+ data_index = i;
+ break;
+ }
+ }
+
+ if (data_index == AruidIndexMax) {
+ return ResultAruidNoAvailableEntries;
+ }
+
+ AruidData& aruid_data = data[data_index];
+
+ aruid_data.aruid = 0;
+ aruid_data.flag.is_initialized.Assign(true);
+ aruid_data.flag.enable_pad_input.Assign(true);
+ aruid_data.flag.enable_six_axis_sensor.Assign(true);
+ aruid_data.flag.bit_18.Assign(true);
+ aruid_data.flag.enable_touchscreen.Assign(true);
+
+ data_index = AruidIndexMax;
+ for (std::size_t i = 0; i < AruidIndexMax; i++) {
+ if (registration_list.flag[i] == RegistrationStatus::Initialized) {
+ if (registration_list.aruid[i] != 0) {
+ continue;
+ }
+ data_index = i;
+ break;
+ }
+ if (registration_list.flag[i] == RegistrationStatus::None) {
+ data_index = i;
+ break;
+ }
+ }
+
+ Result result = ResultSuccess;
+
+ if (data_index == AruidIndexMax) {
+ result = CreateAppletResource(0);
+ } else {
+ registration_list.flag[data_index] = RegistrationStatus::Initialized;
+ registration_list.aruid[data_index] = 0;
+ }
+
+ if (result.IsError()) {
+ UnregisterAppletResourceUserId(0);
+ return result;
+ }
+ }
+ ref_counter++;
+ return ResultSuccess;
+}
+
+Result AppletResource::UnregisterCoreAppletResource() {
+ if (ref_counter == 0) {
+ return ResultAppletResourceNotInitialized;
+ }
+
+ if (--ref_counter == 0) {
+ UnregisterAppletResourceUserId(0);
+ }
+
+ return ResultSuccess;
+}
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/applet_resource.h b/src/core/hle/service/hid/controllers/applet_resource.h
new file mode 100644
index 000000000..e7991f93a
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/applet_resource.h
@@ -0,0 +1,98 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hle/result.h"
+#include "core/hle/service/hid/controllers/shared_memory_holder.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KSharedMemory;
+}
+
+namespace Service::HID {
+struct SharedMemoryFormat;
+
+class AppletResource {
+public:
+ explicit AppletResource(Core::System& system_);
+ ~AppletResource();
+
+ Result CreateAppletResource(u64 aruid);
+
+ Result RegisterAppletResourceUserId(u64 aruid, bool enable_input);
+ void UnregisterAppletResourceUserId(u64 aruid);
+
+ void FreeAppletResourceId(u64 aruid);
+
+ u64 GetActiveAruid();
+ Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
+ Result GetSharedMemoryFormat(SharedMemoryFormat** out_shared_memory_format, u64 aruid);
+
+ u64 GetIndexFromAruid(u64 aruid);
+
+ Result DestroySevenSixAxisTransferMemory();
+
+ void EnableInput(u64 aruid, bool is_enabled);
+ void EnableSixAxisSensor(u64 aruid, bool is_enabled);
+ void EnablePadInput(u64 aruid, bool is_enabled);
+ void EnableTouchScreen(u64 aruid, bool is_enabled);
+ void SetIsPalmaConnectable(u64 aruid, bool is_connectable);
+ void EnablePalmaBoostMode(u64 aruid, bool is_enabled);
+
+ Result RegisterCoreAppletResource();
+ Result UnregisterCoreAppletResource();
+
+private:
+ static constexpr std::size_t AruidIndexMax = 0x20;
+
+ enum RegistrationStatus : u32 {
+ None,
+ Initialized,
+ PendingDelete,
+ };
+
+ struct DataStatusFlag {
+ union {
+ u32 raw{};
+
+ BitField<0, 1, u32> is_initialized;
+ BitField<1, 1, u32> is_assigned;
+ BitField<16, 1, u32> enable_pad_input;
+ BitField<17, 1, u32> enable_six_axis_sensor;
+ BitField<18, 1, u32> bit_18;
+ BitField<19, 1, u32> is_palma_connectable;
+ BitField<20, 1, u32> enable_palma_boost_mode;
+ BitField<21, 1, u32> enable_touchscreen;
+ };
+ };
+
+ struct AruidRegisterList {
+ std::array<RegistrationStatus, AruidIndexMax> flag{};
+ std::array<u64, AruidIndexMax> aruid{};
+ };
+ static_assert(sizeof(AruidRegisterList) == 0x180, "AruidRegisterList is an invalid size");
+
+ struct AruidData {
+ DataStatusFlag flag{};
+ u64 aruid{};
+ SharedMemoryFormat* shared_memory_format{nullptr};
+ };
+
+ u64 active_aruid{};
+ AruidRegisterList registration_list{};
+ std::array<AruidData, AruidIndexMax> data{};
+ std::array<SharedMemoryHolder, AruidIndexMax> shared_memory_holder{};
+ s32 ref_counter{};
+
+ Core::System& system;
+};
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.cpp b/src/core/hle/service/hid/controllers/console_six_axis.cpp
index b2bf1d78d..3961d2b5f 100644
--- a/src/core/hle/service/hid/controllers/console_six_axis.cpp
+++ b/src/core/hle/service/hid/controllers/console_six_axis.cpp
@@ -1,23 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "core/core.h"
#include "core/core_timing.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/console_six_axis.h"
-#include "core/memory.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200;
-ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
+ConsoleSixAxis::ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
+ ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{console_shared_memory} {
console = hid_core.GetEmulatedConsole();
- static_assert(SHARED_MEMORY_OFFSET + sizeof(ConsoleSharedMemory) < shared_memory_size,
- "ConsoleSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<ConsoleSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
}
ConsoleSixAxis::~ConsoleSixAxis() = default;
@@ -33,10 +28,10 @@ void ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
const auto motion_status = console->GetMotion();
- shared_memory->sampling_number++;
- shared_memory->is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
- shared_memory->verticalization_error = motion_status.verticalization_error;
- shared_memory->gyro_bias = motion_status.gyro_bias;
+ shared_memory.sampling_number++;
+ shared_memory.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest;
+ shared_memory.verticalization_error = motion_status.verticalization_error;
+ shared_memory.gyro_bias = motion_status.gyro_bias;
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/console_six_axis.h b/src/core/hle/service/hid/controllers/console_six_axis.h
index 5b7c6a29a..3d1c9ce23 100644
--- a/src/core/hle/service/hid/controllers/console_six_axis.h
+++ b/src/core/hle/service/hid/controllers/console_six_axis.h
@@ -3,7 +3,6 @@
#pragma once
-#include "common/vector_math.h"
#include "core/hle/service/hid/controllers/controller_base.h"
namespace Core::HID {
@@ -11,9 +10,12 @@ class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID {
+struct ConsoleSixAxisSensorSharedMemoryFormat;
+
class ConsoleSixAxis final : public ControllerBase {
public:
- explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit ConsoleSixAxis(Core::HID::HIDCore& hid_core_,
+ ConsoleSixAxisSensorSharedMemoryFormat& console_shared_memory);
~ConsoleSixAxis() override;
// Called when the controller is initialized
@@ -26,18 +28,7 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- // This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
- struct ConsoleSharedMemory {
- u64 sampling_number{};
- bool is_seven_six_axis_sensor_at_rest{};
- INSERT_PADDING_BYTES(3); // padding
- f32 verticalization_error{};
- Common::Vec3f gyro_bias{};
- INSERT_PADDING_BYTES(4); // padding
- };
- static_assert(sizeof(ConsoleSharedMemory) == 0x20, "ConsoleSharedMemory is an invalid size");
-
- ConsoleSharedMemory* shared_memory = nullptr;
+ ConsoleSixAxisSensorSharedMemoryFormat& shared_memory;
Core::HID::EmulatedConsole* console = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/controller_base.h b/src/core/hle/service/hid/controllers/controller_base.h
index 9a44ee41e..4326c7821 100644
--- a/src/core/hle/service/hid/controllers/controller_base.h
+++ b/src/core/hle/service/hid/controllers/controller_base.h
@@ -39,9 +39,6 @@ public:
bool IsControllerActivated() const;
- static const std::size_t hid_entry_count = 17;
- static const std::size_t shared_memory_size = 0x40000;
-
protected:
bool is_activated{false};
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp
index 9de19ebfc..7d2370b4f 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.cpp
+++ b/src/core/hle/service/hid/controllers/debug_pad.cpp
@@ -1,24 +1,19 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000;
-
-DebugPad::DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(DebugPadSharedMemory) < shared_memory_size,
- "DebugPadSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<DebugPadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+
+DebugPad::DebugPad(Core::HID::HIDCore& hid_core_,
+ DebugPadSharedMemoryFormat& debug_pad_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{debug_pad_shared_memory} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
}
@@ -30,12 +25,12 @@ void DebugPad::OnRelease() {}
void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->debug_pad_lifo.buffer_count = 0;
- shared_memory->debug_pad_lifo.buffer_tail = 0;
+ shared_memory.debug_pad_lifo.buffer_count = 0;
+ shared_memory.debug_pad_lifo.buffer_tail = 0;
return;
}
- const auto& last_entry = shared_memory->debug_pad_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.debug_pad_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.debug_pad_enabled) {
@@ -49,7 +44,7 @@ void DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.r_stick = stick_state.right;
}
- shared_memory->debug_pad_lifo.WriteNextEntry(next_state);
+ shared_memory.debug_pad_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/debug_pad.h b/src/core/hle/service/hid/controllers/debug_pad.h
index 5566dba77..8ab29eca8 100644
--- a/src/core/hle/service/hid/controllers/debug_pad.h
+++ b/src/core/hle/service/hid/controllers/debug_pad.h
@@ -3,21 +3,24 @@
#pragma once
-#include "common/bit_field.h"
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/debug_pad_types.h"
namespace Core::HID {
-class EmulatedController;
-struct DebugPadButton;
-struct AnalogStickState;
-} // namespace Core::HID
+class HIDCore;
+}
+
+namespace Core::Timing {
+class CoreTiming;
+}
namespace Service::HID {
+struct DebugPadSharedMemoryFormat;
+
class DebugPad final : public ControllerBase {
public:
- explicit DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit DebugPad(Core::HID::HIDCore& hid_core_,
+ DebugPadSharedMemoryFormat& debug_pad_shared_memory);
~DebugPad() override;
// Called when the controller is initialized
@@ -30,35 +33,8 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- // This is nn::hid::DebugPadAttribute
- struct DebugPadAttribute {
- union {
- u32 raw{};
- BitField<0, 1, u32> connected;
- };
- };
- static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
-
- // This is nn::hid::DebugPadState
- struct DebugPadState {
- s64 sampling_number{};
- DebugPadAttribute attribute{};
- Core::HID::DebugPadButton pad_state{};
- Core::HID::AnalogStickState r_stick{};
- Core::HID::AnalogStickState l_stick{};
- };
- static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
-
- struct DebugPadSharedMemory {
- // This is nn::hid::detail::DebugPadLifo
- Lifo<DebugPadState, hid_entry_count> debug_pad_lifo{};
- static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x4E);
- };
- static_assert(sizeof(DebugPadSharedMemory) == 0x400, "DebugPadSharedMemory is an invalid size");
-
DebugPadState next_state{};
- DebugPadSharedMemory* shared_memory = nullptr;
+ DebugPadSharedMemoryFormat& shared_memory;
Core::HID::EmulatedController* controller = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/gesture.cpp b/src/core/hle/service/hid/controllers/gesture.cpp
index 59b2ec73c..f658005f6 100644
--- a/src/core/hle/service/hid/controllers/gesture.cpp
+++ b/src/core/hle/service/hid/controllers/gesture.cpp
@@ -1,17 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include "common/logging/log.h"
#include "common/math_util.h"
#include "common/settings.h"
-#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
+#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/gesture.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3BA00;
-
// HW is around 700, value is set to 400 to make it easier to trigger with mouse
constexpr f32 swipe_threshold = 400.0f; // Threshold in pixels/s
constexpr f32 angle_threshold = 0.015f; // Threshold in radians
@@ -23,19 +21,15 @@ constexpr f32 Square(s32 num) {
return static_cast<f32>(num * num);
}
-Gesture::Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase(hid_core_) {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(GestureSharedMemory) < shared_memory_size,
- "GestureSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<GestureSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+Gesture::Gesture(Core::HID::HIDCore& hid_core_, GestureSharedMemoryFormat& gesture_shared_memory)
+ : ControllerBase(hid_core_), shared_memory{gesture_shared_memory} {
console = hid_core.GetEmulatedConsole();
}
Gesture::~Gesture() = default;
void Gesture::OnInit() {
- shared_memory->gesture_lifo.buffer_count = 0;
- shared_memory->gesture_lifo.buffer_tail = 0;
+ shared_memory.gesture_lifo.buffer_count = 0;
+ shared_memory.gesture_lifo.buffer_tail = 0;
force_update = true;
}
@@ -43,8 +37,8 @@ void Gesture::OnRelease() {}
void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->gesture_lifo.buffer_count = 0;
- shared_memory->gesture_lifo.buffer_tail = 0;
+ shared_memory.gesture_lifo.buffer_count = 0;
+ shared_memory.gesture_lifo.buffer_tail = 0;
return;
}
@@ -52,7 +46,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
GestureProperties gesture = GetGestureProperties();
f32 time_difference =
- static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) /
+ static_cast<f32>(shared_memory.gesture_lifo.timestamp - last_update_timestamp) /
(1000 * 1000 * 1000);
// Only update if necessary
@@ -60,7 +54,7 @@ void Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return;
}
- last_update_timestamp = shared_memory->gesture_lifo.timestamp;
+ last_update_timestamp = shared_memory.gesture_lifo.timestamp;
UpdateGestureSharedMemory(gesture, time_difference);
}
@@ -103,7 +97,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
GestureType type = GestureType::Idle;
GestureAttribute attributes{};
- const auto& last_entry = shared_memory->gesture_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.gesture_lifo.ReadCurrentEntry().state;
// Reset next state to default
next_state.sampling_number = last_entry.sampling_number + 1;
@@ -133,7 +127,7 @@ void Gesture::UpdateGestureSharedMemory(GestureProperties& gesture, f32 time_dif
next_state.points = gesture.points;
last_gesture = gesture;
- shared_memory->gesture_lifo.WriteNextEntry(next_state);
+ shared_memory.gesture_lifo.WriteNextEntry(next_state);
}
void Gesture::NewGesture(GestureProperties& gesture, GestureType& type,
@@ -305,11 +299,11 @@ void Gesture::SetSwipeEvent(GestureProperties& gesture, GestureProperties& last_
next_state.direction = GestureDirection::Up;
}
-const Gesture::GestureState& Gesture::GetLastGestureEntry() const {
- return shared_memory->gesture_lifo.ReadCurrentEntry().state;
+const GestureState& Gesture::GetLastGestureEntry() const {
+ return shared_memory.gesture_lifo.ReadCurrentEntry().state;
}
-Gesture::GestureProperties Gesture::GetGestureProperties() {
+GestureProperties Gesture::GetGestureProperties() {
GestureProperties gesture;
std::array<Core::HID::TouchFinger, MAX_POINTS> active_fingers;
const auto end_iter = std::copy_if(fingers.begin(), fingers.end(), active_fingers.begin(),
diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h
index 4c6f8ee07..41fdfcd03 100644
--- a/src/core/hle/service/hid/controllers/gesture.h
+++ b/src/core/hle/service/hid/controllers/gesture.h
@@ -4,17 +4,22 @@
#pragma once
#include <array>
-#include "common/bit_field.h"
+
#include "common/common_types.h"
-#include "common/point.h"
-#include "core/hid/emulated_console.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/touch_types.h"
+
+namespace Core::HID {
+class EmulatedConsole;
+}
namespace Service::HID {
+struct GestureSharedMemoryFormat;
+
class Gesture final : public ControllerBase {
public:
- explicit Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Gesture(Core::HID::HIDCore& hid_core_,
+ GestureSharedMemoryFormat& gesture_shared_memory);
~Gesture() override;
// Called when the controller is initialized
@@ -27,79 +32,6 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- static constexpr size_t MAX_FINGERS = 16;
- static constexpr size_t MAX_POINTS = 4;
-
- // This is nn::hid::GestureType
- enum class GestureType : u32 {
- Idle, // Nothing touching the screen
- Complete, // Set at the end of a touch event
- Cancel, // Set when the number of fingers change
- Touch, // A finger just touched the screen
- Press, // Set if last type is touch and the finger hasn't moved
- Tap, // Fast press then release
- Pan, // All points moving together across the screen
- Swipe, // Fast press movement and release of a single point
- Pinch, // All points moving away/closer to the midpoint
- Rotate, // All points rotating from the midpoint
- };
-
- // This is nn::hid::GestureDirection
- enum class GestureDirection : u32 {
- None,
- Left,
- Up,
- Right,
- Down,
- };
-
- // This is nn::hid::GestureAttribute
- struct GestureAttribute {
- union {
- u32 raw{};
-
- BitField<4, 1, u32> is_new_touch;
- BitField<8, 1, u32> is_double_tap;
- };
- };
- static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
-
- // This is nn::hid::GestureState
- struct GestureState {
- s64 sampling_number{};
- s64 detection_count{};
- GestureType type{GestureType::Idle};
- GestureDirection direction{GestureDirection::None};
- Common::Point<s32> pos{};
- Common::Point<s32> delta{};
- f32 vel_x{};
- f32 vel_y{};
- GestureAttribute attributes{};
- f32 scale{};
- f32 rotation_angle{};
- s32 point_count{};
- std::array<Common::Point<s32>, 4> points{};
- };
- static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
-
- struct GestureProperties {
- std::array<Common::Point<s32>, MAX_POINTS> points{};
- std::size_t active_points{};
- Common::Point<s32> mid_point{};
- s64 detection_count{};
- u64 delta_time{};
- f32 average_distance{};
- f32 angle{};
- };
-
- struct GestureSharedMemory {
- // This is nn::hid::detail::GestureLifo
- Lifo<GestureState, hid_entry_count> gesture_lifo{};
- static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x3E);
- };
- static_assert(sizeof(GestureSharedMemory) == 0x800, "GestureSharedMemory is an invalid size");
-
// Reads input from all available input engines
void ReadTouchInput();
@@ -142,7 +74,7 @@ private:
GestureProperties GetGestureProperties();
GestureState next_state{};
- GestureSharedMemory* shared_memory = nullptr;
+ GestureSharedMemoryFormat& shared_memory;
Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{};
diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp
index ddb1b0ba4..871e5036a 100644
--- a/src/core/hle/service/hid/controllers/keyboard.cpp
+++ b/src/core/hle/service/hid/controllers/keyboard.cpp
@@ -1,23 +1,18 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "common/settings.h"
#include "core/core_timing.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/keyboard.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800;
-
-Keyboard::Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(KeyboardSharedMemory) < shared_memory_size,
- "KeyboardSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<KeyboardSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+
+Keyboard::Keyboard(Core::HID::HIDCore& hid_core_,
+ KeyboardSharedMemoryFormat& keyboard_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{keyboard_shared_memory} {
emulated_devices = hid_core.GetEmulatedDevices();
}
@@ -29,12 +24,12 @@ void Keyboard::OnRelease() {}
void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->keyboard_lifo.buffer_count = 0;
- shared_memory->keyboard_lifo.buffer_tail = 0;
+ shared_memory.keyboard_lifo.buffer_count = 0;
+ shared_memory.keyboard_lifo.buffer_tail = 0;
return;
}
- const auto& last_entry = shared_memory->keyboard_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.keyboard_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.keyboard_enabled) {
@@ -46,7 +41,7 @@ void Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.attribute.is_connected.Assign(1);
}
- shared_memory->keyboard_lifo.WriteNextEntry(next_state);
+ shared_memory.keyboard_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/keyboard.h b/src/core/hle/service/hid/controllers/keyboard.h
index 172ec1309..4d72171b9 100644
--- a/src/core/hle/service/hid/controllers/keyboard.h
+++ b/src/core/hle/service/hid/controllers/keyboard.h
@@ -3,20 +3,16 @@
#pragma once
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
-
-namespace Core::HID {
-class EmulatedDevices;
-struct KeyboardModifier;
-struct KeyboardKey;
-} // namespace Core::HID
+#include "core/hle/service/hid/controllers/types/keyboard_types.h"
namespace Service::HID {
+struct KeyboardSharedMemoryFormat;
+
class Keyboard final : public ControllerBase {
public:
- explicit Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Keyboard(Core::HID::HIDCore& hid_core_,
+ KeyboardSharedMemoryFormat& keyboard_shared_memory);
~Keyboard() override;
// Called when the controller is initialized
@@ -29,25 +25,8 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- // This is nn::hid::detail::KeyboardState
- struct KeyboardState {
- s64 sampling_number{};
- Core::HID::KeyboardModifier modifier{};
- Core::HID::KeyboardAttribute attribute{};
- Core::HID::KeyboardKey key{};
- };
- static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
-
- struct KeyboardSharedMemory {
- // This is nn::hid::detail::KeyboardLifo
- Lifo<KeyboardState, hid_entry_count> keyboard_lifo{};
- static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
- INSERT_PADDING_WORDS(0xA);
- };
- static_assert(sizeof(KeyboardSharedMemory) == 0x400, "KeyboardSharedMemory is an invalid size");
-
KeyboardState next_state{};
- KeyboardSharedMemory* shared_memory = nullptr;
+ KeyboardSharedMemoryFormat& shared_memory;
Core::HID::EmulatedDevices* emulated_devices = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.cpp b/src/core/hle/service/hid/controllers/mouse.cpp
index 6e5a04e34..de5b2c804 100644
--- a/src/core/hle/service/hid/controllers/mouse.cpp
+++ b/src/core/hle/service/hid/controllers/mouse.cpp
@@ -1,22 +1,17 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hid/emulated_devices.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/mouse.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400;
-Mouse::Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(MouseSharedMemory) < shared_memory_size,
- "MouseSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<MouseSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
+Mouse::Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{mouse_shared_memory} {
emulated_devices = hid_core.GetEmulatedDevices();
}
@@ -27,14 +22,14 @@ void Mouse::OnRelease() {}
void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
if (!IsControllerActivated()) {
- shared_memory->mouse_lifo.buffer_count = 0;
- shared_memory->mouse_lifo.buffer_tail = 0;
+ shared_memory.mouse_lifo.buffer_count = 0;
+ shared_memory.mouse_lifo.buffer_tail = 0;
return;
}
next_state = {};
- const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.mouse_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
if (Settings::values.mouse_enabled) {
@@ -53,7 +48,7 @@ void Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
next_state.button = mouse_button_state;
}
- shared_memory->mouse_lifo.WriteNextEntry(next_state);
+ shared_memory.mouse_lifo.WriteNextEntry(next_state);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/mouse.h b/src/core/hle/service/hid/controllers/mouse.h
index a80f3823f..363f316a5 100644
--- a/src/core/hle/service/hid/controllers/mouse.h
+++ b/src/core/hle/service/hid/controllers/mouse.h
@@ -3,9 +3,7 @@
#pragma once
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
namespace Core::HID {
class EmulatedDevices;
@@ -14,9 +12,11 @@ struct AnalogStickState;
} // namespace Core::HID
namespace Service::HID {
+struct MouseSharedMemoryFormat;
+
class Mouse final : public ControllerBase {
public:
- explicit Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Mouse(Core::HID::HIDCore& hid_core_, MouseSharedMemoryFormat& mouse_shared_memory);
~Mouse() override;
// Called when the controller is initialized
@@ -29,17 +29,9 @@ public:
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
private:
- struct MouseSharedMemory {
- // This is nn::hid::detail::MouseLifo
- Lifo<Core::HID::MouseState, hid_entry_count> mouse_lifo{};
- static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x2C);
- };
- static_assert(sizeof(MouseSharedMemory) == 0x400, "MouseSharedMemory is an invalid size");
-
Core::HID::MouseState next_state{};
Core::HID::AnalogStickState last_mouse_wheel_state{};
- MouseSharedMemory* shared_memory = nullptr;
+ MouseSharedMemoryFormat& shared_memory;
Core::HID::EmulatedDevices* emulated_devices = nullptr;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index 08ee9de9c..53a737cf5 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -17,12 +17,12 @@
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h"
#include "core/hle/service/kernel_helpers.h"
namespace Service::HID {
-constexpr std::size_t NPAD_OFFSET = 0x9A00;
constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
Core::HID::NpadIdType::Player1, Core::HID::NpadIdType::Player2, Core::HID::NpadIdType::Player3,
Core::HID::NpadIdType::Player4, Core::HID::NpadIdType::Player5, Core::HID::NpadIdType::Player6,
@@ -30,14 +30,12 @@ constexpr std::array<Core::HID::NpadIdType, 10> npad_id_list{
Core::HID::NpadIdType::Handheld,
};
-NPad::NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
+NPad::NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} {
- static_assert(NPAD_OFFSET + (NPAD_COUNT * sizeof(NpadInternalState)) < shared_memory_size);
for (std::size_t i = 0; i < controller_data.size(); ++i) {
auto& controller = controller_data[i];
- controller.shared_memory = std::construct_at(reinterpret_cast<NpadInternalState*>(
- raw_shared_memory_ + NPAD_OFFSET + (i * sizeof(NpadInternalState))));
+ controller.shared_memory = &npad_shared_memory_format.npad_entry[i].internal_state;
controller.device = hid_core.GetEmulatedControllerByIndex(i);
controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value =
Core::HID::DEFAULT_VIBRATION_VALUE;
@@ -617,7 +615,7 @@ void NPad::SetHoldType(NpadJoyHoldType joy_hold_type) {
hold_type = joy_hold_type;
}
-NPad::NpadJoyHoldType NPad::GetHoldType() const {
+NpadJoyHoldType NPad::GetHoldType() const {
return hold_type;
}
@@ -630,7 +628,7 @@ void NPad::SetNpadHandheldActivationMode(NpadHandheldActivationMode activation_m
handheld_activation_mode = activation_mode;
}
-NPad::NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
+NpadHandheldActivationMode NPad::GetNpadHandheldActivationMode() const {
return handheld_activation_mode;
}
@@ -638,7 +636,7 @@ void NPad::SetNpadCommunicationMode(NpadCommunicationMode communication_mode_) {
communication_mode = communication_mode_;
}
-NPad::NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
+NpadCommunicationMode NPad::GetNpadCommunicationMode() const {
return communication_mode;
}
@@ -978,27 +976,27 @@ Result NPad::ResetIsSixAxisSensorDeviceNewlyAssigned(
return ResultSuccess;
}
-NPad::SixAxisLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_fullkey_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_handheld_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_left_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_dual_right_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_left_lifo;
}
-NPad::SixAxisLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
+NpadSixAxisSensorLifo& NPad::GetSixAxisRightLifo(Core::HID::NpadIdType npad_id) {
return GetControllerFromNpadIdType(npad_id).shared_memory->sixaxis_right_lifo;
}
@@ -1343,7 +1341,7 @@ const Core::HID::SixAxisSensorProperties& NPad::GetSixaxisProperties(
}
}
-NPad::AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
+AppletDetailedUiType NPad::GetAppletDetailedUiType(Core::HID::NpadIdType npad_id) {
const auto& shared_memory = GetControllerFromNpadIdType(npad_id).shared_memory;
return {
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 9167c93f0..4e2412356 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -8,12 +8,10 @@
#include <mutex>
#include <span>
-#include "common/bit_field.h"
#include "common/common_types.h"
-
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/npad_types.h"
namespace Core::HID {
class EmulatedController;
@@ -32,10 +30,13 @@ class ServiceContext;
union Result;
namespace Service::HID {
+struct NpadInternalState;
+struct NpadSixAxisSensorLifo;
+struct NpadSharedMemoryFormat;
class NPad final : public ControllerBase {
public:
- explicit NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
+ explicit NPad(Core::HID::HIDCore& hid_core_, NpadSharedMemoryFormat& npad_shared_memory_format,
KernelHelpers::ServiceContext& service_context_);
~NPad() override;
@@ -48,89 +49,6 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
- // This is nn::hid::NpadJoyHoldType
- enum class NpadJoyHoldType : u64 {
- Vertical = 0,
- Horizontal = 1,
- };
-
- // This is nn::hid::NpadJoyAssignmentMode
- enum class NpadJoyAssignmentMode : u32 {
- Dual = 0,
- Single = 1,
- };
-
- // This is nn::hid::NpadJoyDeviceType
- enum class NpadJoyDeviceType : s64 {
- Left = 0,
- Right = 1,
- };
-
- // This is nn::hid::NpadHandheldActivationMode
- enum class NpadHandheldActivationMode : u64 {
- Dual = 0,
- Single = 1,
- None = 2,
- MaxActivationMode = 3,
- };
-
- // This is nn::hid::system::AppletFooterUiAttributesSet
- struct AppletFooterUiAttributes {
- INSERT_PADDING_BYTES(0x4);
- };
-
- // This is nn::hid::system::AppletFooterUiType
- enum class AppletFooterUiType : u8 {
- None = 0,
- HandheldNone = 1,
- HandheldJoyConLeftOnly = 2,
- HandheldJoyConRightOnly = 3,
- HandheldJoyConLeftJoyConRight = 4,
- JoyDual = 5,
- JoyDualLeftOnly = 6,
- JoyDualRightOnly = 7,
- JoyLeftHorizontal = 8,
- JoyLeftVertical = 9,
- JoyRightHorizontal = 10,
- JoyRightVertical = 11,
- SwitchProController = 12,
- CompatibleProController = 13,
- CompatibleJoyCon = 14,
- LarkHvc1 = 15,
- LarkHvc2 = 16,
- LarkNesLeft = 17,
- LarkNesRight = 18,
- Lucia = 19,
- Verification = 20,
- Lagon = 21,
- };
-
- using AppletFooterUiVariant = u8;
-
- // This is "nn::hid::system::AppletDetailedUiType".
- struct AppletDetailedUiType {
- AppletFooterUiVariant ui_variant;
- INSERT_PADDING_BYTES(0x2);
- AppletFooterUiType footer;
- };
- static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
- // This is nn::hid::NpadCommunicationMode
- enum class NpadCommunicationMode : u64 {
- Mode_5ms = 0,
- Mode_10ms = 1,
- Mode_15ms = 2,
- Default = 3,
- };
-
- enum class NpadRevision : u32 {
- Revision0 = 0,
- Revision1 = 1,
- Revision2 = 2,
- Revision3 = 3,
- };
-
- using SixAxisLifo = Lifo<Core::HID::SixAxisSensorState, hid_entry_count>;
-
void SetSupportedStyleSet(Core::HID::NpadStyleTag style_set);
Core::HID::NpadStyleTag GetSupportedStyleSet() const;
@@ -188,12 +106,12 @@ public:
Result ResetIsSixAxisSensorDeviceNewlyAssigned(
const Core::HID::SixAxisSensorHandle& sixaxis_handle);
- SixAxisLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
- SixAxisLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisFullkeyLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisHandheldLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisDualLeftLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisDualRightLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisLeftLifo(Core::HID::NpadIdType npad_id);
+ NpadSixAxisSensorLifo& GetSixAxisRightLifo(Core::HID::NpadIdType npad_id);
Result GetLedPattern(Core::HID::NpadIdType npad_id, Core::HID::LedPattern& pattern) const;
Result IsUnintendedHomeButtonInputProtectionEnabled(Core::HID::NpadIdType npad_id,
@@ -221,214 +139,6 @@ public:
AppletDetailedUiType GetAppletDetailedUiType(Core::HID::NpadIdType npad_id);
private:
- static constexpr std::size_t NPAD_COUNT = 10;
-
- // This is nn::hid::detail::ColorAttribute
- enum class ColorAttribute : u32 {
- Ok = 0,
- ReadError = 1,
- NoController = 2,
- };
- static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
-
- // This is nn::hid::detail::NpadFullKeyColorState
- struct NpadFullKeyColorState {
- ColorAttribute attribute{ColorAttribute::NoController};
- Core::HID::NpadControllerColor fullkey{};
- };
- static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
-
- // This is nn::hid::detail::NpadJoyColorState
- struct NpadJoyColorState {
- ColorAttribute attribute{ColorAttribute::NoController};
- Core::HID::NpadControllerColor left{};
- Core::HID::NpadControllerColor right{};
- };
- static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
-
- // This is nn::hid::NpadAttribute
- struct NpadAttribute {
- union {
- u32 raw{};
- BitField<0, 1, u32> is_connected;
- BitField<1, 1, u32> is_wired;
- BitField<2, 1, u32> is_left_connected;
- BitField<3, 1, u32> is_left_wired;
- BitField<4, 1, u32> is_right_connected;
- BitField<5, 1, u32> is_right_wired;
- };
- };
- static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
-
- // This is nn::hid::NpadFullKeyState
- // This is nn::hid::NpadHandheldState
- // This is nn::hid::NpadJoyDualState
- // This is nn::hid::NpadJoyLeftState
- // This is nn::hid::NpadJoyRightState
- // This is nn::hid::NpadPalmaState
- // This is nn::hid::NpadSystemExtState
- struct NPadGenericState {
- s64_le sampling_number{};
- Core::HID::NpadButtonState npad_buttons{};
- Core::HID::AnalogStickState l_stick{};
- Core::HID::AnalogStickState r_stick{};
- NpadAttribute connection_status{};
- INSERT_PADDING_BYTES(4); // Reserved
- };
- static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
-
- // This is nn::hid::server::NpadGcTriggerState
- struct NpadGcTriggerState {
- s64 sampling_number{};
- s32 l_analog{};
- s32 r_analog{};
- };
- static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
-
- // This is nn::hid::NpadSystemProperties
- struct NPadSystemProperties {
- union {
- s64 raw{};
- BitField<0, 1, s64> is_charging_joy_dual;
- BitField<1, 1, s64> is_charging_joy_left;
- BitField<2, 1, s64> is_charging_joy_right;
- BitField<3, 1, s64> is_powered_joy_dual;
- BitField<4, 1, s64> is_powered_joy_left;
- BitField<5, 1, s64> is_powered_joy_right;
- BitField<9, 1, s64> is_system_unsupported_button;
- BitField<10, 1, s64> is_system_ext_unsupported_button;
- BitField<11, 1, s64> is_vertical;
- BitField<12, 1, s64> is_horizontal;
- BitField<13, 1, s64> use_plus;
- BitField<14, 1, s64> use_minus;
- BitField<15, 1, s64> use_directional_buttons;
- };
- };
- static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
-
- // This is nn::hid::NpadSystemButtonProperties
- struct NpadSystemButtonProperties {
- union {
- s32 raw{};
- BitField<0, 1, s32> is_home_button_protection_enabled;
- };
- };
- static_assert(sizeof(NpadSystemButtonProperties) == 0x4,
- "NPadButtonProperties is an invalid size");
-
- // This is nn::hid::system::DeviceType
- struct DeviceType {
- union {
- u32 raw{};
- BitField<0, 1, s32> fullkey;
- BitField<1, 1, s32> debug_pad;
- BitField<2, 1, s32> handheld_left;
- BitField<3, 1, s32> handheld_right;
- BitField<4, 1, s32> joycon_left;
- BitField<5, 1, s32> joycon_right;
- BitField<6, 1, s32> palma;
- BitField<7, 1, s32> lark_hvc_left;
- BitField<8, 1, s32> lark_hvc_right;
- BitField<9, 1, s32> lark_nes_left;
- BitField<10, 1, s32> lark_nes_right;
- BitField<11, 1, s32> handheld_lark_hvc_left;
- BitField<12, 1, s32> handheld_lark_hvc_right;
- BitField<13, 1, s32> handheld_lark_nes_left;
- BitField<14, 1, s32> handheld_lark_nes_right;
- BitField<15, 1, s32> lucia;
- BitField<16, 1, s32> lagon;
- BitField<17, 1, s32> lager;
- BitField<31, 1, s32> system;
- };
- };
-
- // This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
- struct NfcXcdDeviceHandleStateImpl {
- u64 handle{};
- bool is_available{};
- bool is_activated{};
- INSERT_PADDING_BYTES(0x6); // Reserved
- u64 sampling_number{};
- };
- static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
- "NfcXcdDeviceHandleStateImpl is an invalid size");
-
- // This is nn::hid::NpadLarkType
- enum class NpadLarkType : u32 {
- Invalid,
- H1,
- H2,
- NL,
- NR,
- };
-
- // This is nn::hid::NpadLuciaType
- enum class NpadLuciaType : u32 {
- Invalid,
- J,
- E,
- U,
- };
-
- // This is nn::hid::NpadLagonType
- enum class NpadLagonType : u32 {
- Invalid,
- };
-
- // This is nn::hid::NpadLagerType
- enum class NpadLagerType : u32 {
- Invalid,
- J,
- E,
- U,
- };
-
- // This is nn::hid::detail::NpadInternalState
- struct NpadInternalState {
- Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
- NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
- NpadFullKeyColorState fullkey_color{};
- NpadJoyColorState joycon_color{};
- Lifo<NPadGenericState, hid_entry_count> fullkey_lifo{};
- Lifo<NPadGenericState, hid_entry_count> handheld_lifo{};
- Lifo<NPadGenericState, hid_entry_count> joy_dual_lifo{};
- Lifo<NPadGenericState, hid_entry_count> joy_left_lifo{};
- Lifo<NPadGenericState, hid_entry_count> joy_right_lifo{};
- Lifo<NPadGenericState, hid_entry_count> palma_lifo{};
- Lifo<NPadGenericState, hid_entry_count> system_ext_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_fullkey_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_handheld_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_left_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_dual_right_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_left_lifo{};
- Lifo<Core::HID::SixAxisSensorState, hid_entry_count> sixaxis_right_lifo{};
- DeviceType device_type{};
- INSERT_PADDING_BYTES(0x4); // Reserved
- NPadSystemProperties system_properties{};
- NpadSystemButtonProperties button_properties{};
- Core::HID::NpadBatteryLevel battery_level_dual{};
- Core::HID::NpadBatteryLevel battery_level_left{};
- Core::HID::NpadBatteryLevel battery_level_right{};
- AppletFooterUiAttributes applet_footer_attributes{};
- AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
- INSERT_PADDING_BYTES(0x5B); // Reserved
- INSERT_PADDING_BYTES(0x20); // Unknown
- Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{};
- NpadLarkType lark_type_l_and_main{};
- NpadLarkType lark_type_r{};
- NpadLuciaType lucia_type{};
- NpadLagonType lagon_type{};
- NpadLagerType lager_type{};
- Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
- Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
- Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
- Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
- Core::HID::SixAxisSensorProperties sixaxis_left_properties;
- Core::HID::SixAxisSensorProperties sixaxis_right_properties;
- INSERT_PADDING_BYTES(0xc06); // Unknown
- };
- static_assert(sizeof(NpadInternalState) == 0x5000, "NpadInternalState is an invalid size");
-
struct VibrationData {
bool device_mounted{};
Core::HID::VibrationValue latest_vibration_value{};
@@ -479,7 +189,7 @@ private:
std::atomic<u64> press_state{};
- std::array<NpadControllerData, NPAD_COUNT> controller_data{};
+ std::array<NpadControllerData, NpadCount> controller_data{};
KernelHelpers::ServiceContext& service_context;
std::mutex mutex;
std::vector<Core::HID::NpadIdType> supported_npad_id_types{};
diff --git a/src/core/hle/service/hid/controllers/palma.cpp b/src/core/hle/service/hid/controllers/palma.cpp
index 588ff9d62..aa0454b5e 100644
--- a/src/core/hle/service/hid/controllers/palma.cpp
+++ b/src/core/hle/service/hid/controllers/palma.cpp
@@ -12,8 +12,7 @@
namespace Service::HID {
-Palma::Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
- KernelHelpers::ServiceContext& service_context_)
+Palma::Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_)
: ControllerBase{hid_core_}, service_context{service_context_} {
controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other);
operation_complete_event = service_context.CreateEvent("hid:PalmaOperationCompleteEvent");
diff --git a/src/core/hle/service/hid/controllers/palma.h b/src/core/hle/service/hid/controllers/palma.h
index a6047f36a..73884230d 100644
--- a/src/core/hle/service/hid/controllers/palma.h
+++ b/src/core/hle/service/hid/controllers/palma.h
@@ -97,8 +97,7 @@ public:
static_assert(sizeof(PalmaConnectionHandle) == 0x8,
"PalmaConnectionHandle has incorrect size.");
- explicit Palma(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_,
- KernelHelpers::ServiceContext& service_context_);
+ explicit Palma(Core::HID::HIDCore& hid_core_, KernelHelpers::ServiceContext& service_context_);
~Palma() override;
// Called when the controller is initialized
diff --git a/src/core/hle/service/hid/controllers/shared_memory_format.h b/src/core/hle/service/hid/controllers/shared_memory_format.h
new file mode 100644
index 000000000..2986c113e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_format.h
@@ -0,0 +1,240 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/vector_math.h"
+#include "core/hid/hid_types.h"
+#include "core/hle/service/hid//controllers/types/debug_pad_types.h"
+#include "core/hle/service/hid//controllers/types/keyboard_types.h"
+#include "core/hle/service/hid//controllers/types/mouse_types.h"
+#include "core/hle/service/hid//controllers/types/npad_types.h"
+#include "core/hle/service/hid//controllers/types/touch_types.h"
+#include "core/hle/service/hid/ring_lifo.h"
+
+namespace Service::HID {
+static const std::size_t HidEntryCount = 17;
+
+struct CommonHeader {
+ s64 timestamp{};
+ s64 total_entry_count{};
+ s64 last_entry_index{};
+ s64 entry_count{};
+};
+static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
+
+// This is nn::hid::detail::DebugPadSharedMemoryFormat
+struct DebugPadSharedMemoryFormat {
+ // This is nn::hid::detail::DebugPadLifo
+ Lifo<DebugPadState, HidEntryCount> debug_pad_lifo{};
+ static_assert(sizeof(debug_pad_lifo) == 0x2C8, "debug_pad_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0x4E);
+};
+static_assert(sizeof(DebugPadSharedMemoryFormat) == 0x400,
+ "DebugPadSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::TouchScreenSharedMemoryFormat
+struct TouchScreenSharedMemoryFormat {
+ // This is nn::hid::detail::TouchScreenLifo
+ Lifo<TouchScreenState, HidEntryCount> touch_screen_lifo{};
+ static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0xF2);
+};
+static_assert(sizeof(TouchScreenSharedMemoryFormat) == 0x3000,
+ "TouchScreenSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::MouseSharedMemoryFormat
+struct MouseSharedMemoryFormat {
+ // This is nn::hid::detail::MouseLifo
+ Lifo<Core::HID::MouseState, HidEntryCount> mouse_lifo{};
+ static_assert(sizeof(mouse_lifo) == 0x350, "mouse_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0x2C);
+};
+static_assert(sizeof(MouseSharedMemoryFormat) == 0x400,
+ "MouseSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::KeyboardSharedMemoryFormat
+struct KeyboardSharedMemoryFormat {
+ // This is nn::hid::detail::KeyboardLifo
+ Lifo<KeyboardState, HidEntryCount> keyboard_lifo{};
+ static_assert(sizeof(keyboard_lifo) == 0x3D8, "keyboard_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0xA);
+};
+static_assert(sizeof(KeyboardSharedMemoryFormat) == 0x400,
+ "KeyboardSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::DigitizerSharedMemoryFormat
+struct DigitizerSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0xFE0);
+};
+static_assert(sizeof(DigitizerSharedMemoryFormat) == 0x1000,
+ "DigitizerSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::HomeButtonSharedMemoryFormat
+struct HomeButtonSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x1E0);
+};
+static_assert(sizeof(HomeButtonSharedMemoryFormat) == 0x200,
+ "HomeButtonSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::SleepButtonSharedMemoryFormat
+struct SleepButtonSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x1E0);
+};
+static_assert(sizeof(SleepButtonSharedMemoryFormat) == 0x200,
+ "SleepButtonSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::CaptureButtonSharedMemoryFormat
+struct CaptureButtonSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x1E0);
+};
+static_assert(sizeof(CaptureButtonSharedMemoryFormat) == 0x200,
+ "CaptureButtonSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::InputDetectorSharedMemoryFormat
+struct InputDetectorSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x7E0);
+};
+static_assert(sizeof(InputDetectorSharedMemoryFormat) == 0x800,
+ "InputDetectorSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::UniquePadSharedMemoryFormat
+struct UniquePadSharedMemoryFormat {
+ CommonHeader header;
+ INSERT_PADDING_BYTES(0x3FE0);
+};
+static_assert(sizeof(UniquePadSharedMemoryFormat) == 0x4000,
+ "UniquePadSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::NpadSixAxisSensorLifo
+struct NpadSixAxisSensorLifo {
+ Lifo<Core::HID::SixAxisSensorState, HidEntryCount> lifo;
+};
+
+// This is nn::hid::detail::NpadInternalState
+struct NpadInternalState {
+ Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None};
+ NpadJoyAssignmentMode assignment_mode{NpadJoyAssignmentMode::Dual};
+ NpadFullKeyColorState fullkey_color{};
+ NpadJoyColorState joycon_color{};
+ Lifo<NPadGenericState, HidEntryCount> fullkey_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> handheld_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> joy_dual_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> joy_left_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> joy_right_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> palma_lifo{};
+ Lifo<NPadGenericState, HidEntryCount> system_ext_lifo{};
+ NpadSixAxisSensorLifo sixaxis_fullkey_lifo{};
+ NpadSixAxisSensorLifo sixaxis_handheld_lifo{};
+ NpadSixAxisSensorLifo sixaxis_dual_left_lifo{};
+ NpadSixAxisSensorLifo sixaxis_dual_right_lifo{};
+ NpadSixAxisSensorLifo sixaxis_left_lifo{};
+ NpadSixAxisSensorLifo sixaxis_right_lifo{};
+ DeviceType device_type{};
+ INSERT_PADDING_BYTES(0x4); // Reserved
+ NPadSystemProperties system_properties{};
+ NpadSystemButtonProperties button_properties{};
+ Core::HID::NpadBatteryLevel battery_level_dual{};
+ Core::HID::NpadBatteryLevel battery_level_left{};
+ Core::HID::NpadBatteryLevel battery_level_right{};
+ AppletFooterUiAttributes applet_footer_attributes{};
+ AppletFooterUiType applet_footer_type{AppletFooterUiType::None};
+ INSERT_PADDING_BYTES(0x5B); // Reserved
+ INSERT_PADDING_BYTES(0x20); // Unknown
+ Lifo<NpadGcTriggerState, HidEntryCount> gc_trigger_lifo{};
+ NpadLarkType lark_type_l_and_main{};
+ NpadLarkType lark_type_r{};
+ NpadLuciaType lucia_type{};
+ NpadLagerType lager_type{};
+ Core::HID::SixAxisSensorProperties sixaxis_fullkey_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_handheld_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_dual_left_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_dual_right_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_left_properties;
+ Core::HID::SixAxisSensorProperties sixaxis_right_properties;
+};
+static_assert(sizeof(NpadInternalState) == 0x43F8, "NpadInternalState is an invalid size");
+
+// This is nn::hid::detail::NpadSharedMemoryEntry
+struct NpadSharedMemoryEntry {
+ NpadInternalState internal_state;
+ INSERT_PADDING_BYTES(0xC08);
+};
+static_assert(sizeof(NpadSharedMemoryEntry) == 0x5000, "NpadSharedMemoryEntry is an invalid size");
+
+// This is nn::hid::detail::NpadSharedMemoryFormat
+struct NpadSharedMemoryFormat {
+ std::array<NpadSharedMemoryEntry, NpadCount> npad_entry;
+};
+static_assert(sizeof(NpadSharedMemoryFormat) == 0x32000,
+ "NpadSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::GestureSharedMemoryFormat
+struct GestureSharedMemoryFormat {
+ // This is nn::hid::detail::GestureLifo
+ Lifo<GestureState, HidEntryCount> gesture_lifo{};
+ static_assert(sizeof(gesture_lifo) == 0x708, "gesture_lifo is an invalid size");
+ INSERT_PADDING_WORDS(0x3E);
+};
+static_assert(sizeof(GestureSharedMemoryFormat) == 0x800,
+ "GestureSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::ConsoleSixAxisSensorSharedMemoryFormat
+struct ConsoleSixAxisSensorSharedMemoryFormat {
+ u64 sampling_number{};
+ bool is_seven_six_axis_sensor_at_rest{};
+ INSERT_PADDING_BYTES(3); // padding
+ f32 verticalization_error{};
+ Common::Vec3f gyro_bias{};
+ INSERT_PADDING_BYTES(4); // padding
+};
+static_assert(sizeof(ConsoleSixAxisSensorSharedMemoryFormat) == 0x20,
+ "ConsoleSixAxisSensorSharedMemoryFormat is an invalid size");
+
+// This is nn::hid::detail::SharedMemoryFormat
+struct SharedMemoryFormat {
+ void Initialize() {}
+
+ DebugPadSharedMemoryFormat debug_pad;
+ TouchScreenSharedMemoryFormat touch_screen;
+ MouseSharedMemoryFormat mouse;
+ KeyboardSharedMemoryFormat keyboard;
+ DigitizerSharedMemoryFormat digitizer;
+ HomeButtonSharedMemoryFormat home_button;
+ SleepButtonSharedMemoryFormat sleep_button;
+ CaptureButtonSharedMemoryFormat capture_button;
+ InputDetectorSharedMemoryFormat input_detector;
+ UniquePadSharedMemoryFormat unique_pad;
+ NpadSharedMemoryFormat npad;
+ GestureSharedMemoryFormat gesture;
+ ConsoleSixAxisSensorSharedMemoryFormat console;
+ INSERT_PADDING_BYTES(0x19E0);
+ MouseSharedMemoryFormat debug_mouse;
+ INSERT_PADDING_BYTES(0x2000);
+};
+static_assert(offsetof(SharedMemoryFormat, debug_pad) == 0x0, "debug_pad has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, touch_screen) == 0x400, "touch_screen has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, mouse) == 0x3400, "mouse has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, keyboard) == 0x3800, "keyboard has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, digitizer) == 0x3C00, "digitizer has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, home_button) == 0x4C00, "home_button has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, sleep_button) == 0x4E00,
+ "sleep_button has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, capture_button) == 0x5000,
+ "capture_button has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, input_detector) == 0x5200,
+ "input_detector has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, npad) == 0x9A00, "npad has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, gesture) == 0x3BA00, "gesture has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, console) == 0x3C200, "console has wrong offset");
+static_assert(offsetof(SharedMemoryFormat, debug_mouse) == 0x3DC00, "debug_mouse has wrong offset");
+static_assert(sizeof(SharedMemoryFormat) == 0x40000, "SharedMemoryFormat is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.cpp b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
new file mode 100644
index 000000000..51581188e
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_holder.cpp
@@ -0,0 +1,53 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#include "core/core.h"
+#include "core/hle/kernel/k_shared_memory.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
+#include "core/hle/service/hid/controllers/shared_memory_holder.h"
+#include "core/hle/service/hid/errors.h"
+
+namespace Service::HID {
+SharedMemoryHolder::SharedMemoryHolder() {}
+
+SharedMemoryHolder::~SharedMemoryHolder() {
+ Finalize();
+}
+
+Result SharedMemoryHolder::Initialize(Core::System& system) {
+ shared_memory = Kernel::KSharedMemory::Create(system.Kernel());
+ const Result result = shared_memory->Initialize(
+ system.DeviceMemory(), nullptr, Kernel::Svc::MemoryPermission::None,
+ Kernel::Svc::MemoryPermission::Read, sizeof(SharedMemoryFormat));
+ if (result.IsError()) {
+ return result;
+ }
+ Kernel::KSharedMemory::Register(system.Kernel(), shared_memory);
+
+ is_created = true;
+ is_mapped = true;
+ address = std::construct_at(reinterpret_cast<SharedMemoryFormat*>(shared_memory->GetPointer()));
+ return ResultSuccess;
+}
+
+void SharedMemoryHolder::Finalize() {
+ if (address != nullptr) {
+ shared_memory->Close();
+ }
+ is_created = false;
+ is_mapped = false;
+ address = nullptr;
+}
+
+bool SharedMemoryHolder::IsMapped() {
+ return is_mapped;
+}
+
+SharedMemoryFormat* SharedMemoryHolder::GetAddress() {
+ return address;
+}
+
+Kernel::KSharedMemory* SharedMemoryHolder::GetHandle() {
+ return shared_memory;
+}
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/shared_memory_holder.h b/src/core/hle/service/hid/controllers/shared_memory_holder.h
new file mode 100644
index 000000000..943407c00
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/shared_memory_holder.h
@@ -0,0 +1,44 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "core/hle/result.h"
+
+namespace Core {
+class System;
+}
+
+namespace Kernel {
+class KSharedMemory;
+}
+
+namespace Service::HID {
+struct SharedMemoryFormat;
+
+// This is nn::hid::detail::SharedMemoryHolder
+class SharedMemoryHolder {
+public:
+ SharedMemoryHolder();
+ ~SharedMemoryHolder();
+
+ Result Initialize(Core::System& system);
+ void Finalize();
+
+ bool IsMapped();
+ SharedMemoryFormat* GetAddress();
+ Kernel::KSharedMemory* GetHandle();
+
+private:
+ bool is_owner{};
+ bool is_created{};
+ bool is_mapped{};
+ INSERT_PADDING_BYTES(0x5);
+ Kernel::KSharedMemory* shared_memory;
+ INSERT_PADDING_BYTES(0x38);
+ SharedMemoryFormat* address = nullptr;
+};
+// Correct size is 0x50 bytes
+static_assert(sizeof(SharedMemoryHolder) == 0x50, "SharedMemoryHolder is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/six_axis.cpp b/src/core/hle/service/hid/controllers/six_axis.cpp
index 3d24a5c04..36b72f9ea 100644
--- a/src/core/hle/service/hid/controllers/six_axis.cpp
+++ b/src/core/hle/service/hid/controllers/six_axis.cpp
@@ -6,6 +6,7 @@
#include "core/hid/emulated_controller.h"
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_util.h"
@@ -132,30 +133,30 @@ void SixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
}
sixaxis_fullkey_state.sampling_number =
- sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_fullkey_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_handheld_state.sampling_number =
- sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_handheld_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_dual_left_state.sampling_number =
- sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_dual_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_dual_right_state.sampling_number =
- sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_dual_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_left_lifo_state.sampling_number =
- sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_left_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
sixaxis_right_lifo_state.sampling_number =
- sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1;
+ sixaxis_right_lifo.lifo.ReadCurrentEntry().state.sampling_number + 1;
if (IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) {
// This buffer only is updated on handheld on HW
- sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state);
+ sixaxis_handheld_lifo.lifo.WriteNextEntry(sixaxis_handheld_state);
} else {
// Handheld doesn't update this buffer on HW
- sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state);
+ sixaxis_fullkey_lifo.lifo.WriteNextEntry(sixaxis_fullkey_state);
}
- sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state);
- sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state);
- sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state);
- sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state);
+ sixaxis_dual_left_lifo.lifo.WriteNextEntry(sixaxis_dual_left_state);
+ sixaxis_dual_right_lifo.lifo.WriteNextEntry(sixaxis_dual_right_state);
+ sixaxis_left_lifo.lifo.WriteNextEntry(sixaxis_left_lifo_state);
+ sixaxis_right_lifo.lifo.WriteNextEntry(sixaxis_right_lifo_state);
}
}
diff --git a/src/core/hle/service/hid/controllers/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp
index 9e2f3ab21..e2a5f5d79 100644
--- a/src/core/hle/service/hid/controllers/stubbed.cpp
+++ b/src/core/hle/service/hid/controllers/stubbed.cpp
@@ -1,18 +1,15 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <cstring>
-#include "common/common_types.h"
#include "core/core_timing.h"
-#include "core/hid/hid_core.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/stubbed.h"
namespace Service::HID {
-Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_} {
- raw_shared_memory = raw_shared_memory_;
-}
+Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_,
+ CommonHeader& ring_lifo_header)
+ : ControllerBase{hid_core_}, header{ring_lifo_header} {}
Controller_Stubbed::~Controller_Stubbed() = default;
@@ -25,18 +22,10 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
return;
}
- CommonHeader header{};
header.timestamp = core_timing.GetGlobalTimeNs().count();
header.total_entry_count = 17;
header.entry_count = 0;
header.last_entry_index = 0;
-
- std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader));
-}
-
-void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) {
- common_offset = off;
- smart_update = true;
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h
index 1483a968e..d2052fb17 100644
--- a/src/core/hle/service/hid/controllers/stubbed.h
+++ b/src/core/hle/service/hid/controllers/stubbed.h
@@ -3,13 +3,14 @@
#pragma once
-#include "common/common_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
namespace Service::HID {
+struct CommonHeader;
+
class Controller_Stubbed final : public ControllerBase {
public:
- explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, CommonHeader& ring_lifo_header);
~Controller_Stubbed() override;
// Called when the controller is initialized
@@ -21,19 +22,8 @@ public:
// When the controller is requesting an update for the shared memory
void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
- void SetCommonHeaderOffset(std::size_t off);
-
private:
- struct CommonHeader {
- s64 timestamp{};
- s64 total_entry_count{};
- s64 last_entry_index{};
- s64 entry_count{};
- };
- static_assert(sizeof(CommonHeader) == 0x20, "CommonHeader is an invalid size");
-
- u8* raw_shared_memory = nullptr;
+ CommonHeader& header;
bool smart_update{};
- std::size_t common_offset{};
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp
index fcd973414..469750006 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.cpp
+++ b/src/core/hle/service/hid/controllers/touchscreen.cpp
@@ -2,26 +2,22 @@
// SPDX-License-Identifier: GPL-2.0-or-later
#include <algorithm>
-#include <cstring>
#include "common/common_types.h"
#include "common/settings.h"
-#include "core/core.h"
#include "core/core_timing.h"
#include "core/frontend/emu_window.h"
#include "core/hid/emulated_console.h"
#include "core/hid/hid_core.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400;
-TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_)
- : ControllerBase{hid_core_}, touchscreen_width(Layout::ScreenUndocked::Width),
+TouchScreen::TouchScreen(Core::HID::HIDCore& hid_core_,
+ TouchScreenSharedMemoryFormat& touch_shared_memory)
+ : ControllerBase{hid_core_}, shared_memory{touch_shared_memory},
+ touchscreen_width(Layout::ScreenUndocked::Width),
touchscreen_height(Layout::ScreenUndocked::Height) {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(TouchSharedMemory) < shared_memory_size,
- "TouchSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<TouchSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
console = hid_core.GetEmulatedConsole();
}
@@ -32,11 +28,11 @@ void TouchScreen::OnInit() {}
void TouchScreen::OnRelease() {}
void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
- shared_memory->touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
+ shared_memory.touch_screen_lifo.timestamp = core_timing.GetGlobalTimeNs().count();
if (!IsControllerActivated()) {
- shared_memory->touch_screen_lifo.buffer_count = 0;
- shared_memory->touch_screen_lifo.buffer_tail = 0;
+ shared_memory.touch_screen_lifo.buffer_count = 0;
+ shared_memory.touch_screen_lifo.buffer_tail = 0;
return;
}
@@ -86,7 +82,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter));
const u64 timestamp = static_cast<u64>(core_timing.GetGlobalTimeNs().count());
- const auto& last_entry = shared_memory->touch_screen_lifo.ReadCurrentEntry().state;
+ const auto& last_entry = shared_memory.touch_screen_lifo.ReadCurrentEntry().state;
next_state.sampling_number = last_entry.sampling_number + 1;
next_state.entry_count = static_cast<s32>(active_fingers_count);
@@ -118,7 +114,7 @@ void TouchScreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
}
}
- shared_memory->touch_screen_lifo.WriteNextEntry(next_state);
+ shared_memory.touch_screen_lifo.WriteNextEntry(next_state);
}
void TouchScreen::SetTouchscreenDimensions(u32 width, u32 height) {
diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h
index 79f026a81..5b6305bfc 100644
--- a/src/core/hle/service/hid/controllers/touchscreen.h
+++ b/src/core/hle/service/hid/controllers/touchscreen.h
@@ -3,20 +3,23 @@
#pragma once
-#include "common/common_funcs.h"
-#include "common/common_types.h"
+#include <array>
+
#include "core/hid/hid_types.h"
#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
+#include "core/hle/service/hid/controllers/types/touch_types.h"
namespace Core::HID {
class EmulatedConsole;
} // namespace Core::HID
namespace Service::HID {
+struct TouchScreenSharedMemoryFormat;
+
class TouchScreen final : public ControllerBase {
public:
- explicit TouchScreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
+ explicit TouchScreen(Core::HID::HIDCore& hid_core_,
+ TouchScreenSharedMemoryFormat& touch_shared_memory);
~TouchScreen() override;
// Called when the controller is initialized
@@ -31,27 +34,8 @@ public:
void SetTouchscreenDimensions(u32 width, u32 height);
private:
- static constexpr std::size_t MAX_FINGERS = 16;
-
- // This is nn::hid::TouchScreenState
- struct TouchScreenState {
- s64 sampling_number{};
- s32 entry_count{};
- INSERT_PADDING_BYTES(4); // Reserved
- std::array<Core::HID::TouchState, MAX_FINGERS> states{};
- };
- static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
-
- struct TouchSharedMemory {
- // This is nn::hid::detail::TouchScreenLifo
- Lifo<TouchScreenState, hid_entry_count> touch_screen_lifo{};
- static_assert(sizeof(touch_screen_lifo) == 0x2C38, "touch_screen_lifo is an invalid size");
- INSERT_PADDING_WORDS(0xF2);
- };
- static_assert(sizeof(TouchSharedMemory) == 0x3000, "TouchSharedMemory is an invalid size");
-
TouchScreenState next_state{};
- TouchSharedMemory* shared_memory = nullptr;
+ TouchScreenSharedMemoryFormat& shared_memory;
Core::HID::EmulatedConsole* console = nullptr;
std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{};
diff --git a/src/core/hle/service/hid/controllers/types/debug_pad_types.h b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
new file mode 100644
index 000000000..a96171b62
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/debug_pad_types.h
@@ -0,0 +1,31 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+
+// This is nn::hid::DebugPadAttribute
+struct DebugPadAttribute {
+ union {
+ u32 raw{};
+ BitField<0, 1, u32> connected;
+ };
+};
+static_assert(sizeof(DebugPadAttribute) == 0x4, "DebugPadAttribute is an invalid size");
+
+// This is nn::hid::DebugPadState
+struct DebugPadState {
+ s64 sampling_number{};
+ DebugPadAttribute attribute{};
+ Core::HID::DebugPadButton pad_state{};
+ Core::HID::AnalogStickState r_stick{};
+ Core::HID::AnalogStickState l_stick{};
+};
+static_assert(sizeof(DebugPadState) == 0x20, "DebugPadState is an invalid state");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/gesture_types.h b/src/core/hle/service/hid/controllers/types/gesture_types.h
new file mode 100644
index 000000000..b4f034cd3
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/gesture_types.h
@@ -0,0 +1,77 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+#include "common/bit_field.h"
+#include "common/common_types.h"
+#include "common/point.h"
+
+namespace Service::HID {
+static constexpr size_t MAX_FINGERS = 16;
+static constexpr size_t MAX_POINTS = 4;
+
+// This is nn::hid::GestureType
+enum class GestureType : u32 {
+ Idle, // Nothing touching the screen
+ Complete, // Set at the end of a touch event
+ Cancel, // Set when the number of fingers change
+ Touch, // A finger just touched the screen
+ Press, // Set if last type is touch and the finger hasn't moved
+ Tap, // Fast press then release
+ Pan, // All points moving together across the screen
+ Swipe, // Fast press movement and release of a single point
+ Pinch, // All points moving away/closer to the midpoint
+ Rotate, // All points rotating from the midpoint
+};
+
+// This is nn::hid::GestureDirection
+enum class GestureDirection : u32 {
+ None,
+ Left,
+ Up,
+ Right,
+ Down,
+};
+
+// This is nn::hid::GestureAttribute
+struct GestureAttribute {
+ union {
+ u32 raw{};
+
+ BitField<4, 1, u32> is_new_touch;
+ BitField<8, 1, u32> is_double_tap;
+ };
+};
+static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
+
+// This is nn::hid::GestureState
+struct GestureState {
+ s64 sampling_number{};
+ s64 detection_count{};
+ GestureType type{GestureType::Idle};
+ GestureDirection direction{GestureDirection::None};
+ Common::Point<s32> pos{};
+ Common::Point<s32> delta{};
+ f32 vel_x{};
+ f32 vel_y{};
+ GestureAttribute attributes{};
+ f32 scale{};
+ f32 rotation_angle{};
+ s32 point_count{};
+ std::array<Common::Point<s32>, 4> points{};
+};
+static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
+
+struct GestureProperties {
+ std::array<Common::Point<s32>, MAX_POINTS> points{};
+ std::size_t active_points{};
+ Common::Point<s32> mid_point{};
+ s64 detection_count{};
+ u64 delta_time{};
+ f32 average_distance{};
+ f32 angle{};
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/keyboard_types.h b/src/core/hle/service/hid/controllers/types/keyboard_types.h
new file mode 100644
index 000000000..f44a536b9
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/keyboard_types.h
@@ -0,0 +1,20 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+
+// This is nn::hid::detail::KeyboardState
+struct KeyboardState {
+ s64 sampling_number{};
+ Core::HID::KeyboardModifier modifier{};
+ Core::HID::KeyboardAttribute attribute{};
+ Core::HID::KeyboardKey key{};
+};
+static_assert(sizeof(KeyboardState) == 0x30, "KeyboardState is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/mouse_types.h b/src/core/hle/service/hid/controllers/types/mouse_types.h
new file mode 100644
index 000000000..8bd6e167c
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/mouse_types.h
@@ -0,0 +1,8 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/common_types.h"
+
+namespace Service::HID {} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/npad_types.h b/src/core/hle/service/hid/controllers/types/npad_types.h
new file mode 100644
index 000000000..a5ce2562b
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/npad_types.h
@@ -0,0 +1,254 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+static constexpr std::size_t NpadCount = 10;
+
+// This is nn::hid::NpadJoyHoldType
+enum class NpadJoyHoldType : u64 {
+ Vertical = 0,
+ Horizontal = 1,
+};
+
+// This is nn::hid::NpadJoyAssignmentMode
+enum class NpadJoyAssignmentMode : u32 {
+ Dual = 0,
+ Single = 1,
+};
+
+// This is nn::hid::NpadJoyDeviceType
+enum class NpadJoyDeviceType : s64 {
+ Left = 0,
+ Right = 1,
+};
+
+// This is nn::hid::NpadHandheldActivationMode
+enum class NpadHandheldActivationMode : u64 {
+ Dual = 0,
+ Single = 1,
+ None = 2,
+ MaxActivationMode = 3,
+};
+
+// This is nn::hid::system::AppletFooterUiAttributesSet
+struct AppletFooterUiAttributes {
+ INSERT_PADDING_BYTES(0x4);
+};
+
+// This is nn::hid::system::AppletFooterUiType
+enum class AppletFooterUiType : u8 {
+ None = 0,
+ HandheldNone = 1,
+ HandheldJoyConLeftOnly = 2,
+ HandheldJoyConRightOnly = 3,
+ HandheldJoyConLeftJoyConRight = 4,
+ JoyDual = 5,
+ JoyDualLeftOnly = 6,
+ JoyDualRightOnly = 7,
+ JoyLeftHorizontal = 8,
+ JoyLeftVertical = 9,
+ JoyRightHorizontal = 10,
+ JoyRightVertical = 11,
+ SwitchProController = 12,
+ CompatibleProController = 13,
+ CompatibleJoyCon = 14,
+ LarkHvc1 = 15,
+ LarkHvc2 = 16,
+ LarkNesLeft = 17,
+ LarkNesRight = 18,
+ Lucia = 19,
+ Verification = 20,
+ Lagon = 21,
+};
+
+using AppletFooterUiVariant = u8;
+
+// This is "nn::hid::system::AppletDetailedUiType".
+struct AppletDetailedUiType {
+ AppletFooterUiVariant ui_variant;
+ INSERT_PADDING_BYTES(0x2);
+ AppletFooterUiType footer;
+};
+static_assert(sizeof(AppletDetailedUiType) == 0x4, "AppletDetailedUiType is an invalid size");
+// This is nn::hid::NpadCommunicationMode
+enum class NpadCommunicationMode : u64 {
+ Mode_5ms = 0,
+ Mode_10ms = 1,
+ Mode_15ms = 2,
+ Default = 3,
+};
+
+enum class NpadRevision : u32 {
+ Revision0 = 0,
+ Revision1 = 1,
+ Revision2 = 2,
+ Revision3 = 3,
+};
+
+// This is nn::hid::detail::ColorAttribute
+enum class ColorAttribute : u32 {
+ Ok = 0,
+ ReadError = 1,
+ NoController = 2,
+};
+static_assert(sizeof(ColorAttribute) == 4, "ColorAttribute is an invalid size");
+
+// This is nn::hid::detail::NpadFullKeyColorState
+struct NpadFullKeyColorState {
+ ColorAttribute attribute{ColorAttribute::NoController};
+ Core::HID::NpadControllerColor fullkey{};
+};
+static_assert(sizeof(NpadFullKeyColorState) == 0xC, "NpadFullKeyColorState is an invalid size");
+
+// This is nn::hid::detail::NpadJoyColorState
+struct NpadJoyColorState {
+ ColorAttribute attribute{ColorAttribute::NoController};
+ Core::HID::NpadControllerColor left{};
+ Core::HID::NpadControllerColor right{};
+};
+static_assert(sizeof(NpadJoyColorState) == 0x14, "NpadJoyColorState is an invalid size");
+
+// This is nn::hid::NpadAttribute
+struct NpadAttribute {
+ union {
+ u32 raw{};
+ BitField<0, 1, u32> is_connected;
+ BitField<1, 1, u32> is_wired;
+ BitField<2, 1, u32> is_left_connected;
+ BitField<3, 1, u32> is_left_wired;
+ BitField<4, 1, u32> is_right_connected;
+ BitField<5, 1, u32> is_right_wired;
+ };
+};
+static_assert(sizeof(NpadAttribute) == 4, "NpadAttribute is an invalid size");
+
+// This is nn::hid::NpadFullKeyState
+// This is nn::hid::NpadHandheldState
+// This is nn::hid::NpadJoyDualState
+// This is nn::hid::NpadJoyLeftState
+// This is nn::hid::NpadJoyRightState
+// This is nn::hid::NpadPalmaState
+// This is nn::hid::NpadSystemExtState
+struct NPadGenericState {
+ s64_le sampling_number{};
+ Core::HID::NpadButtonState npad_buttons{};
+ Core::HID::AnalogStickState l_stick{};
+ Core::HID::AnalogStickState r_stick{};
+ NpadAttribute connection_status{};
+ INSERT_PADDING_BYTES(4); // Reserved
+};
+static_assert(sizeof(NPadGenericState) == 0x28, "NPadGenericState is an invalid size");
+
+// This is nn::hid::server::NpadGcTriggerState
+struct NpadGcTriggerState {
+ s64 sampling_number{};
+ s32 l_analog{};
+ s32 r_analog{};
+};
+static_assert(sizeof(NpadGcTriggerState) == 0x10, "NpadGcTriggerState is an invalid size");
+
+// This is nn::hid::NpadSystemProperties
+struct NPadSystemProperties {
+ union {
+ s64 raw{};
+ BitField<0, 1, s64> is_charging_joy_dual;
+ BitField<1, 1, s64> is_charging_joy_left;
+ BitField<2, 1, s64> is_charging_joy_right;
+ BitField<3, 1, s64> is_powered_joy_dual;
+ BitField<4, 1, s64> is_powered_joy_left;
+ BitField<5, 1, s64> is_powered_joy_right;
+ BitField<9, 1, s64> is_system_unsupported_button;
+ BitField<10, 1, s64> is_system_ext_unsupported_button;
+ BitField<11, 1, s64> is_vertical;
+ BitField<12, 1, s64> is_horizontal;
+ BitField<13, 1, s64> use_plus;
+ BitField<14, 1, s64> use_minus;
+ BitField<15, 1, s64> use_directional_buttons;
+ };
+};
+static_assert(sizeof(NPadSystemProperties) == 0x8, "NPadSystemProperties is an invalid size");
+
+// This is nn::hid::NpadSystemButtonProperties
+struct NpadSystemButtonProperties {
+ union {
+ s32 raw{};
+ BitField<0, 1, s32> is_home_button_protection_enabled;
+ };
+};
+static_assert(sizeof(NpadSystemButtonProperties) == 0x4, "NPadButtonProperties is an invalid size");
+
+// This is nn::hid::system::DeviceType
+struct DeviceType {
+ union {
+ u32 raw{};
+ BitField<0, 1, s32> fullkey;
+ BitField<1, 1, s32> debug_pad;
+ BitField<2, 1, s32> handheld_left;
+ BitField<3, 1, s32> handheld_right;
+ BitField<4, 1, s32> joycon_left;
+ BitField<5, 1, s32> joycon_right;
+ BitField<6, 1, s32> palma;
+ BitField<7, 1, s32> lark_hvc_left;
+ BitField<8, 1, s32> lark_hvc_right;
+ BitField<9, 1, s32> lark_nes_left;
+ BitField<10, 1, s32> lark_nes_right;
+ BitField<11, 1, s32> handheld_lark_hvc_left;
+ BitField<12, 1, s32> handheld_lark_hvc_right;
+ BitField<13, 1, s32> handheld_lark_nes_left;
+ BitField<14, 1, s32> handheld_lark_nes_right;
+ BitField<15, 1, s32> lucia;
+ BitField<16, 1, s32> lagon;
+ BitField<17, 1, s32> lager;
+ BitField<31, 1, s32> system;
+ };
+};
+
+// This is nn::hid::detail::NfcXcdDeviceHandleStateImpl
+struct NfcXcdDeviceHandleStateImpl {
+ u64 handle{};
+ bool is_available{};
+ bool is_activated{};
+ INSERT_PADDING_BYTES(0x6); // Reserved
+ u64 sampling_number{};
+};
+static_assert(sizeof(NfcXcdDeviceHandleStateImpl) == 0x18,
+ "NfcXcdDeviceHandleStateImpl is an invalid size");
+
+// This is nn::hid::NpadLarkType
+enum class NpadLarkType : u32 {
+ Invalid,
+ H1,
+ H2,
+ NL,
+ NR,
+};
+
+// This is nn::hid::NpadLuciaType
+enum class NpadLuciaType : u32 {
+ Invalid,
+ J,
+ E,
+ U,
+};
+
+// This is nn::hid::NpadLagonType
+enum class NpadLagonType : u32 {
+ Invalid,
+};
+
+// This is nn::hid::NpadLagerType
+enum class NpadLagerType : u32 {
+ Invalid,
+ J,
+ E,
+ U,
+};
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/types/touch_types.h b/src/core/hle/service/hid/controllers/types/touch_types.h
new file mode 100644
index 000000000..efeaa796d
--- /dev/null
+++ b/src/core/hle/service/hid/controllers/types/touch_types.h
@@ -0,0 +1,90 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-3.0-or-later
+
+#pragma once
+
+#include <array>
+
+#include <array>
+#include "common/bit_field.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+#include "common/point.h"
+#include "core/hid/hid_types.h"
+
+namespace Service::HID {
+static constexpr std::size_t MAX_FINGERS = 16;
+static constexpr size_t MAX_POINTS = 4;
+
+// This is nn::hid::GestureType
+enum class GestureType : u32 {
+ Idle, // Nothing touching the screen
+ Complete, // Set at the end of a touch event
+ Cancel, // Set when the number of fingers change
+ Touch, // A finger just touched the screen
+ Press, // Set if last type is touch and the finger hasn't moved
+ Tap, // Fast press then release
+ Pan, // All points moving together across the screen
+ Swipe, // Fast press movement and release of a single point
+ Pinch, // All points moving away/closer to the midpoint
+ Rotate, // All points rotating from the midpoint
+};
+
+// This is nn::hid::GestureDirection
+enum class GestureDirection : u32 {
+ None,
+ Left,
+ Up,
+ Right,
+ Down,
+};
+
+// This is nn::hid::GestureAttribute
+struct GestureAttribute {
+ union {
+ u32 raw{};
+
+ BitField<4, 1, u32> is_new_touch;
+ BitField<8, 1, u32> is_double_tap;
+ };
+};
+static_assert(sizeof(GestureAttribute) == 4, "GestureAttribute is an invalid size");
+
+// This is nn::hid::GestureState
+struct GestureState {
+ s64 sampling_number{};
+ s64 detection_count{};
+ GestureType type{GestureType::Idle};
+ GestureDirection direction{GestureDirection::None};
+ Common::Point<s32> pos{};
+ Common::Point<s32> delta{};
+ f32 vel_x{};
+ f32 vel_y{};
+ GestureAttribute attributes{};
+ f32 scale{};
+ f32 rotation_angle{};
+ s32 point_count{};
+ std::array<Common::Point<s32>, 4> points{};
+};
+static_assert(sizeof(GestureState) == 0x60, "GestureState is an invalid size");
+
+struct GestureProperties {
+ std::array<Common::Point<s32>, MAX_POINTS> points{};
+ std::size_t active_points{};
+ Common::Point<s32> mid_point{};
+ s64 detection_count{};
+ u64 delta_time{};
+ f32 average_distance{};
+ f32 angle{};
+};
+
+// This is nn::hid::TouchScreenState
+struct TouchScreenState {
+ s64 sampling_number{};
+ s32 entry_count{};
+ INSERT_PADDING_BYTES(4); // Reserved
+ std::array<Core::HID::TouchState, MAX_FINGERS> states{};
+};
+static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size");
+
+} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp
deleted file mode 100644
index 0aaed1fa7..000000000
--- a/src/core/hle/service/hid/controllers/xpad.cpp
+++ /dev/null
@@ -1,39 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#include <cstring>
-#include "common/common_types.h"
-#include "core/core_timing.h"
-#include "core/hid/hid_core.h"
-#include "core/hle/service/hid/controllers/xpad.h"
-
-namespace Service::HID {
-constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00;
-
-XPad::XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_) : ControllerBase{hid_core_} {
- static_assert(SHARED_MEMORY_OFFSET + sizeof(XpadSharedMemory) < shared_memory_size,
- "XpadSharedMemory is bigger than the shared memory");
- shared_memory = std::construct_at(
- reinterpret_cast<XpadSharedMemory*>(raw_shared_memory_ + SHARED_MEMORY_OFFSET));
-}
-XPad::~XPad() = default;
-
-void XPad::OnInit() {}
-
-void XPad::OnRelease() {}
-
-void XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) {
- if (!IsControllerActivated()) {
- shared_memory->basic_xpad_lifo.buffer_count = 0;
- shared_memory->basic_xpad_lifo.buffer_tail = 0;
- return;
- }
-
- const auto& last_entry = shared_memory->basic_xpad_lifo.ReadCurrentEntry().state;
- next_state.sampling_number = last_entry.sampling_number + 1;
- // TODO(ogniK): Update xpad states
-
- shared_memory->basic_xpad_lifo.WriteNextEntry(next_state);
-}
-
-} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/xpad.h b/src/core/hle/service/hid/controllers/xpad.h
deleted file mode 100644
index 9e63a317a..000000000
--- a/src/core/hle/service/hid/controllers/xpad.h
+++ /dev/null
@@ -1,112 +0,0 @@
-// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
-// SPDX-License-Identifier: GPL-2.0-or-later
-
-#pragma once
-
-#include "common/bit_field.h"
-#include "common/common_types.h"
-#include "core/hid/hid_types.h"
-#include "core/hle/service/hid/controllers/controller_base.h"
-#include "core/hle/service/hid/ring_lifo.h"
-
-namespace Service::HID {
-class XPad final : public ControllerBase {
-public:
- explicit XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_);
- ~XPad() override;
-
- // Called when the controller is initialized
- void OnInit() override;
-
- // When the controller is released
- void OnRelease() override;
-
- // When the controller is requesting an update for the shared memory
- void OnUpdate(const Core::Timing::CoreTiming& core_timing) override;
-
-private:
- // This is nn::hid::BasicXpadAttributeSet
- struct BasicXpadAttributeSet {
- union {
- u32 raw{};
- BitField<0, 1, u32> is_connected;
- BitField<1, 1, u32> is_wired;
- BitField<2, 1, u32> is_left_connected;
- BitField<3, 1, u32> is_left_wired;
- BitField<4, 1, u32> is_right_connected;
- BitField<5, 1, u32> is_right_wired;
- };
- };
- static_assert(sizeof(BasicXpadAttributeSet) == 4, "BasicXpadAttributeSet is an invalid size");
-
- // This is nn::hid::BasicXpadButtonSet
- struct BasicXpadButtonSet {
- union {
- u32 raw{};
- // Button states
- BitField<0, 1, u32> a;
- BitField<1, 1, u32> b;
- BitField<2, 1, u32> x;
- BitField<3, 1, u32> y;
- BitField<4, 1, u32> l_stick;
- BitField<5, 1, u32> r_stick;
- BitField<6, 1, u32> l;
- BitField<7, 1, u32> r;
- BitField<8, 1, u32> zl;
- BitField<9, 1, u32> zr;
- BitField<10, 1, u32> plus;
- BitField<11, 1, u32> minus;
-
- // D-Pad
- BitField<12, 1, u32> d_left;
- BitField<13, 1, u32> d_up;
- BitField<14, 1, u32> d_right;
- BitField<15, 1, u32> d_down;
-
- // Left JoyStick
- BitField<16, 1, u32> l_stick_left;
- BitField<17, 1, u32> l_stick_up;
- BitField<18, 1, u32> l_stick_right;
- BitField<19, 1, u32> l_stick_down;
-
- // Right JoyStick
- BitField<20, 1, u32> r_stick_left;
- BitField<21, 1, u32> r_stick_up;
- BitField<22, 1, u32> r_stick_right;
- BitField<23, 1, u32> r_stick_down;
-
- // Not always active?
- BitField<24, 1, u32> left_sl;
- BitField<25, 1, u32> left_sr;
-
- BitField<26, 1, u32> right_sl;
- BitField<27, 1, u32> right_sr;
-
- BitField<28, 1, u32> palma;
- BitField<30, 1, u32> handheld_left_b;
- };
- };
- static_assert(sizeof(BasicXpadButtonSet) == 4, "BasicXpadButtonSet is an invalid size");
-
- // This is nn::hid::detail::BasicXpadState
- struct BasicXpadState {
- s64 sampling_number{};
- BasicXpadAttributeSet attributes{};
- BasicXpadButtonSet pad_states{};
- Core::HID::AnalogStickState l_stick{};
- Core::HID::AnalogStickState r_stick{};
- };
- static_assert(sizeof(BasicXpadState) == 0x20, "BasicXpadState is an invalid size");
-
- struct XpadSharedMemory {
- // This is nn::hid::detail::BasicXpadLifo
- Lifo<BasicXpadState, hid_entry_count> basic_xpad_lifo{};
- static_assert(sizeof(basic_xpad_lifo) == 0x2C8, "basic_xpad_lifo is an invalid size");
- INSERT_PADDING_WORDS(0x4E);
- };
- static_assert(sizeof(XpadSharedMemory) == 0x400, "XpadSharedMemory is an invalid size");
-
- BasicXpadState next_state{};
- XpadSharedMemory* shared_memory = nullptr;
-};
-} // namespace Service::HID
diff --git a/src/core/hle/service/hid/errors.h b/src/core/hle/service/hid/errors.h
index 9585bdaf0..6dc976fe1 100644
--- a/src/core/hle/service/hid/errors.h
+++ b/src/core/hle/service/hid/errors.h
@@ -19,6 +19,14 @@ constexpr Result NpadIsSameType{ErrorModule::HID, 602};
constexpr Result InvalidNpadId{ErrorModule::HID, 709};
constexpr Result NpadNotConnected{ErrorModule::HID, 710};
constexpr Result InvalidArraySize{ErrorModule::HID, 715};
+
+constexpr Result ResultAppletResourceOverflow{ErrorModule::HID, 1041};
+constexpr Result ResultAppletResourceNotInitialized{ErrorModule::HID, 1042};
+constexpr Result ResultSharedMemoryNotInitialized{ErrorModule::HID, 1043};
+constexpr Result ResultAruidNoAvailableEntries{ErrorModule::HID, 1044};
+constexpr Result ResultAruidAlreadyRegistered{ErrorModule::HID, 1046};
+constexpr Result ResultAruidNotRegistered{ErrorModule::HID, 1047};
+
constexpr Result InvalidPalmaHandle{ErrorModule::HID, 3302};
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index 1b7381d8d..afbcb019f 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -1,6 +1,8 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/kernel/kernel.h"
#include "core/hle/service/hid/hid.h"
#include "core/hle/service/hid/hid_debug_server.h"
#include "core/hle/service/hid/hid_firmware_settings.h"
@@ -20,6 +22,12 @@ void LoopProcess(Core::System& system) {
std::shared_ptr<HidFirmwareSettings> firmware_settings =
std::make_shared<HidFirmwareSettings>();
+ // TODO: Remove this hack until this service is emulated properly.
+ const auto process_list = system.Kernel().GetProcessList();
+ if (!process_list.empty()) {
+ resouce_manager->RegisterAppletResourceUserId(process_list[0]->GetId(), true);
+ }
+
server_manager->RegisterNamedService(
"hid", std::make_shared<IHidServer>(system, resouce_manager, firmware_settings));
server_manager->RegisterNamedService(
diff --git a/src/core/hle/service/hid/hid_server.cpp b/src/core/hle/service/hid/hid_server.cpp
index a7d1578d9..de24b0401 100644
--- a/src/core/hle/service/hid/hid_server.cpp
+++ b/src/core/hle/service/hid/hid_server.cpp
@@ -28,6 +28,7 @@
#include "core/hle/service/hid/controllers/seven_six_axis.h"
#include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/controllers/types/npad_types.h"
namespace Service::HID {
@@ -222,11 +223,14 @@ void IHidServer::CreateAppletResource(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+ Result result = GetResourceManager()->CreateAppletResource(applet_resource_user_id);
+
+ LOG_DEBUG(Service_HID, "called, applet_resource_user_id={}, result=0x{:X}",
+ applet_resource_user_id, result.raw);
IPC::ResponseBuilder rb{ctx, 2, 0, 1};
- rb.Push(ResultSuccess);
- rb.PushIpcInterface<IAppletResource>(system, resource_manager);
+ rb.Push(result);
+ rb.PushIpcInterface<IAppletResource>(system, resource_manager, applet_resource_user_id);
}
void IHidServer::ActivateDebugPad(HLERequestContext& ctx) {
@@ -1096,7 +1100,7 @@ void IHidServer::GetPlayerLedPattern(HLERequestContext& ctx) {
void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
struct Parameters {
- NPad::NpadRevision revision;
+ NpadRevision revision;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
};
@@ -1119,7 +1123,7 @@ void IHidServer::ActivateNpadWithRevision(HLERequestContext& ctx) {
void IHidServer::SetNpadJoyHoldType(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto hold_type{rp.PopEnum<NPad::NpadJoyHoldType>()};
+ const auto hold_type{rp.PopEnum<NpadJoyHoldType>()};
GetResourceManager()->GetNpad()->SetHoldType(hold_type);
@@ -1154,8 +1158,8 @@ void IHidServer::SetNpadJoyAssignmentModeSingleByDefault(HLERequestContext& ctx)
Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad();
- controller->SetNpadMode(new_npad_id, parameters.npad_id, NPad::NpadJoyDeviceType::Left,
- NPad::NpadJoyAssignmentMode::Single);
+ controller->SetNpadMode(new_npad_id, parameters.npad_id, NpadJoyDeviceType::Left,
+ NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id);
@@ -1170,7 +1174,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
- NPad::NpadJoyDeviceType npad_joy_device_type;
+ NpadJoyDeviceType npad_joy_device_type;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@@ -1179,7 +1183,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingle(HLERequestContext& ctx) {
Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad();
controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
- NPad::NpadJoyAssignmentMode::Single);
+ NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id,
@@ -1202,7 +1206,7 @@ void IHidServer::SetNpadJoyAssignmentModeDual(HLERequestContext& ctx) {
Core::HID::NpadIdType new_npad_id{};
auto controller = GetResourceManager()->GetNpad();
- controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NPad::NpadJoyAssignmentMode::Dual);
+ controller->SetNpadMode(new_npad_id, parameters.npad_id, {}, NpadJoyAssignmentMode::Dual);
LOG_DEBUG(Service_HID, "called, npad_id={}, applet_resource_user_id={}", parameters.npad_id,
parameters.applet_resource_user_id); // Spams a lot when controller applet is open
@@ -1254,7 +1258,7 @@ void IHidServer::StopLrAssignmentMode(HLERequestContext& ctx) {
void IHidServer::SetNpadHandheldActivationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto activation_mode{rp.PopEnum<NPad::NpadHandheldActivationMode>()};
+ const auto activation_mode{rp.PopEnum<NpadHandheldActivationMode>()};
GetResourceManager()->GetNpad()->SetNpadHandheldActivationMode(activation_mode);
@@ -1346,7 +1350,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
Core::HID::NpadIdType npad_id;
INSERT_PADDING_WORDS_NOINIT(1);
u64 applet_resource_user_id;
- NPad::NpadJoyDeviceType npad_joy_device_type;
+ NpadJoyDeviceType npad_joy_device_type;
};
static_assert(sizeof(Parameters) == 0x18, "Parameters has incorrect size.");
@@ -1356,7 +1360,7 @@ void IHidServer::SetNpadJoyAssignmentModeSingleWithDestination(HLERequestContext
auto controller = GetResourceManager()->GetNpad();
const auto is_reassigned =
controller->SetNpadMode(new_npad_id, parameters.npad_id, parameters.npad_joy_device_type,
- NPad::NpadJoyAssignmentMode::Single);
+ NpadJoyAssignmentMode::Single);
LOG_INFO(Service_HID, "called, npad_id={}, applet_resource_user_id={}, npad_joy_device_type={}",
parameters.npad_id, parameters.applet_resource_user_id,
@@ -2312,7 +2316,7 @@ void IHidServer::SetDisallowedPalmaConnection(HLERequestContext& ctx) {
void IHidServer::SetNpadCommunicationMode(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto applet_resource_user_id{rp.Pop<u64>()};
- const auto communication_mode{rp.PopEnum<NPad::NpadCommunicationMode>()};
+ const auto communication_mode{rp.PopEnum<NpadCommunicationMode>()};
GetResourceManager()->GetNpad()->SetNpadCommunicationMode(communication_mode);
diff --git a/src/core/hle/service/hid/hid_system_server.cpp b/src/core/hle/service/hid/hid_system_server.cpp
index b56d0347a..5cc88c4a1 100644
--- a/src/core/hle/service/hid/hid_system_server.cpp
+++ b/src/core/hle/service/hid/hid_system_server.cpp
@@ -3,7 +3,9 @@
#include "core/hid/hid_core.h"
#include "core/hle/service/hid/controllers/npad.h"
+#include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
+#include "core/hle/service/hid/controllers/types/npad_types.h"
#include "core/hle/service/hid/errors.h"
#include "core/hle/service/hid/hid_system_server.h"
#include "core/hle/service/hid/resource_manager.h"
@@ -63,13 +65,13 @@ IHidSystemServer::IHidSystemServer(Core::System& system_, std::shared_ptr<Resour
{329, nullptr, "DetachAbstractedPadAll"},
{330, nullptr, "CheckAbstractedPadConnection"},
{500, nullptr, "SetAppletResourceUserId"},
- {501, nullptr, "RegisterAppletResourceUserId"},
- {502, nullptr, "UnregisterAppletResourceUserId"},
- {503, nullptr, "EnableAppletToGetInput"},
+ {501, &IHidSystemServer::RegisterAppletResourceUserId, "RegisterAppletResourceUserId"},
+ {502, &IHidSystemServer::UnregisterAppletResourceUserId, "UnregisterAppletResourceUserId"},
+ {503, &IHidSystemServer::EnableAppletToGetInput, "EnableAppletToGetInput"},
{504, nullptr, "SetAruidValidForVibration"},
- {505, nullptr, "EnableAppletToGetSixAxisSensor"},
- {506, nullptr, "EnableAppletToGetPadInput"},
- {507, nullptr, "EnableAppletToGetTouchScreen"},
+ {505, &IHidSystemServer::EnableAppletToGetSixAxisSensor, "EnableAppletToGetSixAxisSensor"},
+ {506, &IHidSystemServer::EnableAppletToGetPadInput, "EnableAppletToGetPadInput"},
+ {507, &IHidSystemServer::EnableAppletToGetTouchScreen, "EnableAppletToGetTouchScreen"},
{510, nullptr, "SetVibrationMasterVolume"},
{511, nullptr, "GetVibrationMasterVolume"},
{512, nullptr, "BeginPermitVibrationSession"},
@@ -327,7 +329,7 @@ void IHidSystemServer::GetAppletDetailedUiType(HLERequestContext& ctx) {
LOG_DEBUG(Service_HID, "called, npad_id_type={}",
npad_id_type); // Spams a lot when controller applet is running
- const NPad::AppletDetailedUiType detailed_ui_type =
+ const AppletDetailedUiType detailed_ui_type =
GetResourceManager()->GetNpad()->GetAppletDetailedUiType(npad_id_type);
IPC::ResponseBuilder rb{ctx, 3};
@@ -420,6 +422,129 @@ void IHidSystemServer::GetIrSensorState(HLERequestContext& ctx) {
IPC::ResponseBuilder rb{ctx, 2};
rb.Push(ResultSuccess);
}
+void IHidSystemServer::RegisterAppletResourceUserId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool enable_input;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_INFO(Service_HID, "called, enable_input={}, applet_resource_user_id={}",
+ parameters.enable_input, parameters.applet_resource_user_id);
+
+ Result result = GetResourceManager()->RegisterAppletResourceUserId(
+ parameters.applet_resource_user_id, parameters.enable_input);
+
+ if (result.IsSuccess()) {
+ // result = GetResourceManager()->GetNpad()->RegisterAppletResourceUserId(
+ // parameters.applet_resource_user_id);
+ }
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::UnregisterAppletResourceUserId(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ u64 applet_resource_user_id{rp.Pop<u64>()};
+
+ LOG_INFO(Service_HID, "called, applet_resource_user_id={}", applet_resource_user_id);
+
+ GetResourceManager()->UnregisterAppletResourceUserId(applet_resource_user_id);
+ // GetResourceManager()->GetNpad()->UnregisterAppletResourceUserId(applet_resource_user_id);
+ // GetResourceManager()->GetPalma()->UnregisterAppletResourceUserId(applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::EnableAppletToGetInput(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_enabled;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
+ parameters.is_enabled, parameters.applet_resource_user_id);
+
+ GetResourceManager()->EnableInput(parameters.applet_resource_user_id, parameters.is_enabled);
+ // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::EnableAppletToGetSixAxisSensor(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_enabled;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
+ parameters.is_enabled, parameters.applet_resource_user_id);
+
+ GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id,
+ parameters.is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::EnableAppletToGetPadInput(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_enabled;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
+ parameters.is_enabled, parameters.applet_resource_user_id);
+
+ GetResourceManager()->EnablePadInput(parameters.applet_resource_user_id, parameters.is_enabled);
+ // GetResourceManager()->GetNpad()->EnableInput(parameters.applet_resource_user_id);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
+
+void IHidSystemServer::EnableAppletToGetTouchScreen(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ struct Parameters {
+ bool is_enabled;
+ INSERT_PADDING_WORDS_NOINIT(1);
+ u64 applet_resource_user_id;
+ };
+ static_assert(sizeof(Parameters) == 0x10, "Parameters has incorrect size.");
+
+ const auto parameters{rp.PopRaw<Parameters>()};
+
+ LOG_INFO(Service_HID, "called, is_enabled={}, applet_resource_user_id={}",
+ parameters.is_enabled, parameters.applet_resource_user_id);
+
+ GetResourceManager()->EnableTouchScreen(parameters.applet_resource_user_id,
+ parameters.is_enabled);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(ResultSuccess);
+}
void IHidSystemServer::AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx) {
LOG_INFO(Service_AM, "(STUBBED) called");
diff --git a/src/core/hle/service/hid/hid_system_server.h b/src/core/hle/service/hid/hid_system_server.h
index 822d5e5b9..1e623dfc2 100644
--- a/src/core/hle/service/hid/hid_system_server.h
+++ b/src/core/hle/service/hid/hid_system_server.h
@@ -38,6 +38,12 @@ private:
void HasLeftRightBattery(HLERequestContext& ctx);
void GetUniquePadsFromNpad(HLERequestContext& ctx);
void GetIrSensorState(HLERequestContext& ctx);
+ void RegisterAppletResourceUserId(HLERequestContext& ctx);
+ void UnregisterAppletResourceUserId(HLERequestContext& ctx);
+ void EnableAppletToGetInput(HLERequestContext& ctx);
+ void EnableAppletToGetSixAxisSensor(HLERequestContext& ctx);
+ void EnableAppletToGetPadInput(HLERequestContext& ctx);
+ void EnableAppletToGetTouchScreen(HLERequestContext& ctx);
void AcquireConnectionTriggerTimeoutEvent(HLERequestContext& ctx);
void AcquireDeviceRegisteredEventForControllerSupport(HLERequestContext& ctx);
void GetRegisteredDevices(HLERequestContext& ctx);
diff --git a/src/core/hle/service/hid/resource_manager.cpp b/src/core/hle/service/hid/resource_manager.cpp
index e76d4eea9..6c6cbd802 100644
--- a/src/core/hle/service/hid/resource_manager.cpp
+++ b/src/core/hle/service/hid/resource_manager.cpp
@@ -9,6 +9,7 @@
#include "core/hle/service/hid/resource_manager.h"
#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/hid/controllers/applet_resource.h"
#include "core/hle/service/hid/controllers/console_six_axis.h"
#include "core/hle/service/hid/controllers/debug_pad.h"
#include "core/hle/service/hid/controllers/gesture.h"
@@ -17,10 +18,10 @@
#include "core/hle/service/hid/controllers/npad.h"
#include "core/hle/service/hid/controllers/palma.h"
#include "core/hle/service/hid/controllers/seven_six_axis.h"
+#include "core/hle/service/hid/controllers/shared_memory_format.h"
#include "core/hle/service/hid/controllers/six_axis.h"
#include "core/hle/service/hid/controllers/stubbed.h"
#include "core/hle/service/hid/controllers/touchscreen.h"
-#include "core/hle/service/hid/controllers/xpad.h"
namespace Service::HID {
@@ -33,7 +34,9 @@ constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 10
constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz)
ResourceManager::ResourceManager(Core::System& system_)
- : system{system_}, service_context{system_, "hid"} {}
+ : system{system_}, service_context{system_, "hid"} {
+ applet_resource = std::make_shared<AppletResource>(system);
+}
ResourceManager::~ResourceManager() = default;
@@ -42,41 +45,49 @@ void ResourceManager::Initialize() {
return;
}
- u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer();
- debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory);
- mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory);
- debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory);
- keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory);
- unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory);
- npad = std::make_shared<NPad>(system.HIDCore(), shared_memory, service_context);
- gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory);
- touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory);
- xpad = std::make_shared<XPad>(system.HIDCore(), shared_memory);
+ system.HIDCore().ReloadInputDevices();
+ is_initialized = true;
+}
+
+void ResourceManager::InitializeController(u64 aruid) {
+ SharedMemoryFormat* shared_memory = nullptr;
+ const auto result = applet_resource->GetSharedMemoryFormat(&shared_memory, aruid);
+ if (result.IsError()) {
+ return;
+ }
+
+ debug_pad = std::make_shared<DebugPad>(system.HIDCore(), shared_memory->debug_pad);
+ mouse = std::make_shared<Mouse>(system.HIDCore(), shared_memory->mouse);
+ debug_mouse = std::make_shared<DebugMouse>(system.HIDCore(), shared_memory->debug_mouse);
+ keyboard = std::make_shared<Keyboard>(system.HIDCore(), shared_memory->keyboard);
+ unique_pad = std::make_shared<UniquePad>(system.HIDCore(), shared_memory->unique_pad.header);
+ npad = std::make_shared<NPad>(system.HIDCore(), shared_memory->npad, service_context);
+ gesture = std::make_shared<Gesture>(system.HIDCore(), shared_memory->gesture);
+ touch_screen = std::make_shared<TouchScreen>(system.HIDCore(), shared_memory->touch_screen);
- palma = std::make_shared<Palma>(system.HIDCore(), shared_memory, service_context);
+ palma = std::make_shared<Palma>(system.HIDCore(), service_context);
- home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory);
- sleep_button = std::make_shared<SleepButton>(system.HIDCore(), shared_memory);
- capture_button = std::make_shared<CaptureButton>(system.HIDCore(), shared_memory);
+ home_button = std::make_shared<HomeButton>(system.HIDCore(), shared_memory->home_button.header);
+ sleep_button =
+ std::make_shared<SleepButton>(system.HIDCore(), shared_memory->sleep_button.header);
+ capture_button =
+ std::make_shared<CaptureButton>(system.HIDCore(), shared_memory->capture_button.header);
+ digitizer = std::make_shared<Digitizer>(system.HIDCore(), shared_memory->digitizer.header);
six_axis = std::make_shared<SixAxis>(system.HIDCore(), npad);
- console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory);
+ console_six_axis = std::make_shared<ConsoleSixAxis>(system.HIDCore(), shared_memory->console);
seven_six_axis = std::make_shared<SevenSixAxis>(system);
- home_button->SetCommonHeaderOffset(0x4C00);
- sleep_button->SetCommonHeaderOffset(0x4E00);
- capture_button->SetCommonHeaderOffset(0x5000);
- unique_pad->SetCommonHeaderOffset(0x5A00);
- debug_mouse->SetCommonHeaderOffset(0x3DC00);
-
// Homebrew doesn't try to activate some controllers, so we activate them by default
npad->Activate();
six_axis->Activate();
touch_screen->Activate();
+}
- system.HIDCore().ReloadInputDevices();
- is_initialized = true;
+std::shared_ptr<AppletResource> ResourceManager::GetAppletResource() const {
+ return applet_resource;
}
+
std::shared_ptr<CaptureButton> ResourceManager::GetCaptureButton() const {
return capture_button;
}
@@ -93,6 +104,10 @@ std::shared_ptr<DebugPad> ResourceManager::GetDebugPad() const {
return debug_pad;
}
+std::shared_ptr<Digitizer> ResourceManager::GetDigitizer() const {
+ return digitizer;
+}
+
std::shared_ptr<Gesture> ResourceManager::GetGesture() const {
return gesture;
}
@@ -137,10 +152,86 @@ std::shared_ptr<UniquePad> ResourceManager::GetUniquePad() const {
return unique_pad;
}
+Result ResourceManager::CreateAppletResource(u64 aruid) {
+ if (aruid == 0) {
+ const auto result = RegisterCoreAppletResource();
+ if (result.IsError()) {
+ return result;
+ }
+ return GetNpad()->Activate();
+ }
+
+ const auto result = CreateAppletResourceImpl(aruid);
+ if (result.IsError()) {
+ return result;
+ }
+ return GetNpad()->Activate(aruid);
+}
+
+Result ResourceManager::CreateAppletResourceImpl(u64 aruid) {
+ std::scoped_lock lock{shared_mutex};
+ const auto result = applet_resource->CreateAppletResource(aruid);
+ if (result.IsSuccess()) {
+ InitializeController(aruid);
+ }
+ return result;
+}
+
+Result ResourceManager::RegisterCoreAppletResource() {
+ std::scoped_lock lock{shared_mutex};
+ return applet_resource->RegisterCoreAppletResource();
+}
+
+Result ResourceManager::UnregisterCoreAppletResource() {
+ std::scoped_lock lock{shared_mutex};
+ return applet_resource->UnregisterCoreAppletResource();
+}
+
+Result ResourceManager::RegisterAppletResourceUserId(u64 aruid, bool bool_value) {
+ std::scoped_lock lock{shared_mutex};
+ return applet_resource->RegisterAppletResourceUserId(aruid, bool_value);
+}
+
+void ResourceManager::UnregisterAppletResourceUserId(u64 aruid) {
+ std::scoped_lock lock{shared_mutex};
+ applet_resource->UnregisterAppletResourceUserId(aruid);
+}
+
+Result ResourceManager::GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid) {
+ std::scoped_lock lock{shared_mutex};
+ return applet_resource->GetSharedMemoryHandle(out_handle, aruid);
+}
+
+void ResourceManager::FreeAppletResourceId(u64 aruid) {
+ std::scoped_lock lock{shared_mutex};
+ applet_resource->FreeAppletResourceId(aruid);
+}
+
+void ResourceManager::EnableInput(u64 aruid, bool is_enabled) {
+ std::scoped_lock lock{shared_mutex};
+ applet_resource->EnableInput(aruid, is_enabled);
+}
+
+void ResourceManager::EnableSixAxisSensor(u64 aruid, bool is_enabled) {
+ std::scoped_lock lock{shared_mutex};
+ applet_resource->EnableSixAxisSensor(aruid, is_enabled);
+}
+
+void ResourceManager::EnablePadInput(u64 aruid, bool is_enabled) {
+ std::scoped_lock lock{shared_mutex};
+ applet_resource->EnablePadInput(aruid, is_enabled);
+}
+
+void ResourceManager::EnableTouchScreen(u64 aruid, bool is_enabled) {
+ std::scoped_lock lock{shared_mutex};
+ applet_resource->EnableTouchScreen(aruid, is_enabled);
+}
+
void ResourceManager::UpdateControllers(std::uintptr_t user_data,
std::chrono::nanoseconds ns_late) {
auto& core_timing = system.CoreTiming();
debug_pad->OnUpdate(core_timing);
+ digitizer->OnUpdate(core_timing);
unique_pad->OnUpdate(core_timing);
gesture->OnUpdate(core_timing);
touch_screen->OnUpdate(core_timing);
@@ -148,7 +239,6 @@ void ResourceManager::UpdateControllers(std::uintptr_t user_data,
home_button->OnUpdate(core_timing);
sleep_button->OnUpdate(core_timing);
capture_button->OnUpdate(core_timing);
- xpad->OnUpdate(core_timing);
}
void ResourceManager::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) {
@@ -171,15 +261,15 @@ void ResourceManager::UpdateMotion(std::uintptr_t user_data, std::chrono::nanose
console_six_axis->OnUpdate(core_timing);
}
-IAppletResource::IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource)
- : ServiceFramework{system_, "IAppletResource"} {
+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);
- resource->Initialize();
-
// Register update callbacks
npad_update_event = Core::Timing::CreateEvent(
"HID::UpdatePadCallback",
@@ -228,14 +318,18 @@ IAppletResource::~IAppletResource() {
system.CoreTiming().UnscheduleEvent(default_update_event, 0);
system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0);
system.CoreTiming().UnscheduleEvent(motion_update_event, 0);
+ resource_manager->FreeAppletResourceId(aruid);
}
void IAppletResource::GetSharedMemoryHandle(HLERequestContext& ctx) {
- LOG_DEBUG(Service_HID, "called");
+ 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(ResultSuccess);
- rb.PushCopyObjects(&system.Kernel().GetHidSharedMem());
+ rb.Push(result);
+ rb.PushCopyObjects(handle);
}
} // namespace Service::HID
diff --git a/src/core/hle/service/hid/resource_manager.h b/src/core/hle/service/hid/resource_manager.h
index 2b6a9b5e6..5ad7cb564 100644
--- a/src/core/hle/service/hid/resource_manager.h
+++ b/src/core/hle/service/hid/resource_manager.h
@@ -6,11 +6,20 @@
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/service.h"
+namespace Core {
+class System;
+}
+
namespace Core::Timing {
struct EventType;
}
+namespace Kernel {
+class KSharedMemory;
+}
+
namespace Service::HID {
+class AppletResource;
class Controller_Stubbed;
class ConsoleSixAxis;
class DebugPad;
@@ -22,10 +31,10 @@ class Palma;
class SevenSixAxis;
class SixAxis;
class TouchScreen;
-class XPad;
using CaptureButton = Controller_Stubbed;
-using DebugMouse = Controller_Stubbed;
+using DebugMouse = Mouse;
+using Digitizer = Controller_Stubbed;
using HomeButton = Controller_Stubbed;
using SleepButton = Controller_Stubbed;
using UniquePad = Controller_Stubbed;
@@ -37,11 +46,14 @@ public:
~ResourceManager();
void Initialize();
+ void InitializeController(u64 aruid);
+ std::shared_ptr<AppletResource> GetAppletResource() const;
std::shared_ptr<CaptureButton> GetCaptureButton() const;
std::shared_ptr<ConsoleSixAxis> GetConsoleSixAxis() const;
std::shared_ptr<DebugMouse> GetDebugMouse() const;
std::shared_ptr<DebugPad> GetDebugPad() const;
+ std::shared_ptr<Digitizer> GetDigitizer() const;
std::shared_ptr<Gesture> GetGesture() const;
std::shared_ptr<HomeButton> GetHomeButton() const;
std::shared_ptr<Keyboard> GetKeyboard() const;
@@ -54,18 +66,39 @@ public:
std::shared_ptr<TouchScreen> GetTouchScreen() const;
std::shared_ptr<UniquePad> GetUniquePad() const;
+ Result CreateAppletResource(u64 aruid);
+
+ Result RegisterCoreAppletResource();
+ Result UnregisterCoreAppletResource();
+ Result RegisterAppletResourceUserId(u64 aruid, bool bool_value);
+ void UnregisterAppletResourceUserId(u64 aruid);
+
+ Result GetSharedMemoryHandle(Kernel::KSharedMemory** out_handle, u64 aruid);
+ void FreeAppletResourceId(u64 aruid);
+
+ void EnableInput(u64 aruid, bool is_enabled);
+ void EnableSixAxisSensor(u64 aruid, bool is_enabled);
+ void EnablePadInput(u64 aruid, bool is_enabled);
+ void EnableTouchScreen(u64 aruid, bool is_enabled);
+
void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late);
private:
+ Result CreateAppletResourceImpl(u64 aruid);
+
bool is_initialized{false};
+ mutable std::mutex shared_mutex;
+ std::shared_ptr<AppletResource> applet_resource = nullptr;
+
std::shared_ptr<CaptureButton> capture_button = nullptr;
std::shared_ptr<ConsoleSixAxis> console_six_axis = nullptr;
std::shared_ptr<DebugMouse> debug_mouse = nullptr;
std::shared_ptr<DebugPad> debug_pad = nullptr;
+ std::shared_ptr<Digitizer> digitizer = nullptr;
std::shared_ptr<Gesture> gesture = nullptr;
std::shared_ptr<HomeButton> home_button = nullptr;
std::shared_ptr<Keyboard> keyboard = nullptr;
@@ -77,7 +110,6 @@ private:
std::shared_ptr<SleepButton> sleep_button = nullptr;
std::shared_ptr<TouchScreen> touch_screen = nullptr;
std::shared_ptr<UniquePad> unique_pad = nullptr;
- std::shared_ptr<XPad> xpad = nullptr;
// TODO: Create these resources
// std::shared_ptr<AudioControl> audio_control = nullptr;
@@ -96,7 +128,8 @@ private:
class IAppletResource final : public ServiceFramework<IAppletResource> {
public:
- explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource);
+ explicit IAppletResource(Core::System& system_, std::shared_ptr<ResourceManager> resource,
+ u64 applet_resource_user_id);
~IAppletResource() override;
private:
@@ -106,6 +139,9 @@ private:
std::shared_ptr<Core::Timing::EventType> default_update_event;
std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event;
std::shared_ptr<Core::Timing::EventType> motion_update_event;
+
+ u64 aruid;
+ std::shared_ptr<ResourceManager> resource_manager;
};
} // namespace Service::HID
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp
index ff374ae39..38955932c 100644
--- a/src/core/hle/service/hle_ipc.cpp
+++ b/src/core/hle/service/hle_ipc.cpp
@@ -146,8 +146,10 @@ HLERequestContext::HLERequestContext(Kernel::KernelCore& kernel_, Core::Memory::
HLERequestContext::~HLERequestContext() = default;
-void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_table,
- u32_le* src_cmdbuf, bool incoming) {
+void HLERequestContext::ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf,
+ bool incoming) {
+ client_handle_table = &process.GetHandleTable();
+
IPC::RequestParser rp(src_cmdbuf);
command_header = rp.PopRaw<IPC::CommandHeader>();
@@ -160,7 +162,8 @@ void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_ta
if (command_header->enable_handle_descriptor) {
handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>();
if (handle_descriptor_header->send_current_pid) {
- pid = rp.Pop<u64>();
+ pid = process.GetProcessId();
+ rp.Skip(2, false);
}
if (incoming) {
// Populate the object lists with the data in the IPC request.
@@ -267,9 +270,9 @@ void HLERequestContext::ParseCommandBuffer(const Kernel::KHandleTable& handle_ta
rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
}
-Result HLERequestContext::PopulateFromIncomingCommandBuffer(
- const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf) {
- ParseCommandBuffer(handle_table, src_cmdbuf, true);
+Result HLERequestContext::PopulateFromIncomingCommandBuffer(Kernel::KProcess& process,
+ u32_le* src_cmdbuf) {
+ ParseCommandBuffer(process, src_cmdbuf, true);
if (command_header->IsCloseCommand()) {
// Close does not populate the rest of the IPC header
diff --git a/src/core/hle/service/hle_ipc.h b/src/core/hle/service/hle_ipc.h
index ad5259a5c..18d464c63 100644
--- a/src/core/hle/service/hle_ipc.h
+++ b/src/core/hle/service/hle_ipc.h
@@ -38,6 +38,7 @@ namespace Kernel {
class KAutoObject;
class KernelCore;
class KHandleTable;
+class KProcess;
class KServerSession;
class KThread;
} // namespace Kernel
@@ -75,6 +76,7 @@ protected:
using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>;
using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>;
+using SessionRequestHandlerFactory = std::function<SessionRequestHandlerPtr()>;
/**
* Manages the underlying HLE requests for a session, and whether (or not) the session should be
@@ -194,8 +196,7 @@ public:
}
/// Populates this context with data from the requesting process/thread.
- Result PopulateFromIncomingCommandBuffer(const Kernel::KHandleTable& handle_table,
- u32_le* src_cmdbuf);
+ Result PopulateFromIncomingCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf);
/// Writes data from this context back to the requesting process/thread.
Result WriteToOutgoingCommandBuffer(Kernel::KThread& requesting_thread);
@@ -358,6 +359,10 @@ public:
return *thread;
}
+ Kernel::KHandleTable& GetClientHandleTable() {
+ return *client_handle_table;
+ }
+
[[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const {
return manager.lock();
}
@@ -373,12 +378,12 @@ public:
private:
friend class IPC::ResponseBuilder;
- void ParseCommandBuffer(const Kernel::KHandleTable& handle_table, u32_le* src_cmdbuf,
- bool incoming);
+ void ParseCommandBuffer(Kernel::KProcess& process, u32_le* src_cmdbuf, bool incoming);
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
Kernel::KServerSession* server_session{};
- Kernel::KThread* thread;
+ Kernel::KHandleTable* client_handle_table{};
+ Kernel::KThread* thread{};
std::vector<Handle> incoming_move_handles;
std::vector<Handle> incoming_copy_handles;
diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp
index be996870f..65851fc05 100644
--- a/src/core/hle/service/jit/jit.cpp
+++ b/src/core/hle/service/jit/jit.cpp
@@ -1,6 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
+#include "core/arm/debug.h"
#include "core/arm/symbols.h"
#include "core/core.h"
#include "core/hle/kernel/k_code_memory.h"
@@ -98,8 +99,9 @@ public:
if (return_value == 0) {
// The callback has written to the output executable code range,
// requiring an instruction cache invalidation
- system.InvalidateCpuInstructionCacheRange(configuration.user_rx_memory.offset,
- configuration.user_rx_memory.size);
+ Core::InvalidateInstructionCacheRange(process.GetPointerUnsafe(),
+ configuration.user_rx_memory.offset,
+ configuration.user_rx_memory.size);
// Write back to the IPC output buffer, if provided
if (ctx.CanWriteBuffer()) {
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp
index 97b6a9385..ba58b3a09 100644
--- a/src/core/hle/service/ldr/ldr.cpp
+++ b/src/core/hle/service/ldr/ldr.cpp
@@ -1,117 +1,12 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
-#include <memory>
-#include <fmt/format.h>
-#include <mbedtls/sha256.h>
-
-#include "common/alignment.h"
-#include "common/hex_util.h"
-#include "common/scope_exit.h"
-#include "core/core.h"
-#include "core/hle/kernel/k_page_table.h"
-#include "core/hle/kernel/svc_results.h"
-#include "core/hle/kernel/svc_types.h"
-#include "core/hle/service/ipc_helpers.h"
#include "core/hle/service/ldr/ldr.h"
#include "core/hle/service/server_manager.h"
#include "core/hle/service/service.h"
-#include "core/loader/nro.h"
-#include "core/memory.h"
namespace Service::LDR {
-constexpr Result ERROR_INSUFFICIENT_ADDRESS_SPACE{ErrorModule::RO, 2};
-
-[[maybe_unused]] constexpr Result ERROR_INVALID_MEMORY_STATE{ErrorModule::Loader, 51};
-constexpr Result ERROR_INVALID_NRO{ErrorModule::Loader, 52};
-constexpr Result ERROR_INVALID_NRR{ErrorModule::Loader, 53};
-constexpr Result ERROR_MISSING_NRR_HASH{ErrorModule::Loader, 54};
-constexpr Result ERROR_MAXIMUM_NRO{ErrorModule::Loader, 55};
-constexpr Result ERROR_MAXIMUM_NRR{ErrorModule::Loader, 56};
-constexpr Result ERROR_ALREADY_LOADED{ErrorModule::Loader, 57};
-constexpr Result ERROR_INVALID_ALIGNMENT{ErrorModule::Loader, 81};
-constexpr Result ERROR_INVALID_SIZE{ErrorModule::Loader, 82};
-constexpr Result ERROR_INVALID_NRO_ADDRESS{ErrorModule::Loader, 84};
-[[maybe_unused]] constexpr Result ERROR_INVALID_NRR_ADDRESS{ErrorModule::Loader, 85};
-constexpr Result ERROR_NOT_INITIALIZED{ErrorModule::Loader, 87};
-
-constexpr std::size_t MAXIMUM_LOADED_RO{0x40};
-constexpr std::size_t MAXIMUM_MAP_RETRIES{0x200};
-
-constexpr std::size_t TEXT_INDEX{0};
-constexpr std::size_t RO_INDEX{1};
-constexpr std::size_t DATA_INDEX{2};
-
-struct NRRCertification {
- u64_le application_id_mask;
- u64_le application_id_pattern;
- INSERT_PADDING_BYTES(0x10);
- std::array<u8, 0x100> public_key; // Also known as modulus
- std::array<u8, 0x100> signature;
-};
-static_assert(sizeof(NRRCertification) == 0x220, "NRRCertification has invalid size.");
-
-struct NRRHeader {
- u32_le magic;
- u32_le certification_signature_key_generation; // 9.0.0+
- INSERT_PADDING_WORDS(2);
- NRRCertification certification;
- std::array<u8, 0x100> signature;
- u64_le application_id;
- u32_le size;
- u8 nrr_kind; // 7.0.0+
- INSERT_PADDING_BYTES(3);
- u32_le hash_offset;
- u32_le hash_count;
- INSERT_PADDING_WORDS(2);
-};
-static_assert(sizeof(NRRHeader) == 0x350, "NRRHeader has invalid size.");
-
-struct SegmentHeader {
- u32_le memory_offset;
- u32_le memory_size;
-};
-static_assert(sizeof(SegmentHeader) == 0x8, "SegmentHeader has invalid size.");
-
-struct NROHeader {
- // Switchbrew calls this "Start" (0x10)
- INSERT_PADDING_WORDS(1);
- u32_le mod_offset;
- INSERT_PADDING_WORDS(2);
-
- // Switchbrew calls this "Header" (0x70)
- u32_le magic;
- u32_le version;
- u32_le nro_size;
- u32_le flags;
- // .text, .ro, .data
- std::array<SegmentHeader, 3> segment_headers;
- u32_le bss_size;
- INSERT_PADDING_WORDS(1);
- std::array<u8, 0x20> build_id;
- u32_le dso_handle_offset;
- INSERT_PADDING_WORDS(1);
- // .apiInfo, .dynstr, .dynsym
- std::array<SegmentHeader, 3> segment_headers_2;
-};
-static_assert(sizeof(NROHeader) == 0x80, "NROHeader has invalid size.");
-
-using SHA256Hash = std::array<u8, 0x20>;
-
-struct NROInfo {
- SHA256Hash hash{};
- VAddr nro_address{};
- std::size_t nro_size{};
- VAddr bss_address{};
- std::size_t bss_size{};
- std::size_t text_size{};
- std::size_t ro_size{};
- std::size_t data_size{};
- VAddr src_addr{};
-};
-static_assert(sizeof(NROInfo) == 0x60, "NROInfo has invalid size.");
-
class DebugMonitor final : public ServiceFramework<DebugMonitor> {
public:
explicit DebugMonitor(Core::System& system_) : ServiceFramework{system_, "ldr:dmnt"} {
@@ -158,541 +53,12 @@ public:
}
};
-class RelocatableObject final : public ServiceFramework<RelocatableObject> {
-public:
- explicit RelocatableObject(Core::System& system_) : ServiceFramework{system_, "ldr:ro"} {
- // clang-format off
- static const FunctionInfo functions[] = {
- {0, &RelocatableObject::LoadModule, "LoadModule"},
- {1, &RelocatableObject::UnloadModule, "UnloadModule"},
- {2, &RelocatableObject::RegisterModuleInfo, "RegisterModuleInfo"},
- {3, &RelocatableObject::UnregisterModuleInfo, "UnregisterModuleInfo"},
- {4, &RelocatableObject::Initialize, "Initialize"},
- {10, nullptr, "RegisterModuleInfo2"},
- };
- // clang-format on
-
- RegisterHandlers(functions);
- }
-
- void RegisterModuleInfo(HLERequestContext& ctx) {
- struct Parameters {
- u64_le process_id;
- u64_le nrr_address;
- u64_le nrr_size;
- };
-
- IPC::RequestParser rp{ctx};
- const auto [process_id, nrr_address, nrr_size] = rp.PopRaw<Parameters>();
-
- LOG_DEBUG(Service_LDR,
- "called with process_id={:016X}, nrr_address={:016X}, nrr_size={:016X}",
- process_id, nrr_address, nrr_size);
-
- if (!initialized) {
- LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- if (nrr.size() >= MAXIMUM_LOADED_RO) {
- LOG_ERROR(Service_LDR, "Loading new NRR would exceed the maximum number of loaded NRRs "
- "(0x40)! Failing...");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_MAXIMUM_NRR);
- return;
- }
-
- // NRR Address does not fall on 0x1000 byte boundary
- if (!Common::Is4KBAligned(nrr_address)) {
- LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!",
- nrr_address);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ALIGNMENT);
- return;
- }
-
- // NRR Size is zero or causes overflow
- if (nrr_address + nrr_size <= nrr_address || nrr_size == 0 ||
- !Common::Is4KBAligned(nrr_size)) {
- LOG_ERROR(Service_LDR, "NRR Size is invalid! (nrr_address={:016X}, nrr_size={:016X})",
- nrr_address, nrr_size);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_SIZE);
- return;
- }
-
- // Read NRR data from memory
- std::vector<u8> nrr_data(nrr_size);
- system.ApplicationMemory().ReadBlock(nrr_address, nrr_data.data(), nrr_size);
- NRRHeader header;
- std::memcpy(&header, nrr_data.data(), sizeof(NRRHeader));
-
- if (header.magic != Common::MakeMagic('N', 'R', 'R', '0')) {
- LOG_ERROR(Service_LDR, "NRR did not have magic 'NRR0' (actual {:08X})!", header.magic);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_NRR);
- return;
- }
-
- if (header.size != nrr_size) {
- LOG_ERROR(Service_LDR,
- "NRR header reported size did not match LoadNrr parameter size! "
- "(header_size={:016X}, loadnrr_size={:016X})",
- header.size, nrr_size);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_SIZE);
- return;
- }
-
- if (system.GetApplicationProcessProgramID() != header.application_id) {
- LOG_ERROR(Service_LDR,
- "Attempting to load NRR with title ID other than current process. (actual "
- "{:016X})!",
- header.application_id);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_NRR);
- return;
- }
-
- std::vector<SHA256Hash> hashes;
-
- // Copy all hashes in the NRR (specified by hash count/hash offset) into vector.
- for (std::size_t i = header.hash_offset;
- i < (header.hash_offset + (header.hash_count * sizeof(SHA256Hash))); i += 8) {
- SHA256Hash hash;
- std::memcpy(hash.data(), nrr_data.data() + i, sizeof(SHA256Hash));
- hashes.emplace_back(hash);
- }
-
- nrr.insert_or_assign(nrr_address, std::move(hashes));
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
- void UnregisterModuleInfo(HLERequestContext& ctx) {
- IPC::RequestParser rp{ctx};
- const auto pid = rp.Pop<u64>();
- const auto nrr_address = rp.Pop<VAddr>();
-
- LOG_DEBUG(Service_LDR, "called with pid={}, nrr_address={:016X}", pid, nrr_address);
-
- nrr.erase(nrr_address);
-
- IPC::ResponseBuilder rb{ctx, 2};
-
- rb.Push(ResultSuccess);
- }
-
- bool ValidateRegionForMap(Kernel::KProcessPageTable& page_table, VAddr start,
- std::size_t size) const {
- const std::size_t padding_size{page_table.GetNumGuardPages() * Kernel::PageSize};
-
- Kernel::KMemoryInfo start_info;
- Kernel::Svc::PageInfo page_info;
- R_ASSERT(
- page_table.QueryInfo(std::addressof(start_info), std::addressof(page_info), start - 1));
-
- if (start_info.GetState() != Kernel::KMemoryState::Free) {
- return {};
- }
-
- if (start_info.GetAddress() > (start - padding_size)) {
- return {};
- }
-
- Kernel::KMemoryInfo end_info;
- R_ASSERT(page_table.QueryInfo(std::addressof(end_info), std::addressof(page_info),
- start + size));
-
- if (end_info.GetState() != Kernel::KMemoryState::Free) {
- return {};
- }
-
- return (start + size + padding_size) <= (end_info.GetAddress() + end_info.GetSize());
- }
-
- Result GetAvailableMapRegion(Kernel::KProcessPageTable& page_table, u64 size, VAddr& out_addr) {
- size = Common::AlignUp(size, Kernel::PageSize);
- size += page_table.GetNumGuardPages() * Kernel::PageSize * 4;
-
- const auto is_region_available = [&](VAddr addr) {
- const auto end_addr = addr + size;
- while (addr < end_addr) {
- if (system.ApplicationMemory().IsValidVirtualAddress(addr)) {
- return false;
- }
-
- if (!page_table.Contains(out_addr, size)) {
- return false;
- }
-
- if (page_table.IsInHeapRegion(out_addr, size)) {
- return false;
- }
-
- if (page_table.IsInAliasRegion(out_addr, size)) {
- return false;
- }
-
- addr += Kernel::PageSize;
- }
- return true;
- };
-
- bool succeeded = false;
- const auto map_region_end =
- GetInteger(page_table.GetAliasCodeRegionStart()) + page_table.GetAliasCodeRegionSize();
- while (current_map_addr < map_region_end) {
- if (is_region_available(current_map_addr)) {
- succeeded = true;
- break;
- }
- current_map_addr += 0x100000;
- }
-
- if (!succeeded) {
- ASSERT_MSG(false, "Out of address space!");
- return Kernel::ResultOutOfMemory;
- }
-
- out_addr = current_map_addr;
- current_map_addr += size;
-
- return ResultSuccess;
- }
-
- Result MapProcessCodeMemory(VAddr* out_map_location, Kernel::KProcess* process, VAddr base_addr,
- u64 size) {
- auto& page_table{process->GetPageTable()};
- VAddr addr{};
-
- for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
- R_TRY(GetAvailableMapRegion(page_table, size, addr));
-
- const Result result{page_table.MapCodeMemory(addr, base_addr, size)};
- if (result == Kernel::ResultInvalidCurrentMemory) {
- continue;
- }
-
- R_TRY(result);
-
- if (ValidateRegionForMap(page_table, addr, size)) {
- *out_map_location = addr;
- return ResultSuccess;
- }
- }
-
- return ERROR_INSUFFICIENT_ADDRESS_SPACE;
- }
-
- Result MapNro(VAddr* out_map_location, Kernel::KProcess* process, VAddr nro_addr,
- std::size_t nro_size, VAddr bss_addr, std::size_t bss_size, std::size_t size) {
- for (std::size_t retry = 0; retry < MAXIMUM_MAP_RETRIES; retry++) {
- auto& page_table{process->GetPageTable()};
- VAddr addr{};
-
- R_TRY(MapProcessCodeMemory(&addr, process, nro_addr, nro_size));
-
- if (bss_size) {
- auto block_guard = detail::ScopeExit([&] {
- page_table.UnmapCodeMemory(addr + nro_size, bss_addr, bss_size);
- page_table.UnmapCodeMemory(addr, nro_addr, nro_size);
- });
-
- const Result result{page_table.MapCodeMemory(addr + nro_size, bss_addr, bss_size)};
-
- if (result == Kernel::ResultInvalidCurrentMemory) {
- continue;
- }
-
- if (result.IsError()) {
- return result;
- }
-
- block_guard.Cancel();
- }
-
- if (ValidateRegionForMap(page_table, addr, size)) {
- *out_map_location = addr;
- return ResultSuccess;
- }
- }
-
- return ERROR_INSUFFICIENT_ADDRESS_SPACE;
- }
-
- Result LoadNro(Kernel::KProcess* process, const NROHeader& nro_header, VAddr nro_addr,
- VAddr start) const {
- const VAddr text_start{start + nro_header.segment_headers[TEXT_INDEX].memory_offset};
- const VAddr ro_start{start + nro_header.segment_headers[RO_INDEX].memory_offset};
- const VAddr data_start{start + nro_header.segment_headers[DATA_INDEX].memory_offset};
- const VAddr bss_start{data_start + nro_header.segment_headers[DATA_INDEX].memory_size};
- const VAddr bss_end_addr{
- Common::AlignUp(bss_start + nro_header.bss_size, Kernel::PageSize)};
-
- const auto CopyCode = [this](VAddr src_addr, VAddr dst_addr, u64 size) {
- system.ApplicationMemory().CopyBlock(dst_addr, src_addr, size);
- };
- CopyCode(nro_addr + nro_header.segment_headers[TEXT_INDEX].memory_offset, text_start,
- nro_header.segment_headers[TEXT_INDEX].memory_size);
- CopyCode(nro_addr + nro_header.segment_headers[RO_INDEX].memory_offset, ro_start,
- nro_header.segment_headers[RO_INDEX].memory_size);
- CopyCode(nro_addr + nro_header.segment_headers[DATA_INDEX].memory_offset, data_start,
- nro_header.segment_headers[DATA_INDEX].memory_size);
-
- R_TRY(process->GetPageTable().SetProcessMemoryPermission(
- text_start, ro_start - text_start, Kernel::Svc::MemoryPermission::ReadExecute));
- R_TRY(process->GetPageTable().SetProcessMemoryPermission(
- ro_start, data_start - ro_start, Kernel::Svc::MemoryPermission::Read));
-
- return process->GetPageTable().SetProcessMemoryPermission(
- data_start, bss_end_addr - data_start, Kernel::Svc::MemoryPermission::ReadWrite);
- }
-
- void LoadModule(HLERequestContext& ctx) {
- struct Parameters {
- u64_le process_id;
- u64_le image_address;
- u64_le image_size;
- u64_le bss_address;
- u64_le bss_size;
- };
-
- IPC::RequestParser rp{ctx};
- const auto [process_id, nro_address, nro_size, bss_address, bss_size] =
- rp.PopRaw<Parameters>();
-
- LOG_DEBUG(Service_LDR,
- "called with pid={:016X}, nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, "
- "bss_size={:016X}",
- process_id, nro_address, nro_size, bss_address, bss_size);
-
- if (!initialized) {
- LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- if (nro.size() >= MAXIMUM_LOADED_RO) {
- LOG_ERROR(Service_LDR, "Loading new NRO would exceed the maximum number of loaded NROs "
- "(0x40)! Failing...");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_MAXIMUM_NRO);
- return;
- }
-
- // NRO Address does not fall on 0x1000 byte boundary
- if (!Common::Is4KBAligned(nro_address)) {
- LOG_ERROR(Service_LDR, "NRO Address has invalid alignment (actual {:016X})!",
- nro_address);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ALIGNMENT);
- return;
- }
-
- // NRO Size or BSS Size is zero or causes overflow
- const auto nro_size_valid =
- nro_size != 0 && nro_address + nro_size > nro_address && Common::Is4KBAligned(nro_size);
- const auto bss_size_valid = nro_size + bss_size >= nro_size &&
- (bss_size == 0 || bss_address + bss_size > bss_address);
-
- if (!nro_size_valid || !bss_size_valid) {
- LOG_ERROR(Service_LDR,
- "NRO Size or BSS Size is invalid! (nro_address={:016X}, nro_size={:016X}, "
- "bss_address={:016X}, bss_size={:016X})",
- nro_address, nro_size, bss_address, bss_size);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_SIZE);
- return;
- }
-
- // Read NRO data from memory
- std::vector<u8> nro_data(nro_size);
- system.ApplicationMemory().ReadBlock(nro_address, nro_data.data(), nro_size);
-
- SHA256Hash hash{};
- mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
-
- // NRO Hash is already loaded
- if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
- return info.second.hash == hash;
- })) {
- LOG_ERROR(Service_LDR, "NRO is already loaded!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_ALREADY_LOADED);
- return;
- }
-
- // NRO Hash is not in any loaded NRR
- if (!IsValidNROHash(hash)) {
- LOG_ERROR(Service_LDR,
- "NRO hash is not present in any currently loaded NRRs (hash={})!",
- Common::HexToString(hash));
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_MISSING_NRR_HASH);
- return;
- }
-
- // Load and validate the NRO header
- NROHeader header{};
- std::memcpy(&header, nro_data.data(), sizeof(NROHeader));
- if (!IsValidNRO(header, nro_size, bss_size)) {
- LOG_ERROR(Service_LDR, "NRO was invalid!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_NRO);
- return;
- }
-
- // Map memory for the NRO
- VAddr map_location{};
- const auto map_result{MapNro(&map_location, system.ApplicationProcess(), nro_address,
- nro_size, bss_address, bss_size, nro_size + bss_size)};
- if (map_result != ResultSuccess) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(map_result);
- }
-
- // Load the NRO into the mapped memory
- if (const auto result{
- LoadNro(system.ApplicationProcess(), header, nro_address, map_location)};
- result.IsError()) {
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(result);
- }
-
- // Track the loaded NRO
- nro.insert_or_assign(map_location,
- NROInfo{hash, map_location, nro_size, bss_address, bss_size,
- header.segment_headers[TEXT_INDEX].memory_size,
- header.segment_headers[RO_INDEX].memory_size,
- header.segment_headers[DATA_INDEX].memory_size, nro_address});
-
- IPC::ResponseBuilder rb{ctx, 4};
- rb.Push(ResultSuccess);
- rb.Push(map_location);
- }
-
- Result UnmapNro(const NROInfo& info) {
- // Each region must be unmapped separately to validate memory state
- auto& page_table{system.ApplicationProcess()->GetPageTable()};
-
- if (info.bss_size != 0) {
- R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size +
- info.data_size,
- info.bss_address, info.bss_size));
- }
-
- R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size + info.ro_size,
- info.src_addr + info.text_size + info.ro_size,
- info.data_size));
- R_TRY(page_table.UnmapCodeMemory(info.nro_address + info.text_size,
- info.src_addr + info.text_size, info.ro_size));
- R_TRY(page_table.UnmapCodeMemory(info.nro_address, info.src_addr, info.text_size));
- return ResultSuccess;
- }
-
- void UnloadModule(HLERequestContext& ctx) {
- if (!initialized) {
- LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!");
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_NOT_INITIALIZED);
- return;
- }
-
- struct Parameters {
- u64_le process_id;
- u64_le nro_address;
- };
-
- IPC::RequestParser rp{ctx};
- const auto [process_id, nro_address] = rp.PopRaw<Parameters>();
- LOG_DEBUG(Service_LDR, "called with process_id={:016X}, nro_address=0x{:016X}", process_id,
- nro_address);
-
- if (!Common::Is4KBAligned(nro_address)) {
- LOG_ERROR(Service_LDR, "NRO address has invalid alignment (nro_address=0x{:016X})",
- nro_address);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_ALIGNMENT);
- return;
- }
-
- const auto iter = nro.find(nro_address);
- if (iter == nro.end()) {
- LOG_ERROR(Service_LDR,
- "The NRO attempting to be unmapped was not mapped or has an invalid address "
- "(nro_address=0x{:016X})!",
- nro_address);
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ERROR_INVALID_NRO_ADDRESS);
- return;
- }
-
- const auto result{UnmapNro(iter->second)};
-
- nro.erase(iter);
-
- IPC::ResponseBuilder rb{ctx, 2};
-
- rb.Push(result);
- }
-
- void Initialize(HLERequestContext& ctx) {
- LOG_WARNING(Service_LDR, "(STUBBED) called");
-
- initialized = true;
- current_map_addr =
- GetInteger(system.ApplicationProcess()->GetPageTable().GetAliasCodeRegionStart());
-
- IPC::ResponseBuilder rb{ctx, 2};
- rb.Push(ResultSuccess);
- }
-
-private:
- bool initialized{};
-
- std::map<VAddr, NROInfo> nro;
- std::map<VAddr, std::vector<SHA256Hash>> nrr;
- VAddr current_map_addr{};
-
- bool IsValidNROHash(const SHA256Hash& hash) const {
- return std::any_of(nrr.begin(), nrr.end(), [&hash](const auto& p) {
- return std::find(p.second.begin(), p.second.end(), hash) != p.second.end();
- });
- }
-
- static bool IsValidNRO(const NROHeader& header, u64 nro_size, u64 bss_size) {
- return header.magic == Common::MakeMagic('N', 'R', 'O', '0') &&
- header.nro_size == nro_size && header.bss_size == bss_size &&
-
- header.segment_headers[RO_INDEX].memory_offset ==
- header.segment_headers[TEXT_INDEX].memory_offset +
- header.segment_headers[TEXT_INDEX].memory_size &&
-
- header.segment_headers[DATA_INDEX].memory_offset ==
- header.segment_headers[RO_INDEX].memory_offset +
- header.segment_headers[RO_INDEX].memory_size &&
-
- nro_size == header.segment_headers[DATA_INDEX].memory_offset +
- header.segment_headers[DATA_INDEX].memory_size &&
-
- Common::Is4KBAligned(header.segment_headers[TEXT_INDEX].memory_size) &&
- Common::Is4KBAligned(header.segment_headers[RO_INDEX].memory_size) &&
- Common::Is4KBAligned(header.segment_headers[DATA_INDEX].memory_size);
- }
-};
-
void LoopProcess(Core::System& system) {
auto server_manager = std::make_unique<ServerManager>(system);
server_manager->RegisterNamedService("ldr:dmnt", std::make_shared<DebugMonitor>(system));
server_manager->RegisterNamedService("ldr:pm", std::make_shared<ProcessManager>(system));
server_manager->RegisterNamedService("ldr:shel", std::make_shared<Shell>(system));
- server_manager->RegisterNamedService("ldr:ro", std::make_shared<RelocatableObject>(system));
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
index d7db24f42..75bf31e32 100644
--- a/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
+++ b/src/core/hle/service/nvnflinger/fb_share_buffer_manager.cpp
@@ -171,6 +171,7 @@ void MakeGraphicBuffer(android::BufferQueueProducer& producer, u32 slot, u32 han
buffer->height = SharedBufferHeight;
buffer->stride = SharedBufferBlockLinearStride;
buffer->format = SharedBufferBlockLinearFormat;
+ buffer->external_format = SharedBufferBlockLinearFormat;
buffer->buffer_id = handle;
buffer->offset = slot * SharedBufferSlotSize;
ASSERT(producer.SetPreallocatedBuffer(slot, buffer) == android::Status::NoError);
diff --git a/src/core/hle/service/ro/ro.cpp b/src/core/hle/service/ro/ro.cpp
new file mode 100644
index 000000000..17110d3f1
--- /dev/null
+++ b/src/core/hle/service/ro/ro.cpp
@@ -0,0 +1,709 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include <mbedtls/sha256.h>
+
+#include "common/scope_exit.h"
+#include "core/hle/kernel/k_process.h"
+
+#include "core/hle/service/ipc_helpers.h"
+#include "core/hle/service/ro/ro.h"
+#include "core/hle/service/ro/ro_nro_utils.h"
+#include "core/hle/service/ro/ro_results.h"
+#include "core/hle/service/ro/ro_types.h"
+#include "core/hle/service/server_manager.h"
+#include "core/hle/service/service.h"
+
+namespace Service::RO {
+
+namespace {
+
+// Convenience definitions.
+constexpr size_t MaxSessions = 0x3;
+constexpr size_t MaxNrrInfos = 0x40;
+constexpr size_t MaxNroInfos = 0x40;
+
+constexpr u64 InvalidProcessId = 0xffffffffffffffffULL;
+constexpr u64 InvalidContextId = 0xffffffffffffffffULL;
+
+// Types.
+using Sha256Hash = std::array<u8, 32>;
+
+struct NroInfo {
+ u64 base_address;
+ u64 nro_heap_address;
+ u64 nro_heap_size;
+ u64 bss_heap_address;
+ u64 bss_heap_size;
+ u64 code_size;
+ u64 rw_size;
+ ModuleId module_id;
+};
+
+struct NrrInfo {
+ u64 nrr_heap_address;
+ u64 nrr_heap_size;
+
+ // Verification.
+ std::vector<Sha256Hash> hashes;
+};
+
+struct ProcessContext {
+ constexpr ProcessContext() = default;
+
+ void Initialize(Kernel::KProcess* process, u64 process_id) {
+ ASSERT(!m_in_use);
+
+ m_nro_in_use = {};
+ m_nrr_in_use = {};
+ m_nro_infos = {};
+ m_nrr_infos = {};
+
+ m_process = process;
+ m_process_id = process_id;
+ m_in_use = true;
+
+ if (m_process) {
+ m_process->Open();
+ }
+ }
+
+ void Finalize() {
+ ASSERT(m_in_use);
+
+ if (m_process) {
+ m_process->Close();
+ }
+
+ m_nro_in_use = {};
+ m_nrr_in_use = {};
+ m_nro_infos = {};
+ m_nrr_infos = {};
+
+ m_process = nullptr;
+ m_process_id = InvalidProcessId;
+ m_in_use = false;
+ }
+
+ Kernel::KProcess* GetProcess() const {
+ return m_process;
+ }
+
+ u64 GetProcessId() const {
+ return m_process_id;
+ }
+
+ bool IsFree() const {
+ return !m_in_use;
+ }
+
+ u64 GetProgramId(Kernel::KProcess* other_process) const {
+ // Automatically select a handle, allowing for override.
+ if (other_process) {
+ return other_process->GetProgramId();
+ } else if (m_process) {
+ return m_process->GetProgramId();
+ } else {
+ return 0;
+ }
+ }
+
+ Result GetNrrInfoByAddress(NrrInfo** out, u64 nrr_heap_address) {
+ for (size_t i = 0; i < MaxNrrInfos; i++) {
+ if (m_nrr_in_use[i] && m_nrr_infos[i].nrr_heap_address == nrr_heap_address) {
+ if (out != nullptr) {
+ *out = std::addressof(m_nrr_infos[i]);
+ }
+ R_SUCCEED();
+ }
+ }
+ R_THROW(RO::ResultNotRegistered);
+ }
+
+ Result GetFreeNrrInfo(NrrInfo** out) {
+ for (size_t i = 0; i < MaxNrrInfos; i++) {
+ if (!m_nrr_in_use[i]) {
+ if (out != nullptr) {
+ *out = std::addressof(m_nrr_infos[i]);
+ }
+ R_SUCCEED();
+ }
+ }
+ R_THROW(RO::ResultTooManyNrr);
+ }
+
+ Result GetNroInfoByAddress(NroInfo** out, u64 nro_address) {
+ for (size_t i = 0; i < MaxNroInfos; i++) {
+ if (m_nro_in_use[i] && m_nro_infos[i].base_address == nro_address) {
+ if (out != nullptr) {
+ *out = std::addressof(m_nro_infos[i]);
+ }
+ R_SUCCEED();
+ }
+ }
+ R_THROW(RO::ResultNotLoaded);
+ }
+
+ Result GetNroInfoByModuleId(NroInfo** out, const ModuleId* module_id) {
+ for (size_t i = 0; i < MaxNroInfos; i++) {
+ if (m_nro_in_use[i] && std::memcmp(std::addressof(m_nro_infos[i].module_id), module_id,
+ sizeof(*module_id)) == 0) {
+ if (out != nullptr) {
+ *out = std::addressof(m_nro_infos[i]);
+ }
+ R_SUCCEED();
+ }
+ }
+ R_THROW(RO::ResultNotLoaded);
+ }
+
+ Result GetFreeNroInfo(NroInfo** out) {
+ for (size_t i = 0; i < MaxNroInfos; i++) {
+ if (!m_nro_in_use[i]) {
+ if (out != nullptr) {
+ *out = std::addressof(m_nro_infos[i]);
+ }
+ R_SUCCEED();
+ }
+ }
+ R_THROW(RO::ResultTooManyNro);
+ }
+
+ Result ValidateHasNroHash(u64 base_address, const NroHeader* nro_header) const {
+ // Calculate hash.
+ Sha256Hash hash;
+ {
+ const u64 size = nro_header->GetSize();
+
+ std::vector<u8> nro_data(size);
+ m_process->GetMemory().ReadBlock(base_address, nro_data.data(), size);
+
+ mbedtls_sha256_ret(nro_data.data(), size, hash.data(), 0);
+ }
+
+ for (size_t i = 0; i < MaxNrrInfos; i++) {
+ // Ensure we only check NRRs that are used.
+ if (!m_nrr_in_use[i]) {
+ continue;
+ }
+
+ // Locate the hash within the hash list.
+ const auto hash_it = std::ranges::find(m_nrr_infos[i].hashes, hash);
+ if (hash_it == m_nrr_infos[i].hashes.end()) {
+ continue;
+ }
+
+ // The hash is valid!
+ R_SUCCEED();
+ }
+
+ R_THROW(RO::ResultNotAuthorized);
+ }
+
+ Result ValidateNro(ModuleId* out_module_id, u64* out_rx_size, u64* out_ro_size,
+ u64* out_rw_size, u64 base_address, u64 expected_nro_size,
+ u64 expected_bss_size) {
+ // Ensure we have a process to work on.
+ R_UNLESS(m_process != nullptr, RO::ResultInvalidProcess);
+
+ // Read the NRO header.
+ NroHeader header{};
+ m_process->GetMemory().ReadBlock(base_address, std::addressof(header), sizeof(header));
+
+ // Validate header.
+ R_UNLESS(header.IsMagicValid(), RO::ResultInvalidNro);
+
+ // Read sizes from header.
+ const u64 nro_size = header.GetSize();
+ const u64 text_ofs = header.GetTextOffset();
+ const u64 text_size = header.GetTextSize();
+ const u64 ro_ofs = header.GetRoOffset();
+ const u64 ro_size = header.GetRoSize();
+ const u64 rw_ofs = header.GetRwOffset();
+ const u64 rw_size = header.GetRwSize();
+ const u64 bss_size = header.GetBssSize();
+
+ // Validate sizes meet expected.
+ R_UNLESS(nro_size == expected_nro_size, RO::ResultInvalidNro);
+ R_UNLESS(bss_size == expected_bss_size, RO::ResultInvalidNro);
+
+ // Validate all sizes are aligned.
+ R_UNLESS(Common::IsAligned(text_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
+ R_UNLESS(Common::IsAligned(ro_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
+ R_UNLESS(Common::IsAligned(rw_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
+ R_UNLESS(Common::IsAligned(bss_size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidNro);
+
+ // Validate sections are in order.
+ R_UNLESS(text_ofs <= ro_ofs, RO::ResultInvalidNro);
+ R_UNLESS(ro_ofs <= rw_ofs, RO::ResultInvalidNro);
+
+ // Validate sections are sequential and contiguous.
+ R_UNLESS(text_ofs == 0, RO::ResultInvalidNro);
+ R_UNLESS(text_ofs + text_size == ro_ofs, RO::ResultInvalidNro);
+ R_UNLESS(ro_ofs + ro_size == rw_ofs, RO::ResultInvalidNro);
+ R_UNLESS(rw_ofs + rw_size == nro_size, RO::ResultInvalidNro);
+
+ // Verify NRO hash.
+ R_TRY(this->ValidateHasNroHash(base_address, std::addressof(header)));
+
+ // Check if NRO has already been loaded.
+ const ModuleId* module_id = header.GetModuleId();
+ R_UNLESS(R_FAILED(this->GetNroInfoByModuleId(nullptr, module_id)), RO::ResultAlreadyLoaded);
+
+ // Apply patches to NRO.
+ // LocateAndApplyIpsPatchesToModule(module_id, static_cast<u8*>(mapped_memory), nro_size);
+
+ // Copy to output.
+ *out_module_id = *module_id;
+ *out_rx_size = text_size;
+ *out_ro_size = ro_size;
+ *out_rw_size = rw_size;
+ R_SUCCEED();
+ }
+
+ void SetNrrInfoInUse(const NrrInfo* info, bool in_use) {
+ ASSERT(std::addressof(m_nrr_infos[0]) <= info &&
+ info <= std::addressof(m_nrr_infos[MaxNrrInfos - 1]));
+ const size_t index = info - std::addressof(m_nrr_infos[0]);
+ m_nrr_in_use[index] = in_use;
+ }
+
+ void SetNroInfoInUse(const NroInfo* info, bool in_use) {
+ ASSERT(std::addressof(m_nro_infos[0]) <= info &&
+ info <= std::addressof(m_nro_infos[MaxNroInfos - 1]));
+ const size_t index = info - std::addressof(m_nro_infos[0]);
+ m_nro_in_use[index] = in_use;
+ }
+
+private:
+ std::array<bool, MaxNroInfos> m_nro_in_use{};
+ std::array<bool, MaxNrrInfos> m_nrr_in_use{};
+ std::array<NroInfo, MaxNroInfos> m_nro_infos{};
+ std::array<NrrInfo, MaxNrrInfos> m_nrr_infos{};
+ Kernel::KProcess* m_process{};
+ u64 m_process_id{InvalidProcessId};
+ bool m_in_use{};
+};
+
+Result ValidateAddressAndNonZeroSize(u64 address, u64 size) {
+ R_UNLESS(Common::IsAligned(address, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidAddress);
+ R_UNLESS(size != 0, RO::ResultInvalidSize);
+ R_UNLESS(Common::IsAligned(size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidSize);
+ R_UNLESS(address < address + size, RO::ResultInvalidSize);
+ R_SUCCEED();
+}
+
+Result ValidateAddressAndSize(u64 address, u64 size) {
+ R_UNLESS(Common::IsAligned(address, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidAddress);
+ R_UNLESS(Common::IsAligned(size, Core::Memory::YUZU_PAGESIZE), RO::ResultInvalidSize);
+ R_UNLESS(size == 0 || address < address + size, RO::ResultInvalidSize);
+ R_SUCCEED();
+}
+
+class RoContext {
+public:
+ explicit RoContext() = default;
+
+ Result RegisterProcess(size_t* out_context_id, Kernel::KProcess* process, u64 process_id) {
+ // Validate process id.
+ R_UNLESS(process->GetProcessId() == process_id, RO::ResultInvalidProcess);
+
+ // Check if a process context already exists.
+ R_UNLESS(this->GetContextByProcessId(process_id) == nullptr, RO::ResultInvalidSession);
+
+ // Allocate a context to manage the process handle.
+ *out_context_id = this->AllocateContext(process, process_id);
+
+ R_SUCCEED();
+ }
+
+ Result ValidateProcess(size_t context_id, u64 process_id) {
+ const ProcessContext* ctx = this->GetContextById(context_id);
+ R_UNLESS(ctx != nullptr, RO::ResultInvalidProcess);
+ R_UNLESS(ctx->GetProcessId() == process_id, RO::ResultInvalidProcess);
+ R_SUCCEED();
+ }
+
+ void UnregisterProcess(size_t context_id) {
+ this->FreeContext(context_id);
+ }
+
+ Result RegisterModuleInfo(size_t context_id, u64 nrr_address, u64 nrr_size, NrrKind nrr_kind,
+ bool enforce_nrr_kind) {
+ // Get context.
+ ProcessContext* context = this->GetContextById(context_id);
+ ASSERT(context != nullptr);
+
+ // Validate address/size.
+ R_TRY(ValidateAddressAndNonZeroSize(nrr_address, nrr_size));
+
+ // Check we have space for a new NRR.
+ NrrInfo* nrr_info = nullptr;
+ R_TRY(context->GetFreeNrrInfo(std::addressof(nrr_info)));
+
+ // Ensure we have a valid process to read from.
+ Kernel::KProcess* process = context->GetProcess();
+ R_UNLESS(process != nullptr, RO::ResultInvalidProcess);
+
+ // Read NRR.
+ NrrHeader header{};
+ process->GetMemory().ReadBlock(nrr_address, std::addressof(header), sizeof(header));
+
+ // Set NRR info.
+ context->SetNrrInfoInUse(nrr_info, true);
+ nrr_info->nrr_heap_address = nrr_address;
+ nrr_info->nrr_heap_size = nrr_size;
+
+ // Read NRR hash list.
+ nrr_info->hashes.resize(header.GetNumHashes());
+ process->GetMemory().ReadBlock(nrr_address + header.GetHashesOffset(),
+ nrr_info->hashes.data(),
+ sizeof(Sha256Hash) * header.GetNumHashes());
+
+ R_SUCCEED();
+ }
+
+ Result UnregisterModuleInfo(size_t context_id, u64 nrr_address) {
+ // Get context.
+ ProcessContext* context = this->GetContextById(context_id);
+ ASSERT(context != nullptr);
+
+ // Validate address.
+ R_UNLESS(Common::IsAligned(nrr_address, Core::Memory::YUZU_PAGESIZE),
+ RO::ResultInvalidAddress);
+
+ // Check the NRR is loaded.
+ NrrInfo* nrr_info = nullptr;
+ R_TRY(context->GetNrrInfoByAddress(std::addressof(nrr_info), nrr_address));
+
+ // Nintendo does this unconditionally, whether or not the actual unmap succeeds.
+ context->SetNrrInfoInUse(nrr_info, false);
+ *nrr_info = {};
+
+ R_SUCCEED();
+ }
+
+ Result MapManualLoadModuleMemory(u64* out_address, size_t context_id, u64 nro_address,
+ u64 nro_size, u64 bss_address, u64 bss_size) {
+ // Get context.
+ ProcessContext* context = this->GetContextById(context_id);
+ ASSERT(context != nullptr);
+
+ // Validate address/size.
+ R_TRY(ValidateAddressAndNonZeroSize(nro_address, nro_size));
+ R_TRY(ValidateAddressAndSize(bss_address, bss_size));
+
+ const u64 total_size = nro_size + bss_size;
+ R_UNLESS(total_size >= nro_size, RO::ResultInvalidSize);
+ R_UNLESS(total_size >= bss_size, RO::ResultInvalidSize);
+
+ // Check we have space for a new NRO.
+ NroInfo* nro_info = nullptr;
+ R_TRY(context->GetFreeNroInfo(std::addressof(nro_info)));
+ nro_info->nro_heap_address = nro_address;
+ nro_info->nro_heap_size = nro_size;
+ nro_info->bss_heap_address = bss_address;
+ nro_info->bss_heap_size = bss_size;
+
+ // Map the NRO.
+ R_TRY(MapNro(std::addressof(nro_info->base_address), context->GetProcess(), nro_address,
+ nro_size, bss_address, bss_size, generate_random));
+ ON_RESULT_FAILURE {
+ UnmapNro(context->GetProcess(), nro_info->base_address, nro_address, nro_size,
+ bss_address, bss_size);
+ };
+
+ // Validate the NRO (parsing region extents).
+ u64 rx_size = 0, ro_size = 0, rw_size = 0;
+ R_TRY(context->ValidateNro(std::addressof(nro_info->module_id), std::addressof(rx_size),
+ std::addressof(ro_size), std::addressof(rw_size),
+ nro_info->base_address, nro_size, bss_size));
+
+ // Set NRO perms.
+ R_TRY(SetNroPerms(context->GetProcess(), nro_info->base_address, rx_size, ro_size,
+ rw_size + bss_size));
+
+ context->SetNroInfoInUse(nro_info, true);
+ nro_info->code_size = rx_size + ro_size;
+ nro_info->rw_size = rw_size;
+ *out_address = nro_info->base_address;
+ R_SUCCEED();
+ }
+
+ Result UnmapManualLoadModuleMemory(size_t context_id, u64 nro_address) {
+ // Get context.
+ ProcessContext* context = this->GetContextById(context_id);
+ ASSERT(context != nullptr);
+
+ // Validate address.
+ R_UNLESS(Common::IsAligned(nro_address, Core::Memory::YUZU_PAGESIZE),
+ RO::ResultInvalidAddress);
+
+ // Check the NRO is loaded.
+ NroInfo* nro_info = nullptr;
+ R_TRY(context->GetNroInfoByAddress(std::addressof(nro_info), nro_address));
+
+ // Unmap.
+ const NroInfo nro_backup = *nro_info;
+ {
+ // Nintendo does this unconditionally, whether or not the actual unmap succeeds.
+ context->SetNroInfoInUse(nro_info, false);
+ std::memset(nro_info, 0, sizeof(*nro_info));
+ }
+ R_RETURN(UnmapNro(context->GetProcess(), nro_backup.base_address,
+ nro_backup.nro_heap_address, nro_backup.code_size + nro_backup.rw_size,
+ nro_backup.bss_heap_address, nro_backup.bss_heap_size));
+ }
+
+private:
+ std::array<ProcessContext, MaxSessions> process_contexts;
+ std::mt19937_64 generate_random;
+
+ // Context Helpers.
+ ProcessContext* GetContextById(size_t context_id) {
+ if (context_id == InvalidContextId) {
+ return nullptr;
+ }
+
+ ASSERT(context_id < process_contexts.size());
+ return std::addressof(process_contexts[context_id]);
+ }
+
+ ProcessContext* GetContextByProcessId(u64 process_id) {
+ for (size_t i = 0; i < MaxSessions; i++) {
+ if (process_contexts[i].GetProcessId() == process_id) {
+ return std::addressof(process_contexts[i]);
+ }
+ }
+ return nullptr;
+ }
+
+ size_t AllocateContext(Kernel::KProcess* process, u64 process_id) {
+ // Find a free process context.
+ for (size_t i = 0; i < MaxSessions; i++) {
+ ProcessContext* context = std::addressof(process_contexts[i]);
+
+ if (context->IsFree()) {
+ context->Initialize(process, process_id);
+ return i;
+ }
+ }
+
+ // Failure to find a free context is actually an abort condition.
+ UNREACHABLE();
+ }
+
+ void FreeContext(size_t context_id) {
+ if (ProcessContext* context = GetContextById(context_id); context != nullptr) {
+ context->Finalize();
+ }
+ }
+};
+
+class RoInterface {
+public:
+ explicit RoInterface(std::shared_ptr<RoContext> ro, NrrKind nrr_kind)
+ : m_ro(ro), m_context_id(InvalidContextId), m_nrr_kind(nrr_kind) {}
+ ~RoInterface() {
+ m_ro->UnregisterProcess(m_context_id);
+ }
+
+ Result MapManualLoadModuleMemory(u64* out_load_address, u64 client_pid, u64 nro_address,
+ u64 nro_size, u64 bss_address, u64 bss_size) {
+ R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
+ R_RETURN(m_ro->MapManualLoadModuleMemory(out_load_address, m_context_id, nro_address,
+ nro_size, bss_address, bss_size));
+ }
+
+ Result UnmapManualLoadModuleMemory(u64 client_pid, u64 nro_address) {
+ R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
+ R_RETURN(m_ro->UnmapManualLoadModuleMemory(m_context_id, nro_address));
+ }
+
+ Result RegisterModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size) {
+ R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
+ R_RETURN(
+ m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, NrrKind::User, true));
+ }
+
+ Result UnregisterModuleInfo(u64 client_pid, u64 nrr_address) {
+ R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
+ R_RETURN(m_ro->UnregisterModuleInfo(m_context_id, nrr_address));
+ }
+
+ Result RegisterProcessHandle(u64 client_pid, Kernel::KProcess* process) {
+ // Register the process.
+ R_RETURN(m_ro->RegisterProcess(std::addressof(m_context_id), process, client_pid));
+ }
+
+ Result RegisterProcessModuleInfo(u64 client_pid, u64 nrr_address, u64 nrr_size,
+ Kernel::KProcess* process) {
+ // Validate the process.
+ R_TRY(m_ro->ValidateProcess(m_context_id, client_pid));
+
+ // Register the module.
+ R_RETURN(m_ro->RegisterModuleInfo(m_context_id, nrr_address, nrr_size, m_nrr_kind,
+ m_nrr_kind == NrrKind::JitPlugin));
+ }
+
+private:
+ std::shared_ptr<RoContext> m_ro{};
+ size_t m_context_id{};
+ NrrKind m_nrr_kind{};
+};
+
+class IRoInterface : public ServiceFramework<IRoInterface> {
+public:
+ explicit IRoInterface(Core::System& system_, const char* name_, std::shared_ptr<RoContext> ro,
+ NrrKind nrr_kind)
+ : ServiceFramework{system_, name_}, interface {
+ ro, nrr_kind
+ } {
+ // clang-format off
+ static const FunctionInfo functions[] = {
+ {0, &IRoInterface::MapManualLoadModuleMemory, "MapManualLoadModuleMemory"},
+ {1, &IRoInterface::UnmapManualLoadModuleMemory, "UnmapManualLoadModuleMemory"},
+ {2, &IRoInterface::RegisterModuleInfo, "RegisterModuleInfo"},
+ {3, &IRoInterface::UnregisterModuleInfo, "UnregisterModuleInfo"},
+ {4, &IRoInterface::RegisterProcessHandle, "RegisterProcessHandle"},
+ {10, &IRoInterface::RegisterProcessModuleInfo, "RegisterProcessModuleInfo"},
+ };
+ // clang-format on
+
+ RegisterHandlers(functions);
+ }
+
+private:
+ void MapManualLoadModuleMemory(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDR, "(called)");
+
+ struct InputParameters {
+ u64 client_pid;
+ u64 nro_address;
+ u64 nro_size;
+ u64 bss_address;
+ u64 bss_size;
+ };
+
+ IPC::RequestParser rp{ctx};
+ auto params = rp.PopRaw<InputParameters>();
+
+ u64 load_address = 0;
+ auto result = interface.MapManualLoadModuleMemory(&load_address, ctx.GetPID(),
+ params.nro_address, params.nro_size,
+ params.bss_address, params.bss_size);
+
+ IPC::ResponseBuilder rb{ctx, 4};
+ rb.Push(result);
+ rb.Push(load_address);
+ }
+
+ void UnmapManualLoadModuleMemory(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDR, "(called)");
+
+ struct InputParameters {
+ u64 client_pid;
+ u64 nro_address;
+ };
+
+ IPC::RequestParser rp{ctx};
+ auto params = rp.PopRaw<InputParameters>();
+ auto result = interface.UnmapManualLoadModuleMemory(ctx.GetPID(), params.nro_address);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
+ void RegisterModuleInfo(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDR, "(called)");
+
+ struct InputParameters {
+ u64 client_pid;
+ u64 nrr_address;
+ u64 nrr_size;
+ };
+
+ IPC::RequestParser rp{ctx};
+ auto params = rp.PopRaw<InputParameters>();
+ auto result =
+ interface.RegisterModuleInfo(ctx.GetPID(), params.nrr_address, params.nrr_size);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
+ void UnregisterModuleInfo(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDR, "(called)");
+
+ struct InputParameters {
+ u64 client_pid;
+ u64 nrr_address;
+ };
+
+ IPC::RequestParser rp{ctx};
+ auto params = rp.PopRaw<InputParameters>();
+ auto result = interface.UnregisterModuleInfo(ctx.GetPID(), params.nrr_address);
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
+ void RegisterProcessHandle(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDR, "(called)");
+
+ auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
+ auto client_pid = ctx.GetPID();
+ auto result = interface.RegisterProcessHandle(client_pid,
+ process_h->DynamicCast<Kernel::KProcess*>());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
+ void RegisterProcessModuleInfo(HLERequestContext& ctx) {
+ LOG_DEBUG(Service_LDR, "(called)");
+
+ struct InputParameters {
+ u64 client_pid;
+ u64 nrr_address;
+ u64 nrr_size;
+ };
+
+ IPC::RequestParser rp{ctx};
+ auto params = rp.PopRaw<InputParameters>();
+ auto process_h = ctx.GetClientHandleTable().GetObject(ctx.GetCopyHandle(0));
+
+ auto client_pid = ctx.GetPID();
+ auto result =
+ interface.RegisterProcessModuleInfo(client_pid, params.nrr_address, params.nrr_size,
+ process_h->DynamicCast<Kernel::KProcess*>());
+
+ IPC::ResponseBuilder rb{ctx, 2};
+ rb.Push(result);
+ }
+
+ RoInterface interface;
+};
+
+} // namespace
+
+void LoopProcess(Core::System& system) {
+ auto server_manager = std::make_unique<ServerManager>(system);
+
+ auto ro = std::make_shared<RoContext>();
+
+ const auto RoInterfaceFactoryForUser = [&, ro] {
+ return std::make_shared<IRoInterface>(system, "ldr:ro", ro, NrrKind::User);
+ };
+
+ const auto RoInterfaceFactoryForJitPlugin = [&, ro] {
+ return std::make_shared<IRoInterface>(system, "ro:1", ro, NrrKind::JitPlugin);
+ };
+
+ server_manager->RegisterNamedService("ldr:ro", std::move(RoInterfaceFactoryForUser));
+ server_manager->RegisterNamedService("ro:1", std::move(RoInterfaceFactoryForJitPlugin));
+
+ ServerManager::RunServer(std::move(server_manager));
+}
+
+} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro.h b/src/core/hle/service/ro/ro.h
new file mode 100644
index 000000000..74dc08536
--- /dev/null
+++ b/src/core/hle/service/ro/ro.h
@@ -0,0 +1,14 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+namespace Core {
+class System;
+}
+
+namespace Service::RO {
+
+void LoopProcess(Core::System& system);
+
+} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_nro_utils.cpp b/src/core/hle/service/ro/ro_nro_utils.cpp
new file mode 100644
index 000000000..268c7f93e
--- /dev/null
+++ b/src/core/hle/service/ro/ro_nro_utils.cpp
@@ -0,0 +1,185 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/kernel/k_process.h"
+#include "core/hle/service/ro/ro_nro_utils.h"
+#include "core/hle/service/ro/ro_results.h"
+
+namespace Service::RO {
+
+namespace {
+
+struct ProcessMemoryRegion {
+ u64 address;
+ u64 size;
+};
+
+size_t GetTotalProcessMemoryRegionSize(const ProcessMemoryRegion* regions, size_t num_regions) {
+ size_t total = 0;
+
+ for (size_t i = 0; i < num_regions; ++i) {
+ total += regions[i].size;
+ }
+
+ return total;
+}
+
+size_t SetupNroProcessMemoryRegions(ProcessMemoryRegion* regions, u64 nro_heap_address,
+ u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) {
+ // Reset region count.
+ size_t num_regions = 0;
+
+ // We always want a region for the nro.
+ regions[num_regions++] = {nro_heap_address, nro_heap_size};
+
+ // If we have bss, create a region for bss.
+ if (bss_heap_size > 0) {
+ regions[num_regions++] = {bss_heap_address, bss_heap_size};
+ }
+
+ return num_regions;
+}
+
+Result SetProcessMemoryPermission(Kernel::KProcess* process, u64 address, u64 size,
+ Kernel::Svc::MemoryPermission permission) {
+ auto& page_table = process->GetPageTable();
+
+ // Set permission.
+ R_RETURN(page_table.SetProcessMemoryPermission(address, size, permission));
+}
+
+Result UnmapProcessCodeMemory(Kernel::KProcess* process, u64 process_code_address,
+ const ProcessMemoryRegion* regions, size_t num_regions) {
+ // Get the total process memory region size.
+ const size_t total_size = GetTotalProcessMemoryRegionSize(regions, num_regions);
+
+ auto& page_table = process->GetPageTable();
+
+ // Unmap each region in order.
+ size_t cur_offset = total_size;
+ for (size_t i = 0; i < num_regions; ++i) {
+ // We want to unmap in reverse order.
+ const auto& cur_region = regions[num_regions - 1 - i];
+
+ // Subtract to update the current offset.
+ cur_offset -= cur_region.size;
+
+ // Unmap.
+ R_TRY(page_table.UnmapCodeMemory(process_code_address + cur_offset, cur_region.address,
+ cur_region.size));
+ }
+
+ R_SUCCEED();
+}
+
+Result EnsureGuardPages(Kernel::KProcessPageTable& page_table, u64 map_address, u64 map_size) {
+ Kernel::KMemoryInfo memory_info;
+ Kernel::Svc::PageInfo page_info;
+
+ // Ensure page before mapping is unmapped.
+ R_TRY(page_table.QueryInfo(std::addressof(memory_info), std::addressof(page_info),
+ map_address - 1));
+ R_UNLESS(memory_info.GetSvcState() == Kernel::Svc::MemoryState::Free,
+ Kernel::ResultInvalidState);
+
+ // Ensure page after mapping is unmapped.
+ R_TRY(page_table.QueryInfo(std::addressof(memory_info), std::addressof(page_info),
+ map_address + map_size));
+ R_UNLESS(memory_info.GetSvcState() == Kernel::Svc::MemoryState::Free,
+ Kernel::ResultInvalidState);
+
+ // Successfully verified guard pages.
+ R_SUCCEED();
+}
+
+Result MapProcessCodeMemory(u64* out, Kernel::KProcess* process, const ProcessMemoryRegion* regions,
+ size_t num_regions, std::mt19937_64& generate_random) {
+ auto& page_table = process->GetPageTable();
+ const u64 alias_code_start =
+ GetInteger(page_table.GetAliasCodeRegionStart()) / Kernel::PageSize;
+ const u64 alias_code_size = page_table.GetAliasCodeRegionSize() / Kernel::PageSize;
+
+ for (size_t trial = 0; trial < 64; trial++) {
+ // Generate a new trial address.
+ const u64 mapped_address =
+ (alias_code_start + (generate_random() % alias_code_size)) * Kernel::PageSize;
+
+ const auto MapRegions = [&] {
+ // Map the regions in order.
+ u64 mapped_size = 0;
+ for (size_t i = 0; i < num_regions; ++i) {
+ // If we fail, unmap up to where we've mapped.
+ ON_RESULT_FAILURE {
+ R_ASSERT(UnmapProcessCodeMemory(process, mapped_address, regions, i));
+ };
+
+ // Map the current region.
+ R_TRY(page_table.MapCodeMemory(mapped_address + mapped_size, regions[i].address,
+ regions[i].size));
+
+ mapped_size += regions[i].size;
+ }
+
+ // If we fail, unmap all mapped regions.
+ ON_RESULT_FAILURE {
+ R_ASSERT(UnmapProcessCodeMemory(process, mapped_address, regions, num_regions));
+ };
+
+ // Ensure guard pages.
+ R_RETURN(EnsureGuardPages(page_table, mapped_address, mapped_size));
+ };
+
+ if (R_SUCCEEDED(MapRegions())) {
+ // Set the output address.
+ *out = mapped_address;
+ R_SUCCEED();
+ }
+ }
+
+ // We failed to map anything.
+ R_THROW(RO::ResultOutOfAddressSpace);
+}
+
+} // namespace
+
+Result MapNro(u64* out_base_address, Kernel::KProcess* process, u64 nro_heap_address,
+ u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size,
+ std::mt19937_64& generate_random) {
+ // Set up the process memory regions.
+ std::array<ProcessMemoryRegion, 2> regions{};
+ const size_t num_regions = SetupNroProcessMemoryRegions(
+ regions.data(), nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size);
+
+ // Re-map the nro/bss as code memory in the destination process.
+ R_RETURN(MapProcessCodeMemory(out_base_address, process, regions.data(), num_regions,
+ generate_random));
+}
+
+Result SetNroPerms(Kernel::KProcess* process, u64 base_address, u64 rx_size, u64 ro_size,
+ u64 rw_size) {
+ const u64 rx_offset = 0;
+ const u64 ro_offset = rx_offset + rx_size;
+ const u64 rw_offset = ro_offset + ro_size;
+
+ R_TRY(SetProcessMemoryPermission(process, base_address + rx_offset, rx_size,
+ Kernel::Svc::MemoryPermission::ReadExecute));
+ R_TRY(SetProcessMemoryPermission(process, base_address + ro_offset, ro_size,
+ Kernel::Svc::MemoryPermission::Read));
+ R_TRY(SetProcessMemoryPermission(process, base_address + rw_offset, rw_size,
+ Kernel::Svc::MemoryPermission::ReadWrite));
+
+ R_SUCCEED();
+}
+
+Result UnmapNro(Kernel::KProcess* process, u64 base_address, u64 nro_heap_address,
+ u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size) {
+ // Set up the process memory regions.
+ std::array<ProcessMemoryRegion, 2> regions{};
+ const size_t num_regions = SetupNroProcessMemoryRegions(
+ regions.data(), nro_heap_address, nro_heap_size, bss_heap_address, bss_heap_size);
+
+ // Unmap the nro/bss.
+ R_RETURN(UnmapProcessCodeMemory(process, base_address, regions.data(), num_regions));
+}
+
+} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_nro_utils.h b/src/core/hle/service/ro/ro_nro_utils.h
new file mode 100644
index 000000000..f7083a1ba
--- /dev/null
+++ b/src/core/hle/service/ro/ro_nro_utils.h
@@ -0,0 +1,26 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#pragma once
+
+#include <random>
+
+#include "common/common_types.h"
+
+namespace Kernel {
+class KProcess;
+}
+
+union Result;
+
+namespace Service::RO {
+
+Result MapNro(u64* out_base_address, Kernel::KProcess* process, u64 nro_heap_address,
+ u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size,
+ std::mt19937_64& generate_random);
+Result SetNroPerms(Kernel::KProcess* process, u64 base_address, u64 rx_size, u64 ro_size,
+ u64 rw_size);
+Result UnmapNro(Kernel::KProcess* process, u64 base_address, u64 nro_heap_address,
+ u64 nro_heap_size, u64 bss_heap_address, u64 bss_heap_size);
+
+} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_results.h b/src/core/hle/service/ro/ro_results.h
new file mode 100644
index 000000000..00f05c5a5
--- /dev/null
+++ b/src/core/hle/service/ro/ro_results.h
@@ -0,0 +1,24 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "core/hle/result.h"
+
+namespace Service::RO {
+
+constexpr Result ResultOutOfAddressSpace{ErrorModule::RO, 2};
+constexpr Result ResultAlreadyLoaded{ErrorModule::RO, 3};
+constexpr Result ResultInvalidNro{ErrorModule::RO, 4};
+constexpr Result ResultInvalidNrr{ErrorModule::RO, 6};
+constexpr Result ResultTooManyNro{ErrorModule::RO, 7};
+constexpr Result ResultTooManyNrr{ErrorModule::RO, 8};
+constexpr Result ResultNotAuthorized{ErrorModule::RO, 9};
+constexpr Result ResultInvalidNrrKind{ErrorModule::RO, 10};
+constexpr Result ResultInternalError{ErrorModule::RO, 1023};
+constexpr Result ResultInvalidAddress{ErrorModule::RO, 1025};
+constexpr Result ResultInvalidSize{ErrorModule::RO, 1026};
+constexpr Result ResultNotLoaded{ErrorModule::RO, 1028};
+constexpr Result ResultNotRegistered{ErrorModule::RO, 1029};
+constexpr Result ResultInvalidSession{ErrorModule::RO, 1030};
+constexpr Result ResultInvalidProcess{ErrorModule::RO, 1031};
+
+} // namespace Service::RO
diff --git a/src/core/hle/service/ro/ro_types.h b/src/core/hle/service/ro/ro_types.h
new file mode 100644
index 000000000..624d52ee5
--- /dev/null
+++ b/src/core/hle/service/ro/ro_types.h
@@ -0,0 +1,181 @@
+// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "common/assert.h"
+#include "common/common_funcs.h"
+#include "common/common_types.h"
+
+namespace Service::RO {
+
+enum class NrrKind : u8 {
+ User = 0,
+ JitPlugin = 1,
+ Count,
+};
+
+static constexpr size_t ModuleIdSize = 0x20;
+struct ModuleId {
+ std::array<u8, ModuleIdSize> data;
+};
+static_assert(sizeof(ModuleId) == ModuleIdSize);
+
+struct NrrCertification {
+ static constexpr size_t RsaKeySize = 0x100;
+ static constexpr size_t SignedSize = 0x120;
+
+ u64 program_id_mask;
+ u64 program_id_pattern;
+ std::array<u8, 0x10> reserved_10;
+ std::array<u8, RsaKeySize> modulus;
+ std::array<u8, RsaKeySize> signature;
+};
+static_assert(sizeof(NrrCertification) ==
+ NrrCertification::RsaKeySize + NrrCertification::SignedSize);
+
+class NrrHeader {
+public:
+ static constexpr u32 Magic = Common::MakeMagic('N', 'R', 'R', '0');
+
+public:
+ bool IsMagicValid() const {
+ return m_magic == Magic;
+ }
+
+ bool IsProgramIdValid() const {
+ return (m_program_id & m_certification.program_id_mask) ==
+ m_certification.program_id_pattern;
+ }
+
+ NrrKind GetNrrKind() const {
+ const NrrKind kind = static_cast<NrrKind>(m_nrr_kind);
+ ASSERT(kind < NrrKind::Count);
+ return kind;
+ }
+
+ u64 GetProgramId() const {
+ return m_program_id;
+ }
+
+ u32 GetSize() const {
+ return m_size;
+ }
+
+ u32 GetNumHashes() const {
+ return m_num_hashes;
+ }
+
+ size_t GetHashesOffset() const {
+ return m_hashes_offset;
+ }
+
+ u32 GetKeyGeneration() const {
+ return m_key_generation;
+ }
+
+ const u8* GetCertificationSignature() const {
+ return m_certification.signature.data();
+ }
+
+ const u8* GetCertificationSignedArea() const {
+ return reinterpret_cast<const u8*>(std::addressof(m_certification));
+ }
+
+ const u8* GetCertificationModulus() const {
+ return m_certification.modulus.data();
+ }
+
+ const u8* GetSignature() const {
+ return m_signature.data();
+ }
+
+ size_t GetSignedAreaSize() const {
+ return m_size - GetSignedAreaOffset();
+ }
+
+ static constexpr size_t GetSignedAreaOffset() {
+ return offsetof(NrrHeader, m_program_id);
+ }
+
+private:
+ u32 m_magic;
+ u32 m_key_generation;
+ INSERT_PADDING_BYTES_NOINIT(8);
+ NrrCertification m_certification;
+ std::array<u8, 0x100> m_signature;
+ u64 m_program_id;
+ u32 m_size;
+ u8 m_nrr_kind; // 7.0.0+
+ INSERT_PADDING_BYTES_NOINIT(3);
+ u32 m_hashes_offset;
+ u32 m_num_hashes;
+ INSERT_PADDING_BYTES_NOINIT(8);
+};
+static_assert(sizeof(NrrHeader) == 0x350, "NrrHeader has wrong size");
+
+class NroHeader {
+public:
+ static constexpr u32 Magic = Common::MakeMagic('N', 'R', 'O', '0');
+
+public:
+ bool IsMagicValid() const {
+ return m_magic == Magic;
+ }
+
+ u32 GetSize() const {
+ return m_size;
+ }
+
+ u32 GetTextOffset() const {
+ return m_text_offset;
+ }
+
+ u32 GetTextSize() const {
+ return m_text_size;
+ }
+
+ u32 GetRoOffset() const {
+ return m_ro_offset;
+ }
+
+ u32 GetRoSize() const {
+ return m_ro_size;
+ }
+
+ u32 GetRwOffset() const {
+ return m_rw_offset;
+ }
+
+ u32 GetRwSize() const {
+ return m_rw_size;
+ }
+
+ u32 GetBssSize() const {
+ return m_bss_size;
+ }
+
+ const ModuleId* GetModuleId() const {
+ return std::addressof(m_module_id);
+ }
+
+private:
+ u32 m_entrypoint_insn;
+ u32 m_mod_offset;
+ INSERT_PADDING_BYTES_NOINIT(0x8);
+ u32 m_magic;
+ INSERT_PADDING_BYTES_NOINIT(0x4);
+ u32 m_size;
+ INSERT_PADDING_BYTES_NOINIT(0x4);
+ u32 m_text_offset;
+ u32 m_text_size;
+ u32 m_ro_offset;
+ u32 m_ro_size;
+ u32 m_rw_offset;
+ u32 m_rw_size;
+ u32 m_bss_size;
+ INSERT_PADDING_BYTES_NOINIT(0x4);
+ ModuleId m_module_id;
+ INSERT_PADDING_BYTES_NOINIT(0x20);
+};
+static_assert(sizeof(NroHeader) == 0x80, "NroHeader has wrong size");
+
+} // namespace Service::RO
diff --git a/src/core/hle/service/server_manager.cpp b/src/core/hle/service/server_manager.cpp
index e2e399534..6808247a9 100644
--- a/src/core/hle/service/server_manager.cpp
+++ b/src/core/hle/service/server_manager.cpp
@@ -93,13 +93,13 @@ Result ServerManager::RegisterSession(Kernel::KServerSession* session,
}
Result ServerManager::RegisterNamedService(const std::string& service_name,
- std::shared_ptr<SessionRequestHandler>&& handler,
+ SessionRequestHandlerFactory&& handler_factory,
u32 max_sessions) {
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
// Add the new server to sm:.
ASSERT(R_SUCCEEDED(
- m_system.ServiceManager().RegisterService(service_name, max_sessions, handler)));
+ m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory)));
// Get the registered port.
Kernel::KPort* port{};
@@ -112,7 +112,7 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
// Begin tracking the server port.
{
std::scoped_lock ll{m_list_mutex};
- m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler));
+ m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory));
}
// Signal the wakeup event.
@@ -121,8 +121,18 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
R_SUCCEED();
}
+Result ServerManager::RegisterNamedService(const std::string& service_name,
+ std::shared_ptr<SessionRequestHandler>&& handler,
+ u32 max_sessions) {
+ // Make the factory.
+ const auto HandlerFactory = [handler]() { return handler; };
+
+ // Register the service with the new factory.
+ R_RETURN(this->RegisterNamedService(service_name, std::move(HandlerFactory), max_sessions));
+}
+
Result ServerManager::ManageNamedPort(const std::string& service_name,
- std::shared_ptr<SessionRequestHandler>&& handler,
+ SessionRequestHandlerFactory&& handler_factory,
u32 max_sessions) {
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
@@ -149,7 +159,7 @@ Result ServerManager::ManageNamedPort(const std::string& service_name,
// Begin tracking the server port.
{
std::scoped_lock ll{m_list_mutex};
- m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler));
+ m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory));
}
// We succeeded.
@@ -269,13 +279,13 @@ Result ServerManager::WaitAndProcessImpl() {
case HandleType::Port: {
// Port signaled.
auto* port = wait_obj->DynamicCast<Kernel::KServerPort*>();
- std::shared_ptr<SessionRequestHandler> handler;
+ SessionRequestHandlerFactory handler_factory;
// Remove from tracking.
{
std::scoped_lock ll{m_list_mutex};
ASSERT(m_ports.contains(port));
- m_ports.at(port).swap(handler);
+ m_ports.at(port).swap(handler_factory);
m_ports.erase(port);
}
@@ -283,7 +293,7 @@ Result ServerManager::WaitAndProcessImpl() {
sl.unlock();
// Finish.
- R_RETURN(this->OnPortEvent(port, std::move(handler)));
+ R_RETURN(this->OnPortEvent(port, std::move(handler_factory)));
}
case HandleType::Session: {
// Session signaled.
@@ -333,19 +343,19 @@ Result ServerManager::WaitAndProcessImpl() {
}
Result ServerManager::OnPortEvent(Kernel::KServerPort* port,
- std::shared_ptr<SessionRequestHandler>&& handler) {
+ SessionRequestHandlerFactory&& handler_factory) {
// Accept a new server session.
Kernel::KServerSession* session = port->AcceptSession();
ASSERT(session != nullptr);
// Create the session manager and install the handler.
auto manager = std::make_shared<SessionRequestManager>(m_system.Kernel(), *this);
- manager->SetSessionHandler(std::shared_ptr(handler));
+ manager->SetSessionHandler(handler_factory());
// Track the server session.
{
std::scoped_lock ll{m_list_mutex};
- m_ports.emplace(port, std::move(handler));
+ m_ports.emplace(port, std::move(handler_factory));
m_sessions.emplace(session, std::move(manager));
}
diff --git a/src/core/hle/service/server_manager.h b/src/core/hle/service/server_manager.h
index 58b0a0832..c4bc07262 100644
--- a/src/core/hle/service/server_manager.h
+++ b/src/core/hle/service/server_manager.h
@@ -13,6 +13,7 @@
#include "common/polyfill_thread.h"
#include "common/thread.h"
#include "core/hle/result.h"
+#include "core/hle/service/hle_ipc.h"
#include "core/hle/service/mutex.h"
namespace Core {
@@ -28,10 +29,6 @@ class KSynchronizationObject;
namespace Service {
-class HLERequestContext;
-class SessionRequestHandler;
-class SessionRequestManager;
-
class ServerManager {
public:
explicit ServerManager(Core::System& system);
@@ -40,10 +37,13 @@ public:
Result RegisterSession(Kernel::KServerSession* session,
std::shared_ptr<SessionRequestManager> manager);
Result RegisterNamedService(const std::string& service_name,
+ SessionRequestHandlerFactory&& handler_factory,
+ u32 max_sessions = 64);
+ Result RegisterNamedService(const std::string& service_name,
std::shared_ptr<SessionRequestHandler>&& handler,
u32 max_sessions = 64);
Result ManageNamedPort(const std::string& service_name,
- std::shared_ptr<SessionRequestHandler>&& handler, u32 max_sessions = 64);
+ SessionRequestHandlerFactory&& handler_factory, u32 max_sessions = 64);
Result ManageDeferral(Kernel::KEvent** out_event);
Result LoopProcess();
@@ -56,7 +56,7 @@ private:
Result LoopProcessImpl();
Result WaitAndProcessImpl();
- Result OnPortEvent(Kernel::KServerPort* port, std::shared_ptr<SessionRequestHandler>&& handler);
+ Result OnPortEvent(Kernel::KServerPort* port, SessionRequestHandlerFactory&& handler_factory);
Result OnSessionEvent(Kernel::KServerSession* session,
std::shared_ptr<SessionRequestManager>&& manager);
Result OnDeferralEvent(std::list<RequestState>&& deferrals);
@@ -68,7 +68,7 @@ private:
std::mutex m_list_mutex;
// Guest state tracking
- std::map<Kernel::KServerPort*, std::shared_ptr<SessionRequestHandler>> m_ports{};
+ std::map<Kernel::KServerPort*, SessionRequestHandlerFactory> m_ports{};
std::map<Kernel::KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions{};
Kernel::KEvent* m_event{};
Kernel::KEvent* m_deferral_event{};
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index 0ad607391..00531b021 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -59,6 +59,7 @@
#include "core/hle/service/prepo/prepo.h"
#include "core/hle/service/psc/psc.h"
#include "core/hle/service/ptm/ptm.h"
+#include "core/hle/service/ro/ro.h"
#include "core/hle/service/service.h"
#include "core/hle/service/set/settings.h"
#include "core/hle/service/sm/sm.h"
@@ -270,6 +271,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system
kernel.RunOnGuestCoreProcess("ProcessManager", [&] { PM::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("psc", [&] { PSC::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("ptm", [&] { PTM::LoopProcess(system); });
+ kernel.RunOnGuestCoreProcess("ro", [&] { RO::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("settings", [&] { Set::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("spl", [&] { SPL::LoopProcess(system); });
kernel.RunOnGuestCoreProcess("ssl", [&] { SSL::LoopProcess(system); });
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp
index 9ab718e0a..296ee6e89 100644
--- a/src/core/hle/service/sm/sm.cpp
+++ b/src/core/hle/service/sm/sm.cpp
@@ -51,7 +51,7 @@ static Result ValidateServiceName(const std::string& name) {
}
Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
- SessionRequestHandlerPtr handler) {
+ SessionRequestHandlerFactory handler) {
R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock};
@@ -121,7 +121,7 @@ void SM::Initialize(HLERequestContext& ctx) {
rb.Push(ResultSuccess);
}
-void SM::GetService(HLERequestContext& ctx) {
+void SM::GetServiceCmif(HLERequestContext& ctx) {
Kernel::KClientSession* client_session{};
auto result = GetServiceImpl(&client_session, ctx);
if (ctx.GetIsDeferred()) {
@@ -192,19 +192,32 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
return result;
}
- LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId());
-
*out_client_session = session;
return ResultSuccess;
}
-void SM::RegisterService(HLERequestContext& ctx) {
+void SM::RegisterServiceCmif(HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
std::string name(PopServiceName(rp));
const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
const auto max_session_count = rp.PopRaw<u32>();
+ this->RegisterServiceImpl(ctx, name, max_session_count, is_light);
+}
+
+void SM::RegisterServiceTipc(HLERequestContext& ctx) {
+ IPC::RequestParser rp{ctx};
+ std::string name(PopServiceName(rp));
+
+ const auto max_session_count = rp.PopRaw<u32>();
+ const auto is_light = static_cast<bool>(rp.PopRaw<u32>());
+
+ this->RegisterServiceImpl(ctx, name, max_session_count, is_light);
+}
+
+void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,
+ bool is_light) {
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
max_session_count, is_light);
@@ -240,15 +253,15 @@ SM::SM(ServiceManager& service_manager_, Core::System& system_)
service_manager{service_manager_}, kernel{system_.Kernel()} {
RegisterHandlers({
{0, &SM::Initialize, "Initialize"},
- {1, &SM::GetService, "GetService"},
- {2, &SM::RegisterService, "RegisterService"},
+ {1, &SM::GetServiceCmif, "GetService"},
+ {2, &SM::RegisterServiceCmif, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"},
});
RegisterHandlersTipc({
{0, &SM::Initialize, "Initialize"},
{1, &SM::GetServiceTipc, "GetService"},
- {2, &SM::RegisterService, "RegisterService"},
+ {2, &SM::RegisterServiceTipc, "RegisterService"},
{3, &SM::UnregisterService, "UnregisterService"},
{4, nullptr, "DetachClient"},
});
@@ -264,7 +277,9 @@ void LoopProcess(Core::System& system) {
server_manager->ManageDeferral(&deferral_event);
service_manager.SetDeferralEvent(deferral_event);
- server_manager->ManageNamedPort("sm:", std::make_shared<SM>(system.ServiceManager(), system));
+ auto sm_service = std::make_shared<SM>(system.ServiceManager(), system);
+ server_manager->ManageNamedPort("sm:", [sm_service] { return sm_service; });
+
ServerManager::RunServer(std::move(server_manager));
}
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h
index 14bfaf8c2..ff74f588a 100644
--- a/src/core/hle/service/sm/sm.h
+++ b/src/core/hle/service/sm/sm.h
@@ -37,12 +37,15 @@ public:
private:
void Initialize(HLERequestContext& ctx);
- void GetService(HLERequestContext& ctx);
+ void GetServiceCmif(HLERequestContext& ctx);
void GetServiceTipc(HLERequestContext& ctx);
- void RegisterService(HLERequestContext& ctx);
+ void RegisterServiceCmif(HLERequestContext& ctx);
+ void RegisterServiceTipc(HLERequestContext& ctx);
void UnregisterService(HLERequestContext& ctx);
Result GetServiceImpl(Kernel::KClientSession** out_client_session, HLERequestContext& ctx);
+ void RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_session_count,
+ bool is_light);
ServiceManager& service_manager;
Kernel::KernelCore& kernel;
@@ -53,7 +56,8 @@ public:
explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager();
- Result RegisterService(std::string name, u32 max_sessions, SessionRequestHandlerPtr handler);
+ Result RegisterService(std::string name, u32 max_sessions,
+ SessionRequestHandlerFactory handler_factory);
Result UnregisterService(const std::string& name);
Result GetServicePort(Kernel::KPort** out_port, const std::string& name);
@@ -64,7 +68,7 @@ public:
LOG_DEBUG(Service, "Can't find service: {}", service_name);
return nullptr;
}
- return std::static_pointer_cast<T>(service->second);
+ return std::static_pointer_cast<T>(service->second());
}
void InvokeControlRequest(HLERequestContext& context);
@@ -79,7 +83,7 @@ private:
/// Map of registered services, retrieved using GetServicePort.
std::mutex lock;
- std::unordered_map<std::string, SessionRequestHandlerPtr> registered_services;
+ std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services;
std::unordered_map<std::string, Kernel::KPort*> service_ports;
/// Kernel context
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp
index 6c8427b0d..0fbb43057 100644
--- a/src/core/hle/service/ssl/ssl.cpp
+++ b/src/core/hle/service/ssl/ssl.cpp
@@ -240,7 +240,7 @@ private:
return ret;
}
- Result ReadImpl(std::vector<u8>* out_data, size_t size) {
+ Result ReadImpl(std::vector<u8>* out_data) {
ASSERT_OR_EXECUTE(did_handshake, { return ResultInternalError; });
size_t actual_size{};
Result res = backend->Read(&actual_size, *out_data);
@@ -326,8 +326,8 @@ private:
}
void Read(HLERequestContext& ctx) {
- std::vector<u8> output_bytes;
- const Result res = ReadImpl(&output_bytes, ctx.GetWriteBufferSize());
+ std::vector<u8> output_bytes(ctx.GetWriteBufferSize());
+ const Result res = ReadImpl(&output_bytes);
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(res);
if (res == ResultSuccess) {