diff options
Diffstat (limited to '')
-rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/k_memory_block.h | 33 | ||||
-rw-r--r-- | src/core/hle/kernel/k_memory_block_manager.h | 9 | ||||
-rw-r--r-- | src/core/hle/kernel/k_shared_memory.h | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/k_thread.h | 4 | ||||
-rw-r--r-- | src/core/hle/kernel/kernel.cpp | 2 | ||||
-rw-r--r-- | src/core/hle/kernel/physical_core.h | 2 | ||||
-rw-r--r-- | src/core/hle/service/nfc/mifare_user.cpp | 400 | ||||
-rw-r--r-- | src/core/hle/service/nfc/mifare_user.h | 52 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc.cpp | 27 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_device.cpp | 84 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_device.h | 13 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_result.h | 8 | ||||
-rw-r--r-- | src/core/hle/service/nfc/nfc_user.cpp | 4 | ||||
-rw-r--r-- | src/core/hle/service/nfp/nfp_types.h | 46 |
15 files changed, 625 insertions, 63 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index ad8b8ef95..c6b5ac196 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -528,6 +528,8 @@ add_library(core STATIC hle/service/mnpp/mnpp_app.h hle/service/ncm/ncm.cpp hle/service/ncm/ncm.h + hle/service/nfc/mifare_user.cpp + hle/service/nfc/mifare_user.h hle/service/nfc/nfc.cpp hle/service/nfc/nfc.h hle/service/nfc/nfc_device.cpp diff --git a/src/core/hle/kernel/k_memory_block.h b/src/core/hle/kernel/k_memory_block.h index 3b6e7baff..87ca65592 100644 --- a/src/core/hle/kernel/k_memory_block.h +++ b/src/core/hle/kernel/k_memory_block.h @@ -280,18 +280,19 @@ struct KMemoryInfo { class KMemoryBlock : public Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock> { private: - u16 m_device_disable_merge_left_count; - u16 m_device_disable_merge_right_count; - VAddr m_address; - size_t m_num_pages; - KMemoryState m_memory_state; - u16 m_ipc_lock_count; - u16 m_device_use_count; - u16 m_ipc_disable_merge_count; - KMemoryPermission m_permission; - KMemoryPermission m_original_permission; - KMemoryAttribute m_attribute; - KMemoryBlockDisableMergeAttribute m_disable_merge_attribute; + u16 m_device_disable_merge_left_count{}; + u16 m_device_disable_merge_right_count{}; + VAddr m_address{}; + size_t m_num_pages{}; + KMemoryState m_memory_state{KMemoryState::None}; + u16 m_ipc_lock_count{}; + u16 m_device_use_count{}; + u16 m_ipc_disable_merge_count{}; + KMemoryPermission m_permission{KMemoryPermission::None}; + KMemoryPermission m_original_permission{KMemoryPermission::None}; + KMemoryAttribute m_attribute{KMemoryAttribute::None}; + KMemoryBlockDisableMergeAttribute m_disable_merge_attribute{ + KMemoryBlockDisableMergeAttribute::None}; public: static constexpr int Compare(const KMemoryBlock& lhs, const KMemoryBlock& rhs) { @@ -367,12 +368,8 @@ public: constexpr KMemoryBlock(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) - : Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), - m_device_disable_merge_left_count(), m_device_disable_merge_right_count(), - m_address(addr), m_num_pages(np), m_memory_state(ms), m_ipc_lock_count(0), - m_device_use_count(0), m_ipc_disable_merge_count(), m_permission(p), - m_original_permission(KMemoryPermission::None), m_attribute(attr), - m_disable_merge_attribute() {} + : Common::IntrusiveRedBlackTreeBaseNode<KMemoryBlock>(), m_address(addr), m_num_pages(np), + m_memory_state(ms), m_permission(p), m_attribute(attr) {} constexpr void Initialize(VAddr addr, size_t np, KMemoryState ms, KMemoryPermission p, KMemoryAttribute attr) { diff --git a/src/core/hle/kernel/k_memory_block_manager.h b/src/core/hle/kernel/k_memory_block_manager.h index 9b5873883..d382722a6 100644 --- a/src/core/hle/kernel/k_memory_block_manager.h +++ b/src/core/hle/kernel/k_memory_block_manager.h @@ -3,6 +3,7 @@ #pragma once +#include <array> #include <functional> #include "common/common_funcs.h" @@ -17,9 +18,9 @@ public: static constexpr size_t MaxBlocks = 2; private: - KMemoryBlock* m_blocks[MaxBlocks]; - size_t m_index; - KMemoryBlockSlabManager* m_slab_manager; + std::array<KMemoryBlock*, MaxBlocks> m_blocks{}; + size_t m_index{MaxBlocks}; + KMemoryBlockSlabManager* m_slab_manager{}; private: Result Initialize(size_t num_blocks) { @@ -41,7 +42,7 @@ private: public: KMemoryBlockManagerUpdateAllocator(Result* out_result, KMemoryBlockSlabManager* sm, size_t num_blocks = MaxBlocks) - : m_blocks(), m_index(MaxBlocks), m_slab_manager(sm) { + : m_slab_manager(sm) { *out_result = this->Initialize(num_blocks); } diff --git a/src/core/hle/kernel/k_shared_memory.h b/src/core/hle/kernel/k_shared_memory.h index 5620c3660..a96c55a3e 100644 --- a/src/core/hle/kernel/k_shared_memory.h +++ b/src/core/hle/kernel/k_shared_memory.h @@ -74,7 +74,7 @@ public: static void PostDestroy([[maybe_unused]] uintptr_t arg) {} private: - Core::DeviceMemory* device_memory; + Core::DeviceMemory* device_memory{}; KProcess* owner_process{}; KPageGroup page_list; Svc::MemoryPermission owner_permission{}; diff --git a/src/core/hle/kernel/k_thread.h b/src/core/hle/kernel/k_thread.h index f38c92bff..dc52b4ed3 100644 --- a/src/core/hle/kernel/k_thread.h +++ b/src/core/hle/kernel/k_thread.h @@ -784,8 +784,8 @@ private: std::vector<KSynchronizationObject*> wait_objects_for_debugging; VAddr mutex_wait_address_for_debugging{}; ThreadWaitReasonForDebugging wait_reason_for_debugging{}; - uintptr_t argument; - VAddr stack_top; + uintptr_t argument{}; + VAddr stack_top{}; public: using ConditionVariableThreadTreeType = ConditionVariableThreadTree; diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp index b77723503..288f97df5 100644 --- a/src/core/hle/kernel/kernel.cpp +++ b/src/core/hle/kernel/kernel.cpp @@ -891,7 +891,7 @@ struct KernelCore::Impl { Common::ThreadWorker service_threads_manager; Common::Barrier service_thread_barrier; - std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads; + std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads{}; std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{}; bool is_multicore{}; diff --git a/src/core/hle/kernel/physical_core.h b/src/core/hle/kernel/physical_core.h index 2fc8d4be2..fb2ba4c6b 100644 --- a/src/core/hle/kernel/physical_core.h +++ b/src/core/hle/kernel/physical_core.h @@ -85,7 +85,7 @@ private: std::mutex guard; std::condition_variable on_interrupt; std::unique_ptr<Core::ARM_Interface> arm_interface; - bool is_interrupted; + bool is_interrupted{}; }; } // namespace Kernel diff --git a/src/core/hle/service/nfc/mifare_user.cpp b/src/core/hle/service/nfc/mifare_user.cpp new file mode 100644 index 000000000..51523a3ae --- /dev/null +++ b/src/core/hle/service/nfc/mifare_user.cpp @@ -0,0 +1,400 @@ +// 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/mifare_user.h" +#include "core/hle/service/nfc/nfc_device.h" +#include "core/hle/service/nfc/nfc_result.h" + +namespace Service::NFC { + +MFIUser::MFIUser(Core::System& system_) + : ServiceFramework{system_, "NFC::MFIUser"}, service_context{system_, service_name} { + static const FunctionInfo functions[] = { + {0, &MFIUser::Initialize, "Initialize"}, + {1, &MFIUser::Finalize, "Finalize"}, + {2, &MFIUser::ListDevices, "ListDevices"}, + {3, &MFIUser::StartDetection, "StartDetection"}, + {4, &MFIUser::StopDetection, "StopDetection"}, + {5, &MFIUser::Read, "Read"}, + {6, &MFIUser::Write, "Write"}, + {7, &MFIUser::GetTagInfo, "GetTagInfo"}, + {8, &MFIUser::GetActivateEventHandle, "GetActivateEventHandle"}, + {9, &MFIUser::GetDeactivateEventHandle, "GetDeactivateEventHandle"}, + {10, &MFIUser::GetState, "GetState"}, + {11, &MFIUser::GetDeviceState, "GetDeviceState"}, + {12, &MFIUser::GetNpadId, "GetNpadId"}, + {13, &MFIUser::GetAvailabilityChangeEventHandle, "GetAvailabilityChangeEventHandle"}, + }; + RegisterHandlers(functions); + + availability_change_event = service_context.CreateEvent("MFIUser: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); + } +} + +MFIUser ::~MFIUser() { + availability_change_event->Close(); +} + +void MFIUser::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 MFIUser::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 MFIUser::ListDevices(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NFC, "called"); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareNfcDisabled); + return; + } + + if (!ctx.CanWriteBuffer()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareInvalidArgument); + return; + } + + if (ctx.GetWriteBufferSize() == 0) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareInvalidArgument); + return; + } + + std::vector<u64> nfp_devices; + const std::size_t max_allowed_devices = ctx.GetWriteBufferNumElements<u64>(); + + for (const 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(MifareDeviceNotFound); + return; + } + + ctx.WriteBuffer(nfp_devices); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<s32>(nfp_devices.size())); +} + +void MFIUser::StartDetection(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(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + const auto result = device.value()->StartDetection(NFP::TagProtocol::All); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void MFIUser::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(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + const auto result = device.value()->StopDetection(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void MFIUser::Read(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto buffer{ctx.ReadBuffer()}; + const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareReadBlockParameter>()}; + std::vector<NFP::MifareReadBlockParameter> read_commands(number_of_commands); + + memcpy(read_commands.data(), buffer.data(), + number_of_commands * sizeof(NFP::MifareReadBlockParameter)); + + LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, read_commands_size={}", + device_handle, number_of_commands); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + Result result = ResultSuccess; + std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); + for (std::size_t i = 0; i < number_of_commands; i++) { + result = device.value()->MifareRead(read_commands[i], out_data[i]); + if (result.IsError()) { + break; + } + } + + ctx.WriteBuffer(out_data); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void MFIUser::Write(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto buffer{ctx.ReadBuffer()}; + const auto number_of_commands{ctx.GetReadBufferNumElements<NFP::MifareWriteBlockParameter>()}; + std::vector<NFP::MifareWriteBlockParameter> write_commands(number_of_commands); + + memcpy(write_commands.data(), buffer.data(), + number_of_commands * sizeof(NFP::MifareWriteBlockParameter)); + + LOG_INFO(Service_NFC, "(STUBBED) called, device_handle={}, write_commands_size={}", + device_handle, number_of_commands); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + Result result = ResultSuccess; + std::vector<NFP::MifareReadBlockData> out_data(number_of_commands); + for (std::size_t i = 0; i < number_of_commands; i++) { + result = device.value()->MifareWrite(write_commands[i]); + if (result.IsError()) { + break; + } + } + + if (result.IsSuccess()) { + result = device.value()->Flush(); + } + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void MFIUser::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(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + NFP::TagInfo tag_info{}; + const auto result = device.value()->GetTagInfo(tag_info, true); + ctx.WriteBuffer(tag_info); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); +} + +void MFIUser::GetActivateEventHandle(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(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(device.value()->GetActivateEvent()); +} + +void MFIUser::GetDeactivateEventHandle(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(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(device.value()->GetDeactivateEvent()); +} + +void MFIUser::GetState(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NFC, "called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(state); +} + +void MFIUser::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(MifareDeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(device.value()->GetCurrentState()); +} + +void MFIUser::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(MifareNfcDisabled); + return; + } + + auto device = GetNfcDevice(device_handle); + + if (!device.has_value()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareDeviceNotFound); + return; + } + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.PushEnum(device.value()->GetNpadId()); +} + +void MFIUser::GetAvailabilityChangeEventHandle(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFC, "called"); + + if (state == State::NonInitialized) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(MifareNfcDisabled); + return; + } + + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(availability_change_event->GetReadableEvent()); +} + +std::optional<std::shared_ptr<NfcDevice>> MFIUser::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/mifare_user.h b/src/core/hle/service/nfc/mifare_user.h new file mode 100644 index 000000000..0e0638cb6 --- /dev/null +++ b/src/core/hle/service/nfc/mifare_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 MFIUser final : public ServiceFramework<MFIUser> { +public: + explicit MFIUser(Core::System& system_); + ~MFIUser(); + +private: + enum class State : u32 { + NonInitialized, + Initialized, + }; + + void Initialize(Kernel::HLERequestContext& ctx); + void Finalize(Kernel::HLERequestContext& ctx); + void ListDevices(Kernel::HLERequestContext& ctx); + void StartDetection(Kernel::HLERequestContext& ctx); + void StopDetection(Kernel::HLERequestContext& ctx); + void Read(Kernel::HLERequestContext& ctx); + void Write(Kernel::HLERequestContext& ctx); + void GetTagInfo(Kernel::HLERequestContext& ctx); + void GetActivateEventHandle(Kernel::HLERequestContext& ctx); + void GetDeactivateEventHandle(Kernel::HLERequestContext& ctx); + void GetState(Kernel::HLERequestContext& ctx); + void GetDeviceState(Kernel::HLERequestContext& ctx); + void GetNpadId(Kernel::HLERequestContext& ctx); + void GetAvailabilityChangeEventHandle(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/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 2f4bacb3b..b17b18ab9 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp @@ -6,6 +6,7 @@ #include "common/logging/log.h" #include "common/settings.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/service/nfc/mifare_user.h" #include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfc/nfc_user.h" #include "core/hle/service/service.h" @@ -50,32 +51,6 @@ private: } }; -class MFIUser final : public ServiceFramework<MFIUser> { -public: - explicit MFIUser(Core::System& system_) : ServiceFramework{system_, "NFC::MFIUser"} { - // clang-format off - static const FunctionInfo functions[] = { - {0, nullptr, "Initialize"}, - {1, nullptr, "Finalize"}, - {2, nullptr, "ListDevices"}, - {3, nullptr, "StartDetection"}, - {4, nullptr, "StopDetection"}, - {5, nullptr, "Read"}, - {6, nullptr, "Write"}, - {7, nullptr, "GetTagInfo"}, - {8, nullptr, "GetActivateEventHandle"}, - {9, nullptr, "GetDeactivateEventHandle"}, - {10, nullptr, "GetState"}, - {11, nullptr, "GetDeviceState"}, - {12, nullptr, "GetNpadId"}, - {13, nullptr, "GetAvailabilityChangeEventHandle"}, - }; - // clang-format on - - RegisterHandlers(functions); - } -}; - class NFC_MF_U final : public ServiceFramework<NFC_MF_U> { public: explicit NFC_MF_U(Core::System& system_) : ServiceFramework{system_, "nfc:mf:u"} { diff --git a/src/core/hle/service/nfc/nfc_device.cpp b/src/core/hle/service/nfc/nfc_device.cpp index 4d514cf5f..78578f723 100644 --- a/src/core/hle/service/nfc/nfc_device.cpp +++ b/src/core/hle/service/nfc/nfc_device.cpp @@ -77,11 +77,13 @@ bool NfcDevice::LoadNfcTag(std::span<const u8> data) { return false; } - if (data.size() != sizeof(NFP::EncryptedNTAG215File)) { + if (data.size() < sizeof(NFP::EncryptedNTAG215File)) { LOG_ERROR(Service_NFC, "Not an amiibo, size={}", data.size()); return false; } + tag_data.resize(data.size()); + memcpy(tag_data.data(), data.data(), data.size()); memcpy(&encrypted_tag_data, data.data(), sizeof(NFP::EncryptedNTAG215File)); device_state = NFP::DeviceState::TagFound; @@ -121,7 +123,7 @@ void NfcDevice::Finalize() { device_state = NFP::DeviceState::Unavailable; } -Result NfcDevice::StartDetection(s32 protocol_) { +Result NfcDevice::StartDetection(NFP::TagProtocol allowed_protocol) { if (device_state != NFP::DeviceState::Initialized && device_state != NFP::DeviceState::TagRemoved) { LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); @@ -134,7 +136,7 @@ Result NfcDevice::StartDetection(s32 protocol_) { } device_state = NFP::DeviceState::SearchingForTag; - protocol = protocol_; + allowed_protocols = allowed_protocol; return ResultSuccess; } @@ -160,7 +162,7 @@ Result NfcDevice::StopDetection() { return WrongDeviceState; } -Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { +Result NfcDevice::Flush() { if (device_state != NFP::DeviceState::TagFound && device_state != NFP::DeviceState::TagMounted) { LOG_ERROR(Service_NFC, "Wrong device state {}", device_state); @@ -170,6 +172,34 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { return WrongDeviceState; } + if (!npad_device->WriteNfc(tag_data)) { + LOG_ERROR(Service_NFP, "Error writing to file"); + return MifareReadError; + } + + return ResultSuccess; +} + +Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) 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; + } + + if (is_mifare) { + 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::Type4, + }; + return ResultSuccess; + } + // Protocol and tag type may change here tag_info = { .uuid = encrypted_tag_data.uuid.uid, @@ -181,6 +211,52 @@ Result NfcDevice::GetTagInfo(NFP::TagInfo& tag_info) const { return ResultSuccess; } +Result NfcDevice::MifareRead(const NFP::MifareReadBlockParameter& parameter, + NFP::MifareReadBlockData& read_block_data) { + const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); + read_block_data.sector_number = parameter.sector_number; + + 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; + } + + if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { + return MifareReadError; + } + + // TODO: Use parameter.sector_key to read encrypted data + memcpy(read_block_data.data.data(), tag_data.data() + sector_index, sizeof(NFP::DataBlock)); + + return ResultSuccess; +} + +Result NfcDevice::MifareWrite(const NFP::MifareWriteBlockParameter& parameter) { + const std::size_t sector_index = parameter.sector_number * sizeof(NFP::DataBlock); + + 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; + } + + if (tag_data.size() < sector_index + sizeof(NFP::DataBlock)) { + return MifareReadError; + } + + // TODO: Use parameter.sector_key to encrypt the data + memcpy(tag_data.data() + sector_index, parameter.data.data(), sizeof(NFP::DataBlock)); + + return ResultSuccess; +} + u64 NfcDevice::GetHandle() const { // Generate a handle based of the npad id return static_cast<u64>(npad_id); diff --git a/src/core/hle/service/nfc/nfc_device.h b/src/core/hle/service/nfc/nfc_device.h index fa1348f1a..a6e114d36 100644 --- a/src/core/hle/service/nfc/nfc_device.h +++ b/src/core/hle/service/nfc/nfc_device.h @@ -34,10 +34,16 @@ public: void Initialize(); void Finalize(); - Result StartDetection(s32 protocol_); + Result StartDetection(NFP::TagProtocol allowed_protocol); Result StopDetection(); + Result Flush(); - Result GetTagInfo(NFP::TagInfo& tag_info) const; + Result GetTagInfo(NFP::TagInfo& tag_info, bool is_mifare) const; + + Result MifareRead(const NFP::MifareReadBlockParameter& parameter, + NFP::MifareReadBlockData& read_block_data); + + Result MifareWrite(const NFP::MifareWriteBlockParameter& parameter); u64 GetHandle() const; NFP::DeviceState GetCurrentState() const; @@ -61,10 +67,11 @@ private: Kernel::KEvent* deactivate_event = nullptr; Kernel::KEvent* availability_change_event = nullptr; - s32 protocol{}; + NFP::TagProtocol allowed_protocols{}; NFP::DeviceState device_state{NFP::DeviceState::Unavailable}; NFP::EncryptedNTAG215File encrypted_tag_data{}; + std::vector<u8> 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 index 537dc15f4..146b8ba61 100644 --- a/src/core/hle/service/nfc/nfc_result.h +++ b/src/core/hle/service/nfc/nfc_result.h @@ -12,6 +12,12 @@ 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); + +constexpr Result MifareDeviceNotFound(ErrorModule::NFCMifare, 64); +constexpr Result MifareInvalidArgument(ErrorModule::NFCMifare, 65); +constexpr Result MifareWrongDeviceState(ErrorModule::NFCMifare, 73); +constexpr Result MifareNfcDisabled(ErrorModule::NFCMifare, 80); +constexpr Result MifareTagRemoved(ErrorModule::NFCMifare, 97); +constexpr Result MifareReadError(ErrorModule::NFCMifare, 288); } // namespace Service::NFC diff --git a/src/core/hle/service/nfc/nfc_user.cpp b/src/core/hle/service/nfc/nfc_user.cpp index ced2d560b..4615697e2 100644 --- a/src/core/hle/service/nfc/nfc_user.cpp +++ b/src/core/hle/service/nfc/nfc_user.cpp @@ -201,7 +201,7 @@ void IUser::AttachAvailabilityChangeEvent(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<NFP::TagProtocol>()}; LOG_INFO(Service_NFC, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); if (state == State::NonInitialized) { @@ -267,7 +267,7 @@ void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { } NFP::TagInfo tag_info{}; - const auto result = device.value()->GetTagInfo(tag_info); + const auto result = device.value()->GetTagInfo(tag_info, false); ctx.WriteBuffer(tag_info); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(result); diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 69858096a..fc228c2b2 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -106,11 +106,24 @@ enum class CabinetMode : u8 { StartFormatter, }; +enum class MifareCmd : u8 { + AuthA = 0x60, + AuthB = 0x61, + Read = 0x30, + Write = 0xA0, + Transfer = 0xB0, + Decrement = 0xC0, + Increment = 0xC1, + Store = 0xC2 +}; + using UniqueSerialNumber = std::array<u8, 7>; using LockBytes = std::array<u8, 2>; using HashData = std::array<u8, 0x20>; using ApplicationArea = std::array<u8, 0xD8>; using AmiiboName = std::array<char, (amiibo_name_length * 4) + 1>; +using DataBlock = std::array<u8, 0x10>; +using KeyData = std::array<u8, 0x6>; struct TagUuid { UniqueSerialNumber uid; @@ -323,4 +336,37 @@ struct RegisterInfo { }; static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); +struct SectorKey { + MifareCmd command; + u8 unknown; // Usually 1 + INSERT_PADDING_BYTES(0x6); + KeyData sector_key; + INSERT_PADDING_BYTES(0x2); +}; +static_assert(sizeof(SectorKey) == 0x10, "SectorKey is an invalid size"); + +struct MifareReadBlockParameter { + u8 sector_number; + INSERT_PADDING_BYTES(0x7); + SectorKey sector_key; +}; +static_assert(sizeof(MifareReadBlockParameter) == 0x18, + "MifareReadBlockParameter is an invalid size"); + +struct MifareReadBlockData { + DataBlock data; + u8 sector_number; + INSERT_PADDING_BYTES(0x7); +}; +static_assert(sizeof(MifareReadBlockData) == 0x18, "MifareReadBlockData is an invalid size"); + +struct MifareWriteBlockParameter { + DataBlock data; + u8 sector_number; + INSERT_PADDING_BYTES(0x7); + SectorKey sector_key; +}; +static_assert(sizeof(MifareWriteBlockParameter) == 0x28, + "MifareWriteBlockParameter is an invalid size"); + } // namespace Service::NFP |