diff options
Diffstat (limited to '')
89 files changed, 1683 insertions, 364 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f67f1ce92..6530d3c60 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -120,6 +120,8 @@ add_library(core STATIC file_sys/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h + frontend/applets/cabinet.cpp + frontend/applets/cabinet.h frontend/applets/controller.cpp frontend/applets/controller.h frontend/applets/error.cpp @@ -312,6 +314,8 @@ add_library(core STATIC hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h + hle/service/am/applets/applet_cabinet.cpp + hle/service/am/applets/applet_cabinet.h hle/service/am/applets/applet_controller.cpp hle/service/am/applets/applet_controller.h hle/service/am/applets/applet_error.cpp @@ -526,6 +530,11 @@ add_library(core STATIC hle/service/ncm/ncm.h hle/service/nfc/nfc.cpp hle/service/nfc/nfc.h + hle/service/nfc/nfc_device.cpp + hle/service/nfc/nfc_device.h + hle/service/nfc/nfc_result.h + hle/service/nfc/nfc_user.cpp + hle/service/nfc/nfc_user.h hle/service/nfp/amiibo_crypto.cpp hle/service/nfp/amiibo_crypto.h hle/service/nfp/nfp.cpp @@ -762,6 +771,7 @@ add_library(core STATIC memory.h perf_stats.cpp perf_stats.h + precompiled_headers.h reporter.cpp reporter.h telemetry_session.cpp @@ -816,3 +826,7 @@ if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64) ) target_link_libraries(core PRIVATE dynarmic) endif() + +if (YUZU_USE_PRECOMPILED_HEADERS) + target_precompile_headers(core PRIVATE precompiled_headers.h) +endif() diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index afb7fb3a0..cb53d64ba 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -348,7 +348,6 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } diff --git a/src/core/core.cpp b/src/core/core.cpp index d8934be52..94d4e2212 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -189,7 +189,7 @@ struct System::Impl { kernel.Suspend(false); core_timing.SyncPause(false); - is_paused = false; + is_paused.store(false, std::memory_order_relaxed); return status; } @@ -200,14 +200,13 @@ struct System::Impl { core_timing.SyncPause(true); kernel.Suspend(true); - is_paused = true; + is_paused.store(true, std::memory_order_relaxed); return status; } bool IsPaused() const { - std::unique_lock lk(suspend_guard); - return is_paused; + return is_paused.load(std::memory_order_relaxed); } std::unique_lock<std::mutex> StallProcesses() { @@ -218,7 +217,7 @@ struct System::Impl { } void UnstallProcesses() { - if (!is_paused) { + if (!IsPaused()) { core_timing.SyncPause(false); kernel.Suspend(false); } @@ -465,7 +464,7 @@ struct System::Impl { } mutable std::mutex suspend_guard; - bool is_paused{}; + std::atomic_bool is_paused{}; std::atomic<bool> is_shutting_down{}; Timing::CoreTiming core_timing; diff --git a/src/core/cpu_manager.h b/src/core/cpu_manager.h index 95ea3ef39..374367468 100644 --- a/src/core/cpu_manager.h +++ b/src/core/cpu_manager.h @@ -10,6 +10,7 @@ #include <thread> #include "common/fiber.h" +#include "common/polyfill_thread.h" #include "common/thread.h" #include "core/hardware_properties.h" diff --git a/src/core/crypto/key_manager.cpp b/src/core/crypto/key_manager.cpp index 443323390..65a9fe802 100644 --- a/src/core/crypto/key_manager.cpp +++ b/src/core/crypto/key_manager.cpp @@ -578,18 +578,18 @@ KeyManager::KeyManager() { if (Settings::values.use_dev_keys) { dev_mode = true; - LoadFromFile(yuzu_keys_dir / "dev.keys", false); LoadFromFile(yuzu_keys_dir / "dev.keys_autogenerated", false); + LoadFromFile(yuzu_keys_dir / "dev.keys", false); } else { dev_mode = false; - LoadFromFile(yuzu_keys_dir / "prod.keys", false); LoadFromFile(yuzu_keys_dir / "prod.keys_autogenerated", false); + LoadFromFile(yuzu_keys_dir / "prod.keys", false); } - LoadFromFile(yuzu_keys_dir / "title.keys", true); LoadFromFile(yuzu_keys_dir / "title.keys_autogenerated", true); - LoadFromFile(yuzu_keys_dir / "console.keys", false); + LoadFromFile(yuzu_keys_dir / "title.keys", true); LoadFromFile(yuzu_keys_dir / "console.keys_autogenerated", false); + LoadFromFile(yuzu_keys_dir / "console.keys", false); } static bool ValidCryptoRevisionString(std::string_view base, size_t begin, size_t length) { diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 1a8e02e6a..a9675df76 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -9,6 +9,7 @@ #include <boost/process/async_pipe.hpp> #include "common/logging/log.h" +#include "common/polyfill_thread.h" #include "common/thread.h" #include "core/core.h" #include "core/debugger/debugger.h" diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 78e56bbbd..50303fe42 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -7,6 +7,7 @@ #include <utility> #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "core/crypto/aes_util.h" #include "core/crypto/ctr_encryption_layer.h" #include "core/crypto/key_manager.h" diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp new file mode 100644 index 000000000..26c7fefe3 --- /dev/null +++ b/src/core/frontend/applets/cabinet.cpp @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/frontend/applets/cabinet.h" + +#include <thread> + +namespace Core::Frontend { + +CabinetApplet::~CabinetApplet() = default; + +void DefaultCabinetApplet::ShowCabinetApplet( + const CabinetCallback& callback, const CabinetParameters& parameters, + std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const { + LOG_WARNING(Service_AM, "(STUBBED) called"); + callback(false, {}); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h new file mode 100644 index 000000000..c28a235c1 --- /dev/null +++ b/src/core/frontend/applets/cabinet.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <functional> +#include "core/hle/service/nfp/nfp_types.h" + +namespace Service::NFP { +class NfpDevice; +} // namespace Service::NFP + +namespace Core::Frontend { + +struct CabinetParameters { + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + Service::NFP::CabinetMode mode; +}; + +using CabinetCallback = std::function<void(bool, const std::string&)>; + +class CabinetApplet { +public: + virtual ~CabinetApplet(); + virtual void ShowCabinetApplet(const CabinetCallback& callback, + const CabinetParameters& parameters, + std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0; +}; + +class DefaultCabinetApplet final : public CabinetApplet { +public: + void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, + std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/controller.h b/src/core/frontend/applets/controller.h index 1d2850ad5..71698df74 100644 --- a/src/core/frontend/applets/controller.h +++ b/src/core/frontend/applets/controller.h @@ -4,6 +4,7 @@ #pragma once #include <functional> +#include <vector> #include "common/common_types.h" diff --git a/src/core/frontend/emu_window.h b/src/core/frontend/emu_window.h index ac1906d5e..95363b645 100644 --- a/src/core/frontend/emu_window.h +++ b/src/core/frontend/emu_window.h @@ -17,6 +17,8 @@ enum class WindowSystemType { Windows, X11, Wayland, + Cocoa, + Android, }; /** diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index aac45907d..b6c8cc58d 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() { } void EmulatedConsole::SetTouchParams() { - // TODO(german77): Support any number of fingers std::size_t index = 0; - // Hardcode mouse, touchscreen and cemuhook parameters + // We can't use mouse as touch if native mouse is enabled if (!Settings::values.mouse_enabled) { - // We can't use mouse as touch if native mouse is enabled touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; } touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; + Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; - touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; - touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; - touch_params[index++] = - Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; - touch_params[index++] = - Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; + Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; + + for (int i = 0; i < static_cast<int>(MaxActiveTouchInputs); i++) { + Common::ParamPackage touchscreen_param{}; + touchscreen_param.Set("engine", "touch"); + touchscreen_param.Set("axis_x", i * 2); + touchscreen_param.Set("axis_y", (i * 2) + 1); + touchscreen_param.Set("button", i); + touch_params[index++] = touchscreen_param; + } const auto button_index = static_cast<u64>(Settings::values.touch_from_button_map_index.GetValue()); @@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() { // Map the rest of the fingers from touch from button configuration for (const auto& config_entry : touch_buttons) { - if (index >= touch_params.size()) { + if (index >= MaxTouchDevices) { continue; } Common::ParamPackage params{config_entry}; @@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() { touch_button_params.Set("button", params.Serialize()); touch_button_params.Set("x", x); touch_button_params.Set("y", y); - touch_button_params.Set("touch_id", static_cast<int>(index)); touch_params[index] = touch_button_params; index++; } @@ -70,7 +68,7 @@ void EmulatedConsole::ReloadInput() { // If you load any device here add the equivalent to the UnloadInput() function SetTouchParams(); - motion_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(motion_params); + motion_devices = Common::Input::CreateInputDevice(motion_params); if (motion_devices) { motion_devices->SetCallback({ .on_change = @@ -81,7 +79,7 @@ void EmulatedConsole::ReloadInput() { // Unique index for identifying touch device source std::size_t index = 0; for (auto& touch_device : touch_devices) { - touch_device = Common::Input::CreateDevice<Common::Input::InputDevice>(touch_params[index]); + touch_device = Common::Input::CreateInputDevice(touch_params[index]); if (!touch_device) { continue; } @@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { } void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { - if (index >= console.touch_values.size()) { + if (index >= MaxTouchDevices) { return; } std::unique_lock lock{mutex}; - console.touch_values[index] = TransformToTouch(callback); + const auto touch_input = TransformToTouch(callback); + auto touch_index = GetIndexFromFingerId(index); + bool is_new_input = false; + + if (!touch_index.has_value() && touch_input.pressed.value) { + touch_index = GetNextFreeIndex(); + is_new_input = true; + } + + // No free entries or invalid state. Ignore input + if (!touch_index.has_value()) { + return; + } + + auto& touch_value = console.touch_values[touch_index.value()]; + + if (is_new_input) { + touch_value.pressed.value = true; + touch_value.id = static_cast<u32>(index); + } + + touch_value.x = touch_input.x; + touch_value.y = touch_input.y; + + if (!touch_input.pressed.value) { + touch_value.pressed.value = false; + } if (is_configuring) { lock.unlock(); @@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st return; } - // TODO(german77): Remap touch id in sequential order - console.touch_state[index] = { - .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, - .id = static_cast<u32>(console.touch_values[index].id), - .pressed = console.touch_values[index].pressed.value, + // Touch outside allowed range. Ignore input + if (touch_index.value() >= MaxActiveTouchInputs) { + return; + } + + console.touch_state[touch_index.value()] = { + .position = {touch_value.x.value, touch_value.y.value}, + .id = static_cast<u32>(touch_index.value()), + .pressed = touch_input.pressed.value, }; lock.unlock(); @@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const { return console.touch_state; } +std::optional<std::size_t> EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const { + for (std::size_t index = 0; index < MaxTouchDevices; ++index) { + const auto& finger = console.touch_values[index]; + if (!finger.pressed.value) { + continue; + } + if (finger.id == static_cast<int>(finger_id)) { + return index; + } + } + return std::nullopt; +} + +std::optional<std::size_t> EmulatedConsole::GetNextFreeIndex() const { + for (std::size_t index = 0; index < MaxTouchDevices; ++index) { + if (!console.touch_values[index].pressed.value) { + return index; + } + } + return std::nullopt; +} + void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 1c510cd19..697ecd2d6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -7,6 +7,7 @@ #include <functional> #include <memory> #include <mutex> +#include <optional> #include <unordered_map> #include "common/common_funcs.h" @@ -20,6 +21,8 @@ #include "core/hid/motion_input.h" namespace Core::HID { +static constexpr std::size_t MaxTouchDevices = 32; +static constexpr std::size_t MaxActiveTouchInputs = 16; struct ConsoleMotionInfo { Common::Input::MotionStatus raw_status{}; @@ -27,13 +30,13 @@ struct ConsoleMotionInfo { }; using ConsoleMotionDevices = std::unique_ptr<Common::Input::InputDevice>; -using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, 16>; +using TouchDevices = std::array<std::unique_ptr<Common::Input::InputDevice>, MaxTouchDevices>; using ConsoleMotionParams = Common::ParamPackage; -using TouchParams = std::array<Common::ParamPackage, 16>; +using TouchParams = std::array<Common::ParamPackage, MaxTouchDevices>; using ConsoleMotionValues = ConsoleMotionInfo; -using TouchValues = std::array<Common::Input::TouchStatus, 16>; +using TouchValues = std::array<Common::Input::TouchStatus, MaxTouchDevices>; struct TouchFinger { u64 last_touch{}; @@ -55,7 +58,7 @@ struct ConsoleMotion { bool is_at_rest{}; }; -using TouchFingerState = std::array<TouchFinger, 16>; +using TouchFingerState = std::array<TouchFinger, MaxActiveTouchInputs>; struct ConsoleStatus { // Data from input_common @@ -166,6 +169,10 @@ private: */ void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); + std::optional<std::size_t> GetIndexFromFingerId(std::size_t finger_id) const; + + std::optional<std::size_t> GetNextFreeIndex() const; + /** * Triggers a callback that something has changed on the console status * @param type Input type of the event to trigger diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a2d106245..74c877728 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -1,6 +1,9 @@ // SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include <algorithm> + +#include "common/polyfill_ranges.h" #include "common/thread.h" #include "core/hid/emulated_controller.h" #include "core/hid/input_converter.h" @@ -143,29 +146,23 @@ void EmulatedController::LoadDevices() { LoadTASParams(); - std::transform(button_params.begin() + Settings::NativeButton::BUTTON_HID_BEGIN, - button_params.begin() + Settings::NativeButton::BUTTON_NS_END, - button_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(stick_params.begin() + Settings::NativeAnalog::STICK_HID_BEGIN, - stick_params.begin() + Settings::NativeAnalog::STICK_HID_END, - stick_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(motion_params.begin() + Settings::NativeMotion::MOTION_HID_BEGIN, - motion_params.begin() + Settings::NativeMotion::MOTION_HID_END, - motion_devices.begin(), Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(trigger_params.begin(), trigger_params.end(), trigger_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(battery_params.begin(), battery_params.end(), battery_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); - camera_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(camera_params); - nfc_devices = Common::Input::CreateDevice<Common::Input::InputDevice>(nfc_params); - std::transform(output_params.begin(), output_params.end(), output_devices.begin(), - Common::Input::CreateDevice<Common::Input::OutputDevice>); + std::ranges::transform(button_params, button_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(stick_params, stick_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(motion_params, motion_devices.begin(), Common::Input::CreateInputDevice); + std::ranges::transform(trigger_params, trigger_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(battery_params, battery_devices.begin(), + Common::Input::CreateInputDevice); + camera_devices = Common::Input::CreateInputDevice(camera_params); + nfc_devices = Common::Input::CreateInputDevice(nfc_params); + std::ranges::transform(output_params, output_devices.begin(), + Common::Input::CreateOutputDevice); // Initialize TAS devices - std::transform(tas_button_params.begin(), tas_button_params.end(), tas_button_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); - std::transform(tas_stick_params.begin(), tas_stick_params.end(), tas_stick_devices.begin(), - Common::Input::CreateDevice<Common::Input::InputDevice>); + std::ranges::transform(tas_button_params, tas_button_devices.begin(), + Common::Input::CreateInputDevice); + std::ranges::transform(tas_stick_params, tas_stick_devices.begin(), + Common::Input::CreateInputDevice); } void EmulatedController::LoadTASParams() { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d004ca56a..3f83108d3 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -8,6 +8,7 @@ #include <memory> #include <mutex> #include <unordered_map> +#include <vector> #include "common/common_types.h" #include "common/input.h" diff --git a/src/core/hid/emulated_devices.cpp b/src/core/hid/emulated_devices.cpp index 8d367b546..e421828d2 100644 --- a/src/core/hid/emulated_devices.cpp +++ b/src/core/hid/emulated_devices.cpp @@ -25,12 +25,12 @@ void EmulatedDevices::ReloadInput() { Common::ParamPackage mouse_params; mouse_params.Set("engine", "mouse"); mouse_params.Set("button", static_cast<int>(key_index)); - mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params); + mouse_device = Common::Input::CreateInputDevice(mouse_params); key_index++; } - mouse_stick_device = Common::Input::CreateDeviceFromString<Common::Input::InputDevice>( - "engine:mouse,axis_x:0,axis_y:1"); + mouse_stick_device = + Common::Input::CreateInputDeviceFromString("engine:mouse,axis_x:0,axis_y:1"); // First two axis are reserved for mouse position key_index = 2; @@ -38,7 +38,7 @@ void EmulatedDevices::ReloadInput() { Common::ParamPackage mouse_params; mouse_params.Set("engine", "mouse"); mouse_params.Set("axis", static_cast<int>(key_index)); - mouse_device = Common::Input::CreateDevice<Common::Input::InputDevice>(mouse_params); + mouse_device = Common::Input::CreateInputDevice(mouse_params); key_index++; } @@ -50,7 +50,7 @@ void EmulatedDevices::ReloadInput() { keyboard_params.Set("button", static_cast<int>(key_index)); keyboard_params.Set("port", 1); keyboard_params.Set("pad", 0); - keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params); + keyboard_device = Common::Input::CreateInputDevice(keyboard_params); key_index++; } @@ -62,11 +62,11 @@ void EmulatedDevices::ReloadInput() { keyboard_params.Set("button", static_cast<int>(key_index)); keyboard_params.Set("port", 1); keyboard_params.Set("pad", 1); - keyboard_device = Common::Input::CreateDevice<Common::Input::InputDevice>(keyboard_params); + keyboard_device = Common::Input::CreateInputDevice(keyboard_params); key_index++; } - ring_analog_device = Common::Input::CreateDevice<Common::Input::InputDevice>(ring_params); + ring_analog_device = Common::Input::CreateInputDevice(ring_params); for (std::size_t index = 0; index < mouse_button_devices.size(); ++index) { if (!mouse_button_devices[index]) { @@ -145,6 +145,7 @@ void EmulatedDevices::UnloadInput() { for (auto& button : keyboard_modifier_devices) { button.reset(); } + ring_analog_device.reset(); } void EmulatedDevices::EnableConfiguration() { diff --git a/src/core/hid/emulated_devices.h b/src/core/hid/emulated_devices.h index 4149eeced..4cdbf9dc6 100644 --- a/src/core/hid/emulated_devices.h +++ b/src/core/hid/emulated_devices.h @@ -8,6 +8,7 @@ #include <memory> #include <mutex> #include <unordered_map> +#include <vector> #include "common/common_types.h" #include "common/input.h" diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5d8b75b50..502692875 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& x = std::clamp(x, 0.0f, 1.0f); y = std::clamp(y, 0.0f, 1.0f); - // Limit id to maximum number of fingers - status.id = std::clamp(status.id, 0, 16); - if (status.pressed.inverted) { status.pressed.value = !status.pressed.value; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index d87be72d6..e252b5f4b 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -199,7 +199,7 @@ public: ~HLERequestContext(); /// Returns a pointer to the IPC command buffer for this request. - u32* CommandBuffer() { + [[nodiscard]] u32* CommandBuffer() { return cmd_buf.data(); } @@ -207,7 +207,7 @@ public: * Returns the session through which this request was made. This can be used as a map key to * access per-client data on services. */ - Kernel::KServerSession* Session() { + [[nodiscard]] Kernel::KServerSession* Session() { return server_session; } @@ -217,61 +217,61 @@ public: /// Writes data from this context back to the requesting process/thread. Result WriteToOutgoingCommandBuffer(KThread& requesting_thread); - u32_le GetHipcCommand() const { + [[nodiscard]] u32_le GetHipcCommand() const { return command; } - u32_le GetTipcCommand() const { + [[nodiscard]] u32_le GetTipcCommand() const { return static_cast<u32_le>(command_header->type.Value()) - static_cast<u32_le>(IPC::CommandType::TIPC_CommandRegion); } - u32_le GetCommand() const { + [[nodiscard]] u32_le GetCommand() const { return command_header->IsTipc() ? GetTipcCommand() : GetHipcCommand(); } - bool IsTipc() const { + [[nodiscard]] bool IsTipc() const { return command_header->IsTipc(); } - IPC::CommandType GetCommandType() const { + [[nodiscard]] IPC::CommandType GetCommandType() const { return command_header->type; } - u64 GetPID() const { + [[nodiscard]] u64 GetPID() const { return pid; } - u32 GetDataPayloadOffset() const { + [[nodiscard]] u32 GetDataPayloadOffset() const { return data_payload_offset; } - const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { + [[nodiscard]] const std::vector<IPC::BufferDescriptorX>& BufferDescriptorX() const { return buffer_x_desciptors; } - const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { + [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorA() const { return buffer_a_desciptors; } - const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { + [[nodiscard]] const std::vector<IPC::BufferDescriptorABW>& BufferDescriptorB() const { return buffer_b_desciptors; } - const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { + [[nodiscard]] const std::vector<IPC::BufferDescriptorC>& BufferDescriptorC() const { return buffer_c_desciptors; } - const IPC::DomainMessageHeader& GetDomainMessageHeader() const { + [[nodiscard]] const IPC::DomainMessageHeader& GetDomainMessageHeader() const { return domain_message_header.value(); } - bool HasDomainMessageHeader() const { + [[nodiscard]] bool HasDomainMessageHeader() const { return domain_message_header.has_value(); } /// Helper function to read a buffer using the appropriate buffer descriptor - std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const; + [[nodiscard]] std::vector<u8> ReadBuffer(std::size_t buffer_index = 0) const; /// Helper function to write a buffer using the appropriate buffer descriptor std::size_t WriteBuffer(const void* buffer, std::size_t size, @@ -308,22 +308,34 @@ public: } /// Helper function to get the size of the input buffer - std::size_t GetReadBufferSize(std::size_t buffer_index = 0) const; + [[nodiscard]] std::size_t GetReadBufferSize(std::size_t buffer_index = 0) const; /// Helper function to get the size of the output buffer - std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const; + [[nodiscard]] std::size_t GetWriteBufferSize(std::size_t buffer_index = 0) const; + + /// Helper function to derive the number of elements able to be contained in the read buffer + template <typename T> + [[nodiscard]] std::size_t GetReadBufferNumElements(std::size_t buffer_index = 0) const { + return GetReadBufferSize(buffer_index) / sizeof(T); + } + + /// Helper function to derive the number of elements able to be contained in the write buffer + template <typename T> + [[nodiscard]] std::size_t GetWriteBufferNumElements(std::size_t buffer_index = 0) const { + return GetWriteBufferSize(buffer_index) / sizeof(T); + } /// Helper function to test whether the input buffer at buffer_index can be read - bool CanReadBuffer(std::size_t buffer_index = 0) const; + [[nodiscard]] bool CanReadBuffer(std::size_t buffer_index = 0) const; /// Helper function to test whether the output buffer at buffer_index can be written - bool CanWriteBuffer(std::size_t buffer_index = 0) const; + [[nodiscard]] bool CanWriteBuffer(std::size_t buffer_index = 0) const; - Handle GetCopyHandle(std::size_t index) const { + [[nodiscard]] Handle GetCopyHandle(std::size_t index) const { return incoming_copy_handles.at(index); } - Handle GetMoveHandle(std::size_t index) const { + [[nodiscard]] Handle GetMoveHandle(std::size_t index) const { return incoming_move_handles.at(index); } @@ -348,13 +360,13 @@ public: manager = manager_; } - std::string Description() const; + [[nodiscard]] std::string Description() const; - KThread& GetThread() { + [[nodiscard]] KThread& GetThread() { return *thread; } - std::shared_ptr<SessionRequestManager> GetManager() const { + [[nodiscard]] std::shared_ptr<SessionRequestManager> GetManager() const { return manager.lock(); } diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index bda098511..7b363eb1e 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { // If we somehow get an invalid type, abort. default: ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); + break; } // If we've hit the end of a gap, free it. diff --git a/src/core/hle/kernel/k_handle_table.cpp b/src/core/hle/kernel/k_handle_table.cpp index 1c7a766c8..3535ddc0c 100644 --- a/src/core/hle/kernel/k_handle_table.cpp +++ b/src/core/hle/kernel/k_handle_table.cpp @@ -2,6 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include "core/hle/kernel/k_handle_table.h" +#include "core/hle/kernel/k_process.h" namespace Kernel { @@ -82,6 +83,22 @@ Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) { R_SUCCEED(); } +KScopedAutoObject<KAutoObject> KHandleTable::GetObjectForIpc(Handle handle, + KThread* cur_thread) const { + // Handle pseudo-handles. + ASSERT(cur_thread != nullptr); + if (handle == Svc::PseudoHandle::CurrentProcess) { + auto* const cur_process = cur_thread->GetOwnerProcess(); + ASSERT(cur_process != nullptr); + return cur_process; + } + if (handle == Svc::PseudoHandle::CurrentThread) { + return cur_thread; + } + + return GetObjectForIpcWithoutPseudoHandle(handle); +} + Result KHandleTable::Reserve(Handle* out_handle) { KScopedDisableDispatch dd{m_kernel}; KScopedSpinLock lk(m_lock); diff --git a/src/core/hle/kernel/k_handle_table.h b/src/core/hle/kernel/k_handle_table.h index 65cae3b27..37a24e7d9 100644 --- a/src/core/hle/kernel/k_handle_table.h +++ b/src/core/hle/kernel/k_handle_table.h @@ -113,21 +113,7 @@ public: return this->GetObjectImpl(handle); } - KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const { - // Handle pseudo-handles. - ASSERT(cur_thread != nullptr); - if (handle == Svc::PseudoHandle::CurrentProcess) { - auto* const cur_process = - static_cast<KAutoObject*>(static_cast<void*>(cur_thread->GetOwnerProcess())); - ASSERT(cur_process != nullptr); - return cur_process; - } - if (handle == Svc::PseudoHandle::CurrentThread) { - return static_cast<KAutoObject*>(cur_thread); - } - - return GetObjectForIpcWithoutPseudoHandle(handle); - } + KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const; KScopedAutoObject<KAutoObject> GetObjectByIndex(Handle* out_handle, size_t index) const { KScopedDisableDispatch dd{m_kernel}; diff --git a/src/core/hle/kernel/k_memory_manager.cpp b/src/core/hle/kernel/k_memory_manager.cpp index c4bf306e8..bd33571da 100644 --- a/src/core/hle/kernel/k_memory_manager.cpp +++ b/src/core/hle/kernel/k_memory_manager.cpp @@ -225,8 +225,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, ON_RESULT_FAILURE { for (const auto& it : out->Nodes()) { auto& manager = this->GetManager(it.GetAddress()); - const size_t node_num_pages = - std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); + const size_t node_num_pages = std::min<u64>( + it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize); manager.Free(it.GetAddress(), node_num_pages); } out->Finalize(); diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 5387bf5fe..612fc76fa 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size, break; default: ASSERT(false); + break; } } @@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_ break; default: ASSERT(false); + break; } addr += size; @@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, break; default: ASSERT(false); + break; } R_SUCCEED(); } diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 55a9c5fae..d1dc62401 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: default: ASSERT(false); + break; } // Create TLS region diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index a8c77a7d4..68469b041 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -6,6 +6,7 @@ #include <atomic> #include "common/assert.h" +#include "common/atomic_ops.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "common/spin_lock.h" @@ -82,16 +83,13 @@ private: private: void UpdatePeakImpl(uintptr_t obj) { - static_assert(std::atomic_ref<uintptr_t>::is_always_lock_free); - std::atomic_ref<uintptr_t> peak_ref(m_peak); - const uintptr_t alloc_peak = obj + this->GetObjectSize(); uintptr_t cur_peak = m_peak; do { if (alloc_peak <= cur_peak) { break; } - } while (!peak_ref.compare_exchange_strong(cur_peak, alloc_peak)); + } while (!Common::AtomicCompareAndSwap(&m_peak, alloc_peak, cur_peak, cur_peak)); } public: diff --git a/src/core/hle/kernel/k_thread_local_page.h b/src/core/hle/kernel/k_thread_local_page.h index 5d466ace7..fe0cff084 100644 --- a/src/core/hle/kernel/k_thread_local_page.h +++ b/src/core/hle/kernel/k_thread_local_page.h @@ -10,6 +10,7 @@ #include "common/assert.h" #include "common/common_types.h" #include "common/intrusive_red_black_tree.h" +#include "common/polyfill_ranges.h" #include "core/hle/kernel/memory_types.h" #include "core/hle/kernel/slab_helpers.h" #include "core/hle/result.h" diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index e6e41ac34..0690f9a1c 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -7,6 +7,7 @@ #include <thread> #include <vector> +#include "common/polyfill_thread.h" #include "common/scope_exit.h" #include "common/thread.h" #include "core/hle/ipc_helpers.h" diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9962ad171..e520cab47 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou return ResultSuccess; } -static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, - [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, - [[maybe_unused]] u32 size) { - // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, - // as all emulation is done in the same cache level in host architecture, thus data cache - // does not need flushing. - LOG_DEBUG(Kernel_SVC, "called"); - return ResultSuccess; +static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address, + u64 size) { + // Validate address/size. + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS(address == static_cast<uintptr_t>(address), ResultInvalidCurrentMemory); + R_UNLESS(size == static_cast<size_t>(size), ResultInvalidCurrentMemory); + + // Get the process from its handle. + KScopedAutoObject process = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject<KProcess>(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Verify the region is within range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Perform the operation. + R_RETURN(system.Memory().FlushDataCache(*process, address, size)); } namespace { diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 272c54cf7..1ea8c7fbc 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -82,7 +82,7 @@ void SvcWrap64(Core::System& system) { } // Used by ControlCodeMemory -template <Result func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> +template <Result func(Core::System&, Handle, u32, VAddr, size_t, Svc::MemoryPermission)> void SvcWrap64(Core::System& system) { FuncReturn(system, func(system, static_cast<Handle>(Param(system, 0)), static_cast<u32>(Param(system, 1)), Param(system, 2), Param(system, 3), @@ -327,7 +327,7 @@ void SvcWrap64(Core::System& system) { } // Used by CreateCodeMemory -template <Result func(Core::System&, Handle*, u64, u64)> +template <Result func(Core::System&, Handle*, VAddr, size_t)> void SvcWrap64(Core::System& system) { u32 param_1 = 0; const u32 retval = func(system, ¶m_1, Param(system, 1), Param(system, 2)).raw; @@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by Invalidate/Store/FlushProcessDataCache32 +template <Result func(Core::System&, Handle, u64, u64)> +void SvcWrap32(Core::System& system) { + const u64 address = (Param(system, 3) << 32) | Param(system, 2); + const u64 size = (Param(system, 4) << 32) | Param(system, 1); + FuncReturn32(system, func(system, Param32(system, 0), address, size).raw); +} + } // namespace Kernel diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 85a3f0802..6d1084fd1 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -7,6 +7,7 @@ #include "common/fs/file.h" #include "common/fs/path_util.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/string_util.h" #include "common/swap.h" #include "core/constants.h" diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 481e0d141..97f7c6688 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -9,6 +9,7 @@ #include "common/fs/file.h" #include "common/fs/fs.h" #include "common/fs/path_util.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "core/hle/service/acc/profile_manager.h" diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 8ea7fd760..22999c942 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -1125,7 +1125,7 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { const u64 offset{rp.Pop<u64>()}; const std::vector<u8> data{ctx.ReadBuffer()}; - const std::size_t size{std::min(data.size(), backing.GetSize() - offset)}; + const std::size_t size{std::min<u64>(data.size(), backing.GetSize() - offset)}; LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); @@ -1149,7 +1149,7 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 offset{rp.Pop<u64>()}; - const std::size_t size{std::min(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; + const std::size_t size{std::min<u64>(ctx.GetWriteBufferSize(), backing.GetSize() - offset)}; LOG_DEBUG(Service_AM, "called, offset={}, size={}", offset, size); diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp new file mode 100644 index 000000000..d0969b0f1 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -0,0 +1,177 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/hid/hid_core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/nfp/nfp_device.h" + +namespace Service::AM::Applets { + +Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_) + : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ + system_, + "CabinetApplet"} { + + availability_change_event = + service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); +} + +Cabinet::~Cabinet() = default; + +void Cabinet::Initialize() { + Applet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Cabinet Applet."); + + LOG_DEBUG(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + + const auto applet_input_data = storage->GetData(); + ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); + + std::memcpy(&applet_input_common, applet_input_data.data(), + sizeof(StartParamForAmiiboSettings)); +} + +bool Cabinet::TransactionComplete() const { + return is_complete; +} + +Result Cabinet::GetStatus() const { + return ResultSuccess; +} + +void Cabinet::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void Cabinet::Execute() { + if (is_complete) { + return; + } + + const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { + DisplayCompleted(apply_changes, amiibo_name); + }; + + // TODO: listen on all controllers + if (nfp_device == nullptr) { + nfp_device = std::make_shared<Service::NFP::NfpDevice>( + system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); + nfp_device->Initialize(); + nfp_device->StartDetection(Service::NFP::TagProtocol::All); + } + + const Core::Frontend::CabinetParameters parameters{ + .tag_info = applet_input_common.tag_info, + .register_info = applet_input_common.register_info, + .mode = applet_input_common.applet_mode, + }; + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: + case Service::NFP::CabinetMode::StartGameDataEraser: + case Service::NFP::CabinetMode::StartRestorer: + case Service::NFP::CabinetMode::StartFormatter: + frontend.ShowCabinetApplet(callback, parameters, nfp_device); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + DisplayCompleted(false, {}); + break; + } +} + +void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { + Service::Mii::MiiManager manager; + ReturnValueForAmiiboSettings applet_output{}; + + if (!apply_changes) { + Cancel(); + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && + nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { + Cancel(); + } + + if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { + nfp_device->Mount(Service::NFP::MountTarget::All); + } + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { + Service::NFP::AmiiboName name{}; + std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); + nfp_device->SetNicknameAndOwner(name); + break; + } + case Service::NFP::CabinetMode::StartGameDataEraser: + nfp_device->DeleteApplicationArea(); + break; + case Service::NFP::CabinetMode::StartRestorer: + nfp_device->RestoreAmiibo(); + break; + case Service::NFP::CabinetMode::StartFormatter: + nfp_device->DeleteAllData(); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + break; + } + + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Cancel; + const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); + const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); + nfp_device->Finalize(); + + if (reg_result.IsSuccess()) { + applet_output.result |= CabinetResult::RegisterInfo; + } + + if (tag_result.IsSuccess()) { + applet_output.result |= CabinetResult::TagInfo; + } + + std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +void Cabinet::Cancel() { + ReturnValueForAmiiboSettings applet_output{}; + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Cancel; + nfp_device->Finalize(); + + std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h new file mode 100644 index 000000000..84197a807 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -0,0 +1,104 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> + +#include "core/hle/result.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nfp/nfp_types.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} // namespace Core + +namespace Service::NFP { +class NfpDevice; +} + +namespace Service::AM::Applets { + +enum class CabinetAppletVersion : u32 { + Version1 = 0x1, +}; + +enum class CabinetResult : u8 { + Cancel = 0, + TagInfo = 1 << 1, + RegisterInfo = 1 << 2, + All = TagInfo | RegisterInfo, +}; +DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) + +// This is nn::nfp::AmiiboSettingsStartParam +struct AmiiboSettingsStartParam { + u64 device_handle; + std::array<u8, 0x20> param_1; + u8 param_2; +}; +static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, + "AmiiboSettingsStartParam is an invalid size"); + +#pragma pack(push, 1) +// This is nn::nfp::StartParamForAmiiboSettings +struct StartParamForAmiiboSettings { + u8 param_1; + Service::NFP::CabinetMode applet_mode; + u8 flags; + u8 amiibo_settings_1; + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + std::array<u8, 0x20> amiibo_settings_3; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, + "StartParamForAmiiboSettings is an invalid size"); + +// This is nn::nfp::ReturnValueForAmiiboSettings +struct ReturnValueForAmiiboSettings { + CabinetResult result; + INSERT_PADDING_BYTES(0x3); + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, + "ReturnValueForAmiiboSettings is an invalid size"); +#pragma pack(pop) + +class Cabinet final : public Applet { +public: + explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_); + ~Cabinet() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); + void Cancel(); + +private: + const Core::Frontend::CabinetApplet& frontend; + Core::System& system; + + bool is_complete{false}; + std::shared_ptr<Service::NFP::NfpDevice> nfp_device; + Kernel::KEvent* availability_change_event; + KernelHelpers::ServiceContext service_context; + StartParamForAmiiboSettings applet_input_common{}; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index fcf34bf7e..bae0d99a6 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -144,6 +144,7 @@ void Error::Initialize() { break; default: UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); + break; } } diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c34ef08b3..e50acdaf6 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -129,6 +129,7 @@ void Auth::Execute() { } default: unimplemented_log(); + break; } } @@ -192,6 +193,7 @@ void PhotoViewer::Execute() { break; default: UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); + break; } } diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7062df21c..10afbc2da 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "core/core.h" +#include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" #include "core/frontend/applets/general_frontend.h" @@ -16,6 +17,7 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_controller.h" #include "core/hle/service/am/applets/applet_error.h" #include "core/hle/service/am/applets/applet_general_backend.h" @@ -171,13 +173,15 @@ void Applet::Initialize() { AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, +AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, + ControllerApplet controller_applet, ErrorApplet error_applet, MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) - : controller{std::move(controller_applet)}, error{std::move(error_applet)}, - mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, + : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, + error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, + parental_controls{std::move(parental_controls_applet)}, photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} @@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { } void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { + if (set.cabinet != nullptr) { + frontend.cabinet = std::move(set.cabinet); + } + if (set.controller != nullptr) { frontend.controller = std::move(set.controller); } @@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() { } void AppletManager::SetDefaultAppletsIfMissing() { + if (frontend.cabinet == nullptr) { + frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>(); + } + if (frontend.controller == nullptr) { frontend.controller = std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore()); @@ -279,6 +291,8 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode switch (id) { case AppletId::Auth: return std::make_shared<Auth>(system, mode, *frontend.parental_controls); + case AppletId::Cabinet: + return std::make_shared<Cabinet>(system, mode, *frontend.cabinet); case AppletId::Controller: return std::make_shared<Controller>(system, mode, *frontend.controller); case AppletId::Error: diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 12c6a5b1a..a22eb62a8 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -16,6 +16,7 @@ class System; } namespace Core::Frontend { +class CabinetApplet; class ControllerApplet; class ECommerceApplet; class ErrorApplet; @@ -176,6 +177,7 @@ protected: }; struct AppletFrontendSet { + using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>; using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>; using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>; using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>; @@ -186,10 +188,11 @@ struct AppletFrontendSet { using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>; AppletFrontendSet(); - AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, - MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, - PhotoViewer photo_viewer_, ProfileSelect profile_select_, - SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); + AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, + ErrorApplet error_applet, MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, + ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, + WebBrowser web_browser_); ~AppletFrontendSet(); AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -198,6 +201,7 @@ struct AppletFrontendSet { AppletFrontendSet(AppletFrontendSet&&) noexcept; AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; + CabinetApplet cabinet; ControllerApplet controller; ErrorApplet error; MiiEdit mii_edit; diff --git a/src/core/hle/service/audio/audin_u.cpp b/src/core/hle/service/audio/audin_u.cpp index 608925dfc..053e8f9dd 100644 --- a/src/core/hle/service/audio/audin_u.cpp +++ b/src/core/hle/service/audio/audin_u.cpp @@ -122,10 +122,10 @@ private: } void GetReleasedAudioInBuffer(Kernel::HLERequestContext& ctx) { - auto write_buffer_size = ctx.GetWriteBufferSize() / sizeof(u64); - std::vector<u64> released_buffers(write_buffer_size, 0); + const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); + std::vector<u64> released_buffers(write_buffer_size); - auto count = impl->GetReleasedBuffers(released_buffers); + const auto count = impl->GetReleasedBuffers(released_buffers); [[maybe_unused]] std::string tags{}; for (u32 i = 0; i < count; i++) { @@ -228,7 +228,7 @@ void AudInU::ListAudioIns(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); const auto write_count = - static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName)); + static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); std::vector<AudioDevice::AudioDeviceName> device_names{}; u32 out_count{0}; @@ -248,7 +248,7 @@ void AudInU::ListAudioInsAutoFiltered(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_Audio, "called"); const auto write_count = - static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName)); + static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); std::vector<AudioDevice::AudioDeviceName> device_names{}; u32 out_count{0}; diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index 122290c6a..29751f075 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -129,16 +129,16 @@ private: } void GetReleasedAudioOutBuffers(Kernel::HLERequestContext& ctx) { - auto write_buffer_size = ctx.GetWriteBufferSize() / sizeof(u64); - std::vector<u64> released_buffers(write_buffer_size, 0); + const auto write_buffer_size = ctx.GetWriteBufferNumElements<u64>(); + std::vector<u64> released_buffers(write_buffer_size); - auto count = impl->GetReleasedBuffers(released_buffers); + const auto count = impl->GetReleasedBuffers(released_buffers); [[maybe_unused]] std::string tags{}; for (u32 i = 0; i < count; i++) { tags += fmt::format("{:08X}, ", released_buffers[i]); } - [[maybe_unused]] auto sessionid{impl->GetSystem().GetSessionId()}; + [[maybe_unused]] const auto sessionid{impl->GetSystem().GetSessionId()}; LOG_TRACE(Service_Audio, "called. Session {} released {} buffers: {}", sessionid, count, tags); @@ -244,7 +244,7 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { std::scoped_lock l{impl->mutex}; const auto write_count = - static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName)); + static_cast<u32>(ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>()); std::vector<AudioDevice::AudioDeviceName> device_names{}; if (write_count > 0) { device_names.emplace_back("DeviceOut"); diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 13423dca6..3a1c231b6 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -14,6 +14,7 @@ #include "common/bit_util.h" #include "common/common_funcs.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/string_util.h" #include "core/core.h" #include "core/hle/ipc_helpers.h" @@ -274,7 +275,7 @@ public: private: void ListAudioDeviceName(Kernel::HLERequestContext& ctx) { - const size_t in_count = ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName); + const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>(); std::vector<AudioDevice::AudioDeviceName> out_names{}; @@ -335,7 +336,7 @@ private: } void GetActiveAudioDeviceName(Kernel::HLERequestContext& ctx) { - const auto write_size = ctx.GetWriteBufferSize() / sizeof(char); + const auto write_size = ctx.GetWriteBufferSize(); std::string out_name{"AudioTvOutput"}; LOG_DEBUG(Service_Audio, "(STUBBED) called. Name={}", out_name); @@ -387,7 +388,7 @@ private: } void ListAudioOutputDeviceName(Kernel::HLERequestContext& ctx) { - const size_t in_count = ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName); + const size_t in_count = ctx.GetWriteBufferNumElements<AudioDevice::AudioDeviceName>(); std::vector<AudioDevice::AudioDeviceName> out_names{}; diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 8bafc3a98..825fb8bcc 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp @@ -68,7 +68,7 @@ private: ExtraBehavior extra_behavior) { u32 consumed = 0; u32 sample_count = 0; - std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); + std::vector<opus_int16> samples(ctx.GetWriteBufferNumElements<opus_int16>()); if (extra_behavior == ExtraBehavior::ResetContext) { ResetDecoderContext(); diff --git a/src/core/hle/service/bcat/bcat_module.cpp b/src/core/hle/service/bcat/bcat_module.cpp index bc08ac487..cbe690a5d 100644 --- a/src/core/hle/service/bcat/bcat_module.cpp +++ b/src/core/hle/service/bcat/bcat_module.cpp @@ -443,7 +443,7 @@ private: } void Read(Kernel::HLERequestContext& ctx) { - auto write_size = ctx.GetWriteBufferSize() / sizeof(DeliveryCacheDirectoryEntry); + auto write_size = ctx.GetWriteBufferNumElements<DeliveryCacheDirectoryEntry>(); LOG_DEBUG(Service_BCAT, "called, write_size={:016X}", write_size); @@ -533,7 +533,7 @@ private: } void EnumerateDeliveryCacheDirectory(Kernel::HLERequestContext& ctx) { - auto size = ctx.GetWriteBufferSize() / sizeof(DirectoryName); + auto size = ctx.GetWriteBufferNumElements<DirectoryName>(); LOG_DEBUG(Service_BCAT, "called, size={:016X}", size); diff --git a/src/core/hle/service/es/es.cpp b/src/core/hle/service/es/es.cpp index ff9b0427c..d183e5829 100644 --- a/src/core/hle/service/es/es.cpp +++ b/src/core/hle/service/es/es.cpp @@ -192,12 +192,10 @@ private: } void ListCommonTicketRightsIds(Kernel::HLERequestContext& ctx) { - u32 out_entries; - if (keys.GetCommonTickets().empty()) - out_entries = 0; - else - out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128)); - + size_t out_entries = 0; + if (!keys.GetCommonTickets().empty()) { + out_entries = ctx.GetWriteBufferNumElements<u128>(); + } LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); keys.PopulateTickets(); @@ -206,20 +204,19 @@ private: std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), [](const auto& pair) { return pair.first; }); - out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries)); + out_entries = std::min(ids.size(), out_entries); ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push<u32>(out_entries); + rb.Push<u32>(static_cast<u32>(out_entries)); } void ListPersonalizedTicketRightsIds(Kernel::HLERequestContext& ctx) { - u32 out_entries; - if (keys.GetPersonalizedTickets().empty()) - out_entries = 0; - else - out_entries = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(u128)); + size_t out_entries = 0; + if (!keys.GetPersonalizedTickets().empty()) { + out_entries = ctx.GetWriteBufferNumElements<u128>(); + } LOG_DEBUG(Service_ETicket, "called, entries={:016X}", out_entries); @@ -229,12 +226,12 @@ private: std::transform(tickets.begin(), tickets.end(), std::back_inserter(ids), [](const auto& pair) { return pair.first; }); - out_entries = static_cast<u32>(std::min<std::size_t>(ids.size(), out_entries)); + out_entries = std::min(ids.size(), out_entries); ctx.WriteBuffer(ids.data(), out_entries * sizeof(u128)); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.Push<u32>(out_entries); + rb.Push<u32>(static_cast<u32>(out_entries)); } void GetCommonTicketSize(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index c08274ef9..fbb16a7da 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -277,7 +277,7 @@ private: LOG_DEBUG(Service_FS, "called."); // Calculate how many entries we can fit in the output buffer - const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(FileSys::Entry); + const u64 count_entries = ctx.GetWriteBufferNumElements<FileSys::Entry>(); // Cap at total number of entries. const u64 actual_entries = std::min(count_entries, entries.size() - next_entry_index); @@ -543,7 +543,7 @@ public: LOG_DEBUG(Service_FS, "called"); // Calculate how many entries we can fit in the output buffer - const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); + const u64 count_entries = ctx.GetWriteBufferNumElements<SaveDataInfo>(); // Cap at total number of entries. const u64 actual_entries = std::min(count_entries, info.size() - next_entry_index); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 79375bd2f..bf28440c6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -36,8 +36,9 @@ namespace Service::HID { // Updating period for each HID device. // Period time is obtained by measuring the number of samples in a second on HW using a homebrew -// Correct pad_update_ns is 4ms this is overclocked to lower input lag -constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +// Correct npad_update_ns is 4ms this is overclocked to lower input lag +constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz) constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) @@ -75,11 +76,19 @@ IAppletResource::IAppletResource(Core::System& system_, GetController<Controller_Stubbed>(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); // Register update callbacks - pad_update_event = Core::Timing::CreateEvent( + npad_update_event = Core::Timing::CreateEvent( "HID::UpdatePadCallback", [this](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { const auto guard = LockService(); + UpdateNpad(user_data, ns_late); + return std::nullopt; + }); + default_update_event = Core::Timing::CreateEvent( + "HID::UpdateDefaultCallback", + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional<std::chrono::nanoseconds> { + const auto guard = LockService(); UpdateControllers(user_data, ns_late); return std::nullopt; }); @@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_, return std::nullopt; }); - system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); + system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event); + system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns, + default_update_event); system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, mouse_keyboard_update_event); system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, @@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) { } IAppletResource::~IAppletResource() { - system.CoreTiming().UnscheduleEvent(pad_update_event, 0); + system.CoreTiming().UnscheduleEvent(npad_update_event, 0); + system.CoreTiming().UnscheduleEvent(default_update_event, 0); system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (controller == controllers[static_cast<size_t>(HidController::Mouse)]) { continue; } + // Npad has it's own update event + if (controller == controllers[static_cast<size_t>(HidController::NPad)]) { + continue; + } controller->OnUpdate(core_timing); } } +void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + auto& core_timing = system.CoreTiming(); + + controllers[static_cast<size_t>(HidController::NPad)]->OnUpdate(core_timing); +} + void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 340d26fdc..b7c2a23ef 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -71,12 +71,14 @@ private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); + void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); KernelHelpers::ServiceContext& service_context; - std::shared_ptr<Core::Timing::EventType> pad_update_event; + std::shared_ptr<Core::Timing::EventType> npad_update_event; + std::shared_ptr<Core::Timing::EventType> default_update_event; std::shared_ptr<Core::Timing::EventType> mouse_keyboard_update_event; std::shared_ptr<Core::Timing::EventType> motion_update_event; diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 6df563136..c49c61cff 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -292,7 +292,7 @@ public: void GetNetworkInfoLatestUpdate(Kernel::HLERequestContext& ctx) { const std::size_t network_buffer_size = ctx.GetWriteBufferSize(0); - const std::size_t node_buffer_count = ctx.GetWriteBufferSize(1) / sizeof(NodeLatestUpdate); + const std::size_t node_buffer_count = ctx.GetWriteBufferNumElements<NodeLatestUpdate>(1); if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { LOG_ERROR(Service_LDN, "Invalid buffer, size = {}, count = {}", network_buffer_size, @@ -333,7 +333,7 @@ public: const auto channel{rp.PopEnum<WifiChannel>()}; const auto scan_filter{rp.PopRaw<ScanFilter>()}; - const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo); + const std::size_t network_info_size = ctx.GetWriteBufferNumElements<NetworkInfo>(); if (network_info_size == 0) { LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size); diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 046c5f18f..2f4bacb3b 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -7,6 +7,7 @@ #include "common/settings.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/nfc/nfc.h" +#include "core/hle/service/nfc/nfc_user.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" @@ -97,76 +98,6 @@ private: } }; -class IUser final : public ServiceFramework<IUser> { -public: - explicit IUser(Core::System& system_) : ServiceFramework{system_, "NFC::IUser"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, &IUser::InitializeOld, "InitializeOld"}, - {1, &IUser::FinalizeOld, "FinalizeOld"}, - {2, &IUser::GetStateOld, "GetStateOld"}, - {3, &IUser::IsNfcEnabledOld, "IsNfcEnabledOld"}, - {400, &IUser::InitializeOld, "Initialize"}, - {401, &IUser::FinalizeOld, "Finalize"}, - {402, &IUser::GetStateOld, "GetState"}, - {403, &IUser::IsNfcEnabledOld, "IsNfcEnabled"}, - {404, nullptr, "ListDevices"}, - {405, nullptr, "GetDeviceState"}, - {406, nullptr, "GetNpadId"}, - {407, nullptr, "AttachAvailabilityChangeEvent"}, - {408, nullptr, "StartDetection"}, - {409, nullptr, "StopDetection"}, - {410, nullptr, "GetTagInfo"}, - {411, nullptr, "AttachActivateEvent"}, - {412, nullptr, "AttachDeactivateEvent"}, - {1000, nullptr, "ReadMifare"}, - {1001, nullptr, "WriteMifare"}, - {1300, nullptr, "SendCommandByPassThrough"}, - {1301, nullptr, "KeepPassThroughSession"}, - {1302, nullptr, "ReleasePassThroughSession"}, - }; - // clang-format on - - RegisterHandlers(functions); - } - -private: - enum class NfcStates : u32 { - Finalized = 6, - }; - - void InitializeOld(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFC, "called"); - - IPC::ResponseBuilder rb{ctx, 2, 0}; - rb.Push(ResultSuccess); - // We don't deal with hardware initialization so we can just stub this. - } - - void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFC, "IsNfcEnabledOld"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw<u8>(true); - } - - void GetStateOld(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFC, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushEnum(NfcStates::Finalized); // TODO(ogniK): Figure out if this matches nfp - } - - void FinalizeOld(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFC, "(STUBBED) called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } -}; - class NFC_U final : public ServiceFramework<NFC_U> { public: explicit NFC_U(Core::System& system_) : ServiceFramework{system_, "nfc:user"} { diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp new file mode 100644 index 000000000..4d514cf5f --- /dev/null +++ b/src/core/hle/service/nfc/nfc_device.cpp @@ -0,0 +1,197 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/input.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/nfc/nfc_device.h" +#include "core/hle/service/nfc/nfc_result.h" +#include "core/hle/service/nfc/nfc_user.h" + +namespace Service::NFC { +NfcDevice::NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, + KernelHelpers::ServiceContext& service_context_, + Kernel::KEvent* availability_change_event_) + : npad_id{npad_id_}, system{system_}, service_context{service_context_}, + availability_change_event{availability_change_event_} { + activate_event = service_context.CreateEvent("IUser:NFCActivateEvent"); + deactivate_event = service_context.CreateEvent("IUser:NFCDeactivateEvent"); + npad_device = system.HIDCore().GetEmulatedController(npad_id); + + Core::HID::ControllerUpdateCallback engine_callback{ + .on_change = [this](Core::HID::ControllerTriggerType type) { NpadUpdate(type); }, + .is_npad_service = false, + }; + is_controller_set = true; + callback_key = npad_device->SetCallback(engine_callback); +} + +NfcDevice::~NfcDevice() { + activate_event->Close(); + deactivate_event->Close(); + if (!is_controller_set) { + return; + } + npad_device->DeleteCallback(callback_key); + is_controller_set = false; +}; + +void NfcDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { + if (type == Core::HID::ControllerTriggerType::Connected || + type == Core::HID::ControllerTriggerType::Disconnected) { + availability_change_event->Signal(); + return; + } + + if (type != Core::HID::ControllerTriggerType::Nfc) { + return; + } + + if (!npad_device->IsConnected()) { + return; + } + + const auto nfc_status = npad_device->GetNfc(); + switch (nfc_status.state) { + case Common::Input::NfcState::NewAmiibo: + LoadNfcTag(nfc_status.data); + break; + case Common::Input::NfcState::AmiiboRemoved: + if (device_state != NFP::DeviceState::SearchingForTag) { + CloseNfcTag(); + } + break; + default: + break; + } +} + +bool NfcDevice::LoadNfcTag(std::span<const u8> data) { + if (device_state != NFP::DeviceState::SearchingForTag) { + LOG_ERROR(Service_NFC, "Game is not looking for nfc tag, current state {}", device_state); + return false; + } + + if (data.size() != sizeof(NFP::EncryptedNTAG215File)) { + LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); + return false; + } + + memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); + + device_state = NFP::DeviceState::TagFound; + deactivate_event->GetReadableEvent().Clear(); + activate_event->Signal(); + return true; +} + +void NfcDevice::CloseNfcTag() { + LOG_INFO(Service_NFC, "Remove nfc tag"); + + device_state = NFP::DeviceState::TagRemoved; + encrypted_tag_data = {}; + activate_event->GetReadableEvent().Clear(); + deactivate_event->Signal(); +} + +Kernel::KReadableEvent& NfcDevice::GetActivateEvent() const { + return activate_event->GetReadableEvent(); +} + +Kernel::KReadableEvent& NfcDevice::GetDeactivateEvent() const { + return deactivate_event->GetReadableEvent(); +} + +void NfcDevice::Initialize() { + device_state = + npad_device->HasNfc() ? NFP::DeviceState::Initialized : NFP::DeviceState::Unavailable; + encrypted_tag_data = {}; +} + +void NfcDevice::Finalize() { + if (device_state == NFP::DeviceState::SearchingForTag || + device_state == NFP::DeviceState::TagRemoved) { + StopDetection(); + } + device_state = NFP::DeviceState::Unavailable; +} + +Result NfcDevice::StartDetection(s32 protocol_) { + if (device_state != NFP::DeviceState::Initialized && + device_state != NFP::DeviceState::TagRemoved) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + return WrongDeviceState; + } + + if (!npad_device->SetPollingMode(Common::Input::PollingMode::NFC)) { + LOG_ERROR(Service_NFC, "Nfc not supported"); + return NfcDisabled; + } + + device_state = NFP::DeviceState::SearchingForTag; + protocol = protocol_; + return ResultSuccess; +} + +Result NfcDevice::StopDetection() { + npad_device->SetPollingMode(Common::Input::PollingMode::Active); + + if (device_state == NFP::DeviceState::Initialized) { + return ResultSuccess; + } + + if (device_state == NFP::DeviceState::TagFound || + device_state == NFP::DeviceState::TagMounted) { + CloseNfcTag(); + return ResultSuccess; + } + if (device_state == NFP::DeviceState::SearchingForTag || + device_state == NFP::DeviceState::TagRemoved) { + device_state = NFP::DeviceState::Initialized; + return ResultSuccess; + } + + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + return WrongDeviceState; +} + +Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { + if (device_state != NFP::DeviceState::TagFound && + device_state != NFP::DeviceState::TagMounted) { + LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); + if (device_state == NFP::DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + // Protocol and tag type may change here + tag_info = { + .uuid = encrypted_tag_data.uuid.uid, + .uuid_length = static_cast<u8>(encrypted_tag_data.uuid.uid.size()), + .protocol = NFP::TagProtocol::TypeA, + .tag_type = NFP::TagType::Type2, + }; + + return ResultSuccess; +} + +u64 NfcDevice::GetHandle() const { + // Generate a handle based of the npad id + return static_cast<u64>(npad_id); +} + +NFP::DeviceState NfcDevice::GetCurrentState() const { + return device_state; +} + +Core::HID::NpadIdType NfcDevice::GetNpadId() const { + return npad_id; +} + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h new file mode 100644 index 000000000..fa1348f1a --- /dev/null +++ b/src/core/hle/service/nfc/nfc_device.h @@ -0,0 +1,70 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "common/common_types.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nfp/nfp_types.h" +#include "core/hle/service/service.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} // namespace Core + +namespace Core::HID { +class EmulatedController; +enum class ControllerTriggerType; +enum class NpadIdType : u32; +} // namespace Core::HID + +namespace Service::NFC { +class NfcDevice { +public: + NfcDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, + KernelHelpers::ServiceContext& service_context_, + Kernel::KEvent* availability_change_event_); + ~NfcDevice(); + + void Initialize(); + void Finalize(); + + Result StartDetection(s32 protocol_); + Result StopDetection(); + + Result GetTagInfo(NFP::TagInfo& tag_info) const; + + u64 GetHandle() const; + NFP::DeviceState GetCurrentState() const; + Core::HID::NpadIdType GetNpadId() const; + + Kernel::KReadableEvent& GetActivateEvent() const; + Kernel::KReadableEvent& GetDeactivateEvent() const; + +private: + void NpadUpdate(Core::HID::ControllerTriggerType type); + bool LoadNfcTag(std::span<const u8> data); + void CloseNfcTag(); + + bool is_controller_set{}; + int callback_key; + const Core::HID::NpadIdType npad_id; + Core::System& system; + Core::HID::EmulatedController* npad_device = nullptr; + KernelHelpers::ServiceContext& service_context; + Kernel::KEvent* activate_event = nullptr; + Kernel::KEvent* deactivate_event = nullptr; + Kernel::KEvent* availability_change_event = nullptr; + + s32 protocol{}; + NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; + + NFP::EncryptedNTAG215File encrypted_tag_data{}; +}; + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_result.h b/src/core/hle/service/nfc/nfc_result.h new file mode 100644 index 000000000..537dc15f4 --- /dev/null +++ b/src/core/hle/service/nfc/nfc_result.h @@ -0,0 +1,17 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Service::NFC { + +constexpr Result DeviceNotFound(ErrorModule::NFC, 64); +constexpr Result InvalidArgument(ErrorModule::NFC, 65); +constexpr Result WrongDeviceState(ErrorModule::NFC, 73); +constexpr Result NfcDisabled(ErrorModule::NFC, 80); +constexpr Result TagRemoved(ErrorModule::NFC, 97); +constexpr Result CorruptedData(ErrorModule::NFC, 144); + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp new file mode 100644 index 000000000..ced2d560b --- /dev/null +++ b/src/core/hle/service/nfc/nfc_user.cpp @@ -0,0 +1,365 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/core.h" +#include "core/hid/hid_types.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/service/nfc/nfc_device.h" +#include "core/hle/service/nfc/nfc_result.h" +#include "core/hle/service/nfc/nfc_user.h" +#include "core/hle/service/time/clock_types.h" + +namespace Service::NFC { + +IUser::IUser(Core::System& system_) + : ServiceFramework{system_, "NFC::IUser"}, service_context{system_, service_name} { + static const FunctionInfo functions[] = { + {0, &IUser::Initialize, "InitializeOld"}, + {1, &IUser::Finalize, "FinalizeOld"}, + {2, &IUser::GetState, "GetStateOld"}, + {3, &IUser::IsNfcEnabled, "IsNfcEnabledOld"}, + {400, &IUser::Initialize, "Initialize"}, + {401, &IUser::Finalize, "Finalize"}, + {402, &IUser::GetState, "GetState"}, + {403, &IUser::IsNfcEnabled, "IsNfcEnabled"}, + {404, &IUser::ListDevices, "ListDevices"}, + {405, &IUser::GetDeviceState, "GetDeviceState"}, + {406, &IUser::GetNpadId, "GetNpadId"}, + {407, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, + {408, &IUser::StartDetection, "StartDetection"}, + {409, &IUser::StopDetection, "StopDetection"}, + {410, &IUser::GetTagInfo, "GetTagInfo"}, + {411, &IUser::AttachActivateEvent, "AttachActivateEvent"}, + {412, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {1000, nullptr, "ReadMifare"}, + {1001, nullptr, "WriteMifare"}, + {1300, &IUser::SendCommandByPassThrough, "SendCommandByPassThrough"}, + {1301, nullptr, "KeepPassThroughSession"}, + {1302, nullptr, "ReleasePassThroughSession"}, + }; + RegisterHandlers(functions); + + availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); + + for (u32 device_index = 0; device_index < 10; device_index++) { + devices[device_index] = + std::make_shared<NfcDevice>(Core::HID::IndexToNpadIdType(device_index), system, + service_context, availability_change_event); + } +} + +IUser ::~IUser() { + availability_change_event->Close(); +} + +void IUser::Initialize(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFC, "called"); + + state = State::Initialized; + + for (auto& device : devices) { + device->Initialize(); + } + + IPC::ResponseBuilder rb{ctx, 2, 0}; + rb.Push(ResultSuccess); +} + +void IUser::Finalize(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFC, "called"); + + state = State::NonInitialized; + + for (auto& device : devices) { + device->Finalize(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} + +void IUser::GetState(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NFC, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(state); +} + +void IUser::IsNfcEnabled(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NFC, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(state != State::NonInitialized); +} + +void IUser::ListDevices(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFC, "called"); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + if (!ctx.CanWriteBuffer()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + if (ctx.GetWriteBufferSize() == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(InvalidArgument); + return; + } + + std::vector<u64> nfp_devices; + const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); + + for (auto& device : devices) { + if (nfp_devices.size() >= max_allowed_devices) { + continue; + } + if (device->GetCurrentState() != NFP::DeviceState::Unavailable) { + nfp_devices.push_back(device->GetHandle()); + } + } + + if (nfp_devices.empty()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + ctx.WriteBuffer(nfp_devices); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<s32>(nfp_devices.size())); +} + +void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(device.value()->GetCurrentState()); +} + +void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(device.value()->GetNpadId()); +} + +void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFC, "called"); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(availability_change_event->GetReadableEvent()); +} + +void IUser::StartDetection(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto nfp_protocol{rp.Pop<s32>()}; + LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->StartDetection(nfp_protocol); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IUser::StopDetection(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + const auto result = device.value()->StopDetection(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFC, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + NFP::TagInfo tag_info{}; + const auto result = device.value()->GetTagInfo(tag_info); + ctx.WriteBuffer(tag_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(device.value()->GetActivateEvent()); +} + +void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFC, "called, device_handle={}", device_handle); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(device.value()->GetDeactivateEvent()); +} + +void IUser::SendCommandByPassThrough(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto timeout{rp.PopRaw<Time::Clock::TimeSpanType>()}; + const auto command_data{ctx.ReadBuffer()}; + + LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, timeout={}, data_size={}", + device_handle, timeout.ToSeconds(), command_data.size()); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(NfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(DeviceNotFound); + return; + } + + std::vector<u8> out_data(1); + // TODO: Request data from nfc device + ctx.WriteBuffer(out_data); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<u32>(out_data.size())); +} + +std::optional<std::shared_ptr<NfcDevice>> IUser::GetNfcDevice(u64 handle) { + for (auto& device : devices) { + if (device->GetHandle() == handle) { + return device; + } + } + return std::nullopt; +} + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_user.h b/src/core/hle/service/nfc/nfc_user.h new file mode 100644 index 000000000..a5a4f12f9 --- /dev/null +++ b/src/core/hle/service/nfc/nfc_user.h @@ -0,0 +1,52 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <array> +#include <memory> +#include <optional> + +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/service.h" + +namespace Service::NFC { +class NfcDevice; + +class IUser final : public ServiceFramework<IUser> { +public: + explicit IUser(Core::System& system_); + ~IUser(); + +private: + enum class State : u32 { + NonInitialized, + Initialized, + }; + + void Initialize(Kernel::HLERequestContext& ctx); + void Finalize(Kernel::HLERequestContext& ctx); + void GetState(Kernel::HLERequestContext& ctx); + void IsNfcEnabled(Kernel::HLERequestContext& ctx); + void ListDevices(Kernel::HLERequestContext& ctx); + void GetDeviceState(Kernel::HLERequestContext& ctx); + void GetNpadId(Kernel::HLERequestContext& ctx); + void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx); + void StartDetection(Kernel::HLERequestContext& ctx); + void StopDetection(Kernel::HLERequestContext& ctx); + void GetTagInfo(Kernel::HLERequestContext& ctx); + void AttachActivateEvent(Kernel::HLERequestContext& ctx); + void AttachDeactivateEvent(Kernel::HLERequestContext& ctx); + void SendCommandByPassThrough(Kernel::HLERequestContext& ctx); + + std::optional<std::shared_ptr<NfcDevice>> GetNfcDevice(u64 handle); + + KernelHelpers::ServiceContext service_context; + + std::array<std::shared_ptr<NfcDevice>, 10> devices{}; + + State state{State::NonInitialized}; + Kernel::KEvent* availability_change_event; +}; + +} // namespace Service::NFC diff --git a/src/core/hle/service/nfp/amiibo_crypto.cpp b/src/core/hle/service/nfp/amiibo_crypto.cpp index 167e29572..ffb2f959c 100644 --- a/src/core/hle/service/nfp/amiibo_crypto.cpp +++ b/src/core/hle/service/nfp/amiibo_crypto.cpp @@ -12,7 +12,6 @@ #include "common/fs/fs.h" #include "common/fs/path_util.h" #include "common/logging/log.h" -#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/nfp/amiibo_crypto.h" namespace Service::NFP::AmiiboCrypto { diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index b19672560..c860fd1a1 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -2,10 +2,7 @@ // SPDX-License-Identifier: GPL-2.0-or-later #include <array> -#include <atomic> -#include "common/fs/file.h" -#include "common/fs/path_util.h" #include "common/input.h" #include "common/logging/log.h" #include "common/string_util.h" @@ -19,7 +16,6 @@ #include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/mii/types.h" #include "core/hle/service/nfp/amiibo_crypto.h" -#include "core/hle/service/nfp/nfp.h" #include "core/hle/service/nfp/nfp_device.h" #include "core/hle/service/nfp/nfp_result.h" #include "core/hle/service/nfp/nfp_user.h" @@ -49,6 +45,8 @@ NfpDevice::NfpDevice(Core::HID::NpadIdType npad_id_, Core::System& system_, } NfpDevice::~NfpDevice() { + activate_event->Close(); + deactivate_event->Close(); if (!is_controller_set) { return; } @@ -77,6 +75,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { LoadAmiibo(nfc_status.data); break; case Common::Input::NfcState::AmiiboRemoved: + if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { + break; + } if (device_state != DeviceState::SearchingForTag) { CloseAmiibo(); } @@ -97,6 +98,8 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) { return false; } + // TODO: Filter by allowed_protocols here + memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); device_state = DeviceState::TagFound; @@ -143,7 +146,7 @@ void NfpDevice::Finalize() { device_state = DeviceState::Unavailable; } -Result NfpDevice::StartDetection(s32 protocol_) { +Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); return WrongDeviceState; @@ -155,7 +158,7 @@ Result NfpDevice::StartDetection(s32 protocol_) { } device_state = DeviceState::SearchingForTag; - protocol = protocol_; + allowed_protocols = allowed_protocol; return ResultSuccess; } @@ -469,6 +472,32 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { return ResultSuccess; } +Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { + application_area_id = {}; + + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + if (tag_data.settings.settings.appdata_initialized.Value() == 0) { + LOG_WARNING(Service_NFP, "Application area is not initialized"); + return ApplicationAreaIsNotInitialized; + } + + application_area_id = tag_data.application_area_id; + + return ResultSuccess; +} + Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const { if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 76d0e9ae4..b6a46f2ac 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -3,10 +3,10 @@ #pragma once -#include <array> +#include <span> #include <vector> -#include "common/common_funcs.h" +#include "common/common_types.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nfp/nfp_types.h" #include "core/hle/service/service.h" @@ -37,7 +37,7 @@ public: void Initialize(); void Finalize(); - Result StartDetection(s32 protocol_); + Result StartDetection(TagProtocol allowed_protocol); Result StopDetection(); Result Mount(MountTarget mount_target); Result Unmount(); @@ -53,6 +53,7 @@ public: Result DeleteAllData(); Result OpenApplicationArea(u32 access_id); + Result GetApplicationAreaId(u32& application_area_id) const; Result GetApplicationArea(std::vector<u8>& data) const; Result SetApplicationArea(std::span<const u8> data); Result CreateApplicationArea(u32 access_id, std::span<const u8> data); @@ -88,7 +89,7 @@ private: bool is_data_moddified{}; bool is_app_area_open{}; - s32 protocol{}; + TagProtocol allowed_protocols{}; s64 current_posix_time{}; MountTarget mount_target{MountTarget::None}; DeviceState device_state{DeviceState::Unavailable}; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 63d5917cb..69858096a 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -88,11 +88,22 @@ enum class PackedTagType : u8 { Type5, // ISO15693 RW/RO 540 bytes 106kbit/s }; +// Verify this enum. It might be completely wrong default protocol is 0x48 enum class TagProtocol : u32 { None, - TypeA, // ISO14443A - TypeB, // ISO14443B - TypeF, // Sony Felica + TypeA = 1U << 0, // ISO14443A + TypeB = 1U << 1, // ISO14443B + TypeF = 1U << 2, // Sony Felica + Unknown1 = 1U << 3, + Unknown2 = 1U << 5, + All = 0xFFFFFFFFU, +}; + +enum class CabinetMode : u8 { + StartNicknameAndOwnerSettings, + StartGameDataEraser, + StartRestorer, + StartFormatter, }; using UniqueSerialNumber = std::array<u8, 7>; diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 33e2ef518..49816b4c7 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -1,9 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include <array> -#include <atomic> - #include "common/logging/log.h" #include "core/core.h" #include "core/hid/hid_types.h" @@ -55,8 +52,12 @@ IUser::IUser(Core::System& system_) } } +IUser ::~IUser() { + availability_change_event->Close(); +} + void IUser::Initialize(Kernel::HLERequestContext& ctx) { - LOG_INFO(Service_NFC, "called"); + LOG_INFO(Service_NFP, "called"); state = State::Initialized; @@ -64,7 +65,7 @@ void IUser::Initialize(Kernel::HLERequestContext& ctx) { device->Initialize(); } - IPC::ResponseBuilder rb{ctx, 2, 0}; + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -103,9 +104,9 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { } std::vector<u64> nfp_devices; - const std::size_t max_allowed_devices = ctx.GetWriteBufferSize() / sizeof(u64); + const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); - for (auto& device : devices) { + for (const auto& device : devices) { if (nfp_devices.size() >= max_allowed_devices) { continue; } @@ -114,7 +115,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { } } - if (nfp_devices.size() == 0) { + if (nfp_devices.empty()) { IPC::ResponseBuilder rb{ctx, 2}; rb.Push(DeviceNotFound); return; @@ -130,7 +131,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { void IUser::StartDetection(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop<u64>()}; - const auto nfp_protocol{rp.Pop<s32>()}; + const auto nfp_protocol{rp.PopEnum<TagProtocol>()}; LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); if (state == State::NonInitialized) { @@ -551,9 +552,9 @@ void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { } void IUser::GetState(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFC, "called"); + LOG_DEBUG(Service_NFP, "called"); - IPC::ResponseBuilder rb{ctx, 3, 0}; + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.PushEnum(state); } diff --git a/src/core/hle/service/nfp/nfp_user.h b/src/core/hle/service/nfp/nfp_user.h index 47aff3695..7e9a90af8 100644 --- a/src/core/hle/service/nfp/nfp_user.h +++ b/src/core/hle/service/nfp/nfp_user.h @@ -3,6 +3,10 @@ #pragma once +#include <array> +#include <memory> +#include <optional> + #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/service.h" @@ -12,6 +16,7 @@ class NfpDevice; class IUser final : public ServiceFramework<IUser> { public: explicit IUser(Core::System& system_); + ~IUser(); private: enum class State : u32 { diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index e3ef06481..4fa9f51a6 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -129,6 +129,9 @@ static_assert(sizeof(NifmNetworkProfileData) == 0x18E, "NifmNetworkProfileData has incorrect size."); #pragma pack(pop) +constexpr Result ResultPendingConnection{ErrorModule::NIFM, 111}; +constexpr Result ResultNetworkCommunicationDisabled{ErrorModule::NIFM, 1111}; + class IScanRequest final : public ServiceFramework<IScanRequest> { public: explicit IScanRequest(Core::System& system_) : ServiceFramework{system_, "IScanRequest"} { @@ -192,6 +195,10 @@ private: void Submit(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); + if (state == RequestState::NotSubmitted) { + UpdateState(RequestState::Pending); + } + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } @@ -201,19 +208,32 @@ private: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - - if (Network::GetHostIPv4Address().has_value()) { - rb.PushEnum(RequestState::Connected); - } else { - rb.PushEnum(RequestState::NotSubmitted); - } + rb.PushEnum(state); } void GetResult(Kernel::HLERequestContext& ctx) { LOG_WARNING(Service_NIFM, "(STUBBED) called"); + const auto result = [this] { + const auto has_connection = Network::GetHostIPv4Address().has_value(); + switch (state) { + case RequestState::NotSubmitted: + return has_connection ? ResultSuccess : ResultNetworkCommunicationDisabled; + case RequestState::Pending: + if (has_connection) { + UpdateState(RequestState::Connected); + } else { + UpdateState(RequestState::Error); + } + return ResultPendingConnection; + case RequestState::Connected: + default: + return ResultSuccess; + } + }(); + IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); } void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { @@ -252,8 +272,15 @@ private: rb.Push<u32>(0); } + void UpdateState(RequestState new_state) { + state = new_state; + event1->Signal(); + } + KernelHelpers::ServiceContext service_context; + RequestState state; + Kernel::KEvent* event1; Kernel::KEvent* event2; }; diff --git a/src/core/hle/service/ns/iplatform_service_manager.cpp b/src/core/hle/service/ns/iplatform_service_manager.cpp index fd047ff26..1fab2f0dd 100644 --- a/src/core/hle/service/ns/iplatform_service_manager.cpp +++ b/src/core/hle/service/ns/iplatform_service_manager.cpp @@ -279,13 +279,10 @@ void IPlatformServiceManager::GetSharedFontInOrderOfPriority(Kernel::HLERequestC font_sizes.push_back(region.size); } - // Resize buffers if game requests smaller size output. - font_codes.resize( - std::min<std::size_t>(font_codes.size(), ctx.GetWriteBufferSize(0) / sizeof(u32))); - font_offsets.resize( - std::min<std::size_t>(font_offsets.size(), ctx.GetWriteBufferSize(1) / sizeof(u32))); - font_sizes.resize( - std::min<std::size_t>(font_sizes.size(), ctx.GetWriteBufferSize(2) / sizeof(u32))); + // Resize buffers if game requests smaller size output + font_codes.resize(std::min(font_codes.size(), ctx.GetWriteBufferNumElements<u32>(0))); + font_offsets.resize(std::min(font_offsets.size(), ctx.GetWriteBufferNumElements<u32>(1))); + font_sizes.resize(std::min(font_sizes.size(), ctx.GetWriteBufferNumElements<u32>(2))); ctx.WriteBuffer(font_codes, 0); ctx.WriteBuffer(font_offsets, 1); diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp index eda2041a0..aba51d280 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.cpp @@ -28,13 +28,15 @@ SyncpointManager::SyncpointManager(Tegra::Host1x::Host1x& host1x_) : host1x{host SyncpointManager::~SyncpointManager() = default; u32 SyncpointManager::ReserveSyncpoint(u32 id, bool client_managed) { - if (syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (syncpoint.reserved) { ASSERT_MSG(false, "Requested syncpoint is in use"); return 0; } - syncpoints.at(id).reserved = true; - syncpoints.at(id).interface_managed = client_managed; + syncpoint.reserved = true; + syncpoint.interface_managed = client_managed; return id; } @@ -56,11 +58,12 @@ u32 SyncpointManager::AllocateSyncpoint(bool client_managed) { void SyncpointManager::FreeSyncpoint(u32 id) { std::lock_guard lock(reservation_lock); - ASSERT(syncpoints.at(id).reserved); - syncpoints.at(id).reserved = false; + auto& syncpoint = syncpoints.at(id); + ASSERT(syncpoint.reserved); + syncpoint.reserved = false; } -bool SyncpointManager::IsSyncpointAllocated(u32 id) { +bool SyncpointManager::IsSyncpointAllocated(u32 id) const { return (id <= SyncpointCount) && syncpoints[id].reserved; } @@ -69,7 +72,7 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const { if (!syncpoint.reserved) { ASSERT(false); - return 0; + return false; } // If the interface manages counters then we don't keep track of the maximum value as it handles @@ -82,40 +85,51 @@ bool SyncpointManager::HasSyncpointExpired(u32 id, u32 threshold) const { } u32 SyncpointManager::IncrementSyncpointMaxExt(u32 id, u32 amount) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return 0; } - return syncpoints.at(id).counter_max += amount; + return syncpoint.counter_max += amount; } u32 SyncpointManager::ReadSyncpointMinValue(u32 id) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return 0; } - return syncpoints.at(id).counter_min; + return syncpoint.counter_min; } u32 SyncpointManager::UpdateMin(u32 id) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return 0; } - syncpoints.at(id).counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id); - return syncpoints.at(id).counter_min; + syncpoint.counter_min = host1x.GetSyncpointManager().GetHostSyncpointValue(id); + return syncpoint.counter_min; } NvFence SyncpointManager::GetSyncpointFence(u32 id) { - if (!syncpoints.at(id).reserved) { + auto& syncpoint = syncpoints.at(id); + + if (!syncpoint.reserved) { ASSERT(false); return NvFence{}; } - return {.id = static_cast<s32>(id), .value = syncpoints.at(id).counter_max}; + return { + .id = static_cast<s32>(id), + .value = syncpoint.counter_max, + }; } } // namespace Service::Nvidia::NvCore diff --git a/src/core/hle/service/nvdrv/core/syncpoint_manager.h b/src/core/hle/service/nvdrv/core/syncpoint_manager.h index b76ef9032..4f2cefae5 100644 --- a/src/core/hle/service/nvdrv/core/syncpoint_manager.h +++ b/src/core/hle/service/nvdrv/core/syncpoint_manager.h @@ -44,7 +44,7 @@ public: /** * @brief Checks if the given syncpoint is both allocated and below the number of HW syncpoints */ - bool IsSyncpointAllocated(u32 id); + bool IsSyncpointAllocated(u32 id) const; /** * @brief Finds a free syncpoint and reserves it diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ced57dfe6..b97813fbc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) { return error_notifier_event; case 2: return unknown_event; - default: { + default: LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + return nullptr; } - } - return nullptr; } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 45a759fa8..e123564c6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) { return sm_exception_breakpoint_pause_report_event; case 3: return error_notifier_event; - default: { + default: LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + return nullptr; } - } - return nullptr; } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 9f4c7c99a..6fc8565c0 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp @@ -55,48 +55,40 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger Module::Module(Core::System& system) : container{system.Host1x()}, service_context{system, "nvdrv"}, events_interface{*this} { builders["/dev/nvhost-as-gpu"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_as_gpu>(system, *this, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-gpu"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_gpu>(system, events_interface, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-ctrl-gpu"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_ctrl_gpu>(system, events_interface); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvmap"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvmap>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvmap>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvdisp_disp0"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvdisp_disp0>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvdisp_disp0>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-ctrl"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_ctrl>(system, events_interface, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-nvdec"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_nvdec>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_nvdec>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-nvjpg"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = std::make_shared<Devices::nvhost_nvjpg>(system); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_nvjpg>(system); + return open_files.emplace(fd, std::move(device)).first; }; builders["/dev/nvhost-vic"] = [this, &system](DeviceFD fd) { - std::shared_ptr<Devices::nvdevice> device = - std::make_shared<Devices::nvhost_vic>(system, container); - return open_files.emplace(fd, device).first; + auto device = std::make_shared<Devices::nvhost_vic>(system, container); + return open_files.emplace(fd, std::move(device)).first; }; } diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp index 6d2c92a2c..152bb5bdf 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.cpp @@ -39,7 +39,7 @@ Status BufferItemConsumer::AcquireBuffer(BufferItem* item, std::chrono::nanoseco return Status::NoError; } -Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, Fence& release_fence) { +Status BufferItemConsumer::ReleaseBuffer(const BufferItem& item, const Fence& release_fence) { std::scoped_lock lock{mutex}; if (const auto status = AddReleaseFenceLocked(item.buf, item.graphic_buffer, release_fence); diff --git a/src/core/hle/service/nvflinger/buffer_item_consumer.h b/src/core/hle/service/nvflinger/buffer_item_consumer.h index 69046233d..a5c655d9e 100644 --- a/src/core/hle/service/nvflinger/buffer_item_consumer.h +++ b/src/core/hle/service/nvflinger/buffer_item_consumer.h @@ -22,7 +22,7 @@ public: explicit BufferItemConsumer(std::unique_ptr<BufferQueueConsumer> consumer); Status AcquireBuffer(BufferItem* item, std::chrono::nanoseconds present_when, bool wait_for_fence = true); - Status ReleaseBuffer(const BufferItem& item, Fence& release_fence); + Status ReleaseBuffer(const BufferItem& item, const Fence& release_fence); }; } // namespace Service::android diff --git a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp index 1ce67c771..0767e548d 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_consumer.cpp @@ -169,7 +169,7 @@ Status BufferQueueConsumer::Connect(std::shared_ptr<IConsumerListener> consumer_ return Status::NoInit; } - core->consumer_listener = consumer_listener; + core->consumer_listener = std::move(consumer_listener); core->consumer_controlled_by_app = controlled_by_app; return Status::NoError; diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index ea4a14ea4..3d1338e66 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() { } void BufferQueueCore::SignalDequeueCondition() { + dequeue_possible.store(true); dequeue_condition.notify_all(); } -bool BufferQueueCore::WaitForDequeueCondition() { +bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock<std::mutex>& lk) { if (is_shutting_down) { return false; } - dequeue_condition.wait(mutex); + dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); + dequeue_possible.store(false); return true; } diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index ca6baefaf..85b3bc4c1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -38,7 +38,7 @@ public: private: void SignalDequeueCondition(); - bool WaitForDequeueCondition(); + bool WaitForDequeueCondition(std::unique_lock<std::mutex>& lk); s32 GetMinUndequeuedBufferCountLocked(bool async) const; s32 GetMinMaxBufferCountLocked(bool async) const; @@ -60,7 +60,8 @@ private: BufferQueueDefs::SlotsType slots{}; std::vector<BufferItem> queue; s32 override_max_buffer_count{}; - mutable std::condition_variable_any dequeue_condition; + std::condition_variable dequeue_condition; + std::atomic<bool> dequeue_possible{}; const bool use_async_buffer{}; // This is always disabled on HOS bool dequeue_buffer_cannot_block{}; PixelFormat default_buffer_format{PixelFormat::Rgba8888}; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 41ba44b21..e601b5da1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { return Status::NoError; } -Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, - Status* return_flags) const { +Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, + std::unique_lock<std::mutex>& lk) const { bool try_again = true; while (try_again) { @@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, return Status::WouldBlock; } - if (!core->WaitForDequeueCondition()) { + if (!core->WaitForDequeueCondition(lk)) { // We are no longer running return Status::NoError; } @@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool Status return_flags = Status::NoError; bool attached_by_consumer = false; { - std::scoped_lock lock{core->mutex}; + std::unique_lock lock{core->mutex}; core->WaitWhileAllocatingLocked(); if (format == PixelFormat::NoFormat) { @@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool usage |= core->consumer_usage_bit; s32 found{}; - Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); + Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock); if (status != Status::NoError) { return status; } @@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot, return Status::BadValue; } - std::scoped_lock lock{core->mutex}; + std::unique_lock lock{core->mutex}; core->WaitWhileAllocatingLocked(); Status return_flags = Status::NoError; s32 found{}; - const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); + const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock); if (status != Status::NoError) { return status; } diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index 7526bf8ec..1d380480f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -70,7 +70,8 @@ public: private: BufferQueueProducer(const BufferQueueProducer&) = delete; - Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; + Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, + std::unique_lock<std::mutex>& lk) const; Kernel::KEvent* buffer_wait_event{}; Service::KernelHelpers::ServiceContext& service_context; diff --git a/src/core/hle/service/nvflinger/consumer_base.cpp b/src/core/hle/service/nvflinger/consumer_base.cpp index 5b9995854..982531e2d 100644 --- a/src/core/hle/service/nvflinger/consumer_base.cpp +++ b/src/core/hle/service/nvflinger/consumer_base.cpp @@ -83,7 +83,7 @@ Status ConsumerBase::AcquireBufferLocked(BufferItem* item, std::chrono::nanoseco } Status ConsumerBase::AddReleaseFenceLocked(s32 slot, - const std::shared_ptr<GraphicBuffer> graphic_buffer, + const std::shared_ptr<GraphicBuffer>& graphic_buffer, const Fence& fence) { LOG_DEBUG(Service_NVFlinger, "slot={}", slot); @@ -100,7 +100,7 @@ Status ConsumerBase::AddReleaseFenceLocked(s32 slot, } Status ConsumerBase::ReleaseBufferLocked(s32 slot, - const std::shared_ptr<GraphicBuffer> graphic_buffer) { + const std::shared_ptr<GraphicBuffer>& graphic_buffer) { // If consumer no longer tracks this graphic_buffer (we received a new // buffer on the same slot), the buffer producer is definitely no longer // tracking it. @@ -121,7 +121,7 @@ Status ConsumerBase::ReleaseBufferLocked(s32 slot, } bool ConsumerBase::StillTracking(s32 slot, - const std::shared_ptr<GraphicBuffer> graphic_buffer) const { + const std::shared_ptr<GraphicBuffer>& graphic_buffer) const { if (slot < 0 || slot >= BufferQueueDefs::NUM_BUFFER_SLOTS) { return false; } diff --git a/src/core/hle/service/nvflinger/consumer_base.h b/src/core/hle/service/nvflinger/consumer_base.h index 90ba07f45..9a8a5f6bb 100644 --- a/src/core/hle/service/nvflinger/consumer_base.h +++ b/src/core/hle/service/nvflinger/consumer_base.h @@ -27,18 +27,18 @@ public: protected: explicit ConsumerBase(std::unique_ptr<BufferQueueConsumer> consumer_); - virtual ~ConsumerBase(); + ~ConsumerBase() override; - virtual void OnFrameAvailable(const BufferItem& item) override; - virtual void OnFrameReplaced(const BufferItem& item) override; - virtual void OnBuffersReleased() override; - virtual void OnSidebandStreamChanged() override; + void OnFrameAvailable(const BufferItem& item) override; + void OnFrameReplaced(const BufferItem& item) override; + void OnBuffersReleased() override; + void OnSidebandStreamChanged() override; void FreeBufferLocked(s32 slot_index); Status AcquireBufferLocked(BufferItem* item, std::chrono::nanoseconds present_when); - Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer); - bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer) const; - Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer> graphic_buffer, + Status ReleaseBufferLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer); + bool StillTracking(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer) const; + Status AddReleaseFenceLocked(s32 slot, const std::shared_ptr<GraphicBuffer>& graphic_buffer, const Fence& fence); struct Slot final { diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index c3af12c90..d1cbadde4 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp @@ -307,8 +307,7 @@ void NVFlinger::Compose() { swap_interval = buffer.swap_interval; - auto fence = android::Fence::NoFence(); - layer.GetConsumer().ReleaseBuffer(buffer, fence); + layer.GetConsumer().ReleaseBuffer(buffer, android::Fence::NoFence()); } } diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 460bef976..9b22397db 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h @@ -11,6 +11,7 @@ #include <vector> #include "common/common_types.h" +#include "common/polyfill_thread.h" #include "core/hle/result.h" #include "core/hle/service/kernel_helpers.h" diff --git a/src/core/hle/service/nvflinger/producer_listener.h b/src/core/hle/service/nvflinger/producer_listener.h index 1c4d5db0e..6bf8aaf1e 100644 --- a/src/core/hle/service/nvflinger/producer_listener.h +++ b/src/core/hle/service/nvflinger/producer_listener.h @@ -10,6 +10,7 @@ namespace Service::android { class IProducerListener { public: + virtual ~IProducerListener() = default; virtual void OnBufferReleased() = 0; }; diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5ab41c0c4..0de67f1e1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, } UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); + break; } // If emulation was shutdown, we are closing service threads, do not write the response back to diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index f761c2da4..4f1a8d6b7 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp @@ -83,7 +83,7 @@ void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t num_la } void GetAvailableLanguageCodesImpl(Kernel::HLERequestContext& ctx, std::size_t max_entries) { - const std::size_t requested_amount = ctx.GetWriteBufferSize() / sizeof(LanguageCode); + const std::size_t requested_amount = ctx.GetWriteBufferNumElements<LanguageCode>(); const std::size_t max_amount = std::min(requested_amount, max_entries); const std::size_t copy_amount = std::min(available_language_codes.size(), max_amount); const std::size_t copy_size = copy_amount * sizeof(LanguageCode); diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 2aa675df9..f9ada7c93 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) { } default: ASSERT(false); + break; } return value + rule.transition_time + offset; } diff --git a/src/core/internal_network/network_interface.cpp b/src/core/internal_network/network_interface.cpp index 057fd3661..7b8e510a2 100644 --- a/src/core/internal_network/network_interface.cpp +++ b/src/core/internal_network/network_interface.cpp @@ -9,6 +9,7 @@ #include "common/bit_cast.h" #include "common/common_types.h" #include "common/logging/log.h" +#include "common/polyfill_ranges.h" #include "common/settings.h" #include "common/string_util.h" #include "core/internal_network/network_interface.h" diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3ca80c8ff..3141122f1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -6,6 +6,7 @@ #include "common/assert.h" #include "common/atomic_ops.h" +#include "common/cache_management.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/page_table.h" @@ -329,6 +330,55 @@ struct Memory::Impl { }); } + template <typename Callback> + Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size, + Callback&& cb) { + class InvalidMemoryException : public std::exception {}; + + try { + WalkBlock( + process, dest_addr, size, + [&](const std::size_t block_size, const VAddr current_vaddr) { + LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); + throw InvalidMemoryException(); + }, + [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); }, + [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { + system.GPU().FlushRegion(current_vaddr, block_size); + cb(block_size, host_ptr); + }, + [](const std::size_t block_size) {}); + } catch (InvalidMemoryException&) { + return Kernel::ResultInvalidCurrentMemory; + } + + return ResultSuccess; + } + + Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // Do nothing; this operation (dc ivac) cannot be supported + // from EL0 + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + + Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // dc cvac: Store to point of coherency + Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size); + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + + Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // dc civac: Store to point of coherency, and invalidate from cache + Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size); + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { if (vaddr == 0) { return; @@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s impl->ZeroBlock(process, dest_addr, size); } +Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->InvalidateDataCache(process, dest_addr, size); +} + +Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->StoreDataCache(process, dest_addr, size); +} + +Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->FlushDataCache(process, dest_addr, size); +} + void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { impl->RasterizerMarkRegionCached(vaddr, size, cached); } diff --git a/src/core/memory.h b/src/core/memory.h index 81eac448b..31fe699d8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -7,6 +7,7 @@ #include <memory> #include <string> #include "common/common_types.h" +#include "core/hle/result.h" namespace Common { struct PageTable; @@ -450,6 +451,39 @@ public: void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); /** + * Invalidates a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data invalidated within its address space. + * @param dest_addr The destination virtual address to invalidate the data from. + * @param size The size of the range to invalidate, in bytes. + * + */ + Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** + * Stores a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data stored within its address space. + * @param dest_addr The destination virtual address to store the data from. + * @param size The size of the range to store, in bytes. + * + */ + Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** + * Flushes a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data flushed within its address space. + * @param dest_addr The destination virtual address to flush the data from. + * @param size The size of the range to flush, in bytes. + * + */ + Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** * Marks each page within the specified address range as cached or uncached. * * @param vaddr The virtual address indicating the start of the address range. diff --git a/src/core/memory/dmnt_cheat_vm.cpp b/src/core/memory/dmnt_cheat_vm.cpp index de96fcb8e..31ffc4fbb 100644 --- a/src/core/memory/dmnt_cheat_vm.cpp +++ b/src/core/memory/dmnt_cheat_vm.cpp @@ -761,7 +761,7 @@ void DmntCheatVm::Execute(const CheatProcessMetadata& metadata) { u64 src_address = GetCheatProcessAddress(metadata, begin_cond->mem_type, begin_cond->rel_address); u64 src_value = 0; - switch (store_static->bit_width) { + switch (begin_cond->bit_width) { case 1: case 2: case 4: diff --git a/src/core/precompiled_headers.h b/src/core/precompiled_headers.h new file mode 100644 index 000000000..30a31001d --- /dev/null +++ b/src/core/precompiled_headers.h @@ -0,0 +1,11 @@ +// SPDX-FileCopyrightText: 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include <boost/container/flat_map.hpp> // used by service.h which is heavily included +#include <boost/intrusive/rbtree.hpp> // used by k_auto_object.h which is heavily included + +#include "common/common_precompiled_headers.h" + +#include "core/hle/kernel/k_process.h" diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp index abcf6eb11..8d5f2be2f 100644 --- a/src/core/telemetry_session.cpp +++ b/src/core/telemetry_session.cpp @@ -55,6 +55,8 @@ static const char* TranslateRenderer(Settings::RendererBackend backend) { return "OpenGL"; case Settings::RendererBackend::Vulkan: return "Vulkan"; + case Settings::RendererBackend::Null: + return "Null"; } return "Unknown"; } |