diff options
32 files changed, 731 insertions, 531 deletions
diff --git a/.ci/templates/build-msvc.yml b/.ci/templates/build-msvc.yml index e5f8ea91e..cca3189fa 100644 --- a/.ci/templates/build-msvc.yml +++ b/.ci/templates/build-msvc.yml @@ -8,7 +8,7 @@ steps: displayName: 'Install vulkan-sdk' - script: python -m pip install --upgrade pip conan displayName: 'Install conan' -- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 16 2019" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd .. +- script: refreshenv && mkdir build && cd build && cmake -G "Visual Studio 17 2022" -A x64 -DYUZU_USE_BUNDLED_QT=1 -DYUZU_USE_BUNDLED_SDL2=1 -DYUZU_USE_QT_WEB_ENGINE=ON -DENABLE_COMPATIBILITY_LIST_DOWNLOAD=ON -DYUZU_ENABLE_COMPATIBILITY_REPORTING=${COMPAT} -DYUZU_TESTS=OFF -DUSE_DISCORD_PRESENCE=ON -DENABLE_QT_TRANSLATION=ON -DDISPLAY_VERSION=${{ parameters['version'] }} -DCMAKE_BUILD_TYPE=Release .. && cd .. displayName: 'Configure CMake' - task: MSBuild@1 displayName: 'Build' diff --git a/.ci/yuzu-mainline-step2.yml b/.ci/yuzu-mainline-step2.yml index 91e21a126..b37eab6cd 100644 --- a/.ci/yuzu-mainline-step2.yml +++ b/.ci/yuzu-mainline-step2.yml @@ -47,7 +47,7 @@ stages: timeoutInMinutes: 120 displayName: 'msvc' pool: - vmImage: windows-2019 + vmImage: windows-2022 steps: - template: ./templates/sync-source.yml parameters: diff --git a/.ci/yuzu-patreon-step2.yml b/.ci/yuzu-patreon-step2.yml index ad61ac74e..119123a63 100644 --- a/.ci/yuzu-patreon-step2.yml +++ b/.ci/yuzu-patreon-step2.yml @@ -12,7 +12,7 @@ stages: timeoutInMinutes: 120 displayName: 'windows-msvc' pool: - vmImage: windows-2019 + vmImage: windows-2022 steps: - template: ./templates/sync-source.yml parameters: diff --git a/CMakeLists.txt b/CMakeLists.txt index caeb2ab8e..dcd4011a5 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -405,13 +405,11 @@ if (CONAN_REQUIRED_LIBS) # Download conan.cmake automatically, you can also just copy the conan.cmake file if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") - # TODO: Use a tagged release. The latest tagged release does not support VS2022 as of this writing. - file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/43e385830ee35377dbd2dcbe8d5a9e750301ea00/conan.cmake" - "${CMAKE_BINARY_DIR}/conan.cmake") + file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/release/0.18/conan.cmake" "${CMAKE_BINARY_DIR}/conan.cmake") endif() include(${CMAKE_BINARY_DIR}/conan.cmake) - conan_check(VERSION 1.41.0 REQUIRED) + conan_check(VERSION 1.45.0 REQUIRED) # Manually add iconv to fix a dep conflict between qt and sdl2 # We don't need to add it through find_package or anything since the other two can find it just fine diff --git a/externals/libressl b/externals/libressl -Subproject 8289d0d07de6553bf4b900bf60e808ea3f7f59d +Subproject 8929f818fd748fd31a34fec7c04558399e13014 diff --git a/src/core/hid/hid_types.h b/src/core/hid/hid_types.h index df2b1dfc5..26ec1091b 100644 --- a/src/core/hid/hid_types.h +++ b/src/core/hid/hid_types.h @@ -316,27 +316,27 @@ static_assert(sizeof(TouchAttribute) == 0x4, "TouchAttribute is an invalid size" // This is nn::hid::TouchState struct TouchState { - u64 delta_time; - TouchAttribute attribute; - u32 finger; - Common::Point<u32> position; - u32 diameter_x; - u32 diameter_y; - u32 rotation_angle; + u64 delta_time{}; + TouchAttribute attribute{}; + u32 finger{}; + Common::Point<u32> position{}; + u32 diameter_x{}; + u32 diameter_y{}; + u32 rotation_angle{}; }; static_assert(sizeof(TouchState) == 0x28, "Touchstate is an invalid size"); // This is nn::hid::NpadControllerColor struct NpadControllerColor { - u32 body; - u32 button; + u32 body{}; + u32 button{}; }; static_assert(sizeof(NpadControllerColor) == 8, "NpadControllerColor is an invalid size"); // This is nn::hid::AnalogStickState struct AnalogStickState { - s32 x; - s32 y; + s32 x{}; + s32 y{}; }; static_assert(sizeof(AnalogStickState) == 8, "AnalogStickState is an invalid size"); @@ -354,10 +354,10 @@ static_assert(sizeof(NpadBatteryLevel) == 0x4, "NpadBatteryLevel is an invalid s // This is nn::hid::system::NpadPowerInfo struct NpadPowerInfo { - bool is_powered; - bool is_charging; + bool is_powered{}; + bool is_charging{}; INSERT_PADDING_BYTES(0x6); - NpadBatteryLevel battery_level; + NpadBatteryLevel battery_level{8}; }; static_assert(sizeof(NpadPowerInfo) == 0xC, "NpadPowerInfo is an invalid size"); @@ -474,8 +474,8 @@ static_assert(sizeof(DebugPadButton) == 0x4, "DebugPadButton is an invalid size" // This is nn::hid::ConsoleSixAxisSensorHandle struct ConsoleSixAxisSensorHandle { - u8 unknown_1; - u8 unknown_2; + u8 unknown_1{}; + u8 unknown_2{}; INSERT_PADDING_BYTES_NOINIT(2); }; static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4, @@ -483,9 +483,9 @@ static_assert(sizeof(ConsoleSixAxisSensorHandle) == 4, // This is nn::hid::SixAxisSensorHandle struct SixAxisSensorHandle { - NpadStyleIndex npad_type; - u8 npad_id; - DeviceIndex device_index; + NpadStyleIndex npad_type{NpadStyleIndex::None}; + u8 npad_id{}; + DeviceIndex device_index{DeviceIndex::None}; INSERT_PADDING_BYTES_NOINIT(1); }; static_assert(sizeof(SixAxisSensorHandle) == 4, "SixAxisSensorHandle is an invalid size"); @@ -500,19 +500,19 @@ static_assert(sizeof(SixAxisSensorFusionParameters) == 8, // This is nn::hid::VibrationDeviceHandle struct VibrationDeviceHandle { - NpadStyleIndex npad_type; - u8 npad_id; - DeviceIndex device_index; + NpadStyleIndex npad_type{NpadStyleIndex::None}; + u8 npad_id{}; + DeviceIndex device_index{DeviceIndex::None}; INSERT_PADDING_BYTES_NOINIT(1); }; static_assert(sizeof(VibrationDeviceHandle) == 4, "SixAxisSensorHandle is an invalid size"); // This is nn::hid::VibrationValue struct VibrationValue { - f32 low_amplitude; - f32 low_frequency; - f32 high_amplitude; - f32 high_frequency; + f32 low_amplitude{}; + f32 low_frequency{}; + f32 high_amplitude{}; + f32 high_frequency{}; }; static_assert(sizeof(VibrationValue) == 0x10, "VibrationValue has incorrect size."); @@ -561,7 +561,7 @@ static_assert(sizeof(KeyboardAttribute) == 0x4, "KeyboardAttribute is an invalid // This is nn::hid::KeyboardKey struct KeyboardKey { // This should be a 256 bit flag - std::array<u8, 32> key; + std::array<u8, 32> key{}; }; static_assert(sizeof(KeyboardKey) == 0x20, "KeyboardKey is an invalid size"); @@ -590,16 +590,16 @@ static_assert(sizeof(MouseAttribute) == 0x4, "MouseAttribute is an invalid size" // This is nn::hid::detail::MouseState struct MouseState { - s64 sampling_number; - s32 x; - s32 y; - s32 delta_x; - s32 delta_y; + s64 sampling_number{}; + s32 x{}; + s32 y{}; + s32 delta_x{}; + s32 delta_y{}; // Axis Order in HW is switched for the wheel - s32 delta_wheel_y; - s32 delta_wheel_x; - MouseButton button; - MouseAttribute attribute; + s32 delta_wheel_y{}; + s32 delta_wheel_x{}; + MouseButton button{}; + MouseAttribute attribute{}; }; static_assert(sizeof(MouseState) == 0x28, "MouseState is an invalid size"); diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.cpp b/src/core/hle/service/hid/controllers/console_sixaxis.cpp index f5a0b94dd..bb3cba910 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.cpp +++ b/src/core/hle/service/hid/controllers/console_sixaxis.cpp @@ -9,9 +9,14 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C200; -Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_) +Controller_ConsoleSixAxis::Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, + u8* raw_shared_memory_) : ControllerBase{hid_core_} { 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)); } Controller_ConsoleSixAxis::~Controller_ConsoleSixAxis() = default; @@ -20,8 +25,7 @@ void Controller_ConsoleSixAxis::OnInit() {} void Controller_ConsoleSixAxis::OnRelease() {} -void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated() || !is_transfer_memory_set) { seven_sixaxis_lifo.buffer_count = 0; seven_sixaxis_lifo.buffer_tail = 0; @@ -48,13 +52,11 @@ void Controller_ConsoleSixAxis::OnUpdate(const Core::Timing::CoreTiming& core_ti -motion_status.quaternion.xyz.z, }; - console_six_axis.sampling_number++; - console_six_axis.is_seven_six_axis_sensor_at_rest = motion_status.is_at_rest; - console_six_axis.verticalization_error = motion_status.verticalization_error; - console_six_axis.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; - // Update console six axis shared memory - std::memcpy(data + SHARED_MEMORY_OFFSET, &console_six_axis, sizeof(console_six_axis)); // Update seven six axis transfer memory seven_sixaxis_lifo.WriteNextEntry(next_seven_sixaxis_state); std::memcpy(transfer_memory, &seven_sixaxis_lifo, sizeof(seven_sixaxis_lifo)); diff --git a/src/core/hle/service/hid/controllers/console_sixaxis.h b/src/core/hle/service/hid/controllers/console_sixaxis.h index 6da5e9454..2fd11538f 100644 --- a/src/core/hle/service/hid/controllers/console_sixaxis.h +++ b/src/core/hle/service/hid/controllers/console_sixaxis.h @@ -17,7 +17,7 @@ class EmulatedConsole; namespace Service::HID { class Controller_ConsoleSixAxis final : public ControllerBase { public: - explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_); + explicit Controller_ConsoleSixAxis(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_ConsoleSixAxis() override; // Called when the controller is initialized @@ -27,7 +27,7 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; // Called on InitializeSevenSixAxisSensor void SetTransferMemoryPointer(u8* t_mem); @@ -61,12 +61,13 @@ private: Lifo<SevenSixAxisState, 0x21> seven_sixaxis_lifo{}; static_assert(sizeof(seven_sixaxis_lifo) == 0xA70, "SevenSixAxisState is an invalid size"); - Core::HID::EmulatedConsole* console; + SevenSixAxisState next_seven_sixaxis_state{}; u8* transfer_memory = nullptr; + ConsoleSharedMemory* shared_memory = nullptr; + Core::HID::EmulatedConsole* console = nullptr; + bool is_transfer_memory_set = false; u64 last_saved_timestamp{}; u64 last_global_timestamp{}; - ConsoleSharedMemory console_six_axis{}; - SevenSixAxisState next_seven_sixaxis_state{}; }; } // 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 bb01ea643..d6f7a5073 100644 --- a/src/core/hle/service/hid/controllers/controller_base.h +++ b/src/core/hle/service/hid/controllers/controller_base.h @@ -26,12 +26,10 @@ public: virtual void OnRelease() = 0; // When the controller is requesting an update for the shared memory - virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) = 0; + virtual void OnUpdate(const Core::Timing::CoreTiming& core_timing) = 0; // When the controller is requesting a motion update for the shared memory - virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) {} + virtual void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) {} void ActivateController(); @@ -40,6 +38,7 @@ 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 73309d64e..8ec9f4a95 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp @@ -13,8 +13,12 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x00000; -Controller_DebugPad::Controller_DebugPad(Core::HID::HIDCore& hid_core_) +Controller_DebugPad::Controller_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)); controller = hid_core.GetEmulatedController(Core::HID::NpadIdType::Other); } @@ -24,16 +28,14 @@ void Controller_DebugPad::OnInit() {} void Controller_DebugPad::OnRelease() {} -void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - debug_pad_lifo.buffer_count = 0; - debug_pad_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); + shared_memory->debug_pad_lifo.buffer_count = 0; + shared_memory->debug_pad_lifo.buffer_tail = 0; return; } - const auto& last_entry = 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) { @@ -47,8 +49,7 @@ void Controller_DebugPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, next_state.r_stick = stick_state.right; } - debug_pad_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &debug_pad_lifo, sizeof(debug_pad_lifo)); + 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 388d25b3c..68ff0ea79 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.h +++ b/src/core/hle/service/hid/controllers/debug_pad.h @@ -17,7 +17,7 @@ struct AnalogStickState; namespace Service::HID { class Controller_DebugPad final : public ControllerBase { public: - explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_); + explicit Controller_DebugPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_DebugPad() override; // Called when the controller is initialized @@ -27,7 +27,7 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: // This is nn::hid::DebugPadAttribute @@ -41,19 +41,24 @@ private: // 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; + 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"); - // 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"); - DebugPadState next_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"); - Core::HID::EmulatedController* controller; + DebugPadState next_state{}; + DebugPadSharedMemory* shared_memory = nullptr; + 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 c8dd131dd..3eae1ae35 100644 --- a/src/core/hle/service/hid/controllers/gesture.cpp +++ b/src/core/hle/service/hid/controllers/gesture.cpp @@ -23,25 +23,28 @@ constexpr f32 Square(s32 num) { return static_cast<f32>(num * num); } -Controller_Gesture::Controller_Gesture(Core::HID::HIDCore& hid_core_) : ControllerBase(hid_core_) { +Controller_Gesture::Controller_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)); console = hid_core.GetEmulatedConsole(); } Controller_Gesture::~Controller_Gesture() = default; void Controller_Gesture::OnInit() { - gesture_lifo.buffer_count = 0; - gesture_lifo.buffer_tail = 0; + shared_memory->gesture_lifo.buffer_count = 0; + shared_memory->gesture_lifo.buffer_tail = 0; force_update = true; } void Controller_Gesture::OnRelease() {} -void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - gesture_lifo.buffer_count = 0; - gesture_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); + shared_memory->gesture_lifo.buffer_count = 0; + shared_memory->gesture_lifo.buffer_tail = 0; return; } @@ -49,15 +52,15 @@ void Controller_Gesture::OnUpdate(const Core::Timing::CoreTiming& core_timing, u GestureProperties gesture = GetGestureProperties(); f32 time_difference = - static_cast<f32>(gesture_lifo.timestamp - last_update_timestamp) / (1000 * 1000 * 1000); + static_cast<f32>(shared_memory->gesture_lifo.timestamp - last_update_timestamp) / + (1000 * 1000 * 1000); // Only update if necesary if (!ShouldUpdateGesture(gesture, time_difference)) { return; } - last_update_timestamp = gesture_lifo.timestamp; - UpdateGestureSharedMemory(data, size, gesture, time_difference); + last_update_timestamp = shared_memory->gesture_lifo.timestamp; } void Controller_Gesture::ReadTouchInput() { @@ -97,7 +100,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, GestureType type = GestureType::Idle; GestureAttribute attributes{}; - const auto& last_entry = 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; @@ -127,8 +130,7 @@ void Controller_Gesture::UpdateGestureSharedMemory(u8* data, std::size_t size, next_state.points = gesture.points; last_gesture = gesture; - gesture_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &gesture_lifo, sizeof(gesture_lifo)); + shared_memory->gesture_lifo.WriteNextEntry(next_state); } void Controller_Gesture::NewGesture(GestureProperties& gesture, GestureType& type, @@ -305,7 +307,7 @@ void Controller_Gesture::SetSwipeEvent(GestureProperties& gesture, } const Controller_Gesture::GestureState& Controller_Gesture::GetLastGestureEntry() const { - return gesture_lifo.ReadCurrentEntry().state; + return shared_memory->gesture_lifo.ReadCurrentEntry().state; } Controller_Gesture::GestureProperties Controller_Gesture::GetGestureProperties() { diff --git a/src/core/hle/service/hid/controllers/gesture.h b/src/core/hle/service/hid/controllers/gesture.h index 7a9d28dc6..c62a341bf 100644 --- a/src/core/hle/service/hid/controllers/gesture.h +++ b/src/core/hle/service/hid/controllers/gesture.h @@ -14,7 +14,7 @@ namespace Service::HID { class Controller_Gesture final : public ControllerBase { public: - explicit Controller_Gesture(Core::HID::HIDCore& hid_core_); + explicit Controller_Gesture(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_Gesture() override; // Called when the controller is initialized @@ -24,7 +24,7 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: static constexpr size_t MAX_FINGERS = 16; @@ -66,19 +66,19 @@ private: // This is nn::hid::GestureState struct GestureState { - s64 sampling_number; - s64 detection_count; - GestureType type; - GestureDirection direction; - 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; + 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"); @@ -92,6 +92,14 @@ private: 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(); @@ -134,12 +142,9 @@ private: // Returns the average distance, angle and middle point of the active fingers GestureProperties GetGestureProperties(); - // 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"); GestureState next_state{}; - - Core::HID::EmulatedConsole* console; + GestureSharedMemory* shared_memory = nullptr; + Core::HID::EmulatedConsole* console = nullptr; std::array<Core::HID::TouchFinger, MAX_POINTS> fingers{}; GestureProperties last_gesture{}; diff --git a/src/core/hle/service/hid/controllers/keyboard.cpp b/src/core/hle/service/hid/controllers/keyboard.cpp index 8dc67757b..117d87433 100644 --- a/src/core/hle/service/hid/controllers/keyboard.cpp +++ b/src/core/hle/service/hid/controllers/keyboard.cpp @@ -12,8 +12,12 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3800; -Controller_Keyboard::Controller_Keyboard(Core::HID::HIDCore& hid_core_) +Controller_Keyboard::Controller_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)); emulated_devices = hid_core.GetEmulatedDevices(); } @@ -23,16 +27,14 @@ void Controller_Keyboard::OnInit() {} void Controller_Keyboard::OnRelease() {} -void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - keyboard_lifo.buffer_count = 0; - keyboard_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); + shared_memory->keyboard_lifo.buffer_count = 0; + shared_memory->keyboard_lifo.buffer_tail = 0; return; } - const auto& last_entry = 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) { @@ -44,8 +46,7 @@ void Controller_Keyboard::OnUpdate(const Core::Timing::CoreTiming& core_timing, next_state.attribute.is_connected.Assign(1); } - keyboard_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &keyboard_lifo, sizeof(keyboard_lifo)); + 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 39c6085f1..7532f53c6 100644 --- a/src/core/hle/service/hid/controllers/keyboard.h +++ b/src/core/hle/service/hid/controllers/keyboard.h @@ -16,7 +16,7 @@ struct KeyboardKey; namespace Service::HID { class Controller_Keyboard final : public ControllerBase { public: - explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_); + explicit Controller_Keyboard(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_Keyboard() override; // Called when the controller is initialized @@ -26,23 +26,28 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + 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; + 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"); - // 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"); - KeyboardState next_state{}; + 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"); - Core::HID::EmulatedDevices* emulated_devices; + KeyboardState next_state{}; + KeyboardSharedMemory* shared_memory = nullptr; + 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 a0292f586..b11cb438d 100644 --- a/src/core/hle/service/hid/controllers/mouse.cpp +++ b/src/core/hle/service/hid/controllers/mouse.cpp @@ -12,7 +12,12 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3400; -Controller_Mouse::Controller_Mouse(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} { +Controller_Mouse::Controller_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)); emulated_devices = hid_core.GetEmulatedDevices(); } @@ -21,16 +26,14 @@ Controller_Mouse::~Controller_Mouse() = default; void Controller_Mouse::OnInit() {} void Controller_Mouse::OnRelease() {} -void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - mouse_lifo.buffer_count = 0; - mouse_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); + shared_memory->mouse_lifo.buffer_count = 0; + shared_memory->mouse_lifo.buffer_tail = 0; return; } - const auto& last_entry = mouse_lifo.ReadCurrentEntry().state; + const auto& last_entry = shared_memory->mouse_lifo.ReadCurrentEntry().state; next_state.sampling_number = last_entry.sampling_number + 1; next_state.attribute.raw = 0; @@ -50,8 +53,7 @@ void Controller_Mouse::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* next_state.button = mouse_button_state; } - mouse_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &mouse_lifo, sizeof(mouse_lifo)); + 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 62acdfb77..733d00577 100644 --- a/src/core/hle/service/hid/controllers/mouse.h +++ b/src/core/hle/service/hid/controllers/mouse.h @@ -16,7 +16,7 @@ struct AnalogStickState; namespace Service::HID { class Controller_Mouse final : public ControllerBase { public: - explicit Controller_Mouse(Core::HID::HIDCore& hid_core_); + explicit Controller_Mouse(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_Mouse() override; // Called when the controller is initialized @@ -26,15 +26,20 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: - // 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"); - Core::HID::MouseState next_state{}; + 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::AnalogStickState last_mouse_wheel_state; - Core::HID::EmulatedDevices* emulated_devices; + Core::HID::MouseState next_state{}; + Core::HID::AnalogStickState last_mouse_wheel_state{}; + MouseSharedMemory* shared_memory = nullptr; + 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 16e973b25..17f71beaf 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -61,11 +61,14 @@ bool Controller_NPad::IsDeviceHandleValid(const Core::HID::SixAxisSensorHandle& return npad_id && npad_type && device_index; } -Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, +Controller_NPad::Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, 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.device = hid_core.GetEmulatedControllerByIndex(i); controller.vibration[Core::HID::EmulatedDeviceIndex::LeftIndex].latest_vibration_value = Core::HID::DEFAULT_VIBRATION_VALUE; @@ -115,11 +118,11 @@ void Controller_NPad::ControllerUpdate(Core::HID::ControllerTriggerType type, if (!controller.device->IsConnected()) { return; } - auto& shared_memory = controller.shared_memory_entry; + auto* shared_memory = controller.shared_memory; const auto& battery_level = controller.device->GetBattery(); - shared_memory.battery_level_dual = battery_level.dual.battery_level; - shared_memory.battery_level_left = battery_level.left.battery_level; - shared_memory.battery_level_right = battery_level.right.battery_level; + shared_memory->battery_level_dual = battery_level.dual.battery_level; + shared_memory->battery_level_left = battery_level.left.battery_level; + shared_memory->battery_level_right = battery_level.right.battery_level; break; } default: @@ -134,99 +137,100 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { } LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); - auto& shared_memory = controller.shared_memory_entry; + auto* shared_memory = controller.shared_memory; if (controller_type == Core::HID::NpadStyleIndex::None) { controller.styleset_changed_event->GetWritableEvent().Signal(); return; } - shared_memory.style_tag.raw = Core::HID::NpadStyleSet::None; - shared_memory.device_type.raw = 0; - shared_memory.system_properties.raw = 0; + shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; + shared_memory->device_type.raw = 0; + shared_memory->system_properties.raw = 0; switch (controller_type) { case Core::HID::NpadStyleIndex::None: UNREACHABLE(); break; case Core::HID::NpadStyleIndex::ProController: - shared_memory.style_tag.fullkey.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::SwitchProController; + shared_memory->style_tag.fullkey.Assign(1); + shared_memory->device_type.fullkey.Assign(1); + shared_memory->system_properties.is_vertical.Assign(1); + shared_memory->system_properties.use_plus.Assign(1); + shared_memory->system_properties.use_minus.Assign(1); + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; break; case Core::HID::NpadStyleIndex::Handheld: - shared_memory.style_tag.handheld.Assign(1); - shared_memory.device_type.handheld_left.Assign(1); - shared_memory.device_type.handheld_right.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.system_properties.use_directional_buttons.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; - shared_memory.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; + shared_memory->style_tag.handheld.Assign(1); + shared_memory->device_type.handheld_left.Assign(1); + shared_memory->device_type.handheld_right.Assign(1); + shared_memory->system_properties.is_vertical.Assign(1); + shared_memory->system_properties.use_plus.Assign(1); + shared_memory->system_properties.use_minus.Assign(1); + shared_memory->system_properties.use_directional_buttons.Assign(1); + shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; + shared_memory->applet_nfc_xcd.applet_footer.type = + AppletFooterUiType::HandheldJoyConLeftJoyConRight; break; case Core::HID::NpadStyleIndex::JoyconDual: - shared_memory.style_tag.joycon_dual.Assign(1); + shared_memory->style_tag.joycon_dual.Assign(1); if (controller.is_dual_left_connected) { - shared_memory.device_type.joycon_left.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); + shared_memory->device_type.joycon_left.Assign(1); + shared_memory->system_properties.use_minus.Assign(1); } if (controller.is_dual_right_connected) { - shared_memory.device_type.joycon_right.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); + shared_memory->device_type.joycon_right.Assign(1); + shared_memory->system_properties.use_plus.Assign(1); } - shared_memory.system_properties.use_directional_buttons.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.assignment_mode = NpadJoyAssignmentMode::Dual; + shared_memory->system_properties.use_directional_buttons.Assign(1); + shared_memory->system_properties.is_vertical.Assign(1); + shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; if (controller.is_dual_left_connected && controller.is_dual_right_connected) { - shared_memory.applet_footer.type = AppletFooterUiType::JoyDual; + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; } else if (controller.is_dual_left_connected) { - shared_memory.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; } else { - shared_memory.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; } break; case Core::HID::NpadStyleIndex::JoyconLeft: - shared_memory.style_tag.joycon_left.Assign(1); - shared_memory.device_type.joycon_left.Assign(1); - shared_memory.system_properties.is_horizontal.Assign(1); - shared_memory.system_properties.use_minus.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; + shared_memory->style_tag.joycon_left.Assign(1); + shared_memory->device_type.joycon_left.Assign(1); + shared_memory->system_properties.is_horizontal.Assign(1); + shared_memory->system_properties.use_minus.Assign(1); + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; break; case Core::HID::NpadStyleIndex::JoyconRight: - shared_memory.style_tag.joycon_right.Assign(1); - shared_memory.device_type.joycon_right.Assign(1); - shared_memory.system_properties.is_horizontal.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; + shared_memory->style_tag.joycon_right.Assign(1); + shared_memory->device_type.joycon_right.Assign(1); + shared_memory->system_properties.is_horizontal.Assign(1); + shared_memory->system_properties.use_plus.Assign(1); + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; break; case Core::HID::NpadStyleIndex::GameCube: - shared_memory.style_tag.gamecube.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.system_properties.is_vertical.Assign(1); - shared_memory.system_properties.use_plus.Assign(1); + shared_memory->style_tag.gamecube.Assign(1); + shared_memory->device_type.fullkey.Assign(1); + shared_memory->system_properties.is_vertical.Assign(1); + shared_memory->system_properties.use_plus.Assign(1); break; case Core::HID::NpadStyleIndex::Pokeball: - shared_memory.style_tag.palma.Assign(1); - shared_memory.device_type.palma.Assign(1); + shared_memory->style_tag.palma.Assign(1); + shared_memory->device_type.palma.Assign(1); break; case Core::HID::NpadStyleIndex::NES: - shared_memory.style_tag.lark.Assign(1); - shared_memory.device_type.fullkey.Assign(1); + shared_memory->style_tag.lark.Assign(1); + shared_memory->device_type.fullkey.Assign(1); break; case Core::HID::NpadStyleIndex::SNES: - shared_memory.style_tag.lucia.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::Lucia; + shared_memory->style_tag.lucia.Assign(1); + shared_memory->device_type.fullkey.Assign(1); + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lucia; break; case Core::HID::NpadStyleIndex::N64: - shared_memory.style_tag.lagoon.Assign(1); - shared_memory.device_type.fullkey.Assign(1); - shared_memory.applet_footer.type = AppletFooterUiType::Lagon; + shared_memory->style_tag.lagoon.Assign(1); + shared_memory->device_type.fullkey.Assign(1); + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::Lagon; break; case Core::HID::NpadStyleIndex::SegaGenesis: - shared_memory.style_tag.lager.Assign(1); - shared_memory.device_type.fullkey.Assign(1); + shared_memory->style_tag.lager.Assign(1); + shared_memory->device_type.fullkey.Assign(1); break; default: break; @@ -234,23 +238,23 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { const auto& body_colors = controller.device->GetColors(); - shared_memory.fullkey_color.attribute = ColorAttribute::Ok; - shared_memory.fullkey_color.fullkey = body_colors.fullkey; + shared_memory->fullkey_color.attribute = ColorAttribute::Ok; + shared_memory->fullkey_color.fullkey = body_colors.fullkey; - shared_memory.joycon_color.attribute = ColorAttribute::Ok; - shared_memory.joycon_color.left = body_colors.left; - shared_memory.joycon_color.right = body_colors.right; + shared_memory->joycon_color.attribute = ColorAttribute::Ok; + shared_memory->joycon_color.left = body_colors.left; + shared_memory->joycon_color.right = body_colors.right; // TODO: Investigate when we should report all batery types const auto& battery_level = controller.device->GetBattery(); - shared_memory.battery_level_dual = battery_level.dual.battery_level; - shared_memory.battery_level_left = battery_level.left.battery_level; - shared_memory.battery_level_right = battery_level.right.battery_level; + shared_memory->battery_level_dual = battery_level.dual.battery_level; + shared_memory->battery_level_left = battery_level.left.battery_level; + shared_memory->battery_level_right = battery_level.right.battery_level; controller.is_connected = true; controller.device->Connect(); SignalStyleSetChangedEvent(npad_id); - WriteEmptyEntry(controller.shared_memory_entry); + WriteEmptyEntry(controller.shared_memory); } void Controller_NPad::OnInit() { @@ -270,12 +274,12 @@ void Controller_NPad::OnInit() { // Prefill controller buffers for (auto& controller : controller_data) { - auto& npad = controller.shared_memory_entry; - npad.fullkey_color = { + auto* npad = controller.shared_memory; + npad->fullkey_color = { .attribute = ColorAttribute::NoController, .fullkey = {}, }; - npad.joycon_color = { + npad->joycon_color = { .attribute = ColorAttribute::NoController, .left = {}, .right = {}, @@ -287,25 +291,25 @@ void Controller_NPad::OnInit() { } } -void Controller_NPad::WriteEmptyEntry(NpadInternalState& npad) { +void Controller_NPad::WriteEmptyEntry(NpadInternalState* npad) { NPadGenericState dummy_pad_state{}; NpadGcTriggerState dummy_gc_state{}; - dummy_pad_state.sampling_number = npad.fullkey_lifo.ReadCurrentEntry().sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.handheld_lifo.ReadCurrentEntry().sampling_number + 1; - npad.handheld_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; - npad.joy_dual_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.joy_left_lifo.ReadCurrentEntry().sampling_number + 1; - npad.joy_left_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.joy_right_lifo.ReadCurrentEntry().sampling_number + 1; - npad.joy_right_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.palma_lifo.ReadCurrentEntry().sampling_number + 1; - npad.palma_lifo.WriteNextEntry(dummy_pad_state); - dummy_pad_state.sampling_number = npad.system_ext_lifo.ReadCurrentEntry().sampling_number + 1; - npad.system_ext_lifo.WriteNextEntry(dummy_pad_state); - dummy_gc_state.sampling_number = npad.gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; - npad.gc_trigger_lifo.WriteNextEntry(dummy_gc_state); + dummy_pad_state.sampling_number = npad->fullkey_lifo.ReadCurrentEntry().sampling_number + 1; + npad->fullkey_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad->handheld_lifo.ReadCurrentEntry().sampling_number + 1; + npad->handheld_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad->joy_dual_lifo.ReadCurrentEntry().sampling_number + 1; + npad->joy_dual_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad->joy_left_lifo.ReadCurrentEntry().sampling_number + 1; + npad->joy_left_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad->joy_right_lifo.ReadCurrentEntry().sampling_number + 1; + npad->joy_right_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad->palma_lifo.ReadCurrentEntry().sampling_number + 1; + npad->palma_lifo.WriteNextEntry(dummy_pad_state); + dummy_pad_state.sampling_number = npad->system_ext_lifo.ReadCurrentEntry().sampling_number + 1; + npad->system_ext_lifo.WriteNextEntry(dummy_pad_state); + dummy_gc_state.sampling_number = npad->gc_trigger_lifo.ReadCurrentEntry().sampling_number + 1; + npad->gc_trigger_lifo.WriteNextEntry(dummy_gc_state); } void Controller_NPad::OnRelease() { @@ -371,23 +375,19 @@ void Controller_NPad::RequestPadStateUpdate(Core::HID::NpadIdType npad_id) { } } -void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t data_len) { +void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { return; } for (std::size_t i = 0; i < controller_data.size(); ++i) { auto& controller = controller_data[i]; - auto& npad = controller.shared_memory_entry; + auto* npad = controller.shared_memory; const auto& controller_type = controller.device->GetNpadStyleIndex(); if (controller_type == Core::HID::NpadStyleIndex::None || !controller.device->IsConnected()) { - // Refresh shared memory - std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), - &controller.shared_memory_entry, sizeof(NpadInternalState)); continue; } @@ -415,8 +415,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.connection_status.is_wired.Assign(1); pad_state.sampling_number = - npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(pad_state); + npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->fullkey_lifo.WriteNextEntry(pad_state); break; case Core::HID::NpadStyleIndex::Handheld: pad_state.connection_status.raw = 0; @@ -433,8 +433,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.connection_status.is_left_wired.Assign(1); libnx_state.connection_status.is_right_wired.Assign(1); pad_state.sampling_number = - npad.handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.handheld_lifo.WriteNextEntry(pad_state); + npad->handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->handheld_lifo.WriteNextEntry(pad_state); break; case Core::HID::NpadStyleIndex::JoyconDual: pad_state.connection_status.raw = 0; @@ -449,8 +449,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* } pad_state.sampling_number = - npad.joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.joy_dual_lifo.WriteNextEntry(pad_state); + npad->joy_dual_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->joy_dual_lifo.WriteNextEntry(pad_state); break; case Core::HID::NpadStyleIndex::JoyconLeft: pad_state.connection_status.raw = 0; @@ -459,8 +459,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.connection_status.is_left_connected.Assign(1); pad_state.sampling_number = - npad.joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.joy_left_lifo.WriteNextEntry(pad_state); + npad->joy_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->joy_left_lifo.WriteNextEntry(pad_state); break; case Core::HID::NpadStyleIndex::JoyconRight: pad_state.connection_status.raw = 0; @@ -469,8 +469,8 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.connection_status.is_right_connected.Assign(1); pad_state.sampling_number = - npad.joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.joy_right_lifo.WriteNextEntry(pad_state); + npad->joy_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->joy_right_lifo.WriteNextEntry(pad_state); break; case Core::HID::NpadStyleIndex::GameCube: pad_state.connection_status.raw = 0; @@ -479,18 +479,18 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.connection_status.is_wired.Assign(1); pad_state.sampling_number = - npad.fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; trigger_state.sampling_number = - npad.gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.fullkey_lifo.WriteNextEntry(pad_state); - npad.gc_trigger_lifo.WriteNextEntry(trigger_state); + npad->gc_trigger_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->fullkey_lifo.WriteNextEntry(pad_state); + npad->gc_trigger_lifo.WriteNextEntry(trigger_state); break; case Core::HID::NpadStyleIndex::Pokeball: pad_state.connection_status.raw = 0; pad_state.connection_status.is_connected.Assign(1); pad_state.sampling_number = - npad.palma_lifo.ReadCurrentEntry().state.sampling_number + 1; - npad.palma_lifo.WriteNextEntry(pad_state); + npad->palma_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->palma_lifo.WriteNextEntry(pad_state); break; default: break; @@ -499,17 +499,13 @@ void Controller_NPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* libnx_state.npad_buttons.raw = pad_state.npad_buttons.raw; libnx_state.l_stick = pad_state.l_stick; libnx_state.r_stick = pad_state.r_stick; - npad.system_ext_lifo.WriteNextEntry(pad_state); + npad->system_ext_lifo.WriteNextEntry(pad_state); press_state |= static_cast<u64>(pad_state.npad_buttons.raw); - - std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), - &controller.shared_memory_entry, sizeof(NpadInternalState)); } } -void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t data_len) { +void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { return; } @@ -524,7 +520,7 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing continue; } - auto& npad = controller.shared_memory_entry; + auto* npad = controller.shared_memory; const auto& motion_state = controller.device->GetMotions(); auto& sixaxis_fullkey_state = controller.sixaxis_fullkey_state; auto& sixaxis_handheld_state = controller.sixaxis_handheld_state; @@ -610,32 +606,30 @@ void Controller_NPad::OnMotionUpdate(const Core::Timing::CoreTiming& core_timing } sixaxis_fullkey_state.sampling_number = - npad.sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->sixaxis_fullkey_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_handheld_state.sampling_number = - npad.sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->sixaxis_handheld_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_left_state.sampling_number = - npad.sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->sixaxis_dual_left_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_dual_right_state.sampling_number = - npad.sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->sixaxis_dual_right_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_left_lifo_state.sampling_number = - npad.sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->sixaxis_left_lifo.ReadCurrentEntry().state.sampling_number + 1; sixaxis_right_lifo_state.sampling_number = - npad.sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; + npad->sixaxis_right_lifo.ReadCurrentEntry().state.sampling_number + 1; if (Core::HID::IndexToNpadIdType(i) == Core::HID::NpadIdType::Handheld) { // This buffer only is updated on handheld on HW - npad.sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); + npad->sixaxis_handheld_lifo.WriteNextEntry(sixaxis_handheld_state); } else { // Handheld doesn't update this buffer on HW - npad.sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); + npad->sixaxis_fullkey_lifo.WriteNextEntry(sixaxis_fullkey_state); } - npad.sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); - npad.sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); - npad.sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); - npad.sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); - std::memcpy(data + NPAD_OFFSET + (i * sizeof(NpadInternalState)), - &controller.shared_memory_entry, sizeof(NpadInternalState)); + npad->sixaxis_dual_left_lifo.WriteNextEntry(sixaxis_dual_left_state); + npad->sixaxis_dual_right_lifo.WriteNextEntry(sixaxis_dual_right_state); + npad->sixaxis_left_lifo.WriteNextEntry(sixaxis_left_lifo_state); + npad->sixaxis_right_lifo.WriteNextEntry(sixaxis_right_lifo_state); } } @@ -713,8 +707,8 @@ void Controller_NPad::SetNpadMode(Core::HID::NpadIdType npad_id, NpadJoyDeviceTy } auto& controller = GetControllerFromNpadIdType(npad_id); - if (controller.shared_memory_entry.assignment_mode != assignment_mode) { - controller.shared_memory_entry.assignment_mode = assignment_mode; + if (controller.shared_memory->assignment_mode != assignment_mode) { + controller.shared_memory->assignment_mode = assignment_mode; } if (!controller.device->IsConnected()) { @@ -981,32 +975,32 @@ void Controller_NPad::DisconnectNpad(Core::HID::NpadIdType npad_id) { controller.vibration[device_idx].device_mounted = false; } - auto& shared_memory_entry = controller.shared_memory_entry; - // Don't reset shared_memory_entry.assignment_mode this value is persistent - shared_memory_entry.style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out - shared_memory_entry.device_type.raw = 0; - shared_memory_entry.system_properties.raw = 0; - shared_memory_entry.button_properties.raw = 0; - shared_memory_entry.battery_level_dual = 0; - shared_memory_entry.battery_level_left = 0; - shared_memory_entry.battery_level_right = 0; - shared_memory_entry.fullkey_color = { + auto* shared_memory = controller.shared_memory; + // Don't reset shared_memory->assignment_mode this value is persistent + shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; // Zero out + shared_memory->device_type.raw = 0; + shared_memory->system_properties.raw = 0; + shared_memory->button_properties.raw = 0; + shared_memory->battery_level_dual = 0; + shared_memory->battery_level_left = 0; + shared_memory->battery_level_right = 0; + shared_memory->fullkey_color = { .attribute = ColorAttribute::NoController, .fullkey = {}, }; - shared_memory_entry.joycon_color = { + shared_memory->joycon_color = { .attribute = ColorAttribute::NoController, .left = {}, .right = {}, }; - shared_memory_entry.applet_footer.type = AppletFooterUiType::None; + shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::None; controller.is_dual_left_connected = true; controller.is_dual_right_connected = true; controller.is_connected = false; controller.device->Disconnect(); SignalStyleSetChangedEvent(npad_id); - WriteEmptyEntry(controller.shared_memory_entry); + WriteEmptyEntry(shared_memory); } ResultCode Controller_NPad::SetGyroscopeZeroDriftMode(Core::HID::SixAxisSensorHandle sixaxis_handle, diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index b42532b68..0a96825a5 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h @@ -35,7 +35,7 @@ namespace Service::HID { class Controller_NPad final : public ControllerBase { public: - explicit Controller_NPad(Core::HID::HIDCore& hid_core_, + explicit Controller_NPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_, KernelHelpers::ServiceContext& service_context_); ~Controller_NPad() override; @@ -46,11 +46,10 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; // When the controller is requesting a motion update for the shared memory - void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) override; + void OnMotionUpdate(const Core::Timing::CoreTiming& core_timing) override; // This is nn::hid::GyroscopeZeroDriftMode enum class GyroscopeZeroDriftMode : u32 { @@ -188,6 +187,8 @@ public: static bool IsDeviceHandleValid(const Core::HID::VibrationDeviceHandle& device_handle); private: + static constexpr std::size_t NPAD_COUNT = 10; + // This is nn::hid::detail::ColorAttribute enum class ColorAttribute : u32 { Ok = 0, @@ -409,6 +410,13 @@ private: U, }; + struct AppletNfcXcd { + union { + AppletFooterUi applet_footer{}; + Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo; + }; + }; + // This is nn::hid::detail::NpadInternalState struct NpadInternalState { Core::HID::NpadStyleTag style_tag{Core::HID::NpadStyleSet::None}; @@ -435,10 +443,7 @@ private: Core::HID::NpadBatteryLevel battery_level_dual{}; Core::HID::NpadBatteryLevel battery_level_left{}; Core::HID::NpadBatteryLevel battery_level_right{}; - union { - AppletFooterUi applet_footer{}; - Lifo<NfcXcdDeviceHandleStateImpl, 0x2> nfc_xcd_device_lifo; - }; + AppletNfcXcd applet_nfc_xcd{}; INSERT_PADDING_BYTES(0x20); // Unknown Lifo<NpadGcTriggerState, hid_entry_count> gc_trigger_lifo{}; NpadLarkType lark_type_l_and_main{}; @@ -465,9 +470,9 @@ private: }; struct NpadControllerData { - Core::HID::EmulatedController* device; Kernel::KEvent* styleset_changed_event{}; - NpadInternalState shared_memory_entry{}; + NpadInternalState* shared_memory = nullptr; + Core::HID::EmulatedController* device = nullptr; std::array<VibrationData, 2> vibration{}; bool unintended_home_button_input_protection{}; @@ -497,15 +502,14 @@ private: SixAxisSensorState sixaxis_dual_right_state{}; SixAxisSensorState sixaxis_left_lifo_state{}; SixAxisSensorState sixaxis_right_lifo_state{}; - - int callback_key; + int callback_key{}; }; void ControllerUpdate(Core::HID::ControllerTriggerType type, std::size_t controller_idx); void InitNewlyAddedController(Core::HID::NpadIdType npad_id); bool IsControllerSupported(Core::HID::NpadStyleIndex controller) const; void RequestPadStateUpdate(Core::HID::NpadIdType npad_id); - void WriteEmptyEntry(NpadInternalState& npad); + void WriteEmptyEntry(NpadInternalState* npad); NpadControllerData& GetControllerFromHandle( const Core::HID::SixAxisSensorHandle& device_handle); @@ -520,7 +524,7 @@ private: std::atomic<u64> press_state{}; - std::array<NpadControllerData, 10> controller_data{}; + std::array<NpadControllerData, NPAD_COUNT> 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/stubbed.cpp b/src/core/hle/service/hid/controllers/stubbed.cpp index 4d3b9d2be..df9ee0c3f 100644 --- a/src/core/hle/service/hid/controllers/stubbed.cpp +++ b/src/core/hle/service/hid/controllers/stubbed.cpp @@ -9,15 +9,18 @@ namespace Service::HID { -Controller_Stubbed::Controller_Stubbed(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} +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() = default; void Controller_Stubbed::OnInit() {} void Controller_Stubbed::OnRelease() {} -void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!smart_update) { return; } @@ -28,7 +31,7 @@ void Controller_Stubbed::OnUpdate(const Core::Timing::CoreTiming& core_timing, u header.entry_count = 0; header.last_entry_index = 0; - std::memcpy(data + common_offset, &header, sizeof(CommonHeader)); + std::memcpy(raw_shared_memory + common_offset, &header, sizeof(CommonHeader)); } void Controller_Stubbed::SetCommonHeaderOffset(std::size_t off) { diff --git a/src/core/hle/service/hid/controllers/stubbed.h b/src/core/hle/service/hid/controllers/stubbed.h index 512066eb3..1483a968e 100644 --- a/src/core/hle/service/hid/controllers/stubbed.h +++ b/src/core/hle/service/hid/controllers/stubbed.h @@ -9,7 +9,7 @@ namespace Service::HID { class Controller_Stubbed final : public ControllerBase { public: - explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_); + explicit Controller_Stubbed(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_Stubbed() override; // Called when the controller is initialized @@ -19,19 +19,20 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + 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; + 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; bool smart_update{}; std::size_t common_offset{}; }; diff --git a/src/core/hle/service/hid/controllers/touchscreen.cpp b/src/core/hle/service/hid/controllers/touchscreen.cpp index 5b4b51a69..108ce5a41 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.cpp +++ b/src/core/hle/service/hid/controllers/touchscreen.cpp @@ -15,8 +15,13 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x400; -Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_) +Controller_Touchscreen::Controller_Touchscreen(Core::HID::HIDCore& hid_core_, + u8* raw_shared_memory_) : ControllerBase{hid_core_} { + 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(); } @@ -26,14 +31,12 @@ void Controller_Touchscreen::OnInit() {} void Controller_Touchscreen::OnRelease() {} -void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { - touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); +void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timing) { + shared_memory->touch_screen_lifo.timestamp = core_timing.GetCPUTicks(); if (!IsControllerActivated()) { - touch_screen_lifo.buffer_count = 0; - touch_screen_lifo.buffer_tail = 0; - std::memcpy(data, &touch_screen_lifo, sizeof(touch_screen_lifo)); + shared_memory->touch_screen_lifo.buffer_count = 0; + shared_memory->touch_screen_lifo.buffer_tail = 0; return; } @@ -74,7 +77,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin static_cast<std::size_t>(std::distance(active_fingers.begin(), end_iter)); const u64 tick = core_timing.GetCPUTicks(); - const auto& last_entry = 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); @@ -106,8 +109,7 @@ void Controller_Touchscreen::OnUpdate(const Core::Timing::CoreTiming& core_timin } } - touch_screen_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &touch_screen_lifo, sizeof(touch_screen_lifo)); + shared_memory->touch_screen_lifo.WriteNextEntry(next_state); } } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/touchscreen.h b/src/core/hle/service/hid/controllers/touchscreen.h index 424973b38..e57a3a80e 100644 --- a/src/core/hle/service/hid/controllers/touchscreen.h +++ b/src/core/hle/service/hid/controllers/touchscreen.h @@ -25,14 +25,14 @@ public: // This is nn::hid::TouchScreenConfigurationForNx struct TouchScreenConfigurationForNx { - TouchScreenModeForNx mode; + TouchScreenModeForNx mode{TouchScreenModeForNx::UseSystemSetting}; INSERT_PADDING_BYTES_NOINIT(0x7); INSERT_PADDING_BYTES_NOINIT(0xF); // Reserved }; static_assert(sizeof(TouchScreenConfigurationForNx) == 0x17, "TouchScreenConfigurationForNx is an invalid size"); - explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_); + explicit Controller_Touchscreen(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_Touchscreen() override; // Called when the controller is initialized @@ -42,26 +42,32 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: static constexpr std::size_t MAX_FINGERS = 16; // This is nn::hid::TouchScreenState struct TouchScreenState { - s64 sampling_number; - s32 entry_count; + s64 sampling_number{}; + s32 entry_count{}; INSERT_PADDING_BYTES(4); // Reserved - std::array<Core::HID::TouchState, MAX_FINGERS> states; + std::array<Core::HID::TouchState, MAX_FINGERS> states{}; }; static_assert(sizeof(TouchScreenState) == 0x290, "TouchScreenState is an invalid size"); - // 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"); + 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; + Core::HID::EmulatedConsole* console = nullptr; - std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers; - Core::HID::EmulatedConsole* console; + std::array<Core::HID::TouchFinger, MAX_FINGERS> fingers{}; }; } // namespace Service::HID diff --git a/src/core/hle/service/hid/controllers/xpad.cpp b/src/core/hle/service/hid/controllers/xpad.cpp index fc6ac6457..62119e2c5 100644 --- a/src/core/hle/service/hid/controllers/xpad.cpp +++ b/src/core/hle/service/hid/controllers/xpad.cpp @@ -10,28 +10,31 @@ namespace Service::HID { constexpr std::size_t SHARED_MEMORY_OFFSET = 0x3C00; -Controller_XPad::Controller_XPad(Core::HID::HIDCore& hid_core_) : ControllerBase{hid_core_} {} +Controller_XPad::Controller_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)); +} Controller_XPad::~Controller_XPad() = default; void Controller_XPad::OnInit() {} void Controller_XPad::OnRelease() {} -void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, - std::size_t size) { +void Controller_XPad::OnUpdate(const Core::Timing::CoreTiming& core_timing) { if (!IsControllerActivated()) { - basic_xpad_lifo.buffer_count = 0; - basic_xpad_lifo.buffer_tail = 0; - std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); + shared_memory->basic_xpad_lifo.buffer_count = 0; + shared_memory->basic_xpad_lifo.buffer_tail = 0; return; } - const auto& last_entry = basic_xpad_lifo.ReadCurrentEntry().state; + 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 - basic_xpad_lifo.WriteNextEntry(next_state); - std::memcpy(data + SHARED_MEMORY_OFFSET, &basic_xpad_lifo, sizeof(basic_xpad_lifo)); + 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 index 8211b6ee3..d01dee5fc 100644 --- a/src/core/hle/service/hid/controllers/xpad.h +++ b/src/core/hle/service/hid/controllers/xpad.h @@ -12,7 +12,7 @@ namespace Service::HID { class Controller_XPad final : public ControllerBase { public: - explicit Controller_XPad(Core::HID::HIDCore& hid_core_); + explicit Controller_XPad(Core::HID::HIDCore& hid_core_, u8* raw_shared_memory_); ~Controller_XPad() override; // Called when the controller is initialized @@ -22,7 +22,7 @@ public: void OnRelease() override; // When the controller is requesting an update for the shared memory - void OnUpdate(const Core::Timing::CoreTiming& core_timing, u8* data, std::size_t size) override; + void OnUpdate(const Core::Timing::CoreTiming& core_timing) override; private: // This is nn::hid::BasicXpadAttributeSet @@ -90,17 +90,23 @@ private: // 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; + 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"); - // 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"); + 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/hid.cpp b/src/core/hle/service/hid/hid.cpp index fb1ec52b2..36162ac97 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -39,7 +39,6 @@ constexpr auto pad_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) // TODO: Correct update rate for motion is 5ms. Check why some games don't behave at that speed constexpr auto motion_update_ns = std::chrono::nanoseconds{10 * 1000 * 1000}; // (10ms, 100Hz) -constexpr std::size_t SHARED_MEMORY_SIZE = 0x40000; IAppletResource::IAppletResource(Core::System& system_, KernelHelpers::ServiceContext& service_context_) @@ -48,20 +47,20 @@ IAppletResource::IAppletResource(Core::System& system_, {0, &IAppletResource::GetSharedMemoryHandle, "GetSharedMemoryHandle"}, }; RegisterHandlers(functions); - - MakeController<Controller_DebugPad>(HidController::DebugPad); - MakeController<Controller_Touchscreen>(HidController::Touchscreen); - MakeController<Controller_Mouse>(HidController::Mouse); - MakeController<Controller_Keyboard>(HidController::Keyboard); - MakeController<Controller_XPad>(HidController::XPad); - MakeController<Controller_Stubbed>(HidController::HomeButton); - MakeController<Controller_Stubbed>(HidController::SleepButton); - MakeController<Controller_Stubbed>(HidController::CaptureButton); - MakeController<Controller_Stubbed>(HidController::InputDetector); - MakeController<Controller_Stubbed>(HidController::UniquePad); - MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad); - MakeController<Controller_Gesture>(HidController::Gesture); - MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor); + u8* shared_memory = system.Kernel().GetHidSharedMem().GetPointer(); + MakeController<Controller_DebugPad>(HidController::DebugPad, shared_memory); + MakeController<Controller_Touchscreen>(HidController::Touchscreen, shared_memory); + MakeController<Controller_Mouse>(HidController::Mouse, shared_memory); + MakeController<Controller_Keyboard>(HidController::Keyboard, shared_memory); + MakeController<Controller_XPad>(HidController::XPad, shared_memory); + MakeController<Controller_Stubbed>(HidController::HomeButton, shared_memory); + MakeController<Controller_Stubbed>(HidController::SleepButton, shared_memory); + MakeController<Controller_Stubbed>(HidController::CaptureButton, shared_memory); + MakeController<Controller_Stubbed>(HidController::InputDetector, shared_memory); + MakeController<Controller_Stubbed>(HidController::UniquePad, shared_memory); + MakeControllerWithServiceContext<Controller_NPad>(HidController::NPad, shared_memory); + MakeController<Controller_Gesture>(HidController::Gesture, shared_memory); + MakeController<Controller_ConsoleSixAxis>(HidController::ConsoleSixAxisSensor, shared_memory); // Homebrew doesn't try to activate some controllers, so we activate them by default GetController<Controller_NPad>(HidController::NPad).ActivateController(); @@ -135,8 +134,7 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { continue; } - controller->OnUpdate(core_timing, system.Kernel().GetHidSharedMem().GetPointer(), - SHARED_MEMORY_SIZE); + controller->OnUpdate(core_timing); } // If ns_late is higher than the update rate ignore the delay @@ -151,10 +149,8 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate( - core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); - controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate( - core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); + controllers[static_cast<size_t>(HidController::Mouse)]->OnUpdate(core_timing); + controllers[static_cast<size_t>(HidController::Keyboard)]->OnUpdate(core_timing); // If ns_late is higher than the update rate ignore the delay if (ns_late > mouse_keyboard_update_ns) { @@ -167,8 +163,7 @@ void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, void IAppletResource::UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); - controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate( - core_timing, system.Kernel().GetHidSharedMem().GetPointer(), SHARED_MEMORY_SIZE); + controllers[static_cast<size_t>(HidController::NPad)]->OnMotionUpdate(core_timing); // If ns_late is higher than the update rate ignore the delay if (ns_late > motion_update_ns) { diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 95778e673..e61f8ed08 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -58,13 +58,14 @@ public: private: template <typename T> - void MakeController(HidController controller) { - controllers[static_cast<std::size_t>(controller)] = std::make_unique<T>(system.HIDCore()); + void MakeController(HidController controller, u8* shared_memory) { + controllers[static_cast<std::size_t>(controller)] = + std::make_unique<T>(system.HIDCore(), shared_memory); } template <typename T> - void MakeControllerWithServiceContext(HidController controller) { + void MakeControllerWithServiceContext(HidController controller, u8* shared_memory) { controllers[static_cast<std::size_t>(controller)] = - std::make_unique<T>(system.HIDCore(), service_context); + std::make_unique<T>(system.HIDCore(), shared_memory, service_context); } void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/jit/jit.cpp b/src/core/hle/service/jit/jit.cpp index 185d0387b..8f2920c51 100644 --- a/src/core/hle/service/jit/jit.cpp +++ b/src/core/hle/service/jit/jit.cpp @@ -21,9 +21,10 @@ struct CodeRange { class IJitEnvironment final : public ServiceFramework<IJitEnvironment> { public: - explicit IJitEnvironment(Core::System& system_, CodeRange user_rx, CodeRange user_ro) + explicit IJitEnvironment(Core::System& system_, Kernel::KProcess& process_, CodeRange user_rx, + CodeRange user_ro) : ServiceFramework{system_, "IJitEnvironment", ServiceThreadType::CreateNew}, - context{system_.Memory()} { + process{&process_}, context{system_.Memory()} { // clang-format off static const FunctionInfo functions[] = { {0, &IJitEnvironment::GenerateCode, "GenerateCode"}, @@ -43,54 +44,80 @@ public: } void GenerateCode(Kernel::HLERequestContext& ctx) { - struct Parameters { + LOG_DEBUG(Service_JIT, "called"); + + struct InputParameters { u32 data_size; u64 command; - CodeRange cr1; - CodeRange cr2; + std::array<CodeRange, 2> ranges; Struct32 data; }; + struct OutputParameters { + s32 return_value; + std::array<CodeRange, 2> ranges; + }; + IPC::RequestParser rp{ctx}; - const auto parameters{rp.PopRaw<Parameters>()}; + const auto parameters{rp.PopRaw<InputParameters>()}; + + // Optional input/output buffers std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()}; std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); - const VAddr return_ptr{context.AddHeap(0u)}; - const VAddr cr1_in_ptr{context.AddHeap(parameters.cr1)}; - const VAddr cr2_in_ptr{context.AddHeap(parameters.cr2)}; - const VAddr cr1_out_ptr{ - context.AddHeap(CodeRange{.offset = parameters.cr1.offset, .size = 0})}; - const VAddr cr2_out_ptr{ - context.AddHeap(CodeRange{.offset = parameters.cr2.offset, .size = 0})}; + // Function call prototype: + // void GenerateCode(s32* ret, CodeRange* c0_out, CodeRange* c1_out, JITConfiguration* cfg, + // u64 cmd, u8* input_buf, size_t input_size, CodeRange* c0_in, + // CodeRange* c1_in, Struct32* data, size_t data_size, u8* output_buf, + // size_t output_size); + // + // The command argument is used to control the behavior of the plugin during code + // generation. The configuration allows the plugin to access the output code ranges, and the + // other arguments are used to transfer state between the game and the plugin. + + const VAddr ret_ptr{context.AddHeap(0u)}; + const VAddr c0_in_ptr{context.AddHeap(parameters.ranges[0])}; + const VAddr c1_in_ptr{context.AddHeap(parameters.ranges[1])}; + const VAddr c0_out_ptr{context.AddHeap(ClearSize(parameters.ranges[0]))}; + const VAddr c1_out_ptr{context.AddHeap(ClearSize(parameters.ranges[1]))}; + const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; const VAddr data_ptr{context.AddHeap(parameters.data)}; const VAddr configuration_ptr{context.AddHeap(configuration)}; - context.CallFunction(callbacks.GenerateCode, return_ptr, cr1_out_ptr, cr2_out_ptr, + // The callback does not directly return a value, it only writes to the output pointer + context.CallFunction(callbacks.GenerateCode, ret_ptr, c0_out_ptr, c1_out_ptr, configuration_ptr, parameters.command, input_ptr, input_buffer.size(), - cr1_in_ptr, cr2_in_ptr, data_ptr, parameters.data_size, output_ptr, + c0_in_ptr, c1_in_ptr, data_ptr, parameters.data_size, output_ptr, output_buffer.size()); - const s32 return_value{context.GetHeap<s32>(return_ptr)}; + const s32 return_value{context.GetHeap<s32>(ret_ptr)}; 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); + // Write back to the IPC output buffer, if provided if (ctx.CanWriteBuffer()) { context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size()); ctx.WriteBuffer(output_buffer.data(), output_buffer.size()); } - const auto cr1_out{context.GetHeap<CodeRange>(cr1_out_ptr)}; - const auto cr2_out{context.GetHeap<CodeRange>(cr2_out_ptr)}; + + const OutputParameters out{ + .return_value = return_value, + .ranges = + { + context.GetHeap<CodeRange>(c0_out_ptr), + context.GetHeap<CodeRange>(c1_out_ptr), + }, + }; IPC::ResponseBuilder rb{ctx, 8}; rb.Push(ResultSuccess); - rb.Push<u64>(return_value); - rb.PushRaw(cr1_out); - rb.PushRaw(cr2_out); + rb.PushRaw(out); } else { LOG_WARNING(Service_JIT, "plugin GenerateCode callback failed"); IPC::ResponseBuilder rb{ctx, 2}; @@ -99,25 +126,40 @@ public: }; void Control(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_JIT, "called"); + IPC::RequestParser rp{ctx}; const auto command{rp.PopRaw<u64>()}; - const auto input_buffer{ctx.ReadBuffer()}; + + // Optional input/output buffers + std::vector<u8> input_buffer{ctx.CanReadBuffer() ? ctx.ReadBuffer() : std::vector<u8>()}; std::vector<u8> output_buffer(ctx.CanWriteBuffer() ? ctx.GetWriteBufferSize() : 0); - const VAddr return_ptr{context.AddHeap(0u)}; + // Function call prototype: + // u64 Control(s32* ret, JITConfiguration* cfg, u64 cmd, u8* input_buf, size_t input_size, + // u8* output_buf, size_t output_size); + // + // This function is used to set up the state of the plugin before code generation, generally + // passing objects like pointers to VM state from the game. It is usually called once. + + const VAddr ret_ptr{context.AddHeap(0u)}; const VAddr configuration_ptr{context.AddHeap(configuration)}; const VAddr input_ptr{context.AddHeap(input_buffer.data(), input_buffer.size())}; const VAddr output_ptr{context.AddHeap(output_buffer.data(), output_buffer.size())}; - const u64 wrapper_value{ - context.CallFunction(callbacks.Control, return_ptr, configuration_ptr, command, - input_ptr, input_buffer.size(), output_ptr, output_buffer.size())}; - const s32 return_value{context.GetHeap<s32>(return_ptr)}; + + const u64 wrapper_value{context.CallFunction(callbacks.Control, ret_ptr, configuration_ptr, + command, input_ptr, input_buffer.size(), + output_ptr, output_buffer.size())}; + + const s32 return_value{context.GetHeap<s32>(ret_ptr)}; if (wrapper_value == 0 && return_value == 0) { + // Write back to the IPC output buffer, if provided if (ctx.CanWriteBuffer()) { context.GetHeap(output_ptr, output_buffer.data(), output_buffer.size()); ctx.WriteBuffer(output_buffer.data(), output_buffer.size()); } + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(return_value); @@ -129,8 +171,13 @@ public: } void LoadPlugin(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_JIT, "called"); + IPC::RequestParser rp{ctx}; const auto tmem_size{rp.PopRaw<u64>()}; + const auto tmem_handle{ctx.GetCopyHandle(0)}; + const auto nro_plugin{ctx.ReadBuffer(1)}; + if (tmem_size == 0) { LOG_ERROR(Service_JIT, "attempted to load plugin with empty transfer memory"); IPC::ResponseBuilder rb{ctx, 2}; @@ -138,9 +185,7 @@ public: return; } - const auto tmem_handle{ctx.GetCopyHandle(0)}; - auto tmem{system.CurrentProcess()->GetHandleTable().GetObject<Kernel::KTransferMemory>( - tmem_handle)}; + auto tmem{process->GetHandleTable().GetObject<Kernel::KTransferMemory>(tmem_handle)}; if (tmem.IsNull()) { LOG_ERROR(Service_JIT, "attempted to load plugin with invalid transfer memory handle"); IPC::ResponseBuilder rb{ctx, 2}; @@ -148,24 +193,24 @@ public: return; } - configuration.work_memory.offset = tmem->GetSourceAddress(); - configuration.work_memory.size = tmem_size; + // Set up the configuration with the required TransferMemory address + configuration.transfer_memory.offset = tmem->GetSourceAddress(); + configuration.transfer_memory.size = tmem_size; - const auto nro_plugin{ctx.ReadBuffer(1)}; + // Gather up all the callbacks from the loaded plugin auto symbols{Core::Symbols::GetSymbols(nro_plugin, true)}; - const auto GetSymbol{[&](std::string name) { return symbols[name].first; }}; - - callbacks = - GuestCallbacks{.rtld_fini = GetSymbol("_fini"), - .rtld_init = GetSymbol("_init"), - .Control = GetSymbol("nnjitpluginControl"), - .ResolveBasicSymbols = GetSymbol("nnjitpluginResolveBasicSymbols"), - .SetupDiagnostics = GetSymbol("nnjitpluginSetupDiagnostics"), - .Configure = GetSymbol("nnjitpluginConfigure"), - .GenerateCode = GetSymbol("nnjitpluginGenerateCode"), - .GetVersion = GetSymbol("nnjitpluginGetVersion"), - .Keeper = GetSymbol("nnjitpluginKeeper"), - .OnPrepared = GetSymbol("nnjitpluginOnPrepared")}; + const auto GetSymbol{[&](const std::string& name) { return symbols[name].first; }}; + + callbacks.rtld_fini = GetSymbol("_fini"); + callbacks.rtld_init = GetSymbol("_init"); + callbacks.Control = GetSymbol("nnjitpluginControl"); + callbacks.ResolveBasicSymbols = GetSymbol("nnjitpluginResolveBasicSymbols"); + callbacks.SetupDiagnostics = GetSymbol("nnjitpluginSetupDiagnostics"); + callbacks.Configure = GetSymbol("nnjitpluginConfigure"); + callbacks.GenerateCode = GetSymbol("nnjitpluginGenerateCode"); + callbacks.GetVersion = GetSymbol("nnjitpluginGetVersion"); + callbacks.OnPrepared = GetSymbol("nnjitpluginOnPrepared"); + callbacks.Keeper = GetSymbol("nnjitpluginKeeper"); if (callbacks.GetVersion == 0 || callbacks.Configure == 0 || callbacks.GenerateCode == 0 || callbacks.OnPrepared == 0) { @@ -186,12 +231,16 @@ public: configuration.sys_ro_memory.size); context.MapProcessMemory(configuration.sys_rx_memory.offset, configuration.sys_rx_memory.size); - context.MapProcessMemory(configuration.work_memory.offset, configuration.work_memory.size); + context.MapProcessMemory(configuration.transfer_memory.offset, + configuration.transfer_memory.size); + // Run ELF constructors, if needed if (callbacks.rtld_init != 0) { context.CallFunction(callbacks.rtld_init); } + // Function prototype: + // u64 GetVersion(); const auto version{context.CallFunction(callbacks.GetVersion)}; if (version != 1) { LOG_ERROR(Service_JIT, "unknown plugin version {}", version); @@ -200,16 +249,26 @@ public: return; } + // Function prototype: + // void ResolveBasicSymbols(void (*resolver)(const char* name)); const auto resolve{context.GetHelper("_resolve")}; if (callbacks.ResolveBasicSymbols != 0) { context.CallFunction(callbacks.ResolveBasicSymbols, resolve); } + + // Function prototype: + // void SetupDiagnostics(u32 enabled, void (**resolver)(const char* name)); const auto resolve_ptr{context.AddHeap(resolve)}; if (callbacks.SetupDiagnostics != 0) { context.CallFunction(callbacks.SetupDiagnostics, 0u, resolve_ptr); } - context.CallFunction(callbacks.Configure, 0u); + // Function prototype: + // void Configure(u32* memory_flags); + context.CallFunction(callbacks.Configure, 0ull); + + // Function prototype: + // void OnPrepared(JITConfiguration* cfg); const auto configuration_ptr{context.AddHeap(configuration)}; context.CallFunction(callbacks.OnPrepared, configuration_ptr); @@ -218,6 +277,8 @@ public: } void GetCodeAddress(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_JIT, "called"); + IPC::ResponseBuilder rb{ctx, 6}; rb.Push(ResultSuccess); rb.Push(configuration.user_rx_memory.offset); @@ -243,11 +304,17 @@ private: struct JITConfiguration { CodeRange user_rx_memory; CodeRange user_ro_memory; - CodeRange work_memory; + CodeRange transfer_memory; CodeRange sys_rx_memory; CodeRange sys_ro_memory; }; + static CodeRange ClearSize(CodeRange in) { + in.size = 0; + return in; + } + + Kernel::KScopedAutoObject<Kernel::KProcess> process; GuestCallbacks callbacks; JITConfiguration configuration; JITContext context; @@ -275,8 +342,9 @@ public: IPC::RequestParser rp{ctx}; const auto parameters{rp.PopRaw<Parameters>()}; - const auto executable_mem_handle{ctx.GetCopyHandle(1)}; - const auto readable_mem_handle{ctx.GetCopyHandle(2)}; + const auto process_handle{ctx.GetCopyHandle(0)}; + const auto rx_mem_handle{ctx.GetCopyHandle(1)}; + const auto ro_mem_handle{ctx.GetCopyHandle(2)}; if (parameters.rx_size == 0 || parameters.ro_size == 0) { LOG_ERROR(Service_JIT, "attempted to init with empty code regions"); @@ -285,42 +353,47 @@ public: return; } - // The copy handle at index 0 is the process handle, but handle tables are - // per-process, so there is no point reading it here until we are multiprocess - const auto& process{*system.CurrentProcess()}; + // Fetch using the handle table for the current process here, + // since we are not multiprocess yet. + const auto& handle_table{system.CurrentProcess()->GetHandleTable()}; + + auto process{handle_table.GetObject<Kernel::KProcess>(process_handle)}; + if (process.IsNull()) { + LOG_ERROR(Service_JIT, "process is null for handle=0x{:08X}", process_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultUnknown); + return; + } - auto executable_mem{ - process.GetHandleTable().GetObject<Kernel::KCodeMemory>(executable_mem_handle)}; - if (executable_mem.IsNull()) { - LOG_ERROR(Service_JIT, "executable_mem is null for handle=0x{:08X}", - executable_mem_handle); + auto rx_mem{handle_table.GetObject<Kernel::KCodeMemory>(rx_mem_handle)}; + if (rx_mem.IsNull()) { + LOG_ERROR(Service_JIT, "rx_mem is null for handle=0x{:08X}", rx_mem_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); return; } - auto readable_mem{ - process.GetHandleTable().GetObject<Kernel::KCodeMemory>(readable_mem_handle)}; - if (readable_mem.IsNull()) { - LOG_ERROR(Service_JIT, "readable_mem is null for handle=0x{:08X}", readable_mem_handle); + auto ro_mem{handle_table.GetObject<Kernel::KCodeMemory>(ro_mem_handle)}; + if (ro_mem.IsNull()) { + LOG_ERROR(Service_JIT, "ro_mem is null for handle=0x{:08X}", ro_mem_handle); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); return; } const CodeRange user_rx{ - .offset = executable_mem->GetSourceAddress(), + .offset = rx_mem->GetSourceAddress(), .size = parameters.rx_size, }; const CodeRange user_ro{ - .offset = readable_mem->GetSourceAddress(), + .offset = ro_mem->GetSourceAddress(), .size = parameters.ro_size, }; IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IJitEnvironment>(system, user_rx, user_ro); + rb.PushIpcInterface<IJitEnvironment>(system, *process, user_rx, user_ro); } }; diff --git a/src/core/hle/service/jit/jit_context.cpp b/src/core/hle/service/jit/jit_context.cpp index 17e58131c..19bd85b6c 100644 --- a/src/core/hle/service/jit/jit_context.cpp +++ b/src/core/hle/service/jit/jit_context.cpp @@ -17,61 +17,15 @@ namespace Service::JIT { -constexpr std::array<u8, 4> STOP_ARM64 = { +constexpr std::array<u8, 8> SVC0_ARM64 = { 0x01, 0x00, 0x00, 0xd4, // svc #0 -}; - -constexpr std::array<u8, 8> RESOLVE_ARM64 = { - 0x21, 0x00, 0x00, 0xd4, // svc #1 0xc0, 0x03, 0x5f, 0xd6, // ret }; -constexpr std::array<u8, 4> PANIC_ARM64 = { - 0x41, 0x00, 0x00, 0xd4, // svc #2 -}; - -constexpr std::array<u8, 60> MEMMOVE_ARM64 = { - 0x1f, 0x00, 0x01, 0xeb, // cmp x0, x1 - 0x83, 0x01, 0x00, 0x54, // b.lo #+34 - 0x42, 0x04, 0x00, 0xd1, // sub x2, x2, 1 - 0x22, 0x01, 0xf8, 0xb7, // tbnz x2, #63, #+36 - 0x23, 0x68, 0x62, 0x38, // ldrb w3, [x1, x2] - 0x03, 0x68, 0x22, 0x38, // strb w3, [x0, x2] - 0xfc, 0xff, 0xff, 0x17, // b #-16 - 0x24, 0x68, 0x63, 0x38, // ldrb w4, [x1, x3] - 0x04, 0x68, 0x23, 0x38, // strb w4, [x0, x3] - 0x63, 0x04, 0x00, 0x91, // add x3, x3, 1 - 0x7f, 0x00, 0x02, 0xeb, // cmp x3, x2 - 0x8b, 0xff, 0xff, 0x54, // b.lt #-16 - 0xc0, 0x03, 0x5f, 0xd6, // ret - 0x03, 0x00, 0x80, 0xd2, // mov x3, 0 - 0xfc, 0xff, 0xff, 0x17, // b #-16 +constexpr std::array HELPER_FUNCTIONS{ + "_stop", "_resolve", "_panic", "memcpy", "memmove", "memset", }; -constexpr std::array<u8, 28> MEMSET_ARM64 = { - 0x03, 0x00, 0x80, 0xd2, // mov x3, 0 - 0x7f, 0x00, 0x02, 0xeb, // cmp x3, x2 - 0x4b, 0x00, 0x00, 0x54, // b.lt #+8 - 0xc0, 0x03, 0x5f, 0xd6, // ret - 0x01, 0x68, 0x23, 0x38, // strb w1, [x0, x3] - 0x63, 0x04, 0x00, 0x91, // add x3, x3, 1 - 0xfb, 0xff, 0xff, 0x17, // b #-20 -}; - -struct HelperFunction { - const char* name; - const std::span<const u8> data; -}; - -constexpr std::array<HelperFunction, 6> HELPER_FUNCTIONS{{ - {"_stop", STOP_ARM64}, - {"_resolve", RESOLVE_ARM64}, - {"_panic", PANIC_ARM64}, - {"memcpy", MEMMOVE_ARM64}, - {"memmove", MEMMOVE_ARM64}, - {"memset", MEMSET_ARM64}, -}}; - struct Elf64_Dyn { u64 d_tag; u64 d_un; @@ -224,17 +178,24 @@ public: InsertHelperFunctions(); InsertStack(); return true; - } else { - return false; } + + return false; } bool FixupRelocations() { + // The loaded NRO file has ELF relocations that must be processed before it can run. + // Normally this would be processed by RTLD, but in HLE context, we don't have + // the linker available, so we have to do it ourselves. + const VAddr mod_offset{callbacks->MemoryRead32(4)}; if (callbacks->MemoryRead32(mod_offset) != Common::MakeMagic('M', 'O', 'D', '0')) { return false; } + // For more info about dynamic entries, see the ELF ABI specification: + // https://refspecs.linuxbase.org/elf/gabi4+/ch5.dynamic.html + // https://refspecs.linuxbase.org/elf/gabi4+/ch4.reloc.html VAddr dynamic_offset{mod_offset + callbacks->MemoryRead32(mod_offset + 4)}; VAddr rela_dyn = 0; size_t num_rela = 0; @@ -266,13 +227,15 @@ public: } void InsertHelperFunctions() { - for (const auto& [name, contents] : HELPER_FUNCTIONS) { + for (const auto& name : HELPER_FUNCTIONS) { helpers[name] = local_memory.size(); - local_memory.insert(local_memory.end(), contents.begin(), contents.end()); + local_memory.insert(local_memory.end(), SVC0_ARM64.begin(), SVC0_ARM64.end()); } } void InsertStack() { + // Allocate enough space to avoid any reasonable risk of + // overflowing the stack during plugin execution const u64 pad_amount{Common::AlignUp(local_memory.size(), STACK_ALIGN) - local_memory.size()}; local_memory.insert(local_memory.end(), 0x10000 + pad_amount, 0); @@ -292,9 +255,21 @@ public: } void SetupArguments() { + // The first 8 integer registers are used for the first 8 integer + // arguments. Floating-point arguments are not handled at this time. + // + // If a function takes more than 8 arguments, then stack space is reserved + // for the remaining arguments, and the remaining arguments are inserted in + // ascending memory order, each argument aligned to an 8-byte boundary. The + // stack pointer must remain aligned to 16 bytes. + // + // For more info, see the AArch64 ABI PCS: + // https://github.com/ARM-software/abi-aa/blob/main/aapcs64/aapcs64.rst + for (size_t i = 0; i < 8 && i < argument_stack.size(); i++) { jit->SetRegister(i, argument_stack[i]); } + if (argument_stack.size() > 8) { const VAddr new_sp = Common::AlignDown( top_of_stack - (argument_stack.size() - 8) * sizeof(u64), STACK_ALIGN); @@ -303,6 +278,8 @@ public: } jit->SetSP(new_sp); } + + // Reset the call state for the next invocation argument_stack.clear(); heap_pointer = top_of_stack; } @@ -322,11 +299,16 @@ public: } VAddr AddHeap(const void* data, size_t size) { + // Require all heap data types to have the same alignment as the + // stack pointer, for compatibility const size_t num_bytes{Common::AlignUp(size, STACK_ALIGN)}; + + // Make additional memory space if required if (heap_pointer + num_bytes > local_memory.size()) { local_memory.insert(local_memory.end(), (heap_pointer + num_bytes) - local_memory.size(), 0); } + const VAddr location{heap_pointer}; std::memcpy(local_memory.data() + location, data, size); heap_pointer += num_bytes; @@ -350,30 +332,67 @@ public: }; void DynarmicCallbacks64::CallSVC(u32 swi) { - switch (swi) { - case 0: + // Service calls are used to implement helper functionality. + // + // The most important of these is the _stop helper, which transfers control + // from the plugin back to HLE context to return a value. However, a few more + // are also implemented to reduce the need for direct ARM implementations of + // basic functionality, like memory operations. + // + // When we receive a helper request, the swi number will be zero, and the call + // will have originated from an address we know is a helper function. Otherwise, + // the plugin may be trying to issue a service call, which we shouldn't handle. + + if (swi != 0) { + LOG_CRITICAL(Service_JIT, "plugin issued unknown service call {}", swi); parent.jit->HaltExecution(); - break; + return; + } + + u64 pc{parent.jit->GetPC() - 4}; + auto& helpers{parent.helpers}; + + if (pc == helpers["memcpy"] || pc == helpers["memmove"]) { + const VAddr dest{parent.jit->GetRegister(0)}; + const VAddr src{parent.jit->GetRegister(1)}; + const size_t n{parent.jit->GetRegister(2)}; + + if (dest < src) { + for (size_t i = 0; i < n; i++) { + MemoryWrite8(dest + i, MemoryRead8(src + i)); + } + } else { + for (size_t i = n; i > 0; i--) { + MemoryWrite8(dest + i - 1, MemoryRead8(src + i - 1)); + } + } + } else if (pc == helpers["memset"]) { + const VAddr dest{parent.jit->GetRegister(0)}; + const u64 c{parent.jit->GetRegister(1)}; + const size_t n{parent.jit->GetRegister(2)}; - case 1: { + for (size_t i = 0; i < n; i++) { + MemoryWrite8(dest + i, static_cast<u8>(c)); + } + } else if (pc == helpers["_resolve"]) { // X0 contains a char* for a symbol to resolve - std::string name{MemoryReadCString(parent.jit->GetRegister(0))}; - const auto helper{parent.helpers[name]}; + const auto name{MemoryReadCString(parent.jit->GetRegister(0))}; + const auto helper{helpers[name]}; if (helper != 0) { parent.jit->SetRegister(0, helper); } else { LOG_WARNING(Service_JIT, "plugin requested unknown function {}", name); - parent.jit->SetRegister(0, parent.helpers["_panic"]); + parent.jit->SetRegister(0, helpers["_panic"]); } - break; - } - - case 2: - default: + } else if (pc == helpers["_stop"]) { + parent.jit->HaltExecution(); + } else if (pc == helpers["_panic"]) { LOG_CRITICAL(Service_JIT, "plugin panicked!"); parent.jit->HaltExecution(); - break; + } else { + LOG_CRITICAL(Service_JIT, "plugin issued syscall at unknown address 0x{:x}", pc); + parent.jit->HaltExecution(); } } diff --git a/src/core/hle/service/jit/jit_context.h b/src/core/hle/service/jit/jit_context.h index 3cb935e3c..f17fc5e24 100644 --- a/src/core/hle/service/jit/jit_context.h +++ b/src/core/hle/service/jit/jit_context.h @@ -28,6 +28,7 @@ public: template <typename T, typename... Ts> u64 CallFunction(VAddr func, T argument, Ts... rest) { static_assert(std::is_trivially_copyable_v<T>); + static_assert(!std::is_floating_point_v<T>); PushArgument(&argument, sizeof(argument)); if constexpr (sizeof...(rest) > 0) { diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index 7a1d911eb..7c78d0299 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -127,6 +127,11 @@ void RendererVulkan::SwapBuffers(const Tegra::FramebufferConfig* framebuffer) { if (!render_window.IsShown()) { return; } + // Update screen info if the framebuffer size has changed. + if (screen_info.width != framebuffer->width || screen_info.height != framebuffer->height) { + screen_info.width = framebuffer->width; + screen_info.height = framebuffer->height; + } const VAddr framebuffer_addr = framebuffer->address + framebuffer->offset; const bool use_accelerated = rasterizer.AccelerateDisplay(*framebuffer, framebuffer_addr, framebuffer->stride); diff --git a/src/yuzu/configuration/configure_ui.cpp b/src/yuzu/configuration/configure_ui.cpp index 46e5409db..d3a60cdd1 100644 --- a/src/yuzu/configuration/configure_ui.cpp +++ b/src/yuzu/configuration/configure_ui.cpp @@ -9,6 +9,7 @@ #include <QDirIterator> #include "common/common_types.h" #include "common/fs/path_util.h" +#include "common/logging/log.h" #include "common/settings.h" #include "core/core.h" #include "ui_configure_ui.h" @@ -170,14 +171,74 @@ void ConfigureUi::RetranslateUI() { } void ConfigureUi::InitializeLanguageComboBox() { + // This is a list of lexicographically sorted languages, only the available translations are + // shown to the user. + static const struct { + const QString name; + const char* id; + } languages[] = { + // clang-format off + {QStringLiteral(u"Bahasa Indonesia"), "id"}, // Indonesian + {QStringLiteral(u"Bahasa Melayu"), "ms"}, // Malay + {QStringLiteral(u"Catal\u00E0"), "ca"}, // Catalan + {QStringLiteral(u"\u010Ce\u0161tina"), "cs"}, // Czech + {QStringLiteral(u"Dansk"), "da"}, // Danish + {QStringLiteral(u"Deutsch"), "de"}, // German + {QStringLiteral(u"English"), "en"}, // English + {QStringLiteral(u"Espa\u00F1ol"), "es"}, // Spanish + {QStringLiteral(u"Fran\u00E7ais"), "fr"}, // French + {QStringLiteral(u"Hrvatski"), "hr"}, // Croatian + {QStringLiteral(u"Italiano"), "it"}, // Italian + {QStringLiteral(u"Magyar"), "hu"}, // Hungarian + {QStringLiteral(u"Nederlands"), "nl"}, // Dutch + {QStringLiteral(u"Norsk bokm\u00E5l"), "nb"}, // Norwegian + {QStringLiteral(u"Polski"), "pl"}, // Polish + {QStringLiteral(u"Portugu\u00EAs"), "pt_PT"}, // Portuguese + {QStringLiteral(u"Portugu\u00EAs (Brasil)"), "pt_BR"}, // Portuguese (Brazil) + {QStringLiteral(u"Rom\u00E2n\u0103"), "ro"}, // Romanian + {QStringLiteral(u"Srpski"), "sr"}, // Serbian + {QStringLiteral(u"Suomi"), "fi"}, // Finnish + {QStringLiteral(u"Svenska"), "sv"}, // Swedish + {QStringLiteral(u"Ti\u1EBFng Vi\u1EC7t"), "vi"}, // Vietnamese + {QStringLiteral(u"Ti\u1EBFng Vi\u1EC7t (Vi\u1EC7t Nam)"), "vi_VN"}, // Vietnamese + {QStringLiteral(u"T\u00FCrk\u00E7e"), "tr_TR"}, // Turkish + {QStringLiteral(u"\u0395\u03BB\u03BB\u03B7\u03BD\u03B9\u03BA\u03AC"), "el"}, // Greek + {QStringLiteral(u"\u0420\u0443\u0441\u0441\u043A\u0438\u0439"), "ru_RU"}, // Russian + {QStringLiteral(u"\u0423\u043A\u0440\u0430\u0457\u043D\u0441\u044C\u043A\u0430"), + "uk"}, // Ukrainian + {QStringLiteral(u"\u0627\u0644\u0639\u0631\u0628\u064A\u0629"), "ar"}, // Arabic + {QStringLiteral(u"\u0641\u0627\u0631\u0633\u06CC"), "fa"}, // Farsi + {QStringLiteral(u"\uD55C\uAD6D\uC5B4"), "ko_KR"}, // Korean + {QStringLiteral(u"\u65E5\u672C\u8A9E"), "ja_JP"}, // Japanese + {QStringLiteral(u"\u7B80\u4F53\u4E2D\u6587"), "zh_CN"}, // Simplified Chinese + {QStringLiteral(u"\u7E41\u9AD4\u4E2D\u6587"), "zh_TW"}, // Traditional Chinese + // clang-format on + }; ui->language_combobox->addItem(tr("<System>"), QString{}); - ui->language_combobox->addItem(tr("English"), QStringLiteral("en")); - QDirIterator it(QStringLiteral(":/languages"), QDirIterator::NoIteratorFlags); - while (it.hasNext()) { - QString locale = it.next(); + QDir languages_dir{QStringLiteral(":/languages")}; + QStringList language_files = languages_dir.entryList(); + for (const auto& lang : languages) { + if (QString::fromLatin1(lang.id) == QStringLiteral("en")) { + ui->language_combobox->addItem(lang.name, QStringLiteral("en")); + continue; + } + for (int i = 0; i < language_files.size(); ++i) { + QString locale = language_files[i]; + locale.truncate(locale.lastIndexOf(QLatin1Char{'.'})); + if (QString::fromLatin1(lang.id) == locale) { + ui->language_combobox->addItem(lang.name, locale); + language_files.removeAt(i); + break; + } + } + } + // Anything remaining will be at the bottom + for (const QString& file : language_files) { + LOG_CRITICAL(Frontend, "Unexpected Language File: {}", file.toStdString()); + QString locale = file; locale.truncate(locale.lastIndexOf(QLatin1Char{'.'})); - locale.remove(0, locale.lastIndexOf(QLatin1Char{'/'}) + 1); - const QString lang = QLocale::languageToString(QLocale(locale).language()); + const QString language_name = QLocale::languageToString(QLocale(locale).language()); + const QString lang = QStringLiteral("%1 [%2]").arg(language_name, locale); ui->language_combobox->addItem(lang, locale); } |