diff options
Diffstat (limited to 'src/core/hle')
33 files changed, 1341 insertions, 357 deletions
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index f4072e1c3..ce7fa8275 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -17,7 +17,6 @@ #include "common/thread.h" #include "common/thread_worker.h" #include "core/arm/arm_interface.h" -#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/exclusive_monitor.h" #include "core/core.h" #include "core/core_timing.h" @@ -82,7 +81,7 @@ struct KernelCore::Impl { void InitializeCores() { for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) { - cores[core_id].Initialize((*current_process).Is64BitProcess()); + cores[core_id]->Initialize((*current_process).Is64BitProcess()); system.Memory().SetCurrentPageTable(*current_process, core_id); } } @@ -100,7 +99,9 @@ struct KernelCore::Impl { next_user_process_id = KProcess::ProcessIDMin; next_thread_id = 1; - cores.clear(); + for (auto& core : cores) { + core = nullptr; + } global_handle_table->Finalize(); global_handle_table.reset(); @@ -199,7 +200,7 @@ struct KernelCore::Impl { const s32 core{static_cast<s32>(i)}; schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel()); - cores.emplace_back(i, system, *schedulers[i], interrupts); + cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]); auto* main_thread{Kernel::KThread::Create(system.Kernel())}; main_thread->SetName(fmt::format("MainThread:{}", core)); @@ -761,7 +762,7 @@ struct KernelCore::Impl { std::unordered_set<KAutoObject*> registered_in_use_objects; std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor; - std::vector<Kernel::PhysicalCore> cores; + std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES}; @@ -785,7 +786,6 @@ struct KernelCore::Impl { Common::ThreadWorker service_threads_manager; std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; - std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{}; std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; @@ -874,11 +874,11 @@ const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const { } Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) { - return impl->cores[id]; + return *impl->cores[id]; } const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const { - return impl->cores[id]; + return *impl->cores[id]; } size_t KernelCore::CurrentPhysicalCoreIndex() const { @@ -890,11 +890,11 @@ size_t KernelCore::CurrentPhysicalCoreIndex() const { } Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() { - return impl->cores[CurrentPhysicalCoreIndex()]; + return *impl->cores[CurrentPhysicalCoreIndex()]; } const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const { - return impl->cores[CurrentPhysicalCoreIndex()]; + return *impl->cores[CurrentPhysicalCoreIndex()]; } Kernel::KScheduler* KernelCore::CurrentScheduler() { @@ -906,15 +906,6 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() { return impl->schedulers[core_id].get(); } -std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() { - return impl->interrupts; -} - -const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() - const { - return impl->interrupts; -} - Kernel::TimeManager& KernelCore::TimeManager() { return impl->time_manager; } @@ -939,24 +930,18 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const { return *impl->global_object_list_container; } -void KernelCore::InterruptAllPhysicalCores() { - for (auto& physical_core : impl->cores) { - physical_core.Interrupt(); - } -} - void KernelCore::InvalidateAllInstructionCaches() { for (auto& physical_core : impl->cores) { - physical_core.ArmInterface().ClearInstructionCache(); + physical_core->ArmInterface().ClearInstructionCache(); } } void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) { for (auto& physical_core : impl->cores) { - if (!physical_core.IsInitialized()) { + if (!physical_core->IsInitialized()) { continue; } - physical_core.ArmInterface().InvalidateCacheRange(addr, size); + physical_core->ArmInterface().InvalidateCacheRange(addr, size); } } diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 6c7cf6af2..bcf016a97 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h @@ -9,14 +9,12 @@ #include <string> #include <unordered_map> #include <vector> -#include "core/arm/cpu_interrupt_handler.h" #include "core/hardware_properties.h" #include "core/hle/kernel/k_auto_object.h" #include "core/hle/kernel/k_slab_heap.h" #include "core/hle/kernel/svc_common.h" namespace Core { -class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -183,12 +181,6 @@ public: const KAutoObjectWithListContainer& ObjectListContainer() const; - std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts(); - - const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const; - - void InterruptAllPhysicalCores(); - void InvalidateAllInstructionCaches(); void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size); diff --git a/src/core/hle/kernel/physical_core.cpp b/src/core/hle/kernel/physical_core.cpp index 6e7dacf97..d4375962f 100644 --- a/src/core/hle/kernel/physical_core.cpp +++ b/src/core/hle/kernel/physical_core.cpp @@ -1,7 +1,6 @@ // SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later -#include "core/arm/cpu_interrupt_handler.h" #include "core/arm/dynarmic/arm_dynarmic_32.h" #include "core/arm/dynarmic/arm_dynarmic_64.h" #include "core/core.h" @@ -11,16 +10,14 @@ namespace Kernel { -PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, - Core::CPUInterrupts& interrupts_) - : core_index{core_index_}, system{system_}, scheduler{scheduler_}, - interrupts{interrupts_}, guard{std::make_unique<std::mutex>()} { +PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_) + : core_index{core_index_}, system{system_}, scheduler{scheduler_} { #ifdef ARCHITECTURE_x86_64 // TODO(bunnei): Initialization relies on a core being available. We may later replace this with // a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager. auto& kernel = system.Kernel(); arm_interface = std::make_unique<Core::ARM_Dynarmic_64>( - system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); + system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); #else #error Platform not supported yet. #endif @@ -34,7 +31,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) { if (!is_64_bit) { // We already initialized a 64-bit core, replace with a 32-bit one. arm_interface = std::make_unique<Core::ARM_Dynarmic_32>( - system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); + system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index); } #else #error Platform not supported yet. @@ -47,24 +44,26 @@ void PhysicalCore::Run() { } void PhysicalCore::Idle() { - interrupts[core_index].AwaitInterrupt(); + std::unique_lock lk{guard}; + on_interrupt.wait(lk, [this] { return is_interrupted; }); } bool PhysicalCore::IsInterrupted() const { - return interrupts[core_index].IsInterrupted(); + return is_interrupted; } void PhysicalCore::Interrupt() { - guard->lock(); - interrupts[core_index].SetInterrupt(true); + std::unique_lock lk{guard}; + is_interrupted = true; arm_interface->SignalInterrupt(); - guard->unlock(); + on_interrupt.notify_all(); } void PhysicalCore::ClearInterrupt() { - guard->lock(); - interrupts[core_index].SetInterrupt(false); - guard->unlock(); + std::unique_lock lk{guard}; + is_interrupted = false; + arm_interface->ClearInterrupt(); + on_interrupt.notify_all(); } } // namespace Kernel diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 898d1e5db..2fc8d4be2 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -14,7 +14,6 @@ class KScheduler; } // namespace Kernel namespace Core { -class CPUInterruptHandler; class ExclusiveMonitor; class System; } // namespace Core @@ -23,15 +22,11 @@ namespace Kernel { class PhysicalCore { public: - PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_, - Core::CPUInterrupts& interrupts_); + PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_); ~PhysicalCore(); - PhysicalCore(const PhysicalCore&) = delete; - PhysicalCore& operator=(const PhysicalCore&) = delete; - - PhysicalCore(PhysicalCore&&) = default; - PhysicalCore& operator=(PhysicalCore&&) = delete; + YUZU_NON_COPYABLE(PhysicalCore); + YUZU_NON_MOVEABLE(PhysicalCore); /// Initialize the core for the specified parameters. void Initialize(bool is_64_bit); @@ -86,9 +81,11 @@ private: const std::size_t core_index; Core::System& system; Kernel::KScheduler& scheduler; - Core::CPUInterrupts& interrupts; - std::unique_ptr<std::mutex> guard; + + std::mutex guard; + std::condition_variable on_interrupt; std::unique_ptr<Core::ARM_Interface> arm_interface; + bool is_interrupted; }; } // namespace Kernel diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 4de44cd06..47a1b829b 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -117,6 +117,7 @@ union Result { BitField<0, 9, ErrorModule> module; BitField<9, 13, u32> description; + Result() = default; constexpr explicit Result(u32 raw_) : raw(raw_) {} constexpr Result(ErrorModule module_, u32 description_) @@ -130,6 +131,7 @@ union Result { return !IsSuccess(); } }; +static_assert(std::is_trivial_v<Result>); [[nodiscard]] constexpr bool operator==(const Result& a, const Result& b) { return a.raw == b.raw; diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index def105832..bb838e285 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -534,7 +534,7 @@ public: private: void CheckAvailability(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_ACC, "(STUBBED) called"); + LOG_DEBUG(Service_ACC, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); rb.Push(false); // TODO: Check when this is supposed to return true and when not diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 118f226e4..6fb7e198e 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -754,7 +754,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { } void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_AM, "(STUBBED) called"); + LOG_DEBUG(Service_AM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/am/applets/applet_web_browser.cpp b/src/core/hle/service/am/applets/applet_web_browser.cpp index 4b804b78c..14aa6f69e 100644 --- a/src/core/hle/service/am/applets/applet_web_browser.cpp +++ b/src/core/hle/service/am/applets/applet_web_browser.cpp @@ -21,7 +21,7 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applets/applet_web_browser.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/ns/pl_u.h" +#include "core/hle/service/ns/iplatform_service_manager.h" #include "core/loader/loader.h" namespace Service::AM::Applets { diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp index 4e710491b..d6de84066 100644 --- a/src/core/hle/service/apm/apm_controller.cpp +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -80,7 +80,7 @@ PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(Performa } void Controller::SetClockSpeed(u32 mhz) { - LOG_INFO(Service_APM, "called, mhz={:08X}", mhz); + LOG_DEBUG(Service_APM, "called, mhz={:08X}", mhz); // TODO(DarkLordZach): Actually signal core_timing to change clock speed. // TODO(Rodrigo): Remove [[maybe_unused]] when core_timing is used. } diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index a44dd842a..49c092301 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp @@ -246,9 +246,8 @@ void AudOutU::ListAudioOuts(Kernel::HLERequestContext& ctx) { const auto write_count = static_cast<u32>(ctx.GetWriteBufferSize() / sizeof(AudioDevice::AudioDeviceName)); std::vector<AudioDevice::AudioDeviceName> device_names{}; - std::string print_names{}; if (write_count > 0) { - device_names.push_back(AudioDevice::AudioDeviceName("DeviceOut")); + device_names.emplace_back("DeviceOut"); LOG_DEBUG(Service_Audio, "called. \nName=DeviceOut"); } else { LOG_DEBUG(Service_Audio, "called. Empty buffer passed in."); diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index 381a66ba5..6fb07c37d 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp @@ -50,7 +50,7 @@ public: {7, &IAudioRenderer::QuerySystemEvent, "QuerySystemEvent"}, {8, &IAudioRenderer::SetRenderingTimeLimit, "SetRenderingTimeLimit"}, {9, &IAudioRenderer::GetRenderingTimeLimit, "GetRenderingTimeLimit"}, - {10, nullptr, "RequestUpdateAuto"}, + {10, &IAudioRenderer::RequestUpdate, "RequestUpdateAuto"}, {11, nullptr, "ExecuteAudioRendererRendering"}, }; // clang-format on @@ -113,15 +113,30 @@ private: // These buffers are written manually to avoid an issue with WriteBuffer throwing errors for // checking size 0. Performance size is 0 for most games. - const auto buffers{ctx.BufferDescriptorB()}; - std::vector<u8> output(buffers[0].Size(), 0); - std::vector<u8> performance(buffers[1].Size(), 0); + + std::vector<u8> output{}; + std::vector<u8> performance{}; + auto is_buffer_b{ctx.BufferDescriptorB()[0].Size() != 0}; + if (is_buffer_b) { + const auto buffersB{ctx.BufferDescriptorB()}; + output.resize(buffersB[0].Size(), 0); + performance.resize(buffersB[1].Size(), 0); + } else { + const auto buffersC{ctx.BufferDescriptorC()}; + output.resize(buffersC[0].Size(), 0); + performance.resize(buffersC[1].Size(), 0); + } auto result = impl->RequestUpdate(input, performance, output); if (result.IsSuccess()) { - ctx.WriteBufferB(output.data(), output.size(), 0); - ctx.WriteBufferB(performance.data(), performance.size(), 1); + if (is_buffer_b) { + ctx.WriteBufferB(output.data(), output.size(), 0); + ctx.WriteBufferB(performance.data(), performance.size(), 1); + } else { + ctx.WriteBufferC(output.data(), output.size(), 0); + ctx.WriteBufferC(performance.data(), performance.size(), 1); + } } else { LOG_ERROR(Service_Audio, "RequestUpdate failed error 0x{:02X}!", result.description); } @@ -237,7 +252,7 @@ private: std::vector<AudioDevice::AudioDeviceName> out_names{}; - u32 out_count = impl->ListAudioDeviceName(out_names, in_count); + const u32 out_count = impl->ListAudioDeviceName(out_names, in_count); std::string out{}; for (u32 i = 0; i < out_count; i++) { @@ -350,7 +365,7 @@ private: std::vector<AudioDevice::AudioDeviceName> out_names{}; - u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count); + const u32 out_count = impl->ListAudioOutputDeviceName(out_names, in_count); std::string out{}; for (u32 i = 0; i < out_count; i++) { diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index fae6e5aff..e23eae36a 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp @@ -246,7 +246,8 @@ static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vec entries.reserve(entries.size() + new_data.size()); for (const auto& new_entry : new_data) { - entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize()); + entries.emplace_back(new_entry->GetName(), type, + type == FileSys::EntryType::Directory ? 0 : new_entry->GetSize()); } } diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 3c28dee76..cb29004e8 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp @@ -163,28 +163,51 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { } LOG_DEBUG(Service_HID, "Npad connected {}", npad_id); const auto controller_type = controller.device->GetNpadStyleIndex(); + const auto& body_colors = controller.device->GetColors(); + const auto& battery_level = controller.device->GetBattery(); auto* shared_memory = controller.shared_memory; if (controller_type == Core::HID::NpadStyleIndex::None) { controller.styleset_changed_event->GetWritableEvent().Signal(); return; } + + // Reset memory values shared_memory->style_tag.raw = Core::HID::NpadStyleSet::None; shared_memory->device_type.raw = 0; shared_memory->system_properties.raw = 0; + shared_memory->joycon_color.attribute = ColorAttribute::NoController; + shared_memory->joycon_color.attribute = ColorAttribute::NoController; + shared_memory->fullkey_color = {}; + shared_memory->joycon_color.left = {}; + shared_memory->joycon_color.right = {}; + shared_memory->battery_level_dual = {}; + shared_memory->battery_level_left = {}; + shared_memory->battery_level_right = {}; + switch (controller_type) { case Core::HID::NpadStyleIndex::None: ASSERT(false); break; case Core::HID::NpadStyleIndex::ProController: + shared_memory->fullkey_color.attribute = ColorAttribute::Ok; + shared_memory->fullkey_color.fullkey = body_colors.fullkey; + shared_memory->battery_level_dual = battery_level.dual.battery_level; shared_memory->style_tag.fullkey.Assign(1); shared_memory->device_type.fullkey.Assign(1); shared_memory->system_properties.is_vertical.Assign(1); shared_memory->system_properties.use_plus.Assign(1); shared_memory->system_properties.use_minus.Assign(1); + shared_memory->system_properties.is_charging_joy_dual.Assign( + battery_level.dual.is_charging); shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::SwitchProController; shared_memory->sixaxis_fullkey_properties.is_newly_assigned.Assign(1); break; case Core::HID::NpadStyleIndex::Handheld: + shared_memory->fullkey_color.attribute = ColorAttribute::Ok; + shared_memory->joycon_color.attribute = ColorAttribute::Ok; + shared_memory->fullkey_color.fullkey = body_colors.fullkey; + shared_memory->joycon_color.left = body_colors.left; + shared_memory->joycon_color.right = body_colors.right; shared_memory->style_tag.handheld.Assign(1); shared_memory->device_type.handheld_left.Assign(1); shared_memory->device_type.handheld_right.Assign(1); @@ -192,47 +215,86 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { shared_memory->system_properties.use_plus.Assign(1); shared_memory->system_properties.use_minus.Assign(1); shared_memory->system_properties.use_directional_buttons.Assign(1); + shared_memory->system_properties.is_charging_joy_dual.Assign( + battery_level.left.is_charging); + shared_memory->system_properties.is_charging_joy_left.Assign( + battery_level.left.is_charging); + shared_memory->system_properties.is_charging_joy_right.Assign( + battery_level.right.is_charging); shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::HandheldJoyConLeftJoyConRight; shared_memory->sixaxis_handheld_properties.is_newly_assigned.Assign(1); break; case Core::HID::NpadStyleIndex::JoyconDual: + shared_memory->fullkey_color.attribute = ColorAttribute::Ok; + shared_memory->joycon_color.attribute = ColorAttribute::Ok; shared_memory->style_tag.joycon_dual.Assign(1); if (controller.is_dual_left_connected) { + shared_memory->joycon_color.left = body_colors.left; + shared_memory->battery_level_left = battery_level.left.battery_level; shared_memory->device_type.joycon_left.Assign(1); shared_memory->system_properties.use_minus.Assign(1); + shared_memory->system_properties.is_charging_joy_left.Assign( + battery_level.left.is_charging); shared_memory->sixaxis_dual_left_properties.is_newly_assigned.Assign(1); } if (controller.is_dual_right_connected) { + shared_memory->joycon_color.right = body_colors.right; + shared_memory->battery_level_right = battery_level.right.battery_level; shared_memory->device_type.joycon_right.Assign(1); shared_memory->system_properties.use_plus.Assign(1); + shared_memory->system_properties.is_charging_joy_right.Assign( + battery_level.right.is_charging); shared_memory->sixaxis_dual_right_properties.is_newly_assigned.Assign(1); } shared_memory->system_properties.use_directional_buttons.Assign(1); shared_memory->system_properties.is_vertical.Assign(1); shared_memory->assignment_mode = NpadJoyAssignmentMode::Dual; + if (controller.is_dual_left_connected && controller.is_dual_right_connected) { shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDual; + shared_memory->fullkey_color.fullkey = body_colors.left; + shared_memory->battery_level_dual = battery_level.left.battery_level; + shared_memory->system_properties.is_charging_joy_dual.Assign( + battery_level.left.is_charging); } else if (controller.is_dual_left_connected) { shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualLeftOnly; + shared_memory->fullkey_color.fullkey = body_colors.left; + shared_memory->battery_level_dual = battery_level.left.battery_level; + shared_memory->system_properties.is_charging_joy_dual.Assign( + battery_level.left.is_charging); } else { shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyDualRightOnly; + shared_memory->fullkey_color.fullkey = body_colors.right; + shared_memory->battery_level_dual = battery_level.right.battery_level; + shared_memory->system_properties.is_charging_joy_dual.Assign( + battery_level.right.is_charging); } break; case Core::HID::NpadStyleIndex::JoyconLeft: + shared_memory->joycon_color.attribute = ColorAttribute::Ok; + shared_memory->joycon_color.left = body_colors.left; + shared_memory->battery_level_dual = battery_level.left.battery_level; shared_memory->style_tag.joycon_left.Assign(1); shared_memory->device_type.joycon_left.Assign(1); shared_memory->system_properties.is_horizontal.Assign(1); shared_memory->system_properties.use_minus.Assign(1); + shared_memory->system_properties.is_charging_joy_left.Assign( + battery_level.left.is_charging); shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyLeftHorizontal; shared_memory->sixaxis_left_properties.is_newly_assigned.Assign(1); break; case Core::HID::NpadStyleIndex::JoyconRight: + shared_memory->joycon_color.attribute = ColorAttribute::Ok; + shared_memory->joycon_color.right = body_colors.right; + shared_memory->battery_level_right = battery_level.right.battery_level; shared_memory->style_tag.joycon_right.Assign(1); shared_memory->device_type.joycon_right.Assign(1); shared_memory->system_properties.is_horizontal.Assign(1); shared_memory->system_properties.use_plus.Assign(1); + shared_memory->system_properties.is_charging_joy_right.Assign( + battery_level.right.is_charging); shared_memory->applet_nfc_xcd.applet_footer.type = AppletFooterUiType::JoyRightHorizontal; shared_memory->sixaxis_right_properties.is_newly_assigned.Assign(1); break; @@ -269,21 +331,6 @@ void Controller_NPad::InitNewlyAddedController(Core::HID::NpadIdType npad_id) { break; } - const auto& body_colors = controller.device->GetColors(); - - shared_memory->fullkey_color.attribute = ColorAttribute::Ok; - shared_memory->fullkey_color.fullkey = body_colors.fullkey; - - shared_memory->joycon_color.attribute = ColorAttribute::Ok; - shared_memory->joycon_color.left = body_colors.left; - shared_memory->joycon_color.right = body_colors.right; - - // TODO: Investigate when we should report all batery types - const auto& battery_level = controller.device->GetBattery(); - shared_memory->battery_level_dual = battery_level.dual.battery_level; - shared_memory->battery_level_left = battery_level.left.battery_level; - shared_memory->battery_level_right = battery_level.right.battery_level; - controller.is_connected = true; controller.device->Connect(); SignalStyleSetChangedEvent(npad_id); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 5ecbddf94..3d3457160 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -819,12 +819,12 @@ void Hid::EnableSixAxisSensorUnalteredPassthrough(Kernel::HLERequestContext& ctx const auto result = controller.EnableSixAxisSensorUnalteredPassthrough( parameters.sixaxis_handle, parameters.enabled); - LOG_WARNING(Service_HID, - "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " - "applet_resource_user_id={}", - parameters.enabled, parameters.sixaxis_handle.npad_type, - parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, - parameters.applet_resource_user_id); + LOG_DEBUG(Service_HID, + "(STUBBED) called, enabled={}, npad_type={}, npad_id={}, device_index={}, " + "applet_resource_user_id={}", + parameters.enabled, parameters.sixaxis_handle.npad_type, + parameters.sixaxis_handle.npad_id, parameters.sixaxis_handle.device_index, + parameters.applet_resource_user_id); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); @@ -846,7 +846,7 @@ void Hid::IsSixAxisSensorUnalteredPassthroughEnabled(Kernel::HLERequestContext& const auto result = controller.IsSixAxisSensorUnalteredPassthroughEnabled( parameters.sixaxis_handle, is_unaltered_sisxaxis_enabled); - LOG_WARNING( + LOG_DEBUG( Service_HID, "(STUBBED) called, npad_type={}, npad_id={}, device_index={}, applet_resource_user_id={}", parameters.sixaxis_handle.npad_type, parameters.sixaxis_handle.npad_id, @@ -2146,12 +2146,18 @@ public: {324, nullptr, "GetUniquePadButtonSet"}, {325, nullptr, "GetUniquePadColor"}, {326, nullptr, "GetUniquePadAppletDetailedUiType"}, + {327, nullptr, "GetAbstractedPadIdDataFromNpad"}, + {328, nullptr, "AttachAbstractedPadToNpad"}, + {329, nullptr, "DetachAbstractedPadAll"}, + {330, nullptr, "CheckAbstractedPadConnection"}, {500, nullptr, "SetAppletResourceUserId"}, {501, nullptr, "RegisterAppletResourceUserId"}, {502, nullptr, "UnregisterAppletResourceUserId"}, {503, nullptr, "EnableAppletToGetInput"}, {504, nullptr, "SetAruidValidForVibration"}, {505, nullptr, "EnableAppletToGetSixAxisSensor"}, + {506, nullptr, "EnableAppletToGetPadInput"}, + {507, nullptr, "EnableAppletToGetTouchScreen"}, {510, nullptr, "SetVibrationMasterVolume"}, {511, nullptr, "GetVibrationMasterVolume"}, {512, nullptr, "BeginPermitVibrationSession"}, diff --git a/src/core/hle/service/ldn/errors.h b/src/core/hle/service/ldn/errors.h deleted file mode 100644 index 972a74806..000000000 --- a/src/core/hle/service/ldn/errors.h +++ /dev/null @@ -1,12 +0,0 @@ -// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project -// SPDX-License-Identifier: GPL-2.0-or-later - -#pragma once - -#include "core/hle/result.h" - -namespace Service::LDN { - -constexpr Result ERROR_DISABLED{ErrorModule::LDN, 22}; - -} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 125d4dc4c..c11daff54 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp @@ -3,11 +3,15 @@ #include <memory> -#include "core/hle/ipc_helpers.h" -#include "core/hle/result.h" -#include "core/hle/service/ldn/errors.h" +#include "core/core.h" #include "core/hle/service/ldn/ldn.h" -#include "core/hle/service/sm/sm.h" +#include "core/hle/service/ldn/ldn_results.h" +#include "core/hle/service/ldn/ldn_types.h" +#include "core/internal_network/network.h" +#include "core/internal_network/network_interface.h" + +// This is defined by synchapi.h and conflicts with ServiceContext::CreateEvent +#undef CreateEvent namespace Service::LDN { @@ -100,74 +104,418 @@ class IUserLocalCommunicationService final : public ServiceFramework<IUserLocalCommunicationService> { public: explicit IUserLocalCommunicationService(Core::System& system_) - : ServiceFramework{system_, "IUserLocalCommunicationService"} { + : ServiceFramework{system_, "IUserLocalCommunicationService", ServiceThreadType::CreateNew}, + service_context{system, "IUserLocalCommunicationService"}, room_network{ + system_.GetRoomNetwork()} { // clang-format off static const FunctionInfo functions[] = { {0, &IUserLocalCommunicationService::GetState, "GetState"}, - {1, nullptr, "GetNetworkInfo"}, + {1, &IUserLocalCommunicationService::GetNetworkInfo, "GetNetworkInfo"}, {2, nullptr, "GetIpv4Address"}, - {3, nullptr, "GetDisconnectReason"}, - {4, nullptr, "GetSecurityParameter"}, - {5, nullptr, "GetNetworkConfig"}, - {100, nullptr, "AttachStateChangeEvent"}, - {101, nullptr, "GetNetworkInfoLatestUpdate"}, - {102, nullptr, "Scan"}, - {103, nullptr, "ScanPrivate"}, + {3, &IUserLocalCommunicationService::GetDisconnectReason, "GetDisconnectReason"}, + {4, &IUserLocalCommunicationService::GetSecurityParameter, "GetSecurityParameter"}, + {5, &IUserLocalCommunicationService::GetNetworkConfig, "GetNetworkConfig"}, + {100, &IUserLocalCommunicationService::AttachStateChangeEvent, "AttachStateChangeEvent"}, + {101, &IUserLocalCommunicationService::GetNetworkInfoLatestUpdate, "GetNetworkInfoLatestUpdate"}, + {102, &IUserLocalCommunicationService::Scan, "Scan"}, + {103, &IUserLocalCommunicationService::ScanPrivate, "ScanPrivate"}, {104, nullptr, "SetWirelessControllerRestriction"}, - {200, nullptr, "OpenAccessPoint"}, - {201, nullptr, "CloseAccessPoint"}, - {202, nullptr, "CreateNetwork"}, - {203, nullptr, "CreateNetworkPrivate"}, - {204, nullptr, "DestroyNetwork"}, + {200, &IUserLocalCommunicationService::OpenAccessPoint, "OpenAccessPoint"}, + {201, &IUserLocalCommunicationService::CloseAccessPoint, "CloseAccessPoint"}, + {202, &IUserLocalCommunicationService::CreateNetwork, "CreateNetwork"}, + {203, &IUserLocalCommunicationService::CreateNetworkPrivate, "CreateNetworkPrivate"}, + {204, &IUserLocalCommunicationService::DestroyNetwork, "DestroyNetwork"}, {205, nullptr, "Reject"}, - {206, nullptr, "SetAdvertiseData"}, - {207, nullptr, "SetStationAcceptPolicy"}, - {208, nullptr, "AddAcceptFilterEntry"}, + {206, &IUserLocalCommunicationService::SetAdvertiseData, "SetAdvertiseData"}, + {207, &IUserLocalCommunicationService::SetStationAcceptPolicy, "SetStationAcceptPolicy"}, + {208, &IUserLocalCommunicationService::AddAcceptFilterEntry, "AddAcceptFilterEntry"}, {209, nullptr, "ClearAcceptFilter"}, - {300, nullptr, "OpenStation"}, - {301, nullptr, "CloseStation"}, - {302, nullptr, "Connect"}, + {300, &IUserLocalCommunicationService::OpenStation, "OpenStation"}, + {301, &IUserLocalCommunicationService::CloseStation, "CloseStation"}, + {302, &IUserLocalCommunicationService::Connect, "Connect"}, {303, nullptr, "ConnectPrivate"}, - {304, nullptr, "Disconnect"}, - {400, nullptr, "Initialize"}, - {401, nullptr, "Finalize"}, - {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, // 7.0.0+ + {304, &IUserLocalCommunicationService::Disconnect, "Disconnect"}, + {400, &IUserLocalCommunicationService::Initialize, "Initialize"}, + {401, &IUserLocalCommunicationService::Finalize, "Finalize"}, + {402, &IUserLocalCommunicationService::Initialize2, "Initialize2"}, }; // clang-format on RegisterHandlers(functions); + + state_change_event = + service_context.CreateEvent("IUserLocalCommunicationService:StateChangeEvent"); + } + + ~IUserLocalCommunicationService() { + service_context.CloseEvent(state_change_event); + } + + void OnEventFired() { + state_change_event->GetWritableEvent().Signal(); } void GetState(Kernel::HLERequestContext& ctx) { + State state = State::Error; + LOG_WARNING(Service_LDN, "(STUBBED) called, state = {}", state); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(state); + } + + void GetNetworkInfo(Kernel::HLERequestContext& ctx) { + const auto write_buffer_size = ctx.GetWriteBufferSize(); + + if (write_buffer_size != sizeof(NetworkInfo)) { + LOG_ERROR(Service_LDN, "Invalid buffer size {}", write_buffer_size); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultBadInput); + return; + } + + NetworkInfo network_info{}; + const auto rc = ResultSuccess; + if (rc.IsError()) { + LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(rc); + return; + } + + LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", + network_info.common.ssid.GetStringValue(), network_info.ldn.node_count); + + ctx.WriteBuffer<NetworkInfo>(network_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(rc); + } + + void GetDisconnectReason(Kernel::HLERequestContext& ctx) { + const auto disconnect_reason = DisconnectReason::None; + + LOG_WARNING(Service_LDN, "(STUBBED) called, disconnect_reason={}", disconnect_reason); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(disconnect_reason); + } + + void GetSecurityParameter(Kernel::HLERequestContext& ctx) { + SecurityParameter security_parameter{}; + NetworkInfo info{}; + const Result rc = ResultSuccess; + + if (rc.IsError()) { + LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(rc); + return; + } + + security_parameter.session_id = info.network_id.session_id; + std::memcpy(security_parameter.data.data(), info.ldn.security_parameter.data(), + sizeof(SecurityParameter::data)); + LOG_WARNING(Service_LDN, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(rc); + rb.PushRaw<SecurityParameter>(security_parameter); + } + + void GetNetworkConfig(Kernel::HLERequestContext& ctx) { + NetworkConfig config{}; + NetworkInfo info{}; + const Result rc = ResultSuccess; + + if (rc.IsError()) { + LOG_ERROR(Service_LDN, "NetworkConfig is not valid {}", rc.raw); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(rc); + return; + } + + config.intent_id = info.network_id.intent_id; + config.channel = info.common.channel; + config.node_count_max = info.ldn.node_count_max; + config.local_communication_version = info.ldn.nodes[0].local_communication_version; + + LOG_WARNING(Service_LDN, + "(STUBBED) called, intent_id={}/{}, channel={}, node_count_max={}, " + "local_communication_version={}", + config.intent_id.local_communication_id, config.intent_id.scene_id, + config.channel, config.node_count_max, config.local_communication_version); + + IPC::ResponseBuilder rb{ctx, 10}; + rb.Push(rc); + rb.PushRaw<NetworkConfig>(config); + } + + void AttachStateChangeEvent(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_LDN, "called"); + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(state_change_event->GetReadableEvent()); + } + + 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); + + if (node_buffer_count == 0 || network_buffer_size != sizeof(NetworkInfo)) { + LOG_ERROR(Service_LDN, "Invalid buffer size {}, {}", network_buffer_size, + node_buffer_count); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultBadInput); + return; + } + + NetworkInfo info; + std::vector<NodeLatestUpdate> latest_update(node_buffer_count); + + const auto rc = ResultSuccess; + if (rc.IsError()) { + LOG_ERROR(Service_LDN, "NetworkInfo is not valid {}", rc.raw); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(rc); + return; + } + + LOG_WARNING(Service_LDN, "(STUBBED) called, ssid='{}', nodes={}", + info.common.ssid.GetStringValue(), info.ldn.node_count); + + ctx.WriteBuffer(info, 0); + ctx.WriteBuffer(latest_update, 1); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Scan(Kernel::HLERequestContext& ctx) { + ScanImpl(ctx); + } + + void ScanPrivate(Kernel::HLERequestContext& ctx) { + ScanImpl(ctx, true); + } + + void ScanImpl(Kernel::HLERequestContext& ctx, bool is_private = false) { + IPC::RequestParser rp{ctx}; + const auto channel{rp.PopEnum<WifiChannel>()}; + const auto scan_filter{rp.PopRaw<ScanFilter>()}; + + const std::size_t network_info_size = ctx.GetWriteBufferSize() / sizeof(NetworkInfo); + + if (network_info_size == 0) { + LOG_ERROR(Service_LDN, "Invalid buffer size {}", network_info_size); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultBadInput); + return; + } + + u16 count = 0; + std::vector<NetworkInfo> network_infos(network_info_size); + + LOG_WARNING(Service_LDN, + "(STUBBED) called, channel={}, filter_scan_flag={}, filter_network_type={}", + channel, scan_filter.flag, scan_filter.network_type); + + ctx.WriteBuffer(network_infos); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(count); + } + + void OpenAccessPoint(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void CloseAccessPoint(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void CreateNetwork(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + SecurityConfig security_config; + UserConfig user_config; + INSERT_PADDING_WORDS_NOINIT(1); + NetworkConfig network_config; + }; + static_assert(sizeof(Parameters) == 0x98, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_WARNING(Service_LDN, + "(STUBBED) called, passphrase_size={}, security_mode={}, " + "local_communication_version={}", + parameters.security_config.passphrase_size, + parameters.security_config.security_mode, + parameters.network_config.local_communication_version); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void CreateNetworkPrivate(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + SecurityConfig security_config; + SecurityParameter security_parameter; + UserConfig user_config; + NetworkConfig network_config; + }; + static_assert(sizeof(Parameters) == 0xB8, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_WARNING(Service_LDN, + "(STUBBED) called, passphrase_size={}, security_mode={}, " + "local_communication_version={}", + parameters.security_config.passphrase_size, + parameters.security_config.security_mode, + parameters.network_config.local_communication_version); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void DestroyNetwork(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void SetAdvertiseData(Kernel::HLERequestContext& ctx) { + std::vector<u8> read_buffer = ctx.ReadBuffer(); + + LOG_WARNING(Service_LDN, "(STUBBED) called, size {}", read_buffer.size()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void SetStationAcceptPolicy(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } - // Indicate a network error, as we do not actually emulate LDN - rb.Push(static_cast<u32>(State::Error)); + void AddAcceptFilterEntry(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void OpenStation(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void CloseStation(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Connect(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + struct Parameters { + SecurityConfig security_config; + UserConfig user_config; + u32 local_communication_version; + u32 option; + }; + static_assert(sizeof(Parameters) == 0x7C, "Parameters has incorrect size."); + + const auto parameters{rp.PopRaw<Parameters>()}; + + LOG_WARNING(Service_LDN, + "(STUBBED) called, passphrase_size={}, security_mode={}, " + "local_communication_version={}", + parameters.security_config.passphrase_size, + parameters.security_config.security_mode, + parameters.local_communication_version); + + const std::vector<u8> read_buffer = ctx.ReadBuffer(); + NetworkInfo network_info{}; + + if (read_buffer.size() != sizeof(NetworkInfo)) { + LOG_ERROR(Frontend, "NetworkInfo doesn't match read_buffer size!"); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultBadInput); + return; + } + + std::memcpy(&network_info, read_buffer.data(), read_buffer.size()); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Disconnect(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + void Initialize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + const auto rc = InitializeImpl(ctx); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(rc); + } + + void Finalize(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_LDN, "(STUBBED) called"); + + is_initialized = false; + + IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); } void Initialize2(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_LDN, "called"); + LOG_WARNING(Service_LDN, "(STUBBED) called"); - is_initialized = true; + const auto rc = InitializeImpl(ctx); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_DISABLED); + rb.Push(rc); + } + + Result InitializeImpl(Kernel::HLERequestContext& ctx) { + const auto network_interface = Network::GetSelectedNetworkInterface(); + if (!network_interface) { + LOG_ERROR(Service_LDN, "No network interface is set"); + return ResultAirplaneModeEnabled; + } + + is_initialized = true; + // TODO (flTobi): Change this to ResultSuccess when LDN is fully implemented + return ResultAirplaneModeEnabled; } -private: - enum class State { - None, - Initialized, - AccessPointOpened, - AccessPointCreated, - StationOpened, - StationConnected, - Error, - }; + KernelHelpers::ServiceContext service_context; + Kernel::KEvent* state_change_event; + Network::RoomNetwork& room_network; bool is_initialized{}; }; @@ -273,7 +621,7 @@ public: LOG_WARNING(Service_LDN, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ERROR_DISABLED); + rb.Push(ResultDisabled); } }; diff --git a/src/core/hle/service/ldn/ldn.h b/src/core/hle/service/ldn/ldn.h index a0031ac71..6afe2ea6f 100644 --- a/src/core/hle/service/ldn/ldn.h +++ b/src/core/hle/service/ldn/ldn.h @@ -3,6 +3,12 @@ #pragma once +#include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/result.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/sm/sm.h" + namespace Core { class System; } diff --git a/src/core/hle/service/ldn/ldn_results.h b/src/core/hle/service/ldn/ldn_results.h new file mode 100644 index 000000000..f340bda42 --- /dev/null +++ b/src/core/hle/service/ldn/ldn_results.h @@ -0,0 +1,27 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include "core/hle/result.h" + +namespace Service::LDN { + +constexpr Result ResultAdvertiseDataTooLarge{ErrorModule::LDN, 10}; +constexpr Result ResultAuthenticationFailed{ErrorModule::LDN, 20}; +constexpr Result ResultDisabled{ErrorModule::LDN, 22}; +constexpr Result ResultAirplaneModeEnabled{ErrorModule::LDN, 23}; +constexpr Result ResultInvalidNodeCount{ErrorModule::LDN, 30}; +constexpr Result ResultConnectionFailed{ErrorModule::LDN, 31}; +constexpr Result ResultBadState{ErrorModule::LDN, 32}; +constexpr Result ResultNoIpAddress{ErrorModule::LDN, 33}; +constexpr Result ResultInvalidBufferCount{ErrorModule::LDN, 50}; +constexpr Result ResultAccessPointConnectionFailed{ErrorModule::LDN, 65}; +constexpr Result ResultAuthenticationTimeout{ErrorModule::LDN, 66}; +constexpr Result ResultMaximumNodeCount{ErrorModule::LDN, 67}; +constexpr Result ResultBadInput{ErrorModule::LDN, 96}; +constexpr Result ResultLocalCommunicationIdNotFound{ErrorModule::LDN, 97}; +constexpr Result ResultLocalCommunicationVersionTooLow{ErrorModule::LDN, 113}; +constexpr Result ResultLocalCommunicationVersionTooHigh{ErrorModule::LDN, 114}; + +} // namespace Service::LDN diff --git a/src/core/hle/service/ldn/ldn_types.h b/src/core/hle/service/ldn/ldn_types.h new file mode 100644 index 000000000..6231e936d --- /dev/null +++ b/src/core/hle/service/ldn/ldn_types.h @@ -0,0 +1,292 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-3.0-or-later + +#pragma once + +#include <fmt/format.h> + +#include "common/common_funcs.h" +#include "common/common_types.h" +#include "network/network.h" + +namespace Service::LDN { + +constexpr size_t SsidLengthMax = 32; +constexpr size_t AdvertiseDataSizeMax = 384; +constexpr size_t UserNameBytesMax = 32; +constexpr int NodeCountMax = 8; +constexpr int StationCountMax = NodeCountMax - 1; +constexpr size_t PassphraseLengthMax = 64; + +enum class SecurityMode : u16 { + All, + Retail, + Debug, +}; + +enum class NodeStateChange : u8 { + None, + Connect, + Disconnect, + DisconnectAndConnect, +}; + +enum class ScanFilterFlag : u32 { + None = 0, + LocalCommunicationId = 1 << 0, + SessionId = 1 << 1, + NetworkType = 1 << 2, + Ssid = 1 << 4, + SceneId = 1 << 5, + IntentId = LocalCommunicationId | SceneId, + NetworkId = IntentId | SessionId, +}; + +enum class NetworkType : u32 { + None, + General, + Ldn, + All, +}; + +enum class PackedNetworkType : u8 { + None, + General, + Ldn, + All, +}; + +enum class State : u32 { + None, + Initialized, + AccessPointOpened, + AccessPointCreated, + StationOpened, + StationConnected, + Error, +}; + +enum class DisconnectReason : s16 { + Unknown = -1, + None, + DisconnectedByUser, + DisconnectedBySystem, + DestroyedByUser, + DestroyedBySystem, + Rejected, + SignalLost, +}; + +enum class NetworkError { + Unknown = -1, + None = 0, + PortUnreachable, + TooManyPlayers, + VersionTooLow, + VersionTooHigh, + ConnectFailure, + ConnectNotFound, + ConnectTimeout, + ConnectRejected, + RejectFailed, +}; + +enum class AcceptPolicy : u8 { + AcceptAll, + RejectAll, + BlackList, + WhiteList, +}; + +enum class WifiChannel : s16 { + Default = 0, + wifi24_1 = 1, + wifi24_6 = 6, + wifi24_11 = 11, + wifi50_36 = 36, + wifi50_40 = 40, + wifi50_44 = 44, + wifi50_48 = 48, +}; + +enum class LinkLevel : s8 { + Bad, + Low, + Good, + Excellent, +}; + +struct NodeLatestUpdate { + NodeStateChange state_change; + INSERT_PADDING_BYTES(0x7); // Unknown +}; +static_assert(sizeof(NodeLatestUpdate) == 0x8, "NodeLatestUpdate is an invalid size"); + +struct SessionId { + u64 high; + u64 low; + + bool operator==(const SessionId&) const = default; +}; +static_assert(sizeof(SessionId) == 0x10, "SessionId is an invalid size"); + +struct IntentId { + u64 local_communication_id; + INSERT_PADDING_BYTES(0x2); // Reserved + u16 scene_id; + INSERT_PADDING_BYTES(0x4); // Reserved +}; +static_assert(sizeof(IntentId) == 0x10, "IntentId is an invalid size"); + +struct NetworkId { + IntentId intent_id; + SessionId session_id; +}; +static_assert(sizeof(NetworkId) == 0x20, "NetworkId is an invalid size"); + +struct Ssid { + u8 length{}; + std::array<char, SsidLengthMax + 1> raw{}; + + Ssid() = default; + + explicit Ssid(std::string_view data) { + length = static_cast<u8>(std::min(data.size(), SsidLengthMax)); + data.copy(raw.data(), length); + raw[length] = 0; + } + + std::string GetStringValue() const { + return std::string(raw.data()); + } +}; +static_assert(sizeof(Ssid) == 0x22, "Ssid is an invalid size"); + +struct Ipv4Address { + union { + u32 raw{}; + std::array<u8, 4> bytes; + }; + + std::string GetStringValue() const { + return fmt::format("{}.{}.{}.{}", bytes[3], bytes[2], bytes[1], bytes[0]); + } +}; +static_assert(sizeof(Ipv4Address) == 0x4, "Ipv4Address is an invalid size"); + +struct MacAddress { + std::array<u8, 6> raw{}; + + friend bool operator==(const MacAddress& lhs, const MacAddress& rhs) = default; +}; +static_assert(sizeof(MacAddress) == 0x6, "MacAddress is an invalid size"); + +struct ScanFilter { + NetworkId network_id; + NetworkType network_type; + MacAddress mac_address; + Ssid ssid; + INSERT_PADDING_BYTES(0x10); + ScanFilterFlag flag; +}; +static_assert(sizeof(ScanFilter) == 0x60, "ScanFilter is an invalid size"); + +struct CommonNetworkInfo { + MacAddress bssid; + Ssid ssid; + WifiChannel channel; + LinkLevel link_level; + PackedNetworkType network_type; + INSERT_PADDING_BYTES(0x4); +}; +static_assert(sizeof(CommonNetworkInfo) == 0x30, "CommonNetworkInfo is an invalid size"); + +struct NodeInfo { + Ipv4Address ipv4_address; + MacAddress mac_address; + s8 node_id; + u8 is_connected; + std::array<u8, UserNameBytesMax + 1> user_name; + INSERT_PADDING_BYTES(0x1); // Reserved + s16 local_communication_version; + INSERT_PADDING_BYTES(0x10); // Reserved +}; +static_assert(sizeof(NodeInfo) == 0x40, "NodeInfo is an invalid size"); + +struct LdnNetworkInfo { + std::array<u8, 0x10> security_parameter; + SecurityMode security_mode; + AcceptPolicy station_accept_policy; + u8 has_action_frame; + INSERT_PADDING_BYTES(0x2); // Padding + u8 node_count_max; + u8 node_count; + std::array<NodeInfo, NodeCountMax> nodes; + INSERT_PADDING_BYTES(0x2); // Reserved + u16 advertise_data_size; + std::array<u8, AdvertiseDataSizeMax> advertise_data; + INSERT_PADDING_BYTES(0x8C); // Reserved + u64 random_authentication_id; +}; +static_assert(sizeof(LdnNetworkInfo) == 0x430, "LdnNetworkInfo is an invalid size"); + +struct NetworkInfo { + NetworkId network_id; + CommonNetworkInfo common; + LdnNetworkInfo ldn; +}; +static_assert(sizeof(NetworkInfo) == 0x480, "NetworkInfo is an invalid size"); + +struct SecurityConfig { + SecurityMode security_mode; + u16 passphrase_size; + std::array<u8, PassphraseLengthMax> passphrase; +}; +static_assert(sizeof(SecurityConfig) == 0x44, "SecurityConfig is an invalid size"); + +struct UserConfig { + std::array<u8, UserNameBytesMax + 1> user_name; + INSERT_PADDING_BYTES(0xF); // Reserved +}; +static_assert(sizeof(UserConfig) == 0x30, "UserConfig is an invalid size"); + +#pragma pack(push, 4) +struct ConnectRequest { + SecurityConfig security_config; + UserConfig user_config; + u32 local_communication_version; + u32 option_unknown; + NetworkInfo network_info; +}; +static_assert(sizeof(ConnectRequest) == 0x4FC, "ConnectRequest is an invalid size"); +#pragma pack(pop) + +struct SecurityParameter { + std::array<u8, 0x10> data; // Data, used with the same key derivation as SecurityConfig + SessionId session_id; +}; +static_assert(sizeof(SecurityParameter) == 0x20, "SecurityParameter is an invalid size"); + +struct NetworkConfig { + IntentId intent_id; + WifiChannel channel; + u8 node_count_max; + INSERT_PADDING_BYTES(0x1); // Reserved + u16 local_communication_version; + INSERT_PADDING_BYTES(0xA); // Reserved +}; +static_assert(sizeof(NetworkConfig) == 0x20, "NetworkConfig is an invalid size"); + +struct AddressEntry { + Ipv4Address ipv4_address; + MacAddress mac_address; + INSERT_PADDING_BYTES(0x2); // Reserved +}; +static_assert(sizeof(AddressEntry) == 0xC, "AddressEntry is an invalid size"); + +struct AddressList { + std::array<AddressEntry, 0x8> addresses; +}; +static_assert(sizeof(AddressList) == 0x60, "AddressList is an invalid size"); + +} // namespace Service::LDN diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index 5ebb124a7..ba8c0e230 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp @@ -46,7 +46,7 @@ private: IPC::RequestParser rp{ctx}; min = rp.Pop<u32>(); max = rp.Pop<u32>(); - LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); + LOG_DEBUG(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); current = min; IPC::ResponseBuilder rb{ctx, 2}; @@ -54,7 +54,7 @@ private: } void GetOld(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_MM, "(STUBBED) called"); + LOG_DEBUG(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -81,8 +81,8 @@ private: u32 input_id = rp.Pop<u32>(); min = rp.Pop<u32>(); max = rp.Pop<u32>(); - LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", - input_id, min, max); + LOG_DEBUG(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", input_id, + min, max); current = min; IPC::ResponseBuilder rb{ctx, 2}; @@ -90,7 +90,7 @@ private: } void Get(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_MM, "(STUBBED) called"); + LOG_DEBUG(Service_MM, "(STUBBED) called"); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 2889973e4..e3ef06481 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp @@ -6,7 +6,6 @@ #include "core/hle/kernel/k_event.h" #include "core/hle/service/kernel_helpers.h" #include "core/hle/service/nifm/nifm.h" -#include "core/hle/service/service.h" namespace { @@ -271,213 +270,228 @@ public: } }; -class IGeneralService final : public ServiceFramework<IGeneralService> { -public: - explicit IGeneralService(Core::System& system_); +void IGeneralService::GetClientId(Kernel::HLERequestContext& ctx) { + static constexpr u32 client_id = 1; + LOG_WARNING(Service_NIFM, "(STUBBED) called"); -private: - void GetClientId(Kernel::HLERequestContext& ctx) { - static constexpr u32 client_id = 1; - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 4}; + rb.Push(ResultSuccess); + rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid +} - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(ResultSuccess); - rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid - } +void IGeneralService::CreateScanRequest(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NIFM, "called"); - void CreateScanRequest(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NIFM, "called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IScanRequest>(system); +} - rb.Push(ResultSuccess); - rb.PushIpcInterface<IScanRequest>(system); - } +void IGeneralService::CreateRequest(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NIFM, "called"); - void CreateRequest(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NIFM, "called"); + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; - IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IRequest>(system); +} - rb.Push(ResultSuccess); - rb.PushIpcInterface<IRequest>(system); - } +void IGeneralService::GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); - void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + const auto net_iface = Network::GetSelectedNetworkInterface(); - const auto net_iface = Network::GetSelectedNetworkInterface(); - - const SfNetworkProfileData network_profile_data = [&net_iface] { - if (!net_iface) { - return SfNetworkProfileData{}; - } - - return SfNetworkProfileData{ - .ip_setting_data{ - .ip_address_setting{ - .is_automatic{true}, - .current_address{Network::TranslateIPv4(net_iface->ip_address)}, - .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)}, - .gateway{Network::TranslateIPv4(net_iface->gateway)}, - }, - .dns_setting{ - .is_automatic{true}, - .primary_dns{1, 1, 1, 1}, - .secondary_dns{1, 0, 0, 1}, - }, - .proxy_setting{ - .enabled{false}, - .port{}, - .proxy_server{}, - .automatic_auth_enabled{}, - .user{}, - .password{}, - }, - .mtu{1500}, + SfNetworkProfileData network_profile_data = [&net_iface] { + if (!net_iface) { + return SfNetworkProfileData{}; + } + + return SfNetworkProfileData{ + .ip_setting_data{ + .ip_address_setting{ + .is_automatic{true}, + .current_address{Network::TranslateIPv4(net_iface->ip_address)}, + .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)}, + .gateway{Network::TranslateIPv4(net_iface->gateway)}, }, - .uuid{0xdeadbeef, 0xdeadbeef}, - .network_name{"yuzu Network"}, - .wireless_setting_data{ - .ssid_length{12}, - .ssid{"yuzu Network"}, - .passphrase{"yuzupassword"}, + .dns_setting{ + .is_automatic{true}, + .primary_dns{1, 1, 1, 1}, + .secondary_dns{1, 0, 0, 1}, }, - }; - }(); - - ctx.WriteBuffer(network_profile_data); + .proxy_setting{ + .enabled{false}, + .port{}, + .proxy_server{}, + .automatic_auth_enabled{}, + .user{}, + .password{}, + }, + .mtu{1500}, + }, + .uuid{0xdeadbeef, 0xdeadbeef}, + .network_name{"yuzu Network"}, + .wireless_setting_data{ + .ssid_length{12}, + .ssid{"yuzu Network"}, + .passphrase{"yuzupassword"}, + }, + }; + }(); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + // When we're connected to a room, spoof the hosts IP address + if (auto room_member = network.GetRoomMember().lock()) { + if (room_member->IsConnected()) { + network_profile_data.ip_setting_data.ip_address_setting.current_address = + room_member->GetFakeIpAddress(); + } } - void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + ctx.WriteBuffer(network_profile_data); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} - void GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); +void IGeneralService::RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); - auto ipv4 = Network::GetHostIPv4Address(); - if (!ipv4) { - LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); - ipv4.emplace(Network::IPv4Address{0, 0, 0, 0}); - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw(*ipv4); +void IGeneralService::GetCurrentIpAddress(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); + + auto ipv4 = Network::GetHostIPv4Address(); + if (!ipv4) { + LOG_ERROR(Service_NIFM, "Couldn't get host IPv4 address, defaulting to 0.0.0.0"); + ipv4.emplace(Network::IPv4Address{0, 0, 0, 0}); } - void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NIFM, "called"); + // When we're connected to a room, spoof the hosts IP address + if (auto room_member = network.GetRoomMember().lock()) { + if (room_member->IsConnected()) { + ipv4 = room_member->GetFakeIpAddress(); + } + } - ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, - "SfNetworkProfileData is not the correct size"); - u128 uuid{}; - auto buffer = ctx.ReadBuffer(); - std::memcpy(&uuid, buffer.data() + 8, sizeof(u128)); + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(*ipv4); +} - IPC::ResponseBuilder rb{ctx, 6, 0, 1}; +void IGeneralService::CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NIFM, "called"); - rb.Push(ResultSuccess); - rb.PushIpcInterface<INetworkProfile>(system); - rb.PushRaw<u128>(uuid); - } + ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "SfNetworkProfileData is not the correct size"); + u128 uuid{}; + auto buffer = ctx.ReadBuffer(); + std::memcpy(&uuid, buffer.data() + 8, sizeof(u128)); - void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 6, 0, 1}; - struct IpConfigInfo { - IpAddressSetting ip_address_setting{}; - DnsSetting dns_setting{}; - }; - static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), - "IpConfigInfo has incorrect size."); + rb.Push(ResultSuccess); + rb.PushIpcInterface<INetworkProfile>(system); + rb.PushRaw<u128>(uuid); +} - const auto net_iface = Network::GetSelectedNetworkInterface(); +void IGeneralService::GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); - const IpConfigInfo ip_config_info = [&net_iface] { - if (!net_iface) { - return IpConfigInfo{}; - } + struct IpConfigInfo { + IpAddressSetting ip_address_setting{}; + DnsSetting dns_setting{}; + }; + static_assert(sizeof(IpConfigInfo) == sizeof(IpAddressSetting) + sizeof(DnsSetting), + "IpConfigInfo has incorrect size."); - return IpConfigInfo{ - .ip_address_setting{ - .is_automatic{true}, - .current_address{Network::TranslateIPv4(net_iface->ip_address)}, - .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)}, - .gateway{Network::TranslateIPv4(net_iface->gateway)}, - }, - .dns_setting{ - .is_automatic{true}, - .primary_dns{1, 1, 1, 1}, - .secondary_dns{1, 0, 0, 1}, - }, - }; - }(); + const auto net_iface = Network::GetSelectedNetworkInterface(); - IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; - rb.Push(ResultSuccess); - rb.PushRaw<IpConfigInfo>(ip_config_info); - } + IpConfigInfo ip_config_info = [&net_iface] { + if (!net_iface) { + return IpConfigInfo{}; + } - void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + return IpConfigInfo{ + .ip_address_setting{ + .is_automatic{true}, + .current_address{Network::TranslateIPv4(net_iface->ip_address)}, + .subnet_mask{Network::TranslateIPv4(net_iface->subnet_mask)}, + .gateway{Network::TranslateIPv4(net_iface->gateway)}, + }, + .dns_setting{ + .is_automatic{true}, + .primary_dns{1, 1, 1, 1}, + .secondary_dns{1, 0, 0, 1}, + }, + }; + }(); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u8>(0); + // When we're connected to a room, spoof the hosts IP address + if (auto room_member = network.GetRoomMember().lock()) { + if (room_member->IsConnected()) { + ip_config_info.ip_address_setting.current_address = room_member->GetFakeIpAddress(); + } } - void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + IPC::ResponseBuilder rb{ctx, 2 + (sizeof(IpConfigInfo) + 3) / sizeof(u32)}; + rb.Push(ResultSuccess); + rb.PushRaw<IpConfigInfo>(ip_config_info); +} - struct Output { - InternetConnectionType type{InternetConnectionType::WiFi}; - u8 wifi_strength{3}; - InternetConnectionStatus state{InternetConnectionStatus::Connected}; - }; - static_assert(sizeof(Output) == 0x3, "Output has incorrect size."); +void IGeneralService::IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); - constexpr Output out{}; + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u8>(1); +} - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.PushRaw(out); - } +void IGeneralService::GetInternetConnectionStatus(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); - void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); + struct Output { + InternetConnectionType type{InternetConnectionType::WiFi}; + u8 wifi_strength{3}; + InternetConnectionStatus state{InternetConnectionStatus::Connected}; + }; + static_assert(sizeof(Output) == 0x3, "Output has incorrect size."); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - if (Network::GetHostIPv4Address().has_value()) { - rb.Push<u8>(1); - } else { - rb.Push<u8>(0); - } + constexpr Output out{}; + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushRaw(out); +} + +void IGeneralService::IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_NIFM, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + if (Network::GetHostIPv4Address().has_value()) { + rb.Push<u8>(1); + } else { + rb.Push<u8>(0); } +} - void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NIFM, "(STUBBED) called"); +void IGeneralService::IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { + LOG_ERROR(Service_NIFM, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - if (Network::GetHostIPv4Address().has_value()) { - rb.Push<u8>(1); - } else { - rb.Push<u8>(0); - } + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + if (Network::GetHostIPv4Address().has_value()) { + rb.Push<u8>(1); + } else { + rb.Push<u8>(0); } -}; +} IGeneralService::IGeneralService(Core::System& system_) - : ServiceFramework{system_, "IGeneralService"} { + : ServiceFramework{system_, "IGeneralService"}, network{system_.GetRoomNetwork()} { // clang-format off static const FunctionInfo functions[] = { {1, &IGeneralService::GetClientId, "GetClientId"}, @@ -528,6 +542,8 @@ IGeneralService::IGeneralService(Core::System& system_) RegisterHandlers(functions); } +IGeneralService::~IGeneralService() = default; + class NetworkInterface final : public ServiceFramework<NetworkInterface> { public: explicit NetworkInterface(const char* name, Core::System& system_) diff --git a/src/core/hle/service/nifm/nifm.h b/src/core/hle/service/nifm/nifm.h index 5f62d0014..48161be28 100644 --- a/src/core/hle/service/nifm/nifm.h +++ b/src/core/hle/service/nifm/nifm.h @@ -3,6 +3,11 @@ #pragma once +#include "core/hle/service/service.h" +#include "network/network.h" +#include "network/room.h" +#include "network/room_member.h" + namespace Core { class System; } @@ -16,4 +21,26 @@ namespace Service::NIFM { /// Registers all NIFM services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); +class IGeneralService final : public ServiceFramework<IGeneralService> { +public: + explicit IGeneralService(Core::System& system_); + ~IGeneralService() override; + +private: + void GetClientId(Kernel::HLERequestContext& ctx); + void CreateScanRequest(Kernel::HLERequestContext& ctx); + void CreateRequest(Kernel::HLERequestContext& ctx); + void GetCurrentNetworkProfile(Kernel::HLERequestContext& ctx); + void RemoveNetworkProfile(Kernel::HLERequestContext& ctx); + void GetCurrentIpAddress(Kernel::HLERequestContext& ctx); + void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx); + void GetCurrentIpConfigInfo(Kernel::HLERequestContext& ctx); + void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx); + void GetInternetConnectionStatus(Kernel::HLERequestContext& ctx); + void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx); + void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx); + + Network::RoomNetwork& network; +}; + } // namespace Service::NIFM diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/iplatform_service_manager.cpp index cc11f3e08..fd047ff26 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/iplatform_service_manager.cpp @@ -20,7 +20,7 @@ #include "core/hle/kernel/kernel.h" #include "core/hle/kernel/physical_memory.h" #include "core/hle/service/filesystem/filesystem.h" -#include "core/hle/service/ns/pl_u.h" +#include "core/hle/service/ns/iplatform_service_manager.h" namespace Service::NS { @@ -99,7 +99,7 @@ static u32 GetU32Swapped(const u8* data) { return Common::swap32(value); } -struct PL_U::Impl { +struct IPlatformServiceManager::Impl { const FontRegion& GetSharedFontRegion(std::size_t index) const { if (index >= shared_font_regions.size() || shared_font_regions.empty()) { // No font fallback @@ -134,16 +134,16 @@ struct PL_U::Impl { std::vector<FontRegion> shared_font_regions; }; -PL_U::PL_U(Core::System& system_) - : ServiceFramework{system_, "pl:u"}, impl{std::make_unique<Impl>()} { +IPlatformServiceManager::IPlatformServiceManager(Core::System& system_, const char* service_name_) + : ServiceFramework{system_, service_name_}, impl{std::make_unique<Impl>()} { // clang-format off static const FunctionInfo functions[] = { - {0, &PL_U::RequestLoad, "RequestLoad"}, - {1, &PL_U::GetLoadState, "GetLoadState"}, - {2, &PL_U::GetSize, "GetSize"}, - {3, &PL_U::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, - {4, &PL_U::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, - {5, &PL_U::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, + {0, &IPlatformServiceManager::RequestLoad, "RequestLoad"}, + {1, &IPlatformServiceManager::GetLoadState, "GetLoadState"}, + {2, &IPlatformServiceManager::GetSize, "GetSize"}, + {3, &IPlatformServiceManager::GetSharedMemoryAddressOffset, "GetSharedMemoryAddressOffset"}, + {4, &IPlatformServiceManager::GetSharedMemoryNativeHandle, "GetSharedMemoryNativeHandle"}, + {5, &IPlatformServiceManager::GetSharedFontInOrderOfPriority, "GetSharedFontInOrderOfPriority"}, {6, nullptr, "GetSharedFontInOrderOfPriorityForSystem"}, {100, nullptr, "RequestApplicationFunctionAuthorization"}, {101, nullptr, "RequestApplicationFunctionAuthorizationByProcessId"}, @@ -206,9 +206,9 @@ PL_U::PL_U(Core::System& system_) } } -PL_U::~PL_U() = default; +IPlatformServiceManager::~IPlatformServiceManager() = default; -void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { +void IPlatformServiceManager::RequestLoad(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 shared_font_type{rp.Pop<u32>()}; // Games don't call this so all fonts should be loaded @@ -218,7 +218,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } -void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { +void IPlatformServiceManager::GetLoadState(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 font_id{rp.Pop<u32>()}; LOG_DEBUG(Service_NS, "called, font_id={}", font_id); @@ -228,7 +228,7 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { rb.Push<u32>(static_cast<u32>(LoadState::Done)); } -void PL_U::GetSize(Kernel::HLERequestContext& ctx) { +void IPlatformServiceManager::GetSize(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 font_id{rp.Pop<u32>()}; LOG_DEBUG(Service_NS, "called, font_id={}", font_id); @@ -238,7 +238,7 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); } -void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { +void IPlatformServiceManager::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u32 font_id{rp.Pop<u32>()}; LOG_DEBUG(Service_NS, "called, font_id={}", font_id); @@ -248,7 +248,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); } -void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { +void IPlatformServiceManager::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { // Map backing memory for the font data LOG_DEBUG(Service_NS, "called"); @@ -261,7 +261,7 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { rb.PushCopyObjects(&kernel.GetFontSharedMem()); } -void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { +void IPlatformServiceManager::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); diff --git a/src/core/hle/service/ns/pl_u.h b/src/core/hle/service/ns/iplatform_service_manager.h index 07d0ac934..ed6eda89f 100644 --- a/src/core/hle/service/ns/pl_u.h +++ b/src/core/hle/service/ns/iplatform_service_manager.h @@ -36,10 +36,10 @@ constexpr std::array<std::pair<FontArchives, const char*>, 7> SHARED_FONTS{ void DecryptSharedFontToTTF(const std::vector<u32>& input, std::vector<u8>& output); void EncryptSharedFont(const std::vector<u32>& input, std::vector<u8>& output, std::size_t& offset); -class PL_U final : public ServiceFramework<PL_U> { +class IPlatformServiceManager final : public ServiceFramework<IPlatformServiceManager> { public: - explicit PL_U(Core::System& system_); - ~PL_U() override; + explicit IPlatformServiceManager(Core::System& system_, const char* service_name_); + ~IPlatformServiceManager() override; private: void RequestLoad(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index aafc8fe03..f7318c3cb 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp @@ -9,10 +9,10 @@ #include "core/file_sys/vfs.h" #include "core/hle/ipc_helpers.h" #include "core/hle/service/ns/errors.h" +#include "core/hle/service/ns/iplatform_service_manager.h" #include "core/hle/service/ns/language.h" #include "core/hle/service/ns/ns.h" #include "core/hle/service/ns/pdm_qry.h" -#include "core/hle/service/ns/pl_u.h" #include "core/hle/service/set/set.h" namespace Service::NS { @@ -764,7 +764,8 @@ void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system std::make_shared<PDM_QRY>(system)->InstallAsService(service_manager); - std::make_shared<PL_U>(system)->InstallAsService(service_manager); + std::make_shared<IPlatformServiceManager>(system, "pl:s")->InstallAsService(service_manager); + std::make_shared<IPlatformServiceManager>(system, "pl:u")->InstallAsService(service_manager); } } // namespace Service::NS diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 2a5128c60..a7385fce8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp @@ -1,6 +1,7 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later +#include "audio_core/audio_core.h" #include "common/assert.h" #include "common/logging/log.h" #include "core/core.h" @@ -65,7 +66,10 @@ NvResult nvhost_nvdec::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& return NvResult::NotImplemented; } -void nvhost_nvdec::OnOpen(DeviceFD fd) {} +void nvhost_nvdec::OnOpen(DeviceFD fd) { + LOG_INFO(Service_NVDRV, "NVDEC video stream started"); + system.AudioCore().SetNVDECActive(true); +} void nvhost_nvdec::OnClose(DeviceFD fd) { LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); @@ -73,6 +77,7 @@ void nvhost_nvdec::OnClose(DeviceFD fd) { if (iter != fd_to_id.end()) { system.GPU().ClearCdmaInstance(iter->second); } + system.AudioCore().SetNVDECActive(false); } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 728bfa00b..d8518149d 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp @@ -198,7 +198,7 @@ NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) IocParamParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called type={}", params.param); + LOG_DEBUG(Service_NVDRV, "(STUBBED) called type={}", params.param); auto object = GetObject(params.handle); if (!object) { @@ -243,7 +243,7 @@ NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { IocFreeParams params; std::memcpy(¶ms, input.data(), sizeof(params)); - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + LOG_DEBUG(Service_NVDRV, "(STUBBED) called"); auto itr = handles.find(params.handle); if (itr == handles.end()) { diff --git a/src/core/hle/service/pcv/pcv.cpp b/src/core/hle/service/pcv/pcv.cpp index 0989474be..f7a497a14 100644 --- a/src/core/hle/service/pcv/pcv.cpp +++ b/src/core/hle/service/pcv/pcv.cpp @@ -3,6 +3,7 @@ #include <memory> +#include "core/hle/ipc_helpers.h" #include "core/hle/service/pcv/pcv.h" #include "core/hle/service/service.h" #include "core/hle/service/sm/sm.h" @@ -77,10 +78,102 @@ public: } }; +class IClkrstSession final : public ServiceFramework<IClkrstSession> { +public: + explicit IClkrstSession(Core::System& system_, DeviceCode deivce_code_) + : ServiceFramework{system_, "IClkrstSession"}, deivce_code(deivce_code_) { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "SetClockEnabled"}, + {1, nullptr, "SetClockDisabled"}, + {2, nullptr, "SetResetAsserted"}, + {3, nullptr, "SetResetDeasserted"}, + {4, nullptr, "SetPowerEnabled"}, + {5, nullptr, "SetPowerDisabled"}, + {6, nullptr, "GetState"}, + {7, &IClkrstSession::SetClockRate, "SetClockRate"}, + {8, &IClkrstSession::GetClockRate, "GetClockRate"}, + {9, nullptr, "SetMinVClockRate"}, + {10, nullptr, "GetPossibleClockRates"}, + {11, nullptr, "GetDvfsTable"}, + }; + // clang-format on + RegisterHandlers(functions); + } + +private: + void SetClockRate(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + clock_rate = rp.Pop<u32>(); + LOG_DEBUG(Service_PCV, "(STUBBED) called, clock_rate={}", clock_rate); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void GetClockRate(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_PCV, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push<u32>(clock_rate); + } + + DeviceCode deivce_code; + u32 clock_rate{}; +}; + +class CLKRST final : public ServiceFramework<CLKRST> { +public: + explicit CLKRST(Core::System& system_, const char* name) : ServiceFramework{system_, name} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &CLKRST::OpenSession, "OpenSession"}, + {1, nullptr, "GetTemperatureThresholds"}, + {2, nullptr, "SetTemperature"}, + {3, nullptr, "GetModuleStateTable"}, + {4, nullptr, "GetModuleStateTableEvent"}, + {5, nullptr, "GetModuleStateTableMaxCount"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void OpenSession(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_code = static_cast<DeviceCode>(rp.Pop<u32>()); + const auto unkonwn_input = rp.Pop<u32>(); + + LOG_DEBUG(Service_PCV, "called, device_code={}, input={}", device_code, unkonwn_input); + + IPC::ResponseBuilder rb{ctx, 2, 0, 1}; + rb.Push(ResultSuccess); + rb.PushIpcInterface<IClkrstSession>(system, device_code); + } +}; + +class CLKRST_A final : public ServiceFramework<CLKRST_A> { +public: + explicit CLKRST_A(Core::System& system_) : ServiceFramework{system_, "clkrst:a"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, nullptr, "ReleaseControl"}, + }; + // clang-format on + + RegisterHandlers(functions); + } +}; + void InstallInterfaces(SM::ServiceManager& sm, Core::System& system) { std::make_shared<PCV>(system)->InstallAsService(sm); std::make_shared<PCV_ARB>(system)->InstallAsService(sm); std::make_shared<PCV_IMM>(system)->InstallAsService(sm); + std::make_shared<CLKRST>(system, "clkrst")->InstallAsService(sm); + std::make_shared<CLKRST>(system, "clkrst:i")->InstallAsService(sm); + std::make_shared<CLKRST_A>(system)->InstallAsService(sm); } } // namespace Service::PCV diff --git a/src/core/hle/service/pcv/pcv.h b/src/core/hle/service/pcv/pcv.h index a42e6f8f6..6b26b6fa7 100644 --- a/src/core/hle/service/pcv/pcv.h +++ b/src/core/hle/service/pcv/pcv.h @@ -13,6 +13,97 @@ class ServiceManager; namespace Service::PCV { +enum class DeviceCode : u32 { + Cpu = 0x40000001, + Gpu = 0x40000002, + I2s1 = 0x40000003, + I2s2 = 0x40000004, + I2s3 = 0x40000005, + Pwm = 0x40000006, + I2c1 = 0x02000001, + I2c2 = 0x02000002, + I2c3 = 0x02000003, + I2c4 = 0x02000004, + I2c5 = 0x02000005, + I2c6 = 0x02000006, + Spi1 = 0x07000000, + Spi2 = 0x07000001, + Spi3 = 0x07000002, + Spi4 = 0x07000003, + Disp1 = 0x40000011, + Disp2 = 0x40000012, + Isp = 0x40000013, + Vi = 0x40000014, + Sdmmc1 = 0x40000015, + Sdmmc2 = 0x40000016, + Sdmmc3 = 0x40000017, + Sdmmc4 = 0x40000018, + Owr = 0x40000019, + Csite = 0x4000001A, + Tsec = 0x4000001B, + Mselect = 0x4000001C, + Hda2codec2x = 0x4000001D, + Actmon = 0x4000001E, + I2cSlow = 0x4000001F, + Sor1 = 0x40000020, + Sata = 0x40000021, + Hda = 0x40000022, + XusbCoreHostSrc = 0x40000023, + XusbFalconSrc = 0x40000024, + XusbFsSrc = 0x40000025, + XusbCoreDevSrc = 0x40000026, + XusbSsSrc = 0x40000027, + UartA = 0x03000001, + UartB = 0x35000405, + UartC = 0x3500040F, + UartD = 0x37000001, + Host1x = 0x4000002C, + Entropy = 0x4000002D, + SocTherm = 0x4000002E, + Vic = 0x4000002F, + Nvenc = 0x40000030, + Nvjpg = 0x40000031, + Nvdec = 0x40000032, + Qspi = 0x40000033, + ViI2c = 0x40000034, + Tsecb = 0x40000035, + Ape = 0x40000036, + AudioDsp = 0x40000037, + AudioUart = 0x40000038, + Emc = 0x40000039, + Plle = 0x4000003A, + PlleHwSeq = 0x4000003B, + Dsi = 0x4000003C, + Maud = 0x4000003D, + Dpaux1 = 0x4000003E, + MipiCal = 0x4000003F, + UartFstMipiCal = 0x40000040, + Osc = 0x40000041, + SysBus = 0x40000042, + SorSafe = 0x40000043, + XusbSs = 0x40000044, + XusbHost = 0x40000045, + XusbDevice = 0x40000046, + Extperiph1 = 0x40000047, + Ahub = 0x40000048, + Hda2hdmicodec = 0x40000049, + Gpuaux = 0x4000004A, + UsbD = 0x4000004B, + Usb2 = 0x4000004C, + Pcie = 0x4000004D, + Afi = 0x4000004E, + PciExClk = 0x4000004F, + PExUsbPhy = 0x40000050, + XUsbPadCtl = 0x40000051, + Apbdma = 0x40000052, + Usb2TrkClk = 0x40000053, + XUsbIoPll = 0x40000054, + XUsbIoPllHwSeq = 0x40000055, + Cec = 0x40000056, + Extperiph2 = 0x40000057, + OscClk = 0x40000080 +}; + void InstallInterfaces(SM::ServiceManager& sm, Core::System& system); } // namespace Service::PCV diff --git a/src/core/hle/service/sockets/bsd.cpp b/src/core/hle/service/sockets/bsd.cpp index c7194731e..cc679cc81 100644 --- a/src/core/hle/service/sockets/bsd.cpp +++ b/src/core/hle/service/sockets/bsd.cpp @@ -9,12 +9,16 @@ #include <fmt/format.h> #include "common/microprofile.h" +#include "common/socket_types.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_thread.h" #include "core/hle/service/sockets/bsd.h" #include "core/hle/service/sockets/sockets_translate.h" #include "core/internal_network/network.h" +#include "core/internal_network/socket_proxy.h" #include "core/internal_network/sockets.h" +#include "network/network.h" namespace Service::Sockets { @@ -472,7 +476,13 @@ std::pair<s32, Errno> BSD::SocketImpl(Domain domain, Type type, Protocol protoco LOG_INFO(Service, "New socket fd={}", fd); - descriptor.socket = std::make_unique<Network::Socket>(); + auto room_member = room_network.GetRoomMember().lock(); + if (room_member && room_member->IsConnected()) { + descriptor.socket = std::make_unique<Network::ProxySocket>(room_network); + } else { + descriptor.socket = std::make_unique<Network::Socket>(); + } + descriptor.socket->Initialize(Translate(domain), Translate(type), Translate(type, protocol)); descriptor.is_connection_based = IsConnectionBased(type); @@ -648,7 +658,7 @@ std::pair<s32, Errno> BSD::FcntlImpl(s32 fd, FcntlCmd cmd, s32 arg) { ASSERT(arg == 0); return {descriptor.flags, Errno::SUCCESS}; case FcntlCmd::SETFL: { - const bool enable = (arg & FLAG_O_NONBLOCK) != 0; + const bool enable = (arg & Network::FLAG_O_NONBLOCK) != 0; const Errno bsd_errno = Translate(descriptor.socket->SetNonBlock(enable)); if (bsd_errno != Errno::SUCCESS) { return {-1, bsd_errno}; @@ -669,7 +679,7 @@ Errno BSD::SetSockOptImpl(s32 fd, u32 level, OptName optname, size_t optlen, con return Errno::BADF; } - Network::Socket* const socket = file_descriptors[fd]->socket.get(); + Network::SocketBase* const socket = file_descriptors[fd]->socket.get(); if (optname == OptName::LINGER) { ASSERT(optlen == sizeof(Linger)); @@ -724,6 +734,8 @@ std::pair<s32, Errno> BSD::RecvImpl(s32 fd, u32 flags, std::vector<u8>& message) FileDescriptor& descriptor = *file_descriptors[fd]; // Apply flags + using Network::FLAG_MSG_DONTWAIT; + using Network::FLAG_O_NONBLOCK; if ((flags & FLAG_MSG_DONTWAIT) != 0) { flags &= ~FLAG_MSG_DONTWAIT; if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { @@ -759,6 +771,8 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess } // Apply flags + using Network::FLAG_MSG_DONTWAIT; + using Network::FLAG_O_NONBLOCK; if ((flags & FLAG_MSG_DONTWAIT) != 0) { flags &= ~FLAG_MSG_DONTWAIT; if ((descriptor.flags & FLAG_O_NONBLOCK) == 0) { @@ -857,8 +871,19 @@ void BSD::BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) co rb.PushEnum(bsd_errno); } +void BSD::OnProxyPacketReceived(const Network::ProxyPacket& packet) { + for (auto& optional_descriptor : file_descriptors) { + if (!optional_descriptor.has_value()) { + continue; + } + FileDescriptor& descriptor = *optional_descriptor; + descriptor.socket.get()->HandleProxyPacket(packet); + } +} + BSD::BSD(Core::System& system_, const char* name) - : ServiceFramework{system_, name, ServiceThreadType::CreateNew} { + : ServiceFramework{system_, name, ServiceThreadType::CreateNew}, room_network{ + system_.GetRoomNetwork()} { // clang-format off static const FunctionInfo functions[] = { {0, &BSD::RegisterClient, "RegisterClient"}, @@ -899,9 +924,20 @@ BSD::BSD(Core::System& system_, const char* name) // clang-format on RegisterHandlers(functions); + + if (auto room_member = room_network.GetRoomMember().lock()) { + proxy_packet_received = room_member->BindOnProxyPacketReceived( + [this](const Network::ProxyPacket& packet) { OnProxyPacketReceived(packet); }); + } else { + LOG_ERROR(Service, "Network isn't initalized"); + } } -BSD::~BSD() = default; +BSD::~BSD() { + if (auto room_member = room_network.GetRoomMember().lock()) { + room_member->Unbind(proxy_packet_received); + } +} BSDCFG::BSDCFG(Core::System& system_) : ServiceFramework{system_, "bsdcfg"} { // clang-format off diff --git a/src/core/hle/service/sockets/bsd.h b/src/core/hle/service/sockets/bsd.h index 9ea36428d..81e855e0f 100644 --- a/src/core/hle/service/sockets/bsd.h +++ b/src/core/hle/service/sockets/bsd.h @@ -7,14 +7,17 @@ #include <vector> #include "common/common_types.h" +#include "common/socket_types.h" #include "core/hle/service/service.h" #include "core/hle/service/sockets/sockets.h" +#include "network/network.h" namespace Core { class System; } namespace Network { +class SocketBase; class Socket; } // namespace Network @@ -30,7 +33,7 @@ private: static constexpr size_t MAX_FD = 128; struct FileDescriptor { - std::unique_ptr<Network::Socket> socket; + std::unique_ptr<Network::SocketBase> socket; s32 flags = 0; bool is_connection_based = false; }; @@ -165,6 +168,14 @@ private: void BuildErrnoResponse(Kernel::HLERequestContext& ctx, Errno bsd_errno) const noexcept; std::array<std::optional<FileDescriptor>, MAX_FD> file_descriptors; + + Network::RoomNetwork& room_network; + + /// Callback to parse and handle a received wifi packet. + void OnProxyPacketReceived(const Network::ProxyPacket& packet); + + // Callback identifier for the OnProxyPacketReceived event. + Network::RoomMember::CallbackHandle<Network::ProxyPacket> proxy_packet_received; }; class BSDCFG final : public ServiceFramework<BSDCFG> { diff --git a/src/core/hle/service/sockets/sockets.h b/src/core/hle/service/sockets/sockets.h index b735b00fc..31b7dad33 100644 --- a/src/core/hle/service/sockets/sockets.h +++ b/src/core/hle/service/sockets/sockets.h @@ -22,7 +22,9 @@ enum class Errno : u32 { AGAIN = 11, INVAL = 22, MFILE = 24, + MSGSIZE = 90, NOTCONN = 107, + TIMEDOUT = 110, }; enum class Domain : u32 { @@ -96,10 +98,6 @@ struct Linger { u32 linger; }; -constexpr u32 FLAG_MSG_DONTWAIT = 0x80; - -constexpr u32 FLAG_O_NONBLOCK = 0x800; - /// Registers all Sockets services with the specified service manager. void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); diff --git a/src/core/hle/service/sockets/sockets_translate.cpp b/src/core/hle/service/sockets/sockets_translate.cpp index 2db10ec81..023aa0486 100644 --- a/src/core/hle/service/sockets/sockets_translate.cpp +++ b/src/core/hle/service/sockets/sockets_translate.cpp @@ -25,6 +25,8 @@ Errno Translate(Network::Errno value) { return Errno::MFILE; case Network::Errno::NOTCONN: return Errno::NOTCONN; + case Network::Errno::TIMEDOUT: + return Errno::TIMEDOUT; default: UNIMPLEMENTED_MSG("Unimplemented errno={}", value); return Errno::SUCCESS; |