diff options
Diffstat (limited to 'src/core')
33 files changed, 1682 insertions, 551 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 6e8d11919..0c10cd019 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -467,6 +467,8 @@ add_library(core STATIC hle/service/mii/types.h hle/service/mm/mm_u.cpp hle/service/mm/mm_u.h + hle/service/mnpp/mnpp_app.cpp + hle/service/mnpp/mnpp_app.h hle/service/ncm/ncm.cpp hle/service/ncm/ncm.h hle/service/nfc/nfc.cpp diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 7c0950bb0..f19ac4607 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp @@ -128,15 +128,6 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { if (exefs == nullptr) return exefs; - if (Settings::values.dump_exefs) { - LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); - const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id); - if (dump_dir != nullptr) { - const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); - VfsRawCopyD(exefs, exefs_dir); - } - } - const auto& disabled = Settings::values.disabled_addons[title_id]; const auto update_disabled = std::find(disabled.cbegin(), disabled.cend(), "Update") != disabled.cend(); @@ -179,6 +170,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { } } + if (Settings::values.dump_exefs) { + LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); + const auto dump_dir = fs_controller.GetModificationDumpRoot(title_id); + if (dump_dir != nullptr) { + const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); + VfsRawCopyD(exefs, exefs_dir); + } + } + return exefs; } diff --git a/src/core/frontend/applets/profile_select.cpp b/src/core/frontend/applets/profile_select.cpp index 3e4f90be2..4c58c310f 100644 --- a/src/core/frontend/applets/profile_select.cpp +++ b/src/core/frontend/applets/profile_select.cpp @@ -13,8 +13,7 @@ ProfileSelectApplet::~ProfileSelectApplet() = default; void DefaultProfileSelectApplet::SelectProfile( std::function<void(std::optional<Common::UUID>)> callback) const { Service::Account::ProfileManager manager; - callback(manager.GetUser(Settings::values.current_user.GetValue()) - .value_or(Common::UUID{Common::INVALID_UUID})); + callback(manager.GetUser(Settings::values.current_user.GetValue()).value_or(Common::UUID{})); LOG_INFO(Service_ACC, "called, selecting current user instead of prompting..."); } diff --git a/src/core/hid/emulated_controller.cpp b/src/core/hid/emulated_controller.cpp index a7cdf45e6..7e05666d6 100644 --- a/src/core/hid/emulated_controller.cpp +++ b/src/core/hid/emulated_controller.cpp @@ -269,7 +269,8 @@ void EmulatedController::ReloadInput() { } // Use a common UUID for TAS - const auto tas_uuid = Common::UUID{0x0, 0x7A5}; + static constexpr Common::UUID TAS_UUID = Common::UUID{ + {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x7, 0xA5, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}}; // Register TAS devices. No need to force update for (std::size_t index = 0; index < tas_button_devices.size(); ++index) { @@ -278,8 +279,8 @@ void EmulatedController::ReloadInput() { } tas_button_devices[index]->SetCallback({ .on_change = - [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) { - SetButton(callback, index, tas_uuid); + [this, index](const Common::Input::CallbackStatus& callback) { + SetButton(callback, index, TAS_UUID); }, }); } @@ -290,8 +291,8 @@ void EmulatedController::ReloadInput() { } tas_stick_devices[index]->SetCallback({ .on_change = - [this, index, tas_uuid](const Common::Input::CallbackStatus& callback) { - SetStick(callback, index, tas_uuid); + [this, index](const Common::Input::CallbackStatus& callback) { + SetStick(callback, index, TAS_UUID); }, }); } @@ -884,6 +885,12 @@ bool EmulatedController::TestVibration(std::size_t device_index) { return SetVibration(device_index, DEFAULT_VIBRATION_VALUE); } +bool EmulatedController::SetPollingMode(Common::Input::PollingMode polling_mode) { + LOG_INFO(Service_HID, "Set polling mode {}", polling_mode); + auto& output_device = output_devices[static_cast<std::size_t>(DeviceIndex::Right)]; + return output_device->SetPollingMode(polling_mode) == Common::Input::PollingError::None; +} + void EmulatedController::SetLedPattern() { for (auto& device : output_devices) { if (!device) { diff --git a/src/core/hid/emulated_controller.h b/src/core/hid/emulated_controller.h index d8642c5b3..aa52f9572 100644 --- a/src/core/hid/emulated_controller.h +++ b/src/core/hid/emulated_controller.h @@ -299,16 +299,23 @@ public: /** * Sends a specific vibration to the output device - * @return returns true if vibration had no errors + * @return true if vibration had no errors */ bool SetVibration(std::size_t device_index, VibrationValue vibration); /** * Sends a small vibration to the output device - * @return returns true if SetVibration was successfull + * @return true if SetVibration was successfull */ bool TestVibration(std::size_t device_index); + /** + * Sets the desired data to be polled from a controller + * @param polling_mode type of input desired buttons, gyro, nfc, ir, etc. + * @return true if SetPollingMode was successfull + */ + bool SetPollingMode(Common::Input::PollingMode polling_mode); + /// Returns the led pattern corresponding to this emulated controller LedPattern GetLedPattern() const; diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index cf204f570..026257115 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -404,6 +404,11 @@ inline s32 RequestParser::Pop() { return static_cast<s32>(Pop<u32>()); } +// Ignore the -Wclass-memaccess warning on memcpy for non-trivially default constructible objects. +#if defined(__GNUC__) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wclass-memaccess" +#endif template <typename T> void RequestParser::PopRaw(T& value) { static_assert(std::is_trivially_copyable_v<T>, @@ -411,6 +416,9 @@ void RequestParser::PopRaw(T& value) { std::memcpy(&value, cmdbuf + index, sizeof(T)); index += (sizeof(T) + 3) / 4; // round up to word length } +#if defined(__GNUC__) +#pragma GCC diagnostic pop +#endif template <typename T> T RequestParser::PopRaw() { diff --git a/src/core/hle/kernel/k_code_memory.cpp b/src/core/hle/kernel/k_code_memory.cpp index d69f7ffb7..0b225e8e0 100644 --- a/src/core/hle/kernel/k_code_memory.cpp +++ b/src/core/hle/kernel/k_code_memory.cpp @@ -2,6 +2,7 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include "common/alignment.h" #include "common/common_types.h" #include "core/device_memory.h" #include "core/hle/kernel/k_auto_object.h" @@ -28,8 +29,7 @@ ResultCode KCodeMemory::Initialize(Core::DeviceMemory& device_memory, VAddr addr auto& page_table = m_owner->PageTable(); // Construct the page group. - KMemoryInfo kBlockInfo = page_table.QueryInfo(addr); - m_page_group = KPageLinkedList(kBlockInfo.GetAddress(), kBlockInfo.GetNumPages()); + m_page_group = KPageLinkedList(addr, Common::DivideUp(size, PageSize)); // Lock the memory. R_TRY(page_table.LockForCodeMemory(addr, size)) @@ -143,4 +143,4 @@ ResultCode KCodeMemory::UnmapFromOwner(VAddr address, size_t size) { return ResultSuccess; } -} // namespace Kernel
\ No newline at end of file +} // namespace Kernel diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 912853e5c..88aa2a152 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -41,24 +41,6 @@ constexpr std::size_t GetAddressSpaceWidthFromType(FileSys::ProgramAddressSpaceT } } -constexpr u64 GetAddressInRange(const KMemoryInfo& info, VAddr addr) { - if (info.GetAddress() < addr) { - return addr; - } - return info.GetAddress(); -} - -constexpr std::size_t GetSizeInRange(const KMemoryInfo& info, VAddr start, VAddr end) { - std::size_t size{info.GetSize()}; - if (info.GetAddress() < start) { - size -= start - info.GetAddress(); - } - if (info.GetEndAddress() > end) { - size -= info.GetEndAddress() - end; - } - return size; -} - } // namespace KPageTable::KPageTable(Core::System& system_) @@ -400,148 +382,471 @@ ResultCode KPageTable::UnmapProcessMemory(VAddr dst_addr, std::size_t size, return ResultSuccess; } -ResultCode KPageTable::MapPhysicalMemory(VAddr addr, std::size_t size) { +ResultCode KPageTable::MapPhysicalMemory(VAddr address, std::size_t size) { // Lock the physical memory lock. KScopedLightLock map_phys_mem_lk(map_physical_memory_lock); - // Lock the table. - KScopedLightLock lk(general_lock); - - std::size_t mapped_size{}; - const VAddr end_addr{addr + size}; + // Calculate the last address for convenience. + const VAddr last_address = address + size - 1; - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state != KMemoryState::Free) { - mapped_size += GetSizeInRange(info, addr, end_addr); - } - }); + // Define iteration variables. + VAddr cur_address; + std::size_t mapped_size; - if (mapped_size == size) { - return ResultSuccess; - } + // The entire mapping process can be retried. + while (true) { + // Check if the memory is already mapped. + { + // Lock the table. + KScopedLightLock lk(general_lock); + + // Iterate over the memory. + cur_address = address; + mapped_size = 0; + + auto it = block_manager->FindIterator(cur_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != block_manager->end()); + + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); + + // Check if we're done. + if (last_address <= info.GetLastAddress()) { + if (info.GetState() != KMemoryState::Free) { + mapped_size += (last_address + 1 - cur_address); + } + break; + } + + // Track the memory if it's mapped. + if (info.GetState() != KMemoryState::Free) { + mapped_size += VAddr(info.GetEndAddress()) - cur_address; + } + + // Advance. + cur_address = info.GetEndAddress(); + ++it; + } - const std::size_t remaining_size{size - mapped_size}; - const std::size_t remaining_pages{remaining_size / PageSize}; + // If the size mapped is the size requested, we've nothing to do. + R_SUCCEED_IF(size == mapped_size); + } - // Reserve the memory from the process resource limit. - KScopedResourceReservation memory_reservation( - system.Kernel().CurrentProcess()->GetResourceLimit(), LimitableResource::PhysicalMemory, - remaining_size); - if (!memory_reservation.Succeeded()) { - LOG_ERROR(Kernel, "Could not reserve remaining {:X} bytes", remaining_size); - return ResultLimitReached; + // Allocate and map the memory. + { + // Reserve the memory from the process resource limit. + KScopedResourceReservation memory_reservation( + system.Kernel().CurrentProcess()->GetResourceLimit(), + LimitableResource::PhysicalMemory, size - mapped_size); + R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached); + + // Allocate pages for the new memory. + KPageLinkedList page_linked_list; + R_TRY(system.Kernel().MemoryManager().Allocate( + page_linked_list, (size - mapped_size) / PageSize, memory_pool, allocation_option)); + + // Map the memory. + { + // Lock the table. + KScopedLightLock lk(general_lock); + + size_t num_allocator_blocks = 0; + + // Verify that nobody has mapped memory since we first checked. + { + // Iterate over the memory. + size_t checked_mapped_size = 0; + cur_address = address; + + auto it = block_manager->FindIterator(cur_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != block_manager->end()); + + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); + + const bool is_free = info.GetState() == KMemoryState::Free; + if (is_free) { + if (info.GetAddress() < address) { + ++num_allocator_blocks; + } + if (last_address < info.GetLastAddress()) { + ++num_allocator_blocks; + } + } + + // Check if we're done. + if (last_address <= info.GetLastAddress()) { + if (!is_free) { + checked_mapped_size += (last_address + 1 - cur_address); + } + break; + } + + // Track the memory if it's mapped. + if (!is_free) { + checked_mapped_size += VAddr(info.GetEndAddress()) - cur_address; + } + + // Advance. + cur_address = info.GetEndAddress(); + ++it; + } + + // If the size now isn't what it was before, somebody mapped or unmapped + // concurrently. If this happened, retry. + if (mapped_size != checked_mapped_size) { + continue; + } + } + + // Reset the current tracking address, and make sure we clean up on failure. + cur_address = address; + auto unmap_guard = detail::ScopeExit([&] { + if (cur_address > address) { + const VAddr last_unmap_address = cur_address - 1; + + // Iterate, unmapping the pages. + cur_address = address; + + auto it = block_manager->FindIterator(cur_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != block_manager->end()); + + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); + + // If the memory state is free, we mapped it and need to unmap it. + if (info.GetState() == KMemoryState::Free) { + // Determine the range to unmap. + const size_t cur_pages = + std::min(VAddr(info.GetEndAddress()) - cur_address, + last_unmap_address + 1 - cur_address) / + PageSize; + + // Unmap. + ASSERT(Operate(cur_address, cur_pages, KMemoryPermission::None, + OperationType::Unmap) + .IsSuccess()); + } + + // Check if we're done. + if (last_unmap_address <= info.GetLastAddress()) { + break; + } + + // Advance. + cur_address = info.GetEndAddress(); + ++it; + } + } + }); + + // Iterate over the memory. + auto pg_it = page_linked_list.Nodes().begin(); + PAddr pg_phys_addr = pg_it->GetAddress(); + size_t pg_pages = pg_it->GetNumPages(); + + auto it = block_manager->FindIterator(cur_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != block_manager->end()); + + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); + + // If it's unmapped, we need to map it. + if (info.GetState() == KMemoryState::Free) { + // Determine the range to map. + size_t map_pages = std::min(VAddr(info.GetEndAddress()) - cur_address, + last_address + 1 - cur_address) / + PageSize; + + // While we have pages to map, map them. + while (map_pages > 0) { + // Check if we're at the end of the physical block. + if (pg_pages == 0) { + // Ensure there are more pages to map. + ASSERT(pg_it != page_linked_list.Nodes().end()); + + // Advance our physical block. + ++pg_it; + pg_phys_addr = pg_it->GetAddress(); + pg_pages = pg_it->GetNumPages(); + } + + // Map whatever we can. + const size_t cur_pages = std::min(pg_pages, map_pages); + R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::UserReadWrite, + OperationType::Map, pg_phys_addr)); + + // Advance. + cur_address += cur_pages * PageSize; + map_pages -= cur_pages; + + pg_phys_addr += cur_pages * PageSize; + pg_pages -= cur_pages; + } + } + + // Check if we're done. + if (last_address <= info.GetLastAddress()) { + break; + } + + // Advance. + cur_address = info.GetEndAddress(); + ++it; + } + + // We succeeded, so commit the memory reservation. + memory_reservation.Commit(); + + // Increase our tracked mapped size. + mapped_physical_memory_size += (size - mapped_size); + + // Update the relevant memory blocks. + block_manager->Update(address, size / PageSize, KMemoryState::Free, + KMemoryPermission::None, KMemoryAttribute::None, + KMemoryState::Normal, KMemoryPermission::UserReadWrite, + KMemoryAttribute::None); + + // Cancel our guard. + unmap_guard.Cancel(); + + return ResultSuccess; + } + } } +} - KPageLinkedList page_linked_list; +ResultCode KPageTable::UnmapPhysicalMemory(VAddr address, std::size_t size) { + // Lock the physical memory lock. + KScopedLightLock map_phys_mem_lk(map_physical_memory_lock); - CASCADE_CODE(system.Kernel().MemoryManager().Allocate(page_linked_list, remaining_pages, - memory_pool, allocation_option)); + // Lock the table. + KScopedLightLock lk(general_lock); - // We succeeded, so commit the memory reservation. - memory_reservation.Commit(); + // Calculate the last address for convenience. + const VAddr last_address = address + size - 1; - // Map the memory. - auto node{page_linked_list.Nodes().begin()}; - PAddr map_addr{node->GetAddress()}; - std::size_t src_num_pages{node->GetNumPages()}; - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state != KMemoryState::Free) { - return; - } + // Define iteration variables. + VAddr cur_address = 0; + std::size_t mapped_size = 0; + std::size_t num_allocator_blocks = 0; - std::size_t dst_num_pages{GetSizeInRange(info, addr, end_addr) / PageSize}; - VAddr dst_addr{GetAddressInRange(info, addr)}; + // Check if the memory is mapped. + { + // Iterate over the memory. + cur_address = address; + mapped_size = 0; + + auto it = block_manager->FindIterator(cur_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != block_manager->end()); + + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); + + // Verify the memory's state. + const bool is_normal = info.GetState() == KMemoryState::Normal && + info.GetAttribute() == KMemoryAttribute::None; + const bool is_free = info.GetState() == KMemoryState::Free; + R_UNLESS(is_normal || is_free, ResultInvalidCurrentMemory); + + if (is_normal) { + R_UNLESS(info.GetAttribute() == KMemoryAttribute::None, ResultInvalidCurrentMemory); + + if (info.GetAddress() < address) { + ++num_allocator_blocks; + } + if (last_address < info.GetLastAddress()) { + ++num_allocator_blocks; + } + } - while (dst_num_pages) { - if (!src_num_pages) { - node = std::next(node); - map_addr = node->GetAddress(); - src_num_pages = node->GetNumPages(); + // Check if we're done. + if (last_address <= info.GetLastAddress()) { + if (is_normal) { + mapped_size += (last_address + 1 - cur_address); + } + break; } - const std::size_t num_pages{std::min(src_num_pages, dst_num_pages)}; - Operate(dst_addr, num_pages, KMemoryPermission::UserReadWrite, OperationType::Map, - map_addr); + // Track the memory if it's mapped. + if (is_normal) { + mapped_size += VAddr(info.GetEndAddress()) - cur_address; + } - dst_addr += num_pages * PageSize; - map_addr += num_pages * PageSize; - src_num_pages -= num_pages; - dst_num_pages -= num_pages; + // Advance. + cur_address = info.GetEndAddress(); + ++it; } - }); - - mapped_physical_memory_size += remaining_size; - - const std::size_t num_pages{size / PageSize}; - block_manager->Update(addr, num_pages, KMemoryState::Free, KMemoryPermission::None, - KMemoryAttribute::None, KMemoryState::Normal, - KMemoryPermission::UserReadWrite, KMemoryAttribute::None); - return ResultSuccess; -} + // If there's nothing mapped, we've nothing to do. + R_SUCCEED_IF(mapped_size == 0); + } -ResultCode KPageTable::UnmapPhysicalMemory(VAddr addr, std::size_t size) { - // Lock the physical memory lock. - KScopedLightLock map_phys_mem_lk(map_physical_memory_lock); + // Make a page group for the unmap region. + KPageLinkedList pg; + { + auto& impl = this->PageTableImpl(); + + // Begin traversal. + Common::PageTable::TraversalContext context; + Common::PageTable::TraversalEntry cur_entry = {.phys_addr = 0, .block_size = 0}; + bool cur_valid = false; + Common::PageTable::TraversalEntry next_entry; + bool next_valid = false; + size_t tot_size = 0; + + cur_address = address; + next_valid = impl.BeginTraversal(next_entry, context, cur_address); + next_entry.block_size = + (next_entry.block_size - (next_entry.phys_addr & (next_entry.block_size - 1))); + + // Iterate, building the group. + while (true) { + if ((!next_valid && !cur_valid) || + (next_valid && cur_valid && + next_entry.phys_addr == cur_entry.phys_addr + cur_entry.block_size)) { + cur_entry.block_size += next_entry.block_size; + } else { + if (cur_valid) { + // ASSERT(IsHeapPhysicalAddress(cur_entry.phys_addr)); + R_TRY(pg.AddBlock(cur_entry.phys_addr, cur_entry.block_size / PageSize)); + } + + // Update tracking variables. + tot_size += cur_entry.block_size; + cur_entry = next_entry; + cur_valid = next_valid; + } - // Lock the table. - KScopedLightLock lk(general_lock); + if (cur_entry.block_size + tot_size >= size) { + break; + } - const VAddr end_addr{addr + size}; - ResultCode result{ResultSuccess}; - std::size_t mapped_size{}; + next_valid = impl.ContinueTraversal(next_entry, context); + } - // Verify that the region can be unmapped - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state == KMemoryState::Normal) { - if (info.attribute != KMemoryAttribute::None) { - result = ResultInvalidCurrentMemory; - return; + // Add the last block. + if (cur_valid) { + // ASSERT(IsHeapPhysicalAddress(cur_entry.phys_addr)); + R_TRY(pg.AddBlock(cur_entry.phys_addr, (size - tot_size) / PageSize)); + } + } + ASSERT(pg.GetNumPages() == mapped_size / PageSize); + + // Reset the current tracking address, and make sure we clean up on failure. + cur_address = address; + auto remap_guard = detail::ScopeExit([&] { + if (cur_address > address) { + const VAddr last_map_address = cur_address - 1; + cur_address = address; + + // Iterate over the memory we unmapped. + auto it = block_manager->FindIterator(cur_address); + auto pg_it = pg.Nodes().begin(); + PAddr pg_phys_addr = pg_it->GetAddress(); + size_t pg_pages = pg_it->GetNumPages(); + + while (true) { + // Get the memory info for the pages we unmapped, convert to property. + const KMemoryInfo info = it->GetMemoryInfo(); + + // If the memory is normal, we unmapped it and need to re-map it. + if (info.GetState() == KMemoryState::Normal) { + // Determine the range to map. + size_t map_pages = std::min(VAddr(info.GetEndAddress()) - cur_address, + last_map_address + 1 - cur_address) / + PageSize; + + // While we have pages to map, map them. + while (map_pages > 0) { + // Check if we're at the end of the physical block. + if (pg_pages == 0) { + // Ensure there are more pages to map. + ASSERT(pg_it != pg.Nodes().end()); + + // Advance our physical block. + ++pg_it; + pg_phys_addr = pg_it->GetAddress(); + pg_pages = pg_it->GetNumPages(); + } + + // Map whatever we can. + const size_t cur_pages = std::min(pg_pages, map_pages); + ASSERT(this->Operate(cur_address, cur_pages, info.GetPermission(), + OperationType::Map, pg_phys_addr) == ResultSuccess); + + // Advance. + cur_address += cur_pages * PageSize; + map_pages -= cur_pages; + + pg_phys_addr += cur_pages * PageSize; + pg_pages -= cur_pages; + } + } + + // Check if we're done. + if (last_map_address <= info.GetLastAddress()) { + break; + } + + // Advance. + ++it; } - mapped_size += GetSizeInRange(info, addr, end_addr); - } else if (info.state != KMemoryState::Free) { - result = ResultInvalidCurrentMemory; } }); - if (result.IsError()) { - return result; - } + // Iterate over the memory, unmapping as we go. + auto it = block_manager->FindIterator(cur_address); + while (true) { + // Check that the iterator is valid. + ASSERT(it != block_manager->end()); - if (!mapped_size) { - return ResultSuccess; - } + // Get the memory info. + const KMemoryInfo info = it->GetMemoryInfo(); - // Unmap each region within the range - KPageLinkedList page_linked_list; - block_manager->IterateForRange(addr, end_addr, [&](const KMemoryInfo& info) { - if (info.state == KMemoryState::Normal) { - const std::size_t block_size{GetSizeInRange(info, addr, end_addr)}; - const std::size_t block_num_pages{block_size / PageSize}; - const VAddr block_addr{GetAddressInRange(info, addr)}; - - AddRegionToPages(block_addr, block_size / PageSize, page_linked_list); - - if (result = Operate(block_addr, block_num_pages, KMemoryPermission::None, - OperationType::Unmap); - result.IsError()) { - return; - } + // If the memory state is normal, we need to unmap it. + if (info.GetState() == KMemoryState::Normal) { + // Determine the range to unmap. + const size_t cur_pages = std::min(VAddr(info.GetEndAddress()) - cur_address, + last_address + 1 - cur_address) / + PageSize; + + // Unmap. + R_TRY(Operate(cur_address, cur_pages, KMemoryPermission::None, OperationType::Unmap)); } - }); - if (result.IsError()) { - return result; - } - const std::size_t num_pages{size / PageSize}; - system.Kernel().MemoryManager().Free(page_linked_list, num_pages, memory_pool, - allocation_option); + // Check if we're done. + if (last_address <= info.GetLastAddress()) { + break; + } - block_manager->Update(addr, num_pages, KMemoryState::Free); + // Advance. + cur_address = info.GetEndAddress(); + ++it; + } + // Release the memory resource. + mapped_physical_memory_size -= mapped_size; auto process{system.Kernel().CurrentProcess()}; process->GetResourceLimit()->Release(LimitableResource::PhysicalMemory, mapped_size); - mapped_physical_memory_size -= mapped_size; + + // Update memory blocks. + system.Kernel().MemoryManager().Free(pg, size / PageSize, memory_pool, allocation_option); + block_manager->Update(address, size / PageSize, KMemoryState::Free, KMemoryPermission::None, + KMemoryAttribute::None); + + // We succeeded. + remap_guard.Cancel(); return ResultSuccess; } @@ -681,9 +986,8 @@ ResultCode KPageTable::UnmapPages(VAddr addr, const KPageLinkedList& page_linked VAddr cur_addr{addr}; for (const auto& node : page_linked_list.Nodes()) { - const std::size_t num_pages{(addr - cur_addr) / PageSize}; - if (const auto result{ - Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)}; + if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None, + OperationType::Unmap)}; result.IsError()) { return result; } diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9387373c1..9836809f2 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -645,6 +645,10 @@ static void OutputDebugString(Core::System& system, VAddr address, u64 len) { LOG_DEBUG(Debug_Emulated, "{}", str); } +static void OutputDebugString32(Core::System& system, u32 address, u32 len) { + OutputDebugString(system, address, len); +} + /// Gets system/memory information for the current process static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle handle, u64 info_sub_id) { @@ -1404,7 +1408,7 @@ static ResultCode UnmapProcessMemory(Core::System& system, VAddr dst_address, Ha } static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr address, size_t size) { - LOG_TRACE(Kernel_SVC, "called, handle_out=0x{:X}, address=0x{:X}, size=0x{:X}", + LOG_TRACE(Kernel_SVC, "called, handle_out={}, address=0x{:X}, size=0x{:X}", static_cast<void*>(out), address, size); // Get kernel instance. auto& kernel = system.Kernel(); @@ -1438,6 +1442,10 @@ static ResultCode CreateCodeMemory(Core::System& system, Handle* out, VAddr addr return ResultSuccess; } +static ResultCode CreateCodeMemory32(Core::System& system, Handle* out, u32 address, u32 size) { + return CreateCodeMemory(system, out, address, size); +} + static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_handle, u32 operation, VAddr address, size_t size, Svc::MemoryPermission perm) { @@ -1517,6 +1525,12 @@ static ResultCode ControlCodeMemory(Core::System& system, Handle code_memory_han return ResultSuccess; } +static ResultCode ControlCodeMemory32(Core::System& system, Handle code_memory_handle, + u32 operation, u64 address, u64 size, + Svc::MemoryPermission perm) { + return ControlCodeMemory(system, code_memory_handle, operation, address, size, perm); +} + static ResultCode QueryProcessMemory(Core::System& system, VAddr memory_info_address, VAddr page_info_address, Handle process_handle, VAddr address) { @@ -2559,9 +2573,9 @@ struct FunctionDef { } // namespace static const FunctionDef SVC_Table_32[] = { - {0x00, nullptr, "Unknown"}, + {0x00, nullptr, "Unknown0"}, {0x01, SvcWrap32<SetHeapSize32>, "SetHeapSize32"}, - {0x02, nullptr, "Unknown"}, + {0x02, nullptr, "SetMemoryPermission32"}, {0x03, SvcWrap32<SetMemoryAttribute32>, "SetMemoryAttribute32"}, {0x04, SvcWrap32<MapMemory32>, "MapMemory32"}, {0x05, SvcWrap32<UnmapMemory32>, "UnmapMemory32"}, @@ -2591,97 +2605,97 @@ static const FunctionDef SVC_Table_32[] = { {0x1d, SvcWrap32<SignalProcessWideKey32>, "SignalProcessWideKey32"}, {0x1e, SvcWrap32<GetSystemTick32>, "GetSystemTick32"}, {0x1f, SvcWrap32<ConnectToNamedPort32>, "ConnectToNamedPort32"}, - {0x20, nullptr, "Unknown"}, + {0x20, nullptr, "SendSyncRequestLight32"}, {0x21, SvcWrap32<SendSyncRequest32>, "SendSyncRequest32"}, {0x22, nullptr, "SendSyncRequestWithUserBuffer32"}, - {0x23, nullptr, "Unknown"}, + {0x23, nullptr, "SendAsyncRequestWithUserBuffer32"}, {0x24, SvcWrap32<GetProcessId32>, "GetProcessId32"}, {0x25, SvcWrap32<GetThreadId32>, "GetThreadId32"}, {0x26, SvcWrap32<Break32>, "Break32"}, - {0x27, nullptr, "OutputDebugString32"}, - {0x28, nullptr, "Unknown"}, + {0x27, SvcWrap32<OutputDebugString32>, "OutputDebugString32"}, + {0x28, nullptr, "ReturnFromException32"}, {0x29, SvcWrap32<GetInfo32>, "GetInfo32"}, - {0x2a, nullptr, "Unknown"}, - {0x2b, nullptr, "Unknown"}, + {0x2a, nullptr, "FlushEntireDataCache32"}, + {0x2b, nullptr, "FlushDataCache32"}, {0x2c, SvcWrap32<MapPhysicalMemory32>, "MapPhysicalMemory32"}, {0x2d, SvcWrap32<UnmapPhysicalMemory32>, "UnmapPhysicalMemory32"}, - {0x2e, nullptr, "Unknown"}, - {0x2f, nullptr, "Unknown"}, - {0x30, nullptr, "Unknown"}, - {0x31, nullptr, "Unknown"}, + {0x2e, nullptr, "GetDebugFutureThreadInfo32"}, + {0x2f, nullptr, "GetLastThreadInfo32"}, + {0x30, nullptr, "GetResourceLimitLimitValue32"}, + {0x31, nullptr, "GetResourceLimitCurrentValue32"}, {0x32, SvcWrap32<SetThreadActivity32>, "SetThreadActivity32"}, {0x33, SvcWrap32<GetThreadContext32>, "GetThreadContext32"}, {0x34, SvcWrap32<WaitForAddress32>, "WaitForAddress32"}, {0x35, SvcWrap32<SignalToAddress32>, "SignalToAddress32"}, {0x36, SvcWrap32<SynchronizePreemptionState>, "SynchronizePreemptionState32"}, - {0x37, nullptr, "Unknown"}, - {0x38, nullptr, "Unknown"}, - {0x39, nullptr, "Unknown"}, - {0x3a, nullptr, "Unknown"}, - {0x3b, nullptr, "Unknown"}, - {0x3c, nullptr, "Unknown"}, - {0x3d, nullptr, "Unknown"}, - {0x3e, nullptr, "Unknown"}, - {0x3f, nullptr, "Unknown"}, + {0x37, nullptr, "GetResourceLimitPeakValue32"}, + {0x38, nullptr, "Unknown38"}, + {0x39, nullptr, "CreateIoPool32"}, + {0x3a, nullptr, "CreateIoRegion32"}, + {0x3b, nullptr, "Unknown3b"}, + {0x3c, nullptr, "KernelDebug32"}, + {0x3d, nullptr, "ChangeKernelTraceState32"}, + {0x3e, nullptr, "Unknown3e"}, + {0x3f, nullptr, "Unknown3f"}, {0x40, nullptr, "CreateSession32"}, {0x41, nullptr, "AcceptSession32"}, - {0x42, nullptr, "Unknown"}, + {0x42, nullptr, "ReplyAndReceiveLight32"}, {0x43, nullptr, "ReplyAndReceive32"}, - {0x44, nullptr, "Unknown"}, + {0x44, nullptr, "ReplyAndReceiveWithUserBuffer32"}, {0x45, SvcWrap32<CreateEvent32>, "CreateEvent32"}, - {0x46, nullptr, "Unknown"}, - {0x47, nullptr, "Unknown"}, - {0x48, nullptr, "Unknown"}, - {0x49, nullptr, "Unknown"}, - {0x4a, nullptr, "Unknown"}, - {0x4b, nullptr, "Unknown"}, - {0x4c, nullptr, "Unknown"}, - {0x4d, nullptr, "Unknown"}, - {0x4e, nullptr, "Unknown"}, - {0x4f, nullptr, "Unknown"}, - {0x50, nullptr, "Unknown"}, - {0x51, nullptr, "Unknown"}, - {0x52, nullptr, "Unknown"}, - {0x53, nullptr, "Unknown"}, - {0x54, nullptr, "Unknown"}, - {0x55, nullptr, "Unknown"}, - {0x56, nullptr, "Unknown"}, - {0x57, nullptr, "Unknown"}, - {0x58, nullptr, "Unknown"}, - {0x59, nullptr, "Unknown"}, - {0x5a, nullptr, "Unknown"}, - {0x5b, nullptr, "Unknown"}, - {0x5c, nullptr, "Unknown"}, - {0x5d, nullptr, "Unknown"}, - {0x5e, nullptr, "Unknown"}, + {0x46, nullptr, "MapIoRegion32"}, + {0x47, nullptr, "UnmapIoRegion32"}, + {0x48, nullptr, "MapPhysicalMemoryUnsafe32"}, + {0x49, nullptr, "UnmapPhysicalMemoryUnsafe32"}, + {0x4a, nullptr, "SetUnsafeLimit32"}, + {0x4b, SvcWrap32<CreateCodeMemory32>, "CreateCodeMemory32"}, + {0x4c, SvcWrap32<ControlCodeMemory32>, "ControlCodeMemory32"}, + {0x4d, nullptr, "SleepSystem32"}, + {0x4e, nullptr, "ReadWriteRegister32"}, + {0x4f, nullptr, "SetProcessActivity32"}, + {0x50, nullptr, "CreateSharedMemory32"}, + {0x51, nullptr, "MapTransferMemory32"}, + {0x52, nullptr, "UnmapTransferMemory32"}, + {0x53, nullptr, "CreateInterruptEvent32"}, + {0x54, nullptr, "QueryPhysicalAddress32"}, + {0x55, nullptr, "QueryIoMapping32"}, + {0x56, nullptr, "CreateDeviceAddressSpace32"}, + {0x57, nullptr, "AttachDeviceAddressSpace32"}, + {0x58, nullptr, "DetachDeviceAddressSpace32"}, + {0x59, nullptr, "MapDeviceAddressSpaceByForce32"}, + {0x5a, nullptr, "MapDeviceAddressSpaceAligned32"}, + {0x5b, nullptr, "MapDeviceAddressSpace32"}, + {0x5c, nullptr, "UnmapDeviceAddressSpace32"}, + {0x5d, nullptr, "InvalidateProcessDataCache32"}, + {0x5e, nullptr, "StoreProcessDataCache32"}, {0x5F, SvcWrap32<FlushProcessDataCache32>, "FlushProcessDataCache32"}, - {0x60, nullptr, "Unknown"}, - {0x61, nullptr, "Unknown"}, - {0x62, nullptr, "Unknown"}, - {0x63, nullptr, "Unknown"}, - {0x64, nullptr, "Unknown"}, + {0x60, nullptr, "StoreProcessDataCache32"}, + {0x61, nullptr, "BreakDebugProcess32"}, + {0x62, nullptr, "TerminateDebugProcess32"}, + {0x63, nullptr, "GetDebugEvent32"}, + {0x64, nullptr, "ContinueDebugEvent32"}, {0x65, nullptr, "GetProcessList32"}, - {0x66, nullptr, "Unknown"}, - {0x67, nullptr, "Unknown"}, - {0x68, nullptr, "Unknown"}, - {0x69, nullptr, "Unknown"}, - {0x6A, nullptr, "Unknown"}, - {0x6B, nullptr, "Unknown"}, - {0x6C, nullptr, "Unknown"}, - {0x6D, nullptr, "Unknown"}, - {0x6E, nullptr, "Unknown"}, + {0x66, nullptr, "GetThreadList"}, + {0x67, nullptr, "GetDebugThreadContext32"}, + {0x68, nullptr, "SetDebugThreadContext32"}, + {0x69, nullptr, "QueryDebugProcessMemory32"}, + {0x6A, nullptr, "ReadDebugProcessMemory32"}, + {0x6B, nullptr, "WriteDebugProcessMemory32"}, + {0x6C, nullptr, "SetHardwareBreakPoint32"}, + {0x6D, nullptr, "GetDebugThreadParam32"}, + {0x6E, nullptr, "Unknown6E"}, {0x6f, nullptr, "GetSystemInfo32"}, {0x70, nullptr, "CreatePort32"}, {0x71, nullptr, "ManageNamedPort32"}, {0x72, nullptr, "ConnectToPort32"}, {0x73, nullptr, "SetProcessMemoryPermission32"}, - {0x74, nullptr, "Unknown"}, - {0x75, nullptr, "Unknown"}, - {0x76, nullptr, "Unknown"}, + {0x74, nullptr, "MapProcessMemory32"}, + {0x75, nullptr, "UnmapProcessMemory32"}, + {0x76, nullptr, "QueryProcessMemory32"}, {0x77, nullptr, "MapProcessCodeMemory32"}, {0x78, nullptr, "UnmapProcessCodeMemory32"}, - {0x79, nullptr, "Unknown"}, - {0x7A, nullptr, "Unknown"}, + {0x79, nullptr, "CreateProcess32"}, + {0x7A, nullptr, "StartProcess32"}, {0x7B, nullptr, "TerminateProcess32"}, {0x7C, nullptr, "GetProcessInfo32"}, {0x7D, nullptr, "CreateResourceLimit32"}, @@ -2754,7 +2768,7 @@ static const FunctionDef SVC_Table_32[] = { }; static const FunctionDef SVC_Table_64[] = { - {0x00, nullptr, "Unknown"}, + {0x00, nullptr, "Unknown0"}, {0x01, SvcWrap64<SetHeapSize>, "SetHeapSize"}, {0x02, SvcWrap64<SetMemoryPermission>, "SetMemoryPermission"}, {0x03, SvcWrap64<SetMemoryAttribute>, "SetMemoryAttribute"}, @@ -2809,23 +2823,23 @@ static const FunctionDef SVC_Table_64[] = { {0x34, SvcWrap64<WaitForAddress>, "WaitForAddress"}, {0x35, SvcWrap64<SignalToAddress>, "SignalToAddress"}, {0x36, SvcWrap64<SynchronizePreemptionState>, "SynchronizePreemptionState"}, - {0x37, nullptr, "Unknown"}, - {0x38, nullptr, "Unknown"}, - {0x39, nullptr, "Unknown"}, - {0x3A, nullptr, "Unknown"}, - {0x3B, nullptr, "Unknown"}, + {0x37, nullptr, "GetResourceLimitPeakValue"}, + {0x38, nullptr, "Unknown38"}, + {0x39, nullptr, "CreateIoPool"}, + {0x3A, nullptr, "CreateIoRegion"}, + {0x3B, nullptr, "Unknown3B"}, {0x3C, SvcWrap64<KernelDebug>, "KernelDebug"}, {0x3D, SvcWrap64<ChangeKernelTraceState>, "ChangeKernelTraceState"}, - {0x3E, nullptr, "Unknown"}, - {0x3F, nullptr, "Unknown"}, + {0x3E, nullptr, "Unknown3e"}, + {0x3F, nullptr, "Unknown3f"}, {0x40, nullptr, "CreateSession"}, {0x41, nullptr, "AcceptSession"}, {0x42, nullptr, "ReplyAndReceiveLight"}, {0x43, nullptr, "ReplyAndReceive"}, {0x44, nullptr, "ReplyAndReceiveWithUserBuffer"}, {0x45, SvcWrap64<CreateEvent>, "CreateEvent"}, - {0x46, nullptr, "Unknown"}, - {0x47, nullptr, "Unknown"}, + {0x46, nullptr, "MapIoRegion"}, + {0x47, nullptr, "UnmapIoRegion"}, {0x48, nullptr, "MapPhysicalMemoryUnsafe"}, {0x49, nullptr, "UnmapPhysicalMemoryUnsafe"}, {0x4A, nullptr, "SetUnsafeLimit"}, @@ -2864,7 +2878,7 @@ static const FunctionDef SVC_Table_64[] = { {0x6B, nullptr, "WriteDebugProcessMemory"}, {0x6C, nullptr, "SetHardwareBreakPoint"}, {0x6D, nullptr, "GetDebugThreadParam"}, - {0x6E, nullptr, "Unknown"}, + {0x6E, nullptr, "Unknown6E"}, {0x6F, nullptr, "GetSystemInfo"}, {0x70, nullptr, "CreatePort"}, {0x71, nullptr, "ManageNamedPort"}, diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index a60adfcab..d309f166c 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -669,4 +669,26 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by CreateCodeMemory32 +template <ResultCode func(Core::System&, Handle*, u32, u32)> +void SvcWrap32(Core::System& system) { + Handle handle = 0; + + const u32 retval = func(system, &handle, Param32(system, 1), Param32(system, 2)).raw; + + system.CurrentArmInterface().SetReg(1, handle); + FuncReturn(system, retval); +} + +// Used by ControlCodeMemory32 +template <ResultCode func(Core::System&, Handle, u32, u64, u64, Svc::MemoryPermission)> +void SvcWrap32(Core::System& system) { + const u32 retval = + func(system, Param32(system, 0), Param32(system, 1), Param(system, 2), Param(system, 4), + static_cast<Svc::MemoryPermission>(Param32(system, 6))) + .raw; + + FuncReturn(system, retval); +} + } // namespace Kernel diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 6e63e057e..e34ef5a78 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -39,9 +39,9 @@ constexpr ResultCode ERR_FAILED_SAVE_DATA{ErrorModule::Account, 100}; // Thumbnails are hard coded to be at least this size constexpr std::size_t THUMBNAIL_SIZE = 0x24000; -static std::filesystem::path GetImagePath(Common::UUID uuid) { +static std::filesystem::path GetImagePath(const Common::UUID& uuid) { return Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / - fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormatSwitch()); + fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormattedString()); } static constexpr u32 SanitizeJPEGSize(std::size_t size) { @@ -290,7 +290,7 @@ public: protected: void Get(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString()); ProfileBase profile_base{}; ProfileData data{}; if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { @@ -300,21 +300,21 @@ protected: rb.PushRaw(profile_base); } else { LOG_ERROR(Service_ACC, "Failed to get profile base and data for user=0x{}", - user_id.Format()); + user_id.RawString()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code } } void GetBase(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString()); ProfileBase profile_base{}; if (profile_manager.GetProfileBase(user_id, profile_base)) { IPC::ResponseBuilder rb{ctx, 16}; rb.Push(ResultSuccess); rb.PushRaw(profile_base); } else { - LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.Format()); + LOG_ERROR(Service_ACC, "Failed to get profile base for user=0x{}", user_id.RawString()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultUnknown); // TODO(ogniK): Get actual error code } @@ -373,7 +373,7 @@ protected: LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}", Common::StringFromFixedZeroTerminatedBuffer( reinterpret_cast<const char*>(base.username.data()), base.username.size()), - base.timestamp, base.user_uuid.Format()); + base.timestamp, base.user_uuid.RawString()); if (user_data.size() < sizeof(ProfileData)) { LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); @@ -406,7 +406,7 @@ protected: LOG_DEBUG(Service_ACC, "called, username='{}', timestamp={:016X}, uuid=0x{}", Common::StringFromFixedZeroTerminatedBuffer( reinterpret_cast<const char*>(base.username.data()), base.username.size()), - base.timestamp, base.user_uuid.Format()); + base.timestamp, base.user_uuid.RawString()); if (user_data.size() < sizeof(ProfileData)) { LOG_ERROR(Service_ACC, "ProfileData buffer too small!"); @@ -435,7 +435,7 @@ protected: } ProfileManager& profile_manager; - Common::UUID user_id{Common::INVALID_UUID}; ///< The user id this profile refers to. + Common::UUID user_id{}; ///< The user id this profile refers to. }; class IProfile final : public IProfileCommon { @@ -547,7 +547,7 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw<u64>(user_id.GetNintendoID()); + rb.PushRaw<u64>(user_id.Hash()); } void EnsureIdTokenCacheAsync(Kernel::HLERequestContext& ctx) { @@ -577,7 +577,7 @@ private: IPC::ResponseBuilder rb{ctx, 4}; rb.Push(ResultSuccess); - rb.PushRaw<u64>(user_id.GetNintendoID()); + rb.PushRaw<u64>(user_id.Hash()); } void StoreOpenContext(Kernel::HLERequestContext& ctx) { @@ -587,7 +587,7 @@ private: } std::shared_ptr<EnsureTokenIdCacheAsyncInterface> ensure_token_id{}; - Common::UUID user_id{Common::INVALID_UUID}; + Common::UUID user_id{}; }; // 6.0.0+ @@ -687,7 +687,7 @@ void Module::Interface::GetUserCount(Kernel::HLERequestContext& ctx) { void Module::Interface::GetUserExistence(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString()); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -718,7 +718,7 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called user_id=0x{}", user_id.RawString()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -833,7 +833,7 @@ void Module::Interface::GetProfileEditor(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; Common::UUID user_id = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.Format()); + LOG_DEBUG(Service_ACC, "called, user_id=0x{}", user_id.RawString()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); @@ -875,7 +875,7 @@ void Module::Interface::StoreSaveDataThumbnailApplication(Kernel::HLERequestCont IPC::RequestParser rp{ctx}; const auto uuid = rp.PopRaw<Common::UUID>(); - LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.Format()); + LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}", uuid.RawString()); // TODO(ogniK): Check if application ID is zero on acc initialize. As we don't have a reliable // way of confirming things like the TID, we're going to assume a non zero value for the time @@ -889,7 +889,7 @@ void Module::Interface::StoreSaveDataThumbnailSystem(Kernel::HLERequestContext& const auto uuid = rp.PopRaw<Common::UUID>(); const auto tid = rp.Pop<u64_le>(); - LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.Format(), tid); + LOG_WARNING(Service_ACC, "(STUBBED) called, uuid=0x{}, tid={:016X}", uuid.RawString(), tid); StoreSaveDataThumbnail(ctx, uuid, tid); } @@ -903,7 +903,7 @@ void Module::Interface::StoreSaveDataThumbnail(Kernel::HLERequestContext& ctx, return; } - if (!uuid) { + if (uuid.IsInvalid()) { LOG_ERROR(Service_ACC, "User ID is not valid!"); rb.Push(ERR_INVALID_USER_ID); return; @@ -927,20 +927,20 @@ void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContex IPC::ResponseBuilder rb{ctx, 6}; if (profile_manager->GetUserCount() != 1) { rb.Push(ResultSuccess); - rb.PushRaw<u128>(Common::INVALID_UUID); + rb.PushRaw(Common::InvalidUUID); return; } const auto user_list = profile_manager->GetAllUsers(); if (std::ranges::all_of(user_list, [](const auto& user) { return user.IsInvalid(); })) { rb.Push(ResultUnknown); // TODO(ogniK): Find the correct error code - rb.PushRaw<u128>(Common::INVALID_UUID); + rb.PushRaw(Common::InvalidUUID); return; } // Select the first user we have rb.Push(ResultSuccess); - rb.PushRaw<u128>(profile_manager->GetUser(0)->uuid); + rb.PushRaw(profile_manager->GetUser(0)->uuid); } Module::Interface::Interface(std::shared_ptr<Module> module_, diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 568303ced..fba847142 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -19,8 +19,8 @@ namespace FS = Common::FS; using Common::UUID; struct UserRaw { - UUID uuid{Common::INVALID_UUID}; - UUID uuid2{Common::INVALID_UUID}; + UUID uuid{}; + UUID uuid2{}; u64 timestamp{}; ProfileUsername username{}; ProfileData extra_data{}; @@ -45,7 +45,7 @@ ProfileManager::ProfileManager() { // Create an user if none are present if (user_count == 0) { - CreateNewUser(UUID::Generate(), "yuzu"); + CreateNewUser(UUID::MakeRandom(), "yuzu"); } auto current = @@ -101,7 +101,7 @@ ResultCode ProfileManager::CreateNewUser(UUID uuid, const ProfileUsername& usern if (user_count == MAX_USERS) { return ERROR_TOO_MANY_USERS; } - if (!uuid) { + if (uuid.IsInvalid()) { return ERROR_ARGUMENT_IS_NULL; } if (username[0] == 0x0) { @@ -145,7 +145,7 @@ std::optional<UUID> ProfileManager::GetUser(std::size_t index) const { /// Returns a users profile index based on their user id. std::optional<std::size_t> ProfileManager::GetUserIndex(const UUID& uuid) const { - if (!uuid) { + if (uuid.IsInvalid()) { return std::nullopt; } @@ -250,9 +250,10 @@ UserIDArray ProfileManager::GetOpenUsers() const { std::ranges::transform(profiles, output.begin(), [](const ProfileInfo& p) { if (p.is_open) return p.user_uuid; - return UUID{Common::INVALID_UUID}; + return Common::InvalidUUID; }); - std::stable_partition(output.begin(), output.end(), [](const UUID& uuid) { return uuid; }); + std::stable_partition(output.begin(), output.end(), + [](const UUID& uuid) { return uuid.IsValid(); }); return output; } @@ -299,7 +300,7 @@ bool ProfileManager::RemoveUser(UUID uuid) { profiles[*index] = ProfileInfo{}; std::stable_partition(profiles.begin(), profiles.end(), - [](const ProfileInfo& profile) { return profile.user_uuid; }); + [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); return true; } @@ -361,7 +362,7 @@ void ProfileManager::ParseUserSaveFile() { } std::stable_partition(profiles.begin(), profiles.end(), - [](const ProfileInfo& profile) { return profile.user_uuid; }); + [](const ProfileInfo& profile) { return profile.user_uuid.IsValid(); }); } void ProfileManager::WriteUserSaveFile() { diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index 71b9d5518..17347f7ef 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h @@ -35,7 +35,7 @@ static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect /// This holds general information about a users profile. This is where we store all the information /// based on a specific user struct ProfileInfo { - Common::UUID user_uuid{Common::INVALID_UUID}; + Common::UUID user_uuid{}; ProfileUsername username{}; u64 creation_time{}; ProfileData data{}; // TODO(ognik): Work out what this is @@ -49,7 +49,7 @@ struct ProfileBase { // Zero out all the fields to make the profile slot considered "Empty" void Invalidate() { - user_uuid.Invalidate(); + user_uuid = {}; timestamp = 0; username.fill(0); } @@ -103,7 +103,7 @@ private: std::array<ProfileInfo, MAX_USERS> profiles{}; std::size_t user_count{}; - Common::UUID last_opened_user{Common::INVALID_UUID}; + Common::UUID last_opened_user{}; }; }; // namespace Service::Account diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index e60661fe1..2f8e21568 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp @@ -55,7 +55,7 @@ constexpr u32 LAUNCH_PARAMETER_ACCOUNT_PRESELECTED_USER_MAGIC = 0xC79497CA; struct LaunchParameterAccountPreselectedUser { u32_le magic; u32_le is_account_selected; - u128 current_user; + Common::UUID current_user; INSERT_PADDING_BYTES(0x70); }; static_assert(sizeof(LaunchParameterAccountPreselectedUser) == 0x88); @@ -618,7 +618,7 @@ void AppletMessageQueue::PushMessage(AppletMessage msg) { AppletMessageQueue::AppletMessage AppletMessageQueue::PopMessage() { if (messages.empty()) { on_new_message->GetWritableEvent().Clear(); - return AppletMessage::NoMessage; + return AppletMessage::None; } auto msg = messages.front(); messages.pop(); @@ -633,7 +633,7 @@ std::size_t AppletMessageQueue::GetMessageCount() const { } void AppletMessageQueue::RequestExit() { - PushMessage(AppletMessage::ExitRequested); + PushMessage(AppletMessage::Exit); } void AppletMessageQueue::FocusStateChanged() { @@ -732,7 +732,7 @@ void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { const auto message = msg_queue->PopMessage(); IPC::ResponseBuilder rb{ctx, 3}; - if (message == AppletMessageQueue::AppletMessage::NoMessage) { + if (message == AppletMessageQueue::AppletMessage::None) { LOG_ERROR(Service_AM, "Message queue is empty"); rb.Push(ERR_NO_MESSAGES); rb.PushEnum<AppletMessageQueue::AppletMessage>(message); @@ -1453,8 +1453,8 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { Account::ProfileManager profile_manager{}; const auto uuid = profile_manager.GetUser(static_cast<s32>(Settings::values.current_user)); - ASSERT(uuid); - params.current_user = uuid->uuid; + ASSERT(uuid.has_value() && uuid->IsValid()); + params.current_user = *uuid; IPC::ResponseBuilder rb{ctx, 2, 0, 1}; diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 2a578aea5..fdd937b82 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h @@ -22,6 +22,7 @@ class NVFlinger; namespace Service::AM { +// This is nn::settings::Language enum SystemLanguage { Japanese = 0, English = 1, // en-US @@ -41,16 +42,44 @@ enum SystemLanguage { // 4.0.0+ SimplifiedChinese = 15, TraditionalChinese = 16, + // 10.1.0+ + BrazilianPortuguese = 17, }; class AppletMessageQueue { public: + // This is nn::am::AppletMessage enum class AppletMessage : u32 { - NoMessage = 0, - ExitRequested = 4, + None = 0, + ChangeIntoForeground = 1, + ChangeIntoBackground = 2, + Exit = 4, + ApplicationExited = 6, FocusStateChanged = 15, + Resume = 16, + DetectShortPressingHomeButton = 20, + DetectLongPressingHomeButton = 21, + DetectShortPressingPowerButton = 22, + DetectMiddlePressingPowerButton = 23, + DetectLongPressingPowerButton = 24, + RequestToPrepareSleep = 25, + FinishedSleepSequence = 26, + SleepRequiredByHighTemperature = 27, + SleepRequiredByLowBattery = 28, + AutoPowerDown = 29, OperationModeChanged = 30, PerformanceModeChanged = 31, + DetectReceivingCecSystemStandby = 32, + SdCardRemoved = 33, + LaunchApplicationRequested = 50, + RequestToDisplay = 51, + ShowApplicationLogo = 55, + HideApplicationLogo = 56, + ForceHideApplicationLogo = 57, + FloatingApplicationDetected = 60, + DetectShortPressingCaptureButton = 90, + AlbumScreenShotTaken = 92, + AlbumRecordingSaved = 93, }; explicit AppletMessageQueue(Core::System& system); @@ -179,11 +208,14 @@ public: ~ICommonStateGetter() override; private: + // This is nn::oe::FocusState enum class FocusState : u8 { InFocus = 1, NotInFocus = 2, + Background = 3, }; + // This is nn::oe::OperationMode enum class OperationMode : u8 { Handheld = 0, Docked = 1, diff --git a/src/core/hle/service/am/applets/applet_profile_select.cpp b/src/core/hle/service/am/applets/applet_profile_select.cpp index a6e891944..82500e121 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.cpp +++ b/src/core/hle/service/am/applets/applet_profile_select.cpp @@ -62,11 +62,11 @@ void ProfileSelect::SelectionComplete(std::optional<Common::UUID> uuid) { if (uuid.has_value() && uuid->IsValid()) { output.result = 0; - output.uuid_selected = uuid->uuid; + output.uuid_selected = *uuid; } else { status = ERR_USER_CANCELLED_SELECTION; output.result = ERR_USER_CANCELLED_SELECTION.raw; - output.uuid_selected = Common::INVALID_UUID; + output.uuid_selected = Common::InvalidUUID; } final_data = std::vector<u8>(sizeof(UserSelectionOutput)); diff --git a/src/core/hle/service/am/applets/applet_profile_select.h b/src/core/hle/service/am/applets/applet_profile_select.h index 8fb76e6c4..852e1e0c0 100644 --- a/src/core/hle/service/am/applets/applet_profile_select.h +++ b/src/core/hle/service/am/applets/applet_profile_select.h @@ -27,7 +27,7 @@ static_assert(sizeof(UserSelectionConfig) == 0xA0, "UserSelectionConfig has inco struct UserSelectionOutput { u64 result; - u128 uuid_selected; + Common::UUID uuid_selected; }; static_assert(sizeof(UserSelectionOutput) == 0x18, "UserSelectionOutput has incorrect size."); diff --git a/src/core/hle/service/apm/apm_controller.cpp b/src/core/hle/service/apm/apm_controller.cpp index 98839fe97..187fef2ad 100644 --- a/src/core/hle/service/apm/apm_controller.cpp +++ b/src/core/hle/service/apm/apm_controller.cpp @@ -17,8 +17,8 @@ constexpr auto DEFAULT_PERFORMANCE_CONFIGURATION = PerformanceConfiguration::Con Controller::Controller(Core::Timing::CoreTiming& core_timing_) : core_timing{core_timing_}, configs{ - {PerformanceMode::Handheld, DEFAULT_PERFORMANCE_CONFIGURATION}, - {PerformanceMode::Docked, DEFAULT_PERFORMANCE_CONFIGURATION}, + {PerformanceMode::Normal, DEFAULT_PERFORMANCE_CONFIGURATION}, + {PerformanceMode::Boost, DEFAULT_PERFORMANCE_CONFIGURATION}, } {} Controller::~Controller() = default; @@ -63,13 +63,13 @@ void Controller::SetFromCpuBoostMode(CpuBoostMode mode) { PerformanceConfiguration::Config15, }}; - SetPerformanceConfiguration(PerformanceMode::Docked, + SetPerformanceConfiguration(PerformanceMode::Boost, BOOST_MODE_TO_CONFIG_MAP.at(static_cast<u32>(mode))); } PerformanceMode Controller::GetCurrentPerformanceMode() const { - return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Docked - : PerformanceMode::Handheld; + return Settings::values.use_docked_mode.GetValue() ? PerformanceMode::Boost + : PerformanceMode::Normal; } PerformanceConfiguration Controller::GetCurrentPerformanceConfiguration(PerformanceMode mode) { diff --git a/src/core/hle/service/apm/apm_controller.h b/src/core/hle/service/apm/apm_controller.h index 8d48e0104..d6fbd2c0c 100644 --- a/src/core/hle/service/apm/apm_controller.h +++ b/src/core/hle/service/apm/apm_controller.h @@ -32,15 +32,18 @@ enum class PerformanceConfiguration : u32 { Config16 = 0x9222000C, }; +// This is nn::oe::CpuBoostMode enum class CpuBoostMode : u32 { - Disabled = 0, - Full = 1, // CPU + GPU -> Config 13, 14, 15, or 16 - Partial = 2, // GPU Only -> Config 15 or 16 + Normal = 0, // Boost mode disabled + FastLoad = 1, // CPU + GPU -> Config 13, 14, 15, or 16 + Partial = 2, // GPU Only -> Config 15 or 16 }; -enum class PerformanceMode : u8 { - Handheld = 0, - Docked = 1, +// This is nn::oe::PerformanceMode +enum class PerformanceMode : s32 { + Invalid = -1, + Normal = 0, + Boost = 1, }; // Class to manage the state and change of the emulated system performance. diff --git a/src/core/hle/service/friend/friend.cpp b/src/core/hle/service/friend/friend.cpp index 9f9cea1e0..79cd3acbb 100644 --- a/src/core/hle/service/friend/friend.cpp +++ b/src/core/hle/service/friend/friend.cpp @@ -173,7 +173,7 @@ private: const auto uuid = rp.PopRaw<Common::UUID>(); LOG_WARNING(Service_Friend, "(STUBBED) called, local_play={}, uuid=0x{}", local_play, - uuid.Format()); + uuid.RawString()); IPC::ResponseBuilder rb{ctx, 2}; rb.Push(ResultSuccess); @@ -186,7 +186,7 @@ private: [[maybe_unused]] const auto filter = rp.PopRaw<SizedFriendFilter>(); const auto pid = rp.Pop<u64>(); LOG_WARNING(Service_Friend, "(STUBBED) called, offset={}, uuid=0x{}, pid={}", friend_offset, - uuid.Format(), pid); + uuid.RawString(), pid); IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); @@ -312,7 +312,7 @@ void Module::Interface::CreateNotificationService(Kernel::HLERequestContext& ctx IPC::RequestParser rp{ctx}; auto uuid = rp.PopRaw<Common::UUID>(); - LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.Format()); + LOG_DEBUG(Service_Friend, "called, uuid=0x{}", uuid.RawString()); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index a2bf7defb..d9202ea6c 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -320,7 +320,7 @@ Hid::Hid(Core::System& system_) {308, nullptr, "SetSevenSixAxisSensorFusionStrength"}, {309, nullptr, "GetSevenSixAxisSensorFusionStrength"}, {310, &Hid::ResetSevenSixAxisSensorTimestamp, "ResetSevenSixAxisSensorTimestamp"}, - {400, nullptr, "IsUsbFullKeyControllerEnabled"}, + {400, &Hid::IsUsbFullKeyControllerEnabled, "IsUsbFullKeyControllerEnabled"}, {401, nullptr, "EnableUsbFullKeyController"}, {402, nullptr, "IsUsbFullKeyControllerConnected"}, {403, nullptr, "HasBattery"}, @@ -1673,6 +1673,16 @@ void Hid::ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx) { rb.Push(ResultSuccess); } +void Hid::IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + + LOG_WARNING(Service_HID, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(false); +} + void Hid::SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto applet_resource_user_id{rp.Pop<u64>()}; diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index d290df161..c281081a7 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -159,6 +159,7 @@ private: void InitializeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); void FinalizeSevenSixAxisSensor(Kernel::HLERequestContext& ctx); void ResetSevenSixAxisSensorTimestamp(Kernel::HLERequestContext& ctx); + void IsUsbFullKeyControllerEnabled(Kernel::HLERequestContext& ctx); void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx); void SetPalmaBoostMode(Kernel::HLERequestContext& ctx); void SetNpadCommunicationMode(Kernel::HLERequestContext& ctx); diff --git a/src/core/hle/service/mii/mii_manager.cpp b/src/core/hle/service/mii/mii_manager.cpp index ca4ed35bb..0a57c3cde 100644 --- a/src/core/hle/service/mii/mii_manager.cpp +++ b/src/core/hle/service/mii/mii_manager.cpp @@ -118,16 +118,6 @@ u16 GenerateCrc16(const void* data, std::size_t size) { return Common::swap16(static_cast<u16>(crc)); } -Common::UUID GenerateValidUUID() { - auto uuid{Common::UUID::Generate()}; - - // Bit 7 must be set, and bit 6 unset for the UUID to be valid - uuid.uuid[1] &= 0xFFFFFFFFFFFFFF3FULL; - uuid.uuid[1] |= 0x0000000000000080ULL; - - return uuid; -} - template <typename T> T GetRandomValue(T min, T max) { std::random_device device; @@ -383,7 +373,7 @@ MiiStoreData::MiiStoreData() = default; MiiStoreData::MiiStoreData(const MiiStoreData::Name& name, const MiiStoreBitFields& bit_fields, const Common::UUID& user_id) { data.name = name; - data.uuid = GenerateValidUUID(); + data.uuid = Common::UUID::MakeRandomRFC4122V4(); std::memcpy(data.data.data(), &bit_fields, sizeof(MiiStoreBitFields)); data_crc = GenerateCrc16(data.data.data(), sizeof(data)); diff --git a/src/core/hle/service/mii/mii_manager.h b/src/core/hle/service/mii/mii_manager.h index 8e048fc56..6999d15b1 100644 --- a/src/core/hle/service/mii/mii_manager.h +++ b/src/core/hle/service/mii/mii_manager.h @@ -202,7 +202,7 @@ struct MiiStoreData { static_assert(sizeof(MiiStoreBitFields) == sizeof(data), "data field has incorrect size."); Name name{}; - Common::UUID uuid{Common::INVALID_UUID}; + Common::UUID uuid{}; } data; u16 data_crc{}; @@ -326,7 +326,7 @@ public: ResultCode GetIndex(const MiiInfo& info, u32& index); private: - const Common::UUID user_id{Common::INVALID_UUID}; + const Common::UUID user_id{}; u64 update_counter{}; }; diff --git a/src/core/hle/service/mnpp/mnpp_app.cpp b/src/core/hle/service/mnpp/mnpp_app.cpp new file mode 100644 index 000000000..53497612f --- /dev/null +++ b/src/core/hle/service/mnpp/mnpp_app.cpp @@ -0,0 +1,45 @@ +// Copyright 2022 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include "common/logging/log.h" +#include "core/hle/ipc_helpers.h" +#include "core/hle/service/mnpp/mnpp_app.h" +#include "core/hle/service/sm/sm.h" + +namespace Service::MNPP { + +class MNPP_APP final : public ServiceFramework<MNPP_APP> { +public: + explicit MNPP_APP(Core::System& system_) : ServiceFramework{system_, "mnpp:app"} { + // clang-format off + static const FunctionInfo functions[] = { + {0, &MNPP_APP::Unknown0, "unknown0"}, + {1, &MNPP_APP::Unknown1, "unknown1"}, + }; + // clang-format on + + RegisterHandlers(functions); + } + +private: + void Unknown0(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_MNPP, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } + + void Unknown1(Kernel::HLERequestContext& ctx) { + LOG_WARNING(Service_MNPP, "(STUBBED) called"); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); + } +}; + +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { + std::make_shared<MNPP_APP>(system)->InstallAsService(service_manager); +} + +} // namespace Service::MNPP diff --git a/src/core/hle/service/mnpp/mnpp_app.h b/src/core/hle/service/mnpp/mnpp_app.h new file mode 100644 index 000000000..6bf20b494 --- /dev/null +++ b/src/core/hle/service/mnpp/mnpp_app.h @@ -0,0 +1,20 @@ +// Copyright 2022 yuzu emulator team +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +namespace Core { +class System; +} + +namespace Service::SM { +class ServiceManager; +} + +namespace Service::MNPP { + +/// Registers all MNPP services with the specified service manager. +void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); + +} // namespace Service::MNPP diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 761d0d3c6..513107715 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp @@ -7,6 +7,9 @@ #include "common/logging/log.h" #include "core/core.h" +#include "core/hid/emulated_controller.h" +#include "core/hid/hid_core.h" +#include "core/hid/hid_types.h" #include "core/hle/ipc_helpers.h" #include "core/hle/kernel/k_event.h" #include "core/hle/service/nfp/nfp.h" @@ -14,343 +17,790 @@ namespace Service::NFP { namespace ErrCodes { -constexpr ResultCode ERR_NO_APPLICATION_AREA(ErrorModule::NFP, 152); +constexpr ResultCode DeviceNotFound(ErrorModule::NFP, 64); +constexpr ResultCode WrongDeviceState(ErrorModule::NFP, 73); +constexpr ResultCode ApplicationAreaIsNotInitialized(ErrorModule::NFP, 128); +constexpr ResultCode ApplicationAreaExist(ErrorModule::NFP, 168); } // namespace ErrCodes -Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, - const char* name) - : ServiceFramework{system_, name}, module{std::move(module_)}, service_context{system_, - "NFP::IUser"} { - nfc_tag_load = service_context.CreateEvent("NFP::IUser:NFCTagDetected"); -} - -Module::Interface::~Interface() { - service_context.CloseEvent(nfc_tag_load); -} - -class IUser final : public ServiceFramework<IUser> { -public: - explicit IUser(Module::Interface& nfp_interface_, Core::System& system_, - KernelHelpers::ServiceContext& service_context_) - : ServiceFramework{system_, "NFP::IUser"}, nfp_interface{nfp_interface_}, - service_context{service_context_} { - static const FunctionInfo functions[] = { - {0, &IUser::Initialize, "Initialize"}, - {1, &IUser::Finalize, "Finalize"}, - {2, &IUser::ListDevices, "ListDevices"}, - {3, &IUser::StartDetection, "StartDetection"}, - {4, &IUser::StopDetection, "StopDetection"}, - {5, &IUser::Mount, "Mount"}, - {6, &IUser::Unmount, "Unmount"}, - {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, - {8, &IUser::GetApplicationArea, "GetApplicationArea"}, - {9, nullptr, "SetApplicationArea"}, - {10, nullptr, "Flush"}, - {11, nullptr, "Restore"}, - {12, nullptr, "CreateApplicationArea"}, - {13, &IUser::GetTagInfo, "GetTagInfo"}, - {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, - {15, &IUser::GetCommonInfo, "GetCommonInfo"}, - {16, &IUser::GetModelInfo, "GetModelInfo"}, - {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, - {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, - {19, &IUser::GetState, "GetState"}, - {20, &IUser::GetDeviceState, "GetDeviceState"}, - {21, &IUser::GetNpadId, "GetNpadId"}, - {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, - {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, - {24, nullptr, "RecreateApplicationArea"}, - }; - RegisterHandlers(functions); +constexpr u32 ApplicationAreaSize = 0xD8; + +IUser::IUser(Module::Interface& nfp_interface_, Core::System& system_) + : ServiceFramework{system_, "NFP::IUser"}, service_context{system_, service_name}, + nfp_interface{nfp_interface_} { + static const FunctionInfo functions[] = { + {0, &IUser::Initialize, "Initialize"}, + {1, &IUser::Finalize, "Finalize"}, + {2, &IUser::ListDevices, "ListDevices"}, + {3, &IUser::StartDetection, "StartDetection"}, + {4, &IUser::StopDetection, "StopDetection"}, + {5, &IUser::Mount, "Mount"}, + {6, &IUser::Unmount, "Unmount"}, + {7, &IUser::OpenApplicationArea, "OpenApplicationArea"}, + {8, &IUser::GetApplicationArea, "GetApplicationArea"}, + {9, &IUser::SetApplicationArea, "SetApplicationArea"}, + {10, nullptr, "Flush"}, + {11, nullptr, "Restore"}, + {12, &IUser::CreateApplicationArea, "CreateApplicationArea"}, + {13, &IUser::GetTagInfo, "GetTagInfo"}, + {14, &IUser::GetRegisterInfo, "GetRegisterInfo"}, + {15, &IUser::GetCommonInfo, "GetCommonInfo"}, + {16, &IUser::GetModelInfo, "GetModelInfo"}, + {17, &IUser::AttachActivateEvent, "AttachActivateEvent"}, + {18, &IUser::AttachDeactivateEvent, "AttachDeactivateEvent"}, + {19, &IUser::GetState, "GetState"}, + {20, &IUser::GetDeviceState, "GetDeviceState"}, + {21, &IUser::GetNpadId, "GetNpadId"}, + {22, &IUser::GetApplicationAreaSize, "GetApplicationAreaSize"}, + {23, &IUser::AttachAvailabilityChangeEvent, "AttachAvailabilityChangeEvent"}, + {24, nullptr, "RecreateApplicationArea"}, + }; + RegisterHandlers(functions); - deactivate_event = service_context.CreateEvent("NFP::IUser:DeactivateEvent"); - availability_change_event = - service_context.CreateEvent("NFP::IUser:AvailabilityChangeEvent"); - } + availability_change_event = service_context.CreateEvent("IUser:AvailabilityChangeEvent"); +} - ~IUser() override { - service_context.CloseEvent(deactivate_event); - service_context.CloseEvent(availability_change_event); - } +void IUser::Initialize(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFC, "called"); -private: - struct TagInfo { - std::array<u8, 10> uuid; - u8 uuid_length; // TODO(ogniK): Figure out if this is actual the uuid length or does it - // mean something else - std::array<u8, 0x15> padding_1; - u32_le protocol; - u32_le tag_type; - std::array<u8, 0x2c> padding_2; - }; - static_assert(sizeof(TagInfo) == 0x54, "TagInfo is an invalid size"); + state = State::Initialized; - enum class State : u32 { - NonInitialized = 0, - Initialized = 1, - }; + // TODO(german77): Loop through all interfaces + nfp_interface.Initialize(); - enum class DeviceState : u32 { - Initialized = 0, - SearchingForTag = 1, - TagFound = 2, - TagRemoved = 3, - TagNearby = 4, - Unknown5 = 5, - Finalized = 6 - }; + IPC::ResponseBuilder rb{ctx, 2, 0}; + rb.Push(ResultSuccess); +} - struct CommonInfo { - u16_be last_write_year; - u8 last_write_month; - u8 last_write_day; - u16_be write_counter; - u16_be version; - u32_be application_area_size; - INSERT_PADDING_BYTES(0x34); - }; - static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); +void IUser::Finalize(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); - void Initialize(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFC, "called"); + state = State::NonInitialized; - IPC::ResponseBuilder rb{ctx, 2, 0}; - rb.Push(ResultSuccess); + // TODO(german77): Loop through all interfaces + nfp_interface.Finalize(); - state = State::Initialized; - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ResultSuccess); +} - void GetState(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFC, "called"); +void IUser::ListDevices(Kernel::HLERequestContext& ctx) { + LOG_INFO(Service_NFP, "called"); - IPC::ResponseBuilder rb{ctx, 3, 0}; - rb.Push(ResultSuccess); - rb.PushRaw<u32>(static_cast<u32>(state)); + std::vector<u64> devices; + + // TODO(german77): Loop through all interfaces + devices.push_back(nfp_interface.GetHandle()); + + ctx.WriteBuffer(devices); + + IPC::ResponseBuilder rb{ctx, 3}; + rb.Push(ResultSuccess); + rb.Push(static_cast<s32>(devices.size())); +} + +void IUser::StartDetection(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto nfp_protocol{rp.Pop<s32>()}; + LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.StartDetection(nfp_protocol); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; } - void ListDevices(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u32 array_size = rp.Pop<u32>(); - LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - ctx.WriteBuffer(device_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(1); +void IUser::StopDetection(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.StopDetection(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; } - void GetNpadId(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 dev_handle = rp.Pop<u64>(); - LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(npad_id); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::Mount(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto model_type{rp.PopEnum<ModelType>()}; + const auto mount_target{rp.PopEnum<MountTarget>()}; + LOG_INFO(Service_NFP, "called, device_handle={}, model_type={}, mount_target={}", device_handle, + model_type, mount_target); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.Mount(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; } - void AttachActivateEvent(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 dev_handle = rp.Pop<u64>(); - LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(nfp_interface.GetNFCEvent()); - has_attached_handle = true; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::Unmount(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.Unmount(); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(result); + return; } - void AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - const u64 dev_handle = rp.Pop<u64>(); - LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - IPC::ResponseBuilder rb{ctx, 2, 1}; - rb.Push(ResultSuccess); - rb.PushCopyObjects(deactivate_event->GetReadableEvent()); - } - - void StopDetection(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); - - switch (device_state) { - case DeviceState::TagFound: - case DeviceState::TagNearby: - deactivate_event->GetWritableEvent().Signal(); - device_state = DeviceState::Initialized; - break; - case DeviceState::SearchingForTag: - case DeviceState::TagRemoved: - device_state = DeviceState::Initialized; - break; - default: - break; - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::OpenApplicationArea(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto access_id{rp.Pop<u32>()}; + LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, access_id={}", device_handle, + access_id); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.OpenApplicationArea(access_id); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void GetDeviceState(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::GetApplicationArea(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + std::vector<u8> data{}; + const auto result = nfp_interface.GetApplicationArea(data); + ctx.WriteBuffer(data); IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(ResultSuccess); - rb.Push<u32>(static_cast<u32>(device_state)); + rb.Push(result); + rb.Push(static_cast<u32>(data.size())); + return; } - void StartDetection(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { - device_state = DeviceState::SearchingForTag; - } + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::SetApplicationArea(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto data{ctx.ReadBuffer()}; + LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}", device_handle, + data.size()); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.SetApplicationArea(data); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void GetTagInfo(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::CreateApplicationArea(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + const auto access_id{rp.Pop<u32>()}; + const auto data{ctx.ReadBuffer()}; + LOG_WARNING(Service_NFP, "(STUBBED) called, device_handle={}, data_size={}, access_id={}", + device_handle, access_id, data.size()); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + const auto result = nfp_interface.CreateApplicationArea(access_id, data); IPC::ResponseBuilder rb{ctx, 2}; - const auto& amiibo = nfp_interface.GetAmiiboBuffer(); - const TagInfo tag_info{ - .uuid = amiibo.uuid, - .uuid_length = static_cast<u8>(amiibo.uuid.size()), - .padding_1 = {}, - .protocol = 1, // TODO(ogniK): Figure out actual values - .tag_type = 2, - .padding_2 = {}, - }; - ctx.WriteBuffer(tag_info); - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void Mount(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::GetTagInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); - device_state = DeviceState::TagNearby; + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + TagInfo tag_info{}; + const auto result = nfp_interface.GetTagInfo(tag_info); + ctx.WriteBuffer(tag_info); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void GetModelInfo(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::GetRegisterInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + RegisterInfo register_info{}; + const auto result = nfp_interface.GetRegisterInfo(register_info); + ctx.WriteBuffer(register_info); IPC::ResponseBuilder rb{ctx, 2}; - const auto& amiibo = nfp_interface.GetAmiiboBuffer(); - ctx.WriteBuffer(amiibo.model_info); - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void Unmount(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - device_state = DeviceState::TagFound; + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} +void IUser::GetCommonInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + CommonInfo common_info{}; + const auto result = nfp_interface.GetCommonInfo(common_info); + ctx.WriteBuffer(common_info); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void Finalize(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Service_NFP, "called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} - device_state = DeviceState::Finalized; +void IUser::GetModelInfo(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_INFO(Service_NFP, "called, device_handle={}", device_handle); + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + ModelInfo model_info{}; + const auto result = nfp_interface.GetModelInfo(model_info); + ctx.WriteBuffer(model_info); IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ResultSuccess); + rb.Push(result); + return; } - void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFP, "(STUBBED) called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} +void IUser::AttachActivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); - rb.PushCopyObjects(availability_change_event->GetReadableEvent()); + rb.PushCopyObjects(nfp_interface.GetActivateEvent()); + return; } - void GetRegisterInfo(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFP, "(STUBBED) called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - // TODO(ogniK): Pull Mii and owner data from amiibo + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} - IPC::ResponseBuilder rb{ctx, 2}; +void IUser::AttachDeactivateEvent(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + IPC::ResponseBuilder rb{ctx, 2, 1}; rb.Push(ResultSuccess); + rb.PushCopyObjects(nfp_interface.GetDeactivateEvent()); + return; } - void GetCommonInfo(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFP, "(STUBBED) called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - // TODO(ogniK): Pull common information from amiibo + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} - CommonInfo common_info{}; - common_info.application_area_size = 0; - ctx.WriteBuffer(common_info); +void IUser::GetState(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NFC, "called"); - IPC::ResponseBuilder rb{ctx, 2}; + IPC::ResponseBuilder rb{ctx, 3, 0}; + rb.Push(ResultSuccess); + rb.PushEnum(state); +} + +void IUser::GetDeviceState(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { + IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); + rb.PushEnum(nfp_interface.GetCurrentState()); + return; } - void OpenApplicationArea(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFP, "(STUBBED) called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(ErrCodes::ERR_NO_APPLICATION_AREA); - } + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); - void GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFP, "(STUBBED) called"); - // We don't need to worry about this since we can just open the file + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::GetNpadId(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub + rb.PushEnum(nfp_interface.GetNpadId()); + return; } - void GetApplicationArea(Kernel::HLERequestContext& ctx) { - LOG_WARNING(Service_NFP, "(STUBBED) called"); + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} - // TODO(ogniK): Pull application area from amiibo +void IUser::GetApplicationAreaSize(Kernel::HLERequestContext& ctx) { + IPC::RequestParser rp{ctx}; + const auto device_handle{rp.Pop<u64>()}; + LOG_DEBUG(Service_NFP, "called, device_handle={}", device_handle); + // TODO(german77): Loop through all interfaces + if (device_handle == nfp_interface.GetHandle()) { IPC::ResponseBuilder rb{ctx, 3}; rb.Push(ResultSuccess); - rb.PushRaw<u32>(0); // This is from the GetCommonInfo stub + rb.Push(ApplicationAreaSize); + return; } - Module::Interface& nfp_interface; - KernelHelpers::ServiceContext& service_context; + LOG_ERROR(Service_NFP, "Handle not found, device_handle={}", device_handle); + + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(ErrCodes::DeviceNotFound); +} + +void IUser::AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx) { + LOG_DEBUG(Service_NFP, "(STUBBED) called"); - bool has_attached_handle{}; - const u64 device_handle{0}; // Npad device 1 - const u32 npad_id{0}; // Player 1 controller - State state{State::NonInitialized}; - DeviceState device_state{DeviceState::Initialized}; - Kernel::KEvent* deactivate_event; - Kernel::KEvent* availability_change_event; -}; + IPC::ResponseBuilder rb{ctx, 2, 1}; + rb.Push(ResultSuccess); + rb.PushCopyObjects(availability_change_event->GetReadableEvent()); +} + +Module::Interface::Interface(std::shared_ptr<Module> module_, Core::System& system_, + const char* name) + : ServiceFramework{system_, name}, module{std::move(module_)}, + npad_id{Core::HID::NpadIdType::Player1}, service_context{system_, service_name} { + activate_event = service_context.CreateEvent("IUser:NFPActivateEvent"); + deactivate_event = service_context.CreateEvent("IUser:NFPDeactivateEvent"); +} + +Module::Interface::~Interface() = default; void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service_NFP, "called"); IPC::ResponseBuilder rb{ctx, 2, 0, 1}; rb.Push(ResultSuccess); - rb.PushIpcInterface<IUser>(*this, system, service_context); + rb.PushIpcInterface<IUser>(*this, system); } bool Module::Interface::LoadAmiibo(const std::vector<u8>& buffer) { - if (buffer.size() < sizeof(AmiiboFile)) { + if (device_state != DeviceState::SearchingForTag) { + LOG_ERROR(Service_NFP, "Game is not looking for amiibos, current state {}", device_state); + return false; + } + + constexpr auto tag_size = sizeof(NTAG215File); + constexpr auto tag_size_without_password = sizeof(NTAG215File) - sizeof(NTAG215Password); + + std::vector<u8> amiibo_buffer = buffer; + + if (amiibo_buffer.size() < tag_size_without_password) { + LOG_ERROR(Service_NFP, "Wrong file size {}", buffer.size()); + return false; + } + + // Ensure it has the correct size + if (amiibo_buffer.size() != tag_size) { + amiibo_buffer.resize(tag_size, 0); + } + + LOG_INFO(Service_NFP, "Amiibo detected"); + std::memcpy(&tag_data, buffer.data(), tag_size); + + if (!IsAmiiboValid()) { return false; } - std::memcpy(&amiibo, buffer.data(), sizeof(amiibo)); - nfc_tag_load->GetWritableEvent().Signal(); + // This value can't be dumped from a tag. Generate it + tag_data.password.PWD = GetTagPassword(tag_data.uuid); + + device_state = DeviceState::TagFound; + activate_event->GetWritableEvent().Signal(); return true; } -Kernel::KReadableEvent& Module::Interface::GetNFCEvent() { - return nfc_tag_load->GetReadableEvent(); +void Module::Interface::CloseAmiibo() { + LOG_INFO(Service_NFP, "Remove amiibo"); + device_state = DeviceState::TagRemoved; + is_application_area_initialized = false; + application_area_id = 0; + application_area_data.clear(); + deactivate_event->GetWritableEvent().Signal(); +} + +bool Module::Interface::IsAmiiboValid() const { + const auto& amiibo_data = tag_data.user_memory; + LOG_DEBUG(Service_NFP, "uuid_lock=0x{0:x}", tag_data.lock_bytes); + LOG_DEBUG(Service_NFP, "compability_container=0x{0:x}", tag_data.compability_container); + LOG_DEBUG(Service_NFP, "crypto_init=0x{0:x}", amiibo_data.crypto_init); + LOG_DEBUG(Service_NFP, "write_count={}", amiibo_data.write_count); + + LOG_DEBUG(Service_NFP, "character_id=0x{0:x}", amiibo_data.model_info.character_id); + LOG_DEBUG(Service_NFP, "character_variant={}", amiibo_data.model_info.character_variant); + LOG_DEBUG(Service_NFP, "amiibo_type={}", amiibo_data.model_info.amiibo_type); + LOG_DEBUG(Service_NFP, "model_number=0x{0:x}", amiibo_data.model_info.model_number); + LOG_DEBUG(Service_NFP, "series={}", amiibo_data.model_info.series); + LOG_DEBUG(Service_NFP, "fixed_value=0x{0:x}", amiibo_data.model_info.fixed); + + LOG_DEBUG(Service_NFP, "tag_dynamic_lock=0x{0:x}", tag_data.dynamic_lock); + LOG_DEBUG(Service_NFP, "tag_CFG0=0x{0:x}", tag_data.CFG0); + LOG_DEBUG(Service_NFP, "tag_CFG1=0x{0:x}", tag_data.CFG1); + + // Check against all know constants on an amiibo binary + if (tag_data.lock_bytes != 0xE00F) { + return false; + } + if (tag_data.compability_container != 0xEEFF10F1U) { + return false; + } + if ((amiibo_data.crypto_init & 0xFF) != 0xA5) { + return false; + } + if (amiibo_data.model_info.fixed != 0x02) { + return false; + } + if ((tag_data.dynamic_lock & 0xFFFFFF) != 0x0F0001) { + return false; + } + if (tag_data.CFG0 != 0x04000000U) { + return false; + } + if (tag_data.CFG1 != 0x5F) { + return false; + } + return true; +} + +Kernel::KReadableEvent& Module::Interface::GetActivateEvent() const { + return activate_event->GetReadableEvent(); +} + +Kernel::KReadableEvent& Module::Interface::GetDeactivateEvent() const { + return deactivate_event->GetReadableEvent(); +} + +void Module::Interface::Initialize() { + device_state = DeviceState::Initialized; +} + +void Module::Interface::Finalize() { + device_state = DeviceState::Unaviable; + is_application_area_initialized = false; + application_area_id = 0; + application_area_data.clear(); +} + +ResultCode Module::Interface::StartDetection(s32 protocol_) { + auto npad_device = system.HIDCore().GetEmulatedController(npad_id); + + // TODO(german77): Add callback for when nfc data is available + + if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { + npad_device->SetPollingMode(Common::Input::PollingMode::NFC); + device_state = DeviceState::SearchingForTag; + protocol = protocol_; + return ResultSuccess; + } + + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; +} + +ResultCode Module::Interface::StopDetection() { + auto npad_device = system.HIDCore().GetEmulatedController(npad_id); + npad_device->SetPollingMode(Common::Input::PollingMode::Active); + + if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { + CloseAmiibo(); + return ResultSuccess; + } + if (device_state == DeviceState::SearchingForTag || device_state == DeviceState::TagRemoved) { + device_state = DeviceState::Initialized; + return ResultSuccess; + } + + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; +} + +ResultCode Module::Interface::Mount() { + if (device_state == DeviceState::TagFound) { + device_state = DeviceState::TagMounted; + return ResultSuccess; + } + + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; +} + +ResultCode Module::Interface::Unmount() { + if (device_state == DeviceState::TagMounted) { + is_application_area_initialized = false; + application_area_id = 0; + application_area_data.clear(); + device_state = DeviceState::TagFound; + return ResultSuccess; + } + + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; +} + +ResultCode Module::Interface::GetTagInfo(TagInfo& tag_info) const { + if (device_state == DeviceState::TagFound || device_state == DeviceState::TagMounted) { + tag_info = { + .uuid = tag_data.uuid, + .uuid_length = static_cast<u8>(tag_data.uuid.size()), + .protocol = protocol, + .tag_type = static_cast<u32>(tag_data.user_memory.model_info.amiibo_type), + }; + return ResultSuccess; + } + + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; +} + +ResultCode Module::Interface::GetCommonInfo(CommonInfo& common_info) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + + // Read this data from the amiibo save file + common_info = { + .last_write_year = 2022, + .last_write_month = 2, + .last_write_day = 7, + .write_counter = tag_data.user_memory.write_count, + .version = 1, + .application_area_size = ApplicationAreaSize, + }; + return ResultSuccess; +} + +ResultCode Module::Interface::GetModelInfo(ModelInfo& model_info) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + + model_info = tag_data.user_memory.model_info; + return ResultSuccess; +} + +ResultCode Module::Interface::GetRegisterInfo(RegisterInfo& register_info) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + + Service::Mii::MiiManager manager; + + // Read this data from the amiibo save file + register_info = { + .mii_char_info = manager.BuildDefault(0), + .first_write_year = 2022, + .first_write_month = 2, + .first_write_day = 7, + .amiibo_name = {'Y', 'u', 'z', 'u', 'A', 'm', 'i', 'i', 'b', 'o', 0}, + .unknown = {}, + }; + return ResultSuccess; +} + +ResultCode Module::Interface::OpenApplicationArea(u32 access_id) { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + if (AmiiboApplicationDataExist(access_id)) { + application_area_data = LoadAmiiboApplicationData(access_id); + application_area_id = access_id; + is_application_area_initialized = true; + } + if (!is_application_area_initialized) { + LOG_WARNING(Service_NFP, "Application area is not initialized"); + return ErrCodes::ApplicationAreaIsNotInitialized; + } + return ResultSuccess; +} + +ResultCode Module::Interface::GetApplicationArea(std::vector<u8>& data) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + if (!is_application_area_initialized) { + LOG_ERROR(Service_NFP, "Application area is not initialized"); + return ErrCodes::ApplicationAreaIsNotInitialized; + } + + data = application_area_data; + + return ResultSuccess; +} + +ResultCode Module::Interface::SetApplicationArea(const std::vector<u8>& data) { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + if (!is_application_area_initialized) { + LOG_ERROR(Service_NFP, "Application area is not initialized"); + return ErrCodes::ApplicationAreaIsNotInitialized; + } + application_area_data = data; + SaveAmiiboApplicationData(application_area_id, application_area_data); + return ResultSuccess; +} + +ResultCode Module::Interface::CreateApplicationArea(u32 access_id, const std::vector<u8>& data) { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + return ErrCodes::WrongDeviceState; + } + if (AmiiboApplicationDataExist(access_id)) { + LOG_ERROR(Service_NFP, "Application area already exist"); + return ErrCodes::ApplicationAreaExist; + } + application_area_data = data; + application_area_id = access_id; + SaveAmiiboApplicationData(application_area_id, application_area_data); + return ResultSuccess; +} + +bool Module::Interface::AmiiboApplicationDataExist(u32 access_id) const { + // TODO(german77): Check if file exist + return false; +} + +std::vector<u8> Module::Interface::LoadAmiiboApplicationData(u32 access_id) const { + // TODO(german77): Read file + std::vector<u8> data(ApplicationAreaSize); + return data; +} + +void Module::Interface::SaveAmiiboApplicationData(u32 access_id, + const std::vector<u8>& data) const { + // TODO(german77): Save file +} + +u64 Module::Interface::GetHandle() const { + // Generate a handle based of the npad id + return static_cast<u64>(npad_id); +} + +DeviceState Module::Interface::GetCurrentState() const { + return device_state; +} + +Core::HID::NpadIdType Module::Interface::GetNpadId() const { + return npad_id; } -const Module::Interface::AmiiboFile& Module::Interface::GetAmiiboBuffer() const { - return amiibo; +u32 Module::Interface::GetTagPassword(const TagUuid& uuid) const { + // Verifiy that the generated password is correct + u32 password = 0xAA ^ (uuid[1] ^ uuid[3]); + password &= (0x55 ^ (uuid[2] ^ uuid[4])) << 8; + password &= (0xAA ^ (uuid[3] ^ uuid[5])) << 16; + password &= (0x55 ^ (uuid[4] ^ uuid[6])) << 24; + return password; } void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system) { diff --git a/src/core/hle/service/nfp/nfp.h b/src/core/hle/service/nfp/nfp.h index 95c127efb..022f13b29 100644 --- a/src/core/hle/service/nfp/nfp.h +++ b/src/core/hle/service/nfp/nfp.h @@ -7,15 +7,132 @@ #include <array> #include <vector> +#include "common/common_funcs.h" #include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/mii/mii_manager.h" #include "core/hle/service/service.h" namespace Kernel { class KEvent; -} +class KReadableEvent; +} // namespace Kernel + +namespace Core::HID { +enum class NpadIdType : u32; +} // namespace Core::HID namespace Service::NFP { +enum class ServiceType : u32 { + User, + Debug, + System, +}; + +enum class State : u32 { + NonInitialized, + Initialized, +}; + +enum class DeviceState : u32 { + Initialized, + SearchingForTag, + TagFound, + TagRemoved, + TagMounted, + Unaviable, + Finalized, +}; + +enum class ModelType : u32 { + Amiibo, +}; + +enum class MountTarget : u32 { + Rom, + Ram, + All, +}; + +enum class AmiiboType : u8 { + Figure, + Card, + Yarn, +}; + +enum class AmiiboSeries : u8 { + SuperSmashBros, + SuperMario, + ChibiRobo, + YoshiWoollyWorld, + Splatoon, + AnimalCrossing, + EightBitMario, + Skylanders, + Unknown8, + TheLegendOfZelda, + ShovelKnight, + Unknown11, + Kiby, + Pokemon, + MarioSportsSuperstars, + MonsterHunter, + BoxBoy, + Pikmin, + FireEmblem, + Metroid, + Others, + MegaMan, + Diablo +}; + +using TagUuid = std::array<u8, 10>; + +struct TagInfo { + TagUuid uuid; + u8 uuid_length; + INSERT_PADDING_BYTES(0x15); + s32 protocol; + u32 tag_type; + INSERT_PADDING_BYTES(0x30); +}; +static_assert(sizeof(TagInfo) == 0x58, "TagInfo is an invalid size"); + +struct CommonInfo { + u16 last_write_year; + u8 last_write_month; + u8 last_write_day; + u16 write_counter; + u16 version; + u32 application_area_size; + INSERT_PADDING_BYTES(0x34); +}; +static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); + +struct ModelInfo { + u16 character_id; + u8 character_variant; + AmiiboType amiibo_type; + u16 model_number; + AmiiboSeries series; + u8 fixed; // Must be 02 + INSERT_PADDING_BYTES(0x4); // Unknown + INSERT_PADDING_BYTES(0x20); // Probably a SHA256-(HMAC?) hash + INSERT_PADDING_BYTES(0x14); // SHA256-HMAC +}; +static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); + +struct RegisterInfo { + Service::Mii::MiiInfo mii_char_info; + u16 first_write_year; + u8 first_write_month; + u8 first_write_day; + std::array<u8, 11> amiibo_name; + u8 unknown; + INSERT_PADDING_BYTES(0x98); +}; +static_assert(sizeof(RegisterInfo) == 0x100, "RegisterInfo is an invalid size"); + class Module final { public: class Interface : public ServiceFramework<Interface> { @@ -24,34 +141,131 @@ public: const char* name); ~Interface() override; - struct ModelInfo { - std::array<u8, 0x8> amiibo_identification_block; - INSERT_PADDING_BYTES(0x38); + struct EncryptedAmiiboFile { + u16 crypto_init; // Must be A5 XX + u16 write_count; // Number of times the amiibo has been written? + INSERT_PADDING_BYTES(0x20); // System crypts + INSERT_PADDING_BYTES(0x20); // SHA256-(HMAC?) hash + ModelInfo model_info; // This struct is bigger than documentation + INSERT_PADDING_BYTES(0xC); // SHA256-HMAC + INSERT_PADDING_BYTES(0x114); // section 1 encrypted buffer + INSERT_PADDING_BYTES(0x54); // section 2 encrypted buffer + }; + static_assert(sizeof(EncryptedAmiiboFile) == 0x1F8, "AmiiboFile is an invalid size"); + + struct NTAG215Password { + u32 PWD; // Password to allow write access + u16 PACK; // Password acknowledge reply + u16 RFUI; // Reserved for future use }; - static_assert(sizeof(ModelInfo) == 0x40, "ModelInfo is an invalid size"); + static_assert(sizeof(NTAG215Password) == 0x8, "NTAG215Password is an invalid size"); - struct AmiiboFile { - std::array<u8, 10> uuid; - INSERT_PADDING_BYTES(0x4a); - ModelInfo model_info; + struct NTAG215File { + TagUuid uuid; // Unique serial number + u16 lock_bytes; // Set defined pages as read only + u32 compability_container; // Defines available memory + EncryptedAmiiboFile user_memory; // Writable data + u32 dynamic_lock; // Dynamic lock + u32 CFG0; // Defines memory protected by password + u32 CFG1; // Defines number of verification attempts + NTAG215Password password; // Password data }; - static_assert(sizeof(AmiiboFile) == 0x94, "AmiiboFile is an invalid size"); + static_assert(sizeof(NTAG215File) == 0x21C, "NTAG215File is an invalid size"); void CreateUserInterface(Kernel::HLERequestContext& ctx); bool LoadAmiibo(const std::vector<u8>& buffer); - Kernel::KReadableEvent& GetNFCEvent(); - const AmiiboFile& GetAmiiboBuffer() const; + void CloseAmiibo(); + + void Initialize(); + void Finalize(); + + ResultCode StartDetection(s32 protocol_); + ResultCode StopDetection(); + ResultCode Mount(); + ResultCode Unmount(); + + ResultCode GetTagInfo(TagInfo& tag_info) const; + ResultCode GetCommonInfo(CommonInfo& common_info) const; + ResultCode GetModelInfo(ModelInfo& model_info) const; + ResultCode GetRegisterInfo(RegisterInfo& register_info) const; + + ResultCode OpenApplicationArea(u32 access_id); + ResultCode GetApplicationArea(std::vector<u8>& data) const; + ResultCode SetApplicationArea(const std::vector<u8>& data); + ResultCode CreateApplicationArea(u32 access_id, const std::vector<u8>& data); + + u64 GetHandle() const; + DeviceState GetCurrentState() const; + Core::HID::NpadIdType GetNpadId() const; + + Kernel::KReadableEvent& GetActivateEvent() const; + Kernel::KReadableEvent& GetDeactivateEvent() const; protected: std::shared_ptr<Module> module; private: + /// Validates that the amiibo file is not corrupted + bool IsAmiiboValid() const; + + bool AmiiboApplicationDataExist(u32 access_id) const; + std::vector<u8> LoadAmiiboApplicationData(u32 access_id) const; + void SaveAmiiboApplicationData(u32 access_id, const std::vector<u8>& data) const; + + /// return password needed to allow write access to protected memory + u32 GetTagPassword(const TagUuid& uuid) const; + + const Core::HID::NpadIdType npad_id; + + DeviceState device_state{DeviceState::Unaviable}; KernelHelpers::ServiceContext service_context; - Kernel::KEvent* nfc_tag_load; - AmiiboFile amiibo{}; + Kernel::KEvent* activate_event; + Kernel::KEvent* deactivate_event; + NTAG215File tag_data{}; + s32 protocol; + bool is_application_area_initialized{}; + u32 application_area_id; + std::vector<u8> application_area_data; }; }; +class IUser final : public ServiceFramework<IUser> { +public: + explicit IUser(Module::Interface& nfp_interface_, Core::System& system_); + +private: + 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 Mount(Kernel::HLERequestContext& ctx); + void Unmount(Kernel::HLERequestContext& ctx); + void OpenApplicationArea(Kernel::HLERequestContext& ctx); + void GetApplicationArea(Kernel::HLERequestContext& ctx); + void SetApplicationArea(Kernel::HLERequestContext& ctx); + void CreateApplicationArea(Kernel::HLERequestContext& ctx); + void GetTagInfo(Kernel::HLERequestContext& ctx); + void GetRegisterInfo(Kernel::HLERequestContext& ctx); + void GetCommonInfo(Kernel::HLERequestContext& ctx); + void GetModelInfo(Kernel::HLERequestContext& ctx); + void AttachActivateEvent(Kernel::HLERequestContext& ctx); + void AttachDeactivateEvent(Kernel::HLERequestContext& ctx); + void GetState(Kernel::HLERequestContext& ctx); + void GetDeviceState(Kernel::HLERequestContext& ctx); + void GetNpadId(Kernel::HLERequestContext& ctx); + void GetApplicationAreaSize(Kernel::HLERequestContext& ctx); + void AttachAvailabilityChangeEvent(Kernel::HLERequestContext& ctx); + + KernelHelpers::ServiceContext service_context; + + // TODO(german77): We should have a vector of interfaces + Module::Interface& nfp_interface; + + State state{State::NonInitialized}; + Kernel::KEvent* availability_change_event; +}; + void InstallInterfaces(SM::ServiceManager& service_manager, Core::System& system); } // namespace Service::NFP diff --git a/src/core/hle/service/ns/pdm_qry.cpp b/src/core/hle/service/ns/pdm_qry.cpp index e2fab5c3f..36ce46353 100644 --- a/src/core/hle/service/ns/pdm_qry.cpp +++ b/src/core/hle/service/ns/pdm_qry.cpp @@ -59,7 +59,7 @@ void PDM_QRY::QueryPlayStatisticsByApplicationIdAndUserAccountId(Kernel::HLERequ LOG_WARNING(Service_NS, "(STUBBED) called. unknown={}. application_id=0x{:016X}, user_account_uid=0x{}", - unknown, application_id, user_account_uid.Format()); + unknown, application_id, user_account_uid.RawString()); IPC::ResponseBuilder rb{ctx, 12}; rb.Push(ResultSuccess); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index f54e6fe56..eb1138313 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -39,6 +39,7 @@ #include "core/hle/service/mig/mig.h" #include "core/hle/service/mii/mii.h" #include "core/hle/service/mm/mm_u.h" +#include "core/hle/service/mnpp/mnpp_app.h" #include "core/hle/service/ncm/ncm.h" #include "core/hle/service/nfc/nfc.h" #include "core/hle/service/nfp/nfp.h" @@ -265,6 +266,7 @@ Services::Services(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system Migration::InstallInterfaces(*sm, system); Mii::InstallInterfaces(*sm, system); MM::InstallInterfaces(*sm, system); + MNPP::InstallInterfaces(*sm, system); NCM::InstallInterfaces(*sm, system); NFC::InstallInterfaces(*sm, system); NFP::InstallInterfaces(*sm, system); diff --git a/src/core/hle/service/time/clock_types.h b/src/core/hle/service/time/clock_types.h index 392e16863..d0cacb80c 100644 --- a/src/core/hle/service/time/clock_types.h +++ b/src/core/hle/service/time/clock_types.h @@ -36,7 +36,7 @@ struct SteadyClockTimePoint { } static SteadyClockTimePoint GetRandom() { - return {0, Common::UUID::Generate()}; + return {0, Common::UUID::MakeRandom()}; } }; static_assert(sizeof(SteadyClockTimePoint) == 0x18, "SteadyClockTimePoint is incorrect size"); diff --git a/src/core/hle/service/time/steady_clock_core.h b/src/core/hle/service/time/steady_clock_core.h index d80a2385f..5ee2c0e0a 100644 --- a/src/core/hle/service/time/steady_clock_core.h +++ b/src/core/hle/service/time/steady_clock_core.h @@ -49,7 +49,7 @@ public: } private: - Common::UUID clock_source_id{Common::UUID::Generate()}; + Common::UUID clock_source_id{Common::UUID::MakeRandom()}; bool is_initialized{}; }; diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index c1e4e6cce..00f1ae8cf 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp @@ -45,7 +45,7 @@ struct TimeManager::Impl final { time_zone_content_manager{system} { const auto system_time{Clock::TimeSpanType::FromSeconds(GetExternalRtcValue())}; - SetupStandardSteadyClock(system, Common::UUID::Generate(), system_time, {}, {}); + SetupStandardSteadyClock(system, Common::UUID::MakeRandom(), system_time, {}, {}); SetupStandardLocalSystemClock(system, {}, system_time.ToSeconds()); Clock::SystemClockContext clock_context{}; |