From ceb829cc332a3903e81dd5d32f2c953f25210fc2 Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 10 Nov 2022 17:05:47 -0500 Subject: debugger: allow more than one connection attempt per session --- src/core/debugger/debugger.cpp | 161 ++++++++++++++++++++++++----------------- 1 file changed, 93 insertions(+), 68 deletions(-) (limited to 'src/core') diff --git a/src/core/debugger/debugger.cpp b/src/core/debugger/debugger.cpp index 339f971e6..1a8e02e6a 100644 --- a/src/core/debugger/debugger.cpp +++ b/src/core/debugger/debugger.cpp @@ -27,12 +27,21 @@ static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) { const u8* buffer_start = reinterpret_cast(&buffer); std::span received_data{buffer_start, buffer_start + bytes_read}; c(received_data); + AsyncReceiveInto(r, buffer, c); } - - AsyncReceiveInto(r, buffer, c); }); } +template +static void AsyncAccept(boost::asio::ip::tcp::acceptor& acceptor, Callback&& c) { + acceptor.async_accept([&, c](const boost::system::error_code& error, auto&& peer_socket) { + if (!error.failed()) { + c(peer_socket); + AsyncAccept(acceptor, c); + } + }); +} + template static std::span ReceiveInto(Readable& r, Buffer& buffer) { static_assert(std::is_trivial_v); @@ -59,9 +68,7 @@ namespace Core { class DebuggerImpl : public DebuggerBackend { public: - explicit DebuggerImpl(Core::System& system_, u16 port) - : system{system_}, signal_pipe{io_context}, client_socket{io_context} { - frontend = std::make_unique(*this, system); + explicit DebuggerImpl(Core::System& system_, u16 port) : system{system_} { InitializeServer(port); } @@ -70,39 +77,42 @@ public: } bool SignalDebugger(SignalInfo signal_info) { - { - std::scoped_lock lk{connection_lock}; + std::scoped_lock lk{connection_lock}; - if (stopped) { - // Do not notify the debugger about another event. - // It should be ignored. - return false; - } - - // Set up the state. - stopped = true; - info = signal_info; + if (stopped || !state) { + // Do not notify the debugger about another event. + // It should be ignored. + return false; } + // Set up the state. + stopped = true; + state->info = signal_info; + // Write a single byte into the pipe to wake up the debug interface. - boost::asio::write(signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); + boost::asio::write(state->signal_pipe, boost::asio::buffer(&stopped, sizeof(stopped))); + return true; } + // These functions are callbacks from the frontend, and the lock will be held. + // There is no need to relock it. + std::span ReadFromClient() override { - return ReceiveInto(client_socket, client_data); + return ReceiveInto(state->client_socket, state->client_data); } void WriteToClient(std::span data) override { - boost::asio::write(client_socket, boost::asio::buffer(data.data(), data.size_bytes())); + boost::asio::write(state->client_socket, + boost::asio::buffer(data.data(), data.size_bytes())); } void SetActiveThread(Kernel::KThread* thread) override { - active_thread = thread; + state->active_thread = thread; } Kernel::KThread* GetActiveThread() override { - return active_thread; + return state->active_thread; } private: @@ -113,65 +123,78 @@ private: // Run the connection thread. connection_thread = std::jthread([&, port](std::stop_token stop_token) { + Common::SetCurrentThreadName("Debugger"); + try { // Initialize the listening socket and accept a new client. tcp::endpoint endpoint{boost::asio::ip::address_v4::any(), port}; tcp::acceptor acceptor{io_context, endpoint}; - acceptor.async_accept(client_socket, [](const auto&) {}); - io_context.run_one(); - io_context.restart(); + AsyncAccept(acceptor, [&](auto&& peer) { AcceptConnection(std::move(peer)); }); - if (stop_token.stop_requested()) { - return; + while (!stop_token.stop_requested() && io_context.run()) { } - - ThreadLoop(stop_token); } catch (const std::exception& ex) { LOG_CRITICAL(Debug_GDBStub, "Stopping server: {}", ex.what()); } }); } - void ShutdownServer() { - connection_thread.request_stop(); - io_context.stop(); - connection_thread.join(); - } + void AcceptConnection(boost::asio::ip::tcp::socket&& peer) { + LOG_INFO(Debug_GDBStub, "Accepting new peer connection"); - void ThreadLoop(std::stop_token stop_token) { - Common::SetCurrentThreadName("Debugger"); + std::scoped_lock lk{connection_lock}; + + // Ensure everything is stopped. + PauseEmulation(); + + // Set up the new frontend. + frontend = std::make_unique(*this, system); + + // Set the new state. This will tear down any existing state. + state = ConnectionState{ + .client_socket{std::move(peer)}, + .signal_pipe{io_context}, + .info{}, + .active_thread{}, + .client_data{}, + .pipe_data{}, + }; // Set up the client signals for new data. - AsyncReceiveInto(signal_pipe, pipe_data, [&](auto d) { PipeData(d); }); - AsyncReceiveInto(client_socket, client_data, [&](auto d) { ClientData(d); }); + AsyncReceiveInto(state->signal_pipe, state->pipe_data, [&](auto d) { PipeData(d); }); + AsyncReceiveInto(state->client_socket, state->client_data, [&](auto d) { ClientData(d); }); // Set the active thread. UpdateActiveThread(); // Set up the frontend. frontend->Connected(); + } - // Main event loop. - while (!stop_token.stop_requested() && io_context.run()) { - } + void ShutdownServer() { + connection_thread.request_stop(); + io_context.stop(); + connection_thread.join(); } void PipeData(std::span data) { - switch (info.type) { + std::scoped_lock lk{connection_lock}; + + switch (state->info.type) { case SignalType::Stopped: case SignalType::Watchpoint: // Stop emulation. PauseEmulation(); // Notify the client. - active_thread = info.thread; + state->active_thread = state->info.thread; UpdateActiveThread(); - if (info.type == SignalType::Watchpoint) { - frontend->Watchpoint(active_thread, *info.watchpoint); + if (state->info.type == SignalType::Watchpoint) { + frontend->Watchpoint(state->active_thread, *state->info.watchpoint); } else { - frontend->Stopped(active_thread); + frontend->Stopped(state->active_thread); } break; @@ -179,8 +202,8 @@ private: frontend->ShuttingDown(); // Wait for emulation to shut down gracefully now. - signal_pipe.close(); - client_socket.shutdown(boost::asio::socket_base::shutdown_both); + state->signal_pipe.close(); + state->client_socket.shutdown(boost::asio::socket_base::shutdown_both); LOG_INFO(Debug_GDBStub, "Shut down server"); break; @@ -188,17 +211,16 @@ private: } void ClientData(std::span data) { + std::scoped_lock lk{connection_lock}; + const auto actions{frontend->ClientData(data)}; for (const auto action : actions) { switch (action) { case DebuggerAction::Interrupt: { - { - std::scoped_lock lk{connection_lock}; - stopped = true; - } + stopped = true; PauseEmulation(); UpdateActiveThread(); - frontend->Stopped(active_thread); + frontend->Stopped(state->active_thread); break; } case DebuggerAction::Continue: @@ -206,15 +228,15 @@ private: break; case DebuggerAction::StepThreadUnlocked: MarkResumed([&] { - active_thread->SetStepState(Kernel::StepState::StepPending); - active_thread->Resume(Kernel::SuspendType::Debug); - ResumeEmulation(active_thread); + state->active_thread->SetStepState(Kernel::StepState::StepPending); + state->active_thread->Resume(Kernel::SuspendType::Debug); + ResumeEmulation(state->active_thread); }); break; case DebuggerAction::StepThreadLocked: { MarkResumed([&] { - active_thread->SetStepState(Kernel::StepState::StepPending); - active_thread->Resume(Kernel::SuspendType::Debug); + state->active_thread->SetStepState(Kernel::StepState::StepPending); + state->active_thread->Resume(Kernel::SuspendType::Debug); }); break; } @@ -254,15 +276,14 @@ private: template void MarkResumed(Callback&& cb) { Kernel::KScopedSchedulerLock sl{system.Kernel()}; - std::scoped_lock cl{connection_lock}; stopped = false; cb(); } void UpdateActiveThread() { const auto& threads{ThreadList()}; - if (std::find(threads.begin(), threads.end(), active_thread) == threads.end()) { - active_thread = threads[0]; + if (std::find(threads.begin(), threads.end(), state->active_thread) == threads.end()) { + state->active_thread = threads[0]; } } @@ -274,18 +295,22 @@ private: System& system; std::unique_ptr frontend; + boost::asio::io_context io_context; std::jthread connection_thread; std::mutex connection_lock; - boost::asio::io_context io_context; - boost::process::async_pipe signal_pipe; - boost::asio::ip::tcp::socket client_socket; - SignalInfo info; - Kernel::KThread* active_thread; - bool pipe_data; - bool stopped; + struct ConnectionState { + boost::asio::ip::tcp::socket client_socket; + boost::process::async_pipe signal_pipe; + + SignalInfo info; + Kernel::KThread* active_thread; + std::array client_data; + bool pipe_data; + }; - std::array client_data; + std::optional state{}; + bool stopped{}; }; Debugger::Debugger(Core::System& system, u16 port) { -- cgit v1.2.3 From 18123ff958b0a4d877dab45a54637245c3b296ba Mon Sep 17 00:00:00 2001 From: Liam Date: Thu, 10 Nov 2022 19:17:54 -0500 Subject: gdbstub: add ams monitor commands --- src/core/debugger/gdbstub.cpp | 151 +++++++++++++++++++++++++++++++++++++ src/core/debugger/gdbstub.h | 1 + src/core/hle/kernel/k_page_table.h | 3 + 3 files changed, 155 insertions(+) (limited to 'src/core') diff --git a/src/core/debugger/gdbstub.cpp b/src/core/debugger/gdbstub.cpp index 884229c77..a64a9ac64 100644 --- a/src/core/debugger/gdbstub.cpp +++ b/src/core/debugger/gdbstub.cpp @@ -606,6 +606,8 @@ void GDBStub::HandleQuery(std::string_view command) { } else if (command.starts_with("StartNoAckMode")) { no_ack = true; SendReply(GDB_STUB_REPLY_OK); + } else if (command.starts_with("Rcmd,")) { + HandleRcmd(Common::HexStringToVector(command.substr(5), false)); } else { SendReply(GDB_STUB_REPLY_EMPTY); } @@ -645,6 +647,155 @@ void GDBStub::HandleVCont(std::string_view command, std::vector& } } +constexpr std::array, 22> MemoryStateNames{{ + {"----- Free -----", Kernel::Svc::MemoryState::Free}, + {"Io ", Kernel::Svc::MemoryState::Io}, + {"Static ", Kernel::Svc::MemoryState::Static}, + {"Code ", Kernel::Svc::MemoryState::Code}, + {"CodeData ", Kernel::Svc::MemoryState::CodeData}, + {"Normal ", Kernel::Svc::MemoryState::Normal}, + {"Shared ", Kernel::Svc::MemoryState::Shared}, + {"AliasCode ", Kernel::Svc::MemoryState::AliasCode}, + {"AliasCodeData ", Kernel::Svc::MemoryState::AliasCodeData}, + {"Ipc ", Kernel::Svc::MemoryState::Ipc}, + {"Stack ", Kernel::Svc::MemoryState::Stack}, + {"ThreadLocal ", Kernel::Svc::MemoryState::ThreadLocal}, + {"Transfered ", Kernel::Svc::MemoryState::Transfered}, + {"SharedTransfered", Kernel::Svc::MemoryState::SharedTransfered}, + {"SharedCode ", Kernel::Svc::MemoryState::SharedCode}, + {"Inaccessible ", Kernel::Svc::MemoryState::Inaccessible}, + {"NonSecureIpc ", Kernel::Svc::MemoryState::NonSecureIpc}, + {"NonDeviceIpc ", Kernel::Svc::MemoryState::NonDeviceIpc}, + {"Kernel ", Kernel::Svc::MemoryState::Kernel}, + {"GeneratedCode ", Kernel::Svc::MemoryState::GeneratedCode}, + {"CodeOut ", Kernel::Svc::MemoryState::CodeOut}, + {"Coverage ", Kernel::Svc::MemoryState::Coverage}, +}}; + +static constexpr const char* GetMemoryStateName(Kernel::Svc::MemoryState state) { + for (size_t i = 0; i < MemoryStateNames.size(); i++) { + if (std::get<1>(MemoryStateNames[i]) == state) { + return std::get<0>(MemoryStateNames[i]); + } + } + return "Unknown "; +} + +static constexpr const char* GetMemoryPermissionString(const Kernel::Svc::MemoryInfo& info) { + if (info.state == Kernel::Svc::MemoryState::Free) { + return " "; + } + + switch (info.permission) { + case Kernel::Svc::MemoryPermission::ReadExecute: + return "r-x"; + case Kernel::Svc::MemoryPermission::Read: + return "r--"; + case Kernel::Svc::MemoryPermission::ReadWrite: + return "rw-"; + default: + return "---"; + } +} + +static VAddr GetModuleEnd(Kernel::KPageTable& page_table, VAddr base) { + Kernel::Svc::MemoryInfo mem_info; + VAddr cur_addr{base}; + + // Expect: r-x Code (.text) + mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + cur_addr = mem_info.base_address + mem_info.size; + if (mem_info.state != Kernel::Svc::MemoryState::Code || + mem_info.permission != Kernel::Svc::MemoryPermission::ReadExecute) { + return cur_addr - 1; + } + + // Expect: r-- Code (.rodata) + mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + cur_addr = mem_info.base_address + mem_info.size; + if (mem_info.state != Kernel::Svc::MemoryState::Code || + mem_info.permission != Kernel::Svc::MemoryPermission::Read) { + return cur_addr - 1; + } + + // Expect: rw- CodeData (.data) + mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + cur_addr = mem_info.base_address + mem_info.size; + return cur_addr - 1; +} + +void GDBStub::HandleRcmd(const std::vector& command) { + std::string_view command_str{reinterpret_cast(&command[0]), command.size()}; + std::string reply; + + auto* process = system.CurrentProcess(); + auto& page_table = process->PageTable(); + + if (command_str == "get info") { + Loader::AppLoader::Modules modules; + system.GetAppLoader().ReadNSOModules(modules); + + reply = fmt::format("Process: {:#x} ({})\n" + "Program Id: {:#018x}\n", + process->GetProcessID(), process->GetName(), process->GetProgramID()); + reply += + fmt::format("Layout:\n" + " Alias: {:#012x} - {:#012x}\n" + " Heap: {:#012x} - {:#012x}\n" + " Aslr: {:#012x} - {:#012x}\n" + " Stack: {:#012x} - {:#012x}\n" + "Modules:\n", + page_table.GetAliasRegionStart(), page_table.GetAliasRegionEnd(), + page_table.GetHeapRegionStart(), page_table.GetHeapRegionEnd(), + page_table.GetAliasCodeRegionStart(), page_table.GetAliasCodeRegionEnd(), + page_table.GetStackRegionStart(), page_table.GetStackRegionEnd()); + + for (const auto& [vaddr, name] : modules) { + reply += fmt::format(" {:#012x} - {:#012x} {}\n", vaddr, + GetModuleEnd(page_table, vaddr), name); + } + } else if (command_str == "get mappings") { + reply = "Mappings:\n"; + VAddr cur_addr = 0; + + while (true) { + using MemoryAttribute = Kernel::Svc::MemoryAttribute; + + auto mem_info = page_table.QueryInfo(cur_addr).GetSvcMemoryInfo(); + + if (mem_info.state != Kernel::Svc::MemoryState::Inaccessible || + mem_info.base_address + mem_info.size - 1 != std::numeric_limits::max()) { + const char* state = GetMemoryStateName(mem_info.state); + const char* perm = GetMemoryPermissionString(mem_info); + + const char l = True(mem_info.attribute & MemoryAttribute::Locked) ? 'L' : '-'; + const char i = True(mem_info.attribute & MemoryAttribute::IpcLocked) ? 'I' : '-'; + const char d = True(mem_info.attribute & MemoryAttribute::DeviceShared) ? 'D' : '-'; + const char u = True(mem_info.attribute & MemoryAttribute::Uncached) ? 'U' : '-'; + + reply += + fmt::format(" {:#012x} - {:#012x} {} {} {}{}{}{} [{}, {}]\n", + mem_info.base_address, mem_info.base_address + mem_info.size - 1, + perm, state, l, i, d, u, mem_info.ipc_count, mem_info.device_count); + } + + const uintptr_t next_address = mem_info.base_address + mem_info.size; + if (next_address <= cur_addr) { + break; + } + + cur_addr = next_address; + } + } else if (command_str == "help") { + reply = "Commands:\n get info\n get mappings\n"; + } else { + reply = "Unknown command.\nCommands:\n get info\n get mappings\n"; + } + + std::span reply_span{reinterpret_cast(&reply.front()), reply.size()}; + SendReply(Common::HexToString(reply_span, false)); +} + Kernel::KThread* GDBStub::GetThreadByID(u64 thread_id) { const auto& threads{system.GlobalSchedulerContext().GetThreadList()}; for (auto* thread : threads) { diff --git a/src/core/debugger/gdbstub.h b/src/core/debugger/gdbstub.h index 0b0f56e4b..368197920 100644 --- a/src/core/debugger/gdbstub.h +++ b/src/core/debugger/gdbstub.h @@ -32,6 +32,7 @@ private: void ExecuteCommand(std::string_view packet, std::vector& actions); void HandleVCont(std::string_view command, std::vector& actions); void HandleQuery(std::string_view command); + void HandleRcmd(const std::vector& command); void HandleBreakpointInsert(std::string_view command); void HandleBreakpointRemove(std::string_view command); std::vector::const_iterator CommandEnd() const; diff --git a/src/core/hle/kernel/k_page_table.h b/src/core/hle/kernel/k_page_table.h index 950850291..f1ca785d7 100644 --- a/src/core/hle/kernel/k_page_table.h +++ b/src/core/hle/kernel/k_page_table.h @@ -320,6 +320,9 @@ public: constexpr VAddr GetAliasCodeRegionStart() const { return m_alias_code_region_start; } + constexpr VAddr GetAliasCodeRegionEnd() const { + return m_alias_code_region_end; + } constexpr VAddr GetAliasCodeRegionSize() const { return m_alias_code_region_end - m_alias_code_region_start; } -- cgit v1.2.3 From 651f6598ac8a980700c330f382d711f7429571a8 Mon Sep 17 00:00:00 2001 From: Liam Date: Sat, 12 Nov 2022 11:02:07 -0500 Subject: kernel: implement FlushProcessDataCache --- src/core/hle/kernel/svc.cpp | 26 +++++++++++------ src/core/hle/kernel/svc_wrap.h | 8 ++++++ src/core/memory.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++ src/core/memory.h | 34 ++++++++++++++++++++++ 4 files changed, 125 insertions(+), 8 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index 9962ad171..e520cab47 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -2701,14 +2701,24 @@ static Result GetThreadList(Core::System& system, u32* out_num_threads, VAddr ou return ResultSuccess; } -static Result FlushProcessDataCache32([[maybe_unused]] Core::System& system, - [[maybe_unused]] Handle handle, [[maybe_unused]] u32 address, - [[maybe_unused]] u32 size) { - // Note(Blinkhawk): For emulation purposes of the data cache this is mostly a no-op, - // as all emulation is done in the same cache level in host architecture, thus data cache - // does not need flushing. - LOG_DEBUG(Kernel_SVC, "called"); - return ResultSuccess; +static Result FlushProcessDataCache32(Core::System& system, Handle process_handle, u64 address, + u64 size) { + // Validate address/size. + R_UNLESS(size > 0, ResultInvalidSize); + R_UNLESS(address == static_cast(address), ResultInvalidCurrentMemory); + R_UNLESS(size == static_cast(size), ResultInvalidCurrentMemory); + + // Get the process from its handle. + KScopedAutoObject process = + system.Kernel().CurrentProcess()->GetHandleTable().GetObject(process_handle); + R_UNLESS(process.IsNotNull(), ResultInvalidHandle); + + // Verify the region is within range. + auto& page_table = process->PageTable(); + R_UNLESS(page_table.Contains(address, size), ResultInvalidCurrentMemory); + + // Perform the operation. + R_RETURN(system.Memory().FlushDataCache(*process, address, size)); } namespace { diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 272c54cf7..3730937fe 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h @@ -722,4 +722,12 @@ void SvcWrap32(Core::System& system) { FuncReturn(system, retval); } +// Used by Invalidate/Store/FlushProcessDataCache32 +template +void SvcWrap32(Core::System& system) { + const u64 address = (Param(system, 3) << 32) | Param(system, 2); + const u64 size = (Param(system, 4) << 32) | Param(system, 1); + FuncReturn32(system, func(system, Param32(system, 0), address, size).raw); +} + } // namespace Kernel diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 3ca80c8ff..3141122f1 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp @@ -6,6 +6,7 @@ #include "common/assert.h" #include "common/atomic_ops.h" +#include "common/cache_management.h" #include "common/common_types.h" #include "common/logging/log.h" #include "common/page_table.h" @@ -329,6 +330,55 @@ struct Memory::Impl { }); } + template + Result PerformCacheOperation(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size, + Callback&& cb) { + class InvalidMemoryException : public std::exception {}; + + try { + WalkBlock( + process, dest_addr, size, + [&](const std::size_t block_size, const VAddr current_vaddr) { + LOG_ERROR(HW_Memory, "Unmapped cache maintenance @ {:#018X}", current_vaddr); + throw InvalidMemoryException(); + }, + [&](const std::size_t block_size, u8* const host_ptr) { cb(block_size, host_ptr); }, + [&](const VAddr current_vaddr, const std::size_t block_size, u8* const host_ptr) { + system.GPU().FlushRegion(current_vaddr, block_size); + cb(block_size, host_ptr); + }, + [](const std::size_t block_size) {}); + } catch (InvalidMemoryException&) { + return Kernel::ResultInvalidCurrentMemory; + } + + return ResultSuccess; + } + + Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // Do nothing; this operation (dc ivac) cannot be supported + // from EL0 + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + + Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // dc cvac: Store to point of coherency + Common::DataCacheLineCleanByVAToPoC(host_ptr, block_size); + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + + Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size) { + auto perform = [&](const std::size_t block_size, u8* const host_ptr) { + // dc civac: Store to point of coherency, and invalidate from cache + Common::DataCacheLineCleanAndInvalidateByVAToPoC(host_ptr, block_size); + }; + return PerformCacheOperation(process, dest_addr, size, perform); + } + void MarkRegionDebug(VAddr vaddr, u64 size, bool debug) { if (vaddr == 0) { return; @@ -786,6 +836,21 @@ void Memory::ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, const s impl->ZeroBlock(process, dest_addr, size); } +Result Memory::InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->InvalidateDataCache(process, dest_addr, size); +} + +Result Memory::StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->StoreDataCache(process, dest_addr, size); +} + +Result Memory::FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, + const std::size_t size) { + return impl->FlushDataCache(process, dest_addr, size); +} + void Memory::RasterizerMarkRegionCached(VAddr vaddr, u64 size, bool cached) { impl->RasterizerMarkRegionCached(vaddr, size, cached); } diff --git a/src/core/memory.h b/src/core/memory.h index 81eac448b..31fe699d8 100644 --- a/src/core/memory.h +++ b/src/core/memory.h @@ -7,6 +7,7 @@ #include #include #include "common/common_types.h" +#include "core/hle/result.h" namespace Common { struct PageTable; @@ -449,6 +450,39 @@ public: */ void ZeroBlock(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + /** + * Invalidates a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data invalidated within its address space. + * @param dest_addr The destination virtual address to invalidate the data from. + * @param size The size of the range to invalidate, in bytes. + * + */ + Result InvalidateDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** + * Stores a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data stored within its address space. + * @param dest_addr The destination virtual address to store the data from. + * @param size The size of the range to store, in bytes. + * + */ + Result StoreDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + + /** + * Flushes a range of bytes within the current process' address space at the specified + * virtual address. + * + * @param process The process that will have data flushed within its address space. + * @param dest_addr The destination virtual address to flush the data from. + * @param size The size of the range to flush, in bytes. + * + */ + Result FlushDataCache(const Kernel::KProcess& process, VAddr dest_addr, std::size_t size); + /** * Marks each page within the specified address range as cached or uncached. * -- cgit v1.2.3 From 6c045c9beb9c202fdea49274edd845fb2af491c3 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 10:52:48 -0600 Subject: service: nfc: fix tagprotocol and implement GetApplicationAreaId --- src/core/hle/service/nfp/nfp_device.cpp | 33 +++++++++++++++++++++++++++++++-- src/core/hle/service/nfp/nfp_device.h | 6 ++++-- src/core/hle/service/nfp/nfp_types.h | 10 +++++++--- src/core/hle/service/nfp/nfp_user.cpp | 2 +- 4 files changed, 43 insertions(+), 8 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index b19672560..2f9dfa9c2 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -77,6 +77,9 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) { LoadAmiibo(nfc_status.data); break; case Common::Input::NfcState::AmiiboRemoved: + if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) { + break; + } if (device_state != DeviceState::SearchingForTag) { CloseAmiibo(); } @@ -97,6 +100,8 @@ bool NfpDevice::LoadAmiibo(std::span data) { return false; } + // TODO: Filter by allowed_protocols here + memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File)); device_state = DeviceState::TagFound; @@ -143,7 +148,7 @@ void NfpDevice::Finalize() { device_state = DeviceState::Unavailable; } -Result NfpDevice::StartDetection(s32 protocol_) { +Result NfpDevice::StartDetection([[maybe_unused]] TagProtocol allowed_protocol) { if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); return WrongDeviceState; @@ -155,7 +160,7 @@ Result NfpDevice::StartDetection(s32 protocol_) { } device_state = DeviceState::SearchingForTag; - protocol = protocol_; + allowed_protocols = allowed_protocol; return ResultSuccess; } @@ -469,6 +474,30 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { return ResultSuccess; } +Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { + if (device_state != DeviceState::TagMounted) { + LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); + if (device_state == DeviceState::TagRemoved) { + return TagRemoved; + } + return WrongDeviceState; + } + + if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) { + LOG_ERROR(Service_NFP, "Amiibo is read only", device_state); + return WrongDeviceState; + } + + if (tag_data.settings.settings.appdata_initialized.Value() == 0) { + LOG_WARNING(Service_NFP, "Application area is not initialized"); + return ApplicationAreaIsNotInitialized; + } + + application_area_id = tag_data.application_area_id; + + return ResultSuccess; +} + Result NfpDevice::GetApplicationArea(std::vector& data) const { if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); diff --git a/src/core/hle/service/nfp/nfp_device.h b/src/core/hle/service/nfp/nfp_device.h index 76d0e9ae4..3d1cb4609 100644 --- a/src/core/hle/service/nfp/nfp_device.h +++ b/src/core/hle/service/nfp/nfp_device.h @@ -4,6 +4,7 @@ #pragma once #include +#include #include #include "common/common_funcs.h" @@ -37,7 +38,7 @@ public: void Initialize(); void Finalize(); - Result StartDetection(s32 protocol_); + Result StartDetection(TagProtocol allowed_protocol); Result StopDetection(); Result Mount(MountTarget mount_target); Result Unmount(); @@ -53,6 +54,7 @@ public: Result DeleteAllData(); Result OpenApplicationArea(u32 access_id); + Result GetApplicationAreaId(u32& application_area_id) const; Result GetApplicationArea(std::vector& data) const; Result SetApplicationArea(std::span data); Result CreateApplicationArea(u32 access_id, std::span data); @@ -88,7 +90,7 @@ private: bool is_data_moddified{}; bool is_app_area_open{}; - s32 protocol{}; + TagProtocol allowed_protocols{}; s64 current_posix_time{}; MountTarget mount_target{MountTarget::None}; DeviceState device_state{DeviceState::Unavailable}; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 63d5917cb..866aefe20 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -88,11 +88,15 @@ enum class PackedTagType : u8 { Type5, // ISO15693 RW/RO 540 bytes 106kbit/s }; +// Verify this enum. It might be completely wrong default protocol is 0x48 enum class TagProtocol : u32 { None, - TypeA, // ISO14443A - TypeB, // ISO14443B - TypeF, // Sony Felica + TypeA = 1U << 0, // ISO14443A + TypeB = 1U << 1, // ISO14443B + TypeF = 1U << 2, // Sony Felica + Unknown1 = 1U << 3, + Unknown2 = 1U << 5, + All = 0xFFFFFFFFU, }; using UniqueSerialNumber = std::array; diff --git a/src/core/hle/service/nfp/nfp_user.cpp b/src/core/hle/service/nfp/nfp_user.cpp index 33e2ef518..ac492cc27 100644 --- a/src/core/hle/service/nfp/nfp_user.cpp +++ b/src/core/hle/service/nfp/nfp_user.cpp @@ -130,7 +130,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) { void IUser::StartDetection(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp{ctx}; const auto device_handle{rp.Pop()}; - const auto nfp_protocol{rp.Pop()}; + const auto nfp_protocol{rp.PopEnum()}; LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol); if (state == State::NonInitialized) { -- cgit v1.2.3 From fb57cd26a1219a5c91d2cb4dec402528f8ba308e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 11:07:48 -0600 Subject: service: am: Implement cabinet applet backend --- src/core/CMakeLists.txt | 4 + src/core/frontend/applets/cabinet.cpp | 20 +++ src/core/frontend/applets/cabinet.h | 36 +++++ src/core/hle/service/am/applets/applet_cabinet.cpp | 169 +++++++++++++++++++++ src/core/hle/service/am/applets/applet_cabinet.h | 99 ++++++++++++ src/core/hle/service/am/applets/applets.cpp | 20 ++- src/core/hle/service/am/applets/applets.h | 12 +- src/core/hle/service/nfp/nfp_types.h | 7 + 8 files changed, 360 insertions(+), 7 deletions(-) create mode 100644 src/core/frontend/applets/cabinet.cpp create mode 100644 src/core/frontend/applets/cabinet.h create mode 100644 src/core/hle/service/am/applets/applet_cabinet.cpp create mode 100644 src/core/hle/service/am/applets/applet_cabinet.h (limited to 'src/core') diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index f67f1ce92..740c5b0fd 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -120,6 +120,8 @@ add_library(core STATIC file_sys/vfs_vector.h file_sys/xts_archive.cpp file_sys/xts_archive.h + frontend/applets/cabinet.cpp + frontend/applets/cabinet.h frontend/applets/controller.cpp frontend/applets/controller.h frontend/applets/error.cpp @@ -312,6 +314,8 @@ add_library(core STATIC hle/service/am/applet_ae.h hle/service/am/applet_oe.cpp hle/service/am/applet_oe.h + hle/service/am/applets/applet_cabinet.cpp + hle/service/am/applets/applet_cabinet.h hle/service/am/applets/applet_controller.cpp hle/service/am/applets/applet_controller.h hle/service/am/applets/applet_error.cpp diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp new file mode 100644 index 000000000..5ade75de0 --- /dev/null +++ b/src/core/frontend/applets/cabinet.cpp @@ -0,0 +1,20 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/logging/log.h" +#include "core/frontend/applets/cabinet.h" + +#include + +namespace Core::Frontend { + +CabinetApplet::~CabinetApplet() = default; + +void DefaultCabinetApplet::ShowCabinetApplet( + std::function callback, const CabinetParameters& parameters, + std::shared_ptr nfp_device) const { + LOG_WARNING(Service_AM, "(STUBBED) called"); + callback(false, {}); +} + +} // namespace Core::Frontend diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h new file mode 100644 index 000000000..1c68bf57d --- /dev/null +++ b/src/core/frontend/applets/cabinet.h @@ -0,0 +1,36 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "core/hle/service/nfp/nfp_types.h" + +namespace Service::NFP { +class NfpDevice; +} // namespace Service::NFP + +namespace Core::Frontend { + +struct CabinetParameters { + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + Service::NFP::CabinetMode mode; +}; + +class CabinetApplet { +public: + virtual ~CabinetApplet(); + virtual void ShowCabinetApplet(std::function callback, + const CabinetParameters& parameters, + std::shared_ptr nfp_device) const = 0; +}; + +class DefaultCabinetApplet final : public CabinetApplet { +public: + void ShowCabinetApplet(std::function callback, + const CabinetParameters& parameters, + std::shared_ptr nfp_device) const override; +}; + +} // namespace Core::Frontend diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp new file mode 100644 index 000000000..1eb5a9f22 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -0,0 +1,169 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/assert.h" +#include "common/logging/log.h" +#include "core/core.h" +#include "core/frontend/applets/cabinet.h" +#include "core/hid/hid_core.h" +#include "core/hle/kernel/k_event.h" +#include "core/hle/kernel/k_readable_event.h" +#include "core/hle/service/am/am.h" +#include "core/hle/service/am/applets/applet_cabinet.h" +#include "core/hle/service/mii/mii_manager.h" +#include "core/hle/service/nfp/nfp_device.h" + +namespace Service::AM::Applets { + +Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_) + : Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{ + system_, + "CabinetApplet"} { + + availability_change_event = + service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent"); +} + +Cabinet::~Cabinet() = default; + +void Cabinet::Initialize() { + Applet::Initialize(); + + LOG_INFO(Service_HID, "Initializing Cabinet Applet."); + + LOG_ERROR(Service_HID, + "Initializing Applet with common_args: arg_version={}, lib_version={}, " + "play_startup_sound={}, size={}, system_tick={}, theme_color={}", + common_args.arguments_version, common_args.library_version, + common_args.play_startup_sound, common_args.size, common_args.system_tick, + common_args.theme_color); + + const auto storage = broker.PopNormalDataToApplet(); + ASSERT(storage != nullptr); + + const auto applet_input_data = storage->GetData(); + ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings)); + + std::memcpy(&applet_input_common, applet_input_data.data(), + sizeof(StartParamForAmiiboSettings)); +} + +bool Cabinet::TransactionComplete() const { + return is_complete; +} + +Result Cabinet::GetStatus() const { + return ResultSuccess; +} + +void Cabinet::ExecuteInteractive() { + ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet."); +} + +void Cabinet::Execute() { + if (is_complete) { + return; + } + + const auto callback = [this](bool apply_changes, const std::string& amiibo_name) { + DisplayCompleted(apply_changes, amiibo_name); + }; + + // TODO: listen on all controllers + if (nfp_device == nullptr) { + nfp_device = std::make_shared( + system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event); + nfp_device->Initialize(); + nfp_device->StartDetection(Service::NFP::TagProtocol::All); + } + + const Core::Frontend::CabinetParameters parameters{ + .tag_info = applet_input_common.tag_info, + .register_info = applet_input_common.register_info, + .mode = applet_input_common.applet_mode, + }; + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: + case Service::NFP::CabinetMode::StartGameDataEraser: + case Service::NFP::CabinetMode::StartRestorer: + case Service::NFP::CabinetMode::StartFormatter: + frontend.ShowCabinetApplet(callback, parameters, nfp_device); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + DisplayCompleted(false, {}); + break; + } +} + +void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_name) { + Service::Mii::MiiManager manager; + ReturnValueForAmiiboSettings applet_output{}; + + if (!apply_changes) { + Cancel(); + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound && + nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) { + Cancel(); + } + + if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound) { + nfp_device->Mount(Service::NFP::MountTarget::All); + } + + switch (applet_input_common.applet_mode) { + case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { + Service::NFP::AmiiboName name{}; + memccpy(name.data(), amiibo_name.data(), 0, name.size()); + nfp_device->SetNicknameAndOwner(name); + break; + } + case Service::NFP::CabinetMode::StartGameDataEraser: + nfp_device->DeleteApplicationArea(); + break; + case Service::NFP::CabinetMode::StartRestorer: + nfp_device->RestoreAmiibo(); + break; + case Service::NFP::CabinetMode::StartFormatter: + nfp_device->DeleteAllData(); + break; + default: + UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode); + break; + } + + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Success; + nfp_device->GetRegisterInfo(applet_output.register_info); + nfp_device->GetTagInfo(applet_output.tag_info); + nfp_device->Finalize(); + + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +void Cabinet::Cancel() { + ReturnValueForAmiiboSettings applet_output{}; + applet_output.device_handle = applet_input_common.device_handle; + applet_output.result = CabinetResult::Cancel; + nfp_device->Finalize(); + + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); + std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); + + is_complete = true; + + broker.PushNormalDataFromApplet(std::make_shared(system, std::move(out_data))); + broker.SignalStateChanged(); +} + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h new file mode 100644 index 000000000..2d3f22434 --- /dev/null +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -0,0 +1,99 @@ +// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#include "core/hle/result.h" +#include "core/hle/service/am/applets/applets.h" +#include "core/hle/service/kernel_helpers.h" +#include "core/hle/service/nfp/nfp_types.h" + +namespace Kernel { +class KEvent; +class KReadableEvent; +} // namespace Kernel + +namespace Core { +class System; +} // namespace Core + +namespace Service::NFP { +class NfpDevice; +} + +namespace Service::AM::Applets { + +enum class CabinetAppletVersion : s32 { + Version1 = 0x1, +}; + +enum class CabinetResult : u8 { + Cancel, + Success, +}; + +// This is nn::nfp::AmiiboSettingsStartParam +struct AmiiboSettingsStartParam { + u64 device_handle; + std::array param_1; + std::array param_2; +}; +static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, + "AmiiboSettingsStartParam is an invalid size"); + +// This is nn::nfp::StartParamForAmiiboSettings +struct StartParamForAmiiboSettings { + u8 param_1; + Service::NFP::CabinetMode applet_mode; + u8 flags; + u8 amiibo_settings_1; + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + std::array amiibo_settings_3; + INSERT_PADDING_BYTES(0x20); +}; +static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, + "StartParamForAmiiboSettings is an invalid size"); + +// This is nn::nfp::ReturnValueForAmiiboSettings +struct ReturnValueForAmiiboSettings { + CabinetResult result; + INSERT_PADDING_BYTES(0x3); + u64 device_handle; + Service::NFP::TagInfo tag_info; + Service::NFP::RegisterInfo register_info; + INSERT_PADDING_BYTES(0x24); +}; +static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x190, + "ReturnValueForAmiiboSettings is an invalid size"); + +class Cabinet final : public Applet { +public: + explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_, + const Core::Frontend::CabinetApplet& frontend_); + ~Cabinet() override; + + void Initialize() override; + + bool TransactionComplete() const override; + Result GetStatus() const override; + void ExecuteInteractive() override; + void Execute() override; + void DisplayCompleted(bool apply_changes, const std::string& amiibo_name); + void Cancel(); + +private: + const Core::Frontend::CabinetApplet& frontend; + Core::System& system; + + bool is_complete{false}; + std::shared_ptr nfp_device; + Kernel::KEvent* availability_change_event; + KernelHelpers::ServiceContext service_context; + StartParamForAmiiboSettings applet_input_common{}; +}; + +} // namespace Service::AM::Applets diff --git a/src/core/hle/service/am/applets/applets.cpp b/src/core/hle/service/am/applets/applets.cpp index 7062df21c..10afbc2da 100644 --- a/src/core/hle/service/am/applets/applets.cpp +++ b/src/core/hle/service/am/applets/applets.cpp @@ -5,6 +5,7 @@ #include "common/assert.h" #include "core/core.h" +#include "core/frontend/applets/cabinet.h" #include "core/frontend/applets/controller.h" #include "core/frontend/applets/error.h" #include "core/frontend/applets/general_frontend.h" @@ -16,6 +17,7 @@ #include "core/hle/service/am/am.h" #include "core/hle/service/am/applet_ae.h" #include "core/hle/service/am/applet_oe.h" +#include "core/hle/service/am/applets/applet_cabinet.h" #include "core/hle/service/am/applets/applet_controller.h" #include "core/hle/service/am/applets/applet_error.h" #include "core/hle/service/am/applets/applet_general_backend.h" @@ -171,13 +173,15 @@ void Applet::Initialize() { AppletFrontendSet::AppletFrontendSet() = default; -AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, +AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet, + ControllerApplet controller_applet, ErrorApplet error_applet, MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, WebBrowser web_browser_) - : controller{std::move(controller_applet)}, error{std::move(error_applet)}, - mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)}, + : cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)}, + error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)}, + parental_controls{std::move(parental_controls_applet)}, photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)}, software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {} @@ -196,6 +200,10 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const { } void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) { + if (set.cabinet != nullptr) { + frontend.cabinet = std::move(set.cabinet); + } + if (set.controller != nullptr) { frontend.controller = std::move(set.controller); } @@ -235,6 +243,10 @@ void AppletManager::SetDefaultAppletFrontendSet() { } void AppletManager::SetDefaultAppletsIfMissing() { + if (frontend.cabinet == nullptr) { + frontend.cabinet = std::make_unique(); + } + if (frontend.controller == nullptr) { frontend.controller = std::make_unique(system.HIDCore()); @@ -279,6 +291,8 @@ std::shared_ptr AppletManager::GetApplet(AppletId id, LibraryAppletMode switch (id) { case AppletId::Auth: return std::make_shared(system, mode, *frontend.parental_controls); + case AppletId::Cabinet: + return std::make_shared(system, mode, *frontend.cabinet); case AppletId::Controller: return std::make_shared(system, mode, *frontend.controller); case AppletId::Error: diff --git a/src/core/hle/service/am/applets/applets.h b/src/core/hle/service/am/applets/applets.h index 12c6a5b1a..a22eb62a8 100644 --- a/src/core/hle/service/am/applets/applets.h +++ b/src/core/hle/service/am/applets/applets.h @@ -16,6 +16,7 @@ class System; } namespace Core::Frontend { +class CabinetApplet; class ControllerApplet; class ECommerceApplet; class ErrorApplet; @@ -176,6 +177,7 @@ protected: }; struct AppletFrontendSet { + using CabinetApplet = std::unique_ptr; using ControllerApplet = std::unique_ptr; using ErrorApplet = std::unique_ptr; using MiiEdit = std::unique_ptr; @@ -186,10 +188,11 @@ struct AppletFrontendSet { using WebBrowser = std::unique_ptr; AppletFrontendSet(); - AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet, - MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet, - PhotoViewer photo_viewer_, ProfileSelect profile_select_, - SoftwareKeyboard software_keyboard_, WebBrowser web_browser_); + AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet, + ErrorApplet error_applet, MiiEdit mii_edit_, + ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_, + ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_, + WebBrowser web_browser_); ~AppletFrontendSet(); AppletFrontendSet(const AppletFrontendSet&) = delete; @@ -198,6 +201,7 @@ struct AppletFrontendSet { AppletFrontendSet(AppletFrontendSet&&) noexcept; AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept; + CabinetApplet cabinet; ControllerApplet controller; ErrorApplet error; MiiEdit mii_edit; diff --git a/src/core/hle/service/nfp/nfp_types.h b/src/core/hle/service/nfp/nfp_types.h index 866aefe20..69858096a 100644 --- a/src/core/hle/service/nfp/nfp_types.h +++ b/src/core/hle/service/nfp/nfp_types.h @@ -99,6 +99,13 @@ enum class TagProtocol : u32 { All = 0xFFFFFFFFU, }; +enum class CabinetMode : u8 { + StartNicknameAndOwnerSettings, + StartGameDataEraser, + StartRestorer, + StartFormatter, +}; + using UniqueSerialNumber = std::array; using LockBytes = std::array; using HashData = std::array; -- cgit v1.2.3 From a253d1557d7d1fb1add6ae923ccb452d423d4547 Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 13:59:00 -0600 Subject: service: am: Fix cabinet applet result --- src/core/hle/service/am/applets/applet_cabinet.cpp | 20 ++++++++++++++------ src/core/hle/service/am/applets/applet_cabinet.h | 12 ++++++++---- 2 files changed, 22 insertions(+), 10 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 1eb5a9f22..01f577ab9 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -32,7 +32,7 @@ void Cabinet::Initialize() { LOG_INFO(Service_HID, "Initializing Cabinet Applet."); - LOG_ERROR(Service_HID, + LOG_DEBUG(Service_HID, "Initializing Applet with common_args: arg_version={}, lib_version={}, " "play_startup_sound={}, size={}, system_tick={}, theme_color={}", common_args.arguments_version, common_args.library_version, @@ -111,14 +111,14 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam Cancel(); } - if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound) { + if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) { nfp_device->Mount(Service::NFP::MountTarget::All); } switch (applet_input_common.applet_mode) { case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { Service::NFP::AmiiboName name{}; - memccpy(name.data(), amiibo_name.data(), 0, name.size()); + memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); nfp_device->SetNicknameAndOwner(name); break; } @@ -137,11 +137,19 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam } applet_output.device_handle = applet_input_common.device_handle; - applet_output.result = CabinetResult::Success; - nfp_device->GetRegisterInfo(applet_output.register_info); - nfp_device->GetTagInfo(applet_output.tag_info); + applet_output.result = CabinetResult::Cancel; + const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info); + const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); nfp_device->Finalize(); + if (reg_result.IsSuccess() && tag_result.IsSuccess()) { + applet_output.result = CabinetResult::All; + } else if (reg_result.IsSuccess()) { + applet_output.result = CabinetResult::RegisterInfo; + } else if (tag_result.IsSuccess()) { + applet_output.result = CabinetResult::TagInfo; + } + std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings)); diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h index 2d3f22434..8466d5997 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -31,18 +31,21 @@ enum class CabinetAppletVersion : s32 { enum class CabinetResult : u8 { Cancel, - Success, + TagInfo = 1 << 1, + RegisterInfo = 1 << 2, + All = TagInfo | RegisterInfo, }; // This is nn::nfp::AmiiboSettingsStartParam struct AmiiboSettingsStartParam { u64 device_handle; std::array param_1; - std::array param_2; + u8 param_2; }; static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, "AmiiboSettingsStartParam is an invalid size"); +#pragma pack(1) // This is nn::nfp::StartParamForAmiiboSettings struct StartParamForAmiiboSettings { u8 param_1; @@ -53,7 +56,7 @@ struct StartParamForAmiiboSettings { Service::NFP::TagInfo tag_info; Service::NFP::RegisterInfo register_info; std::array amiibo_settings_3; - INSERT_PADDING_BYTES(0x20); + INSERT_PADDING_BYTES(0x24); }; static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8, "StartParamForAmiiboSettings is an invalid size"); @@ -67,8 +70,9 @@ struct ReturnValueForAmiiboSettings { Service::NFP::RegisterInfo register_info; INSERT_PADDING_BYTES(0x24); }; -static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x190, +static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, "ReturnValueForAmiiboSettings is an invalid size"); +#pragma pack() class Cabinet final : public Applet { public: -- cgit v1.2.3 From 75e6ec85e107d6e5422d882b97faaa813970d42e Mon Sep 17 00:00:00 2001 From: german77 Date: Sun, 13 Nov 2022 15:14:08 -0600 Subject: general: Address review comments --- src/core/frontend/applets/cabinet.cpp | 2 +- src/core/frontend/applets/cabinet.h | 7 ++++--- src/core/hle/service/am/applets/applet_cabinet.cpp | 16 ++++++++-------- src/core/hle/service/am/applets/applet_cabinet.h | 11 ++++++----- src/core/hle/service/nfp/nfp_device.cpp | 4 +++- 5 files changed, 22 insertions(+), 18 deletions(-) (limited to 'src/core') diff --git a/src/core/frontend/applets/cabinet.cpp b/src/core/frontend/applets/cabinet.cpp index 5ade75de0..26c7fefe3 100644 --- a/src/core/frontend/applets/cabinet.cpp +++ b/src/core/frontend/applets/cabinet.cpp @@ -11,7 +11,7 @@ namespace Core::Frontend { CabinetApplet::~CabinetApplet() = default; void DefaultCabinetApplet::ShowCabinetApplet( - std::function callback, const CabinetParameters& parameters, + const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr nfp_device) const { LOG_WARNING(Service_AM, "(STUBBED) called"); callback(false, {}); diff --git a/src/core/frontend/applets/cabinet.h b/src/core/frontend/applets/cabinet.h index 1c68bf57d..c28a235c1 100644 --- a/src/core/frontend/applets/cabinet.h +++ b/src/core/frontend/applets/cabinet.h @@ -18,18 +18,19 @@ struct CabinetParameters { Service::NFP::CabinetMode mode; }; +using CabinetCallback = std::function; + class CabinetApplet { public: virtual ~CabinetApplet(); - virtual void ShowCabinetApplet(std::function callback, + virtual void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr nfp_device) const = 0; }; class DefaultCabinetApplet final : public CabinetApplet { public: - void ShowCabinetApplet(std::function callback, - const CabinetParameters& parameters, + void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters, std::shared_ptr nfp_device) const override; }; diff --git a/src/core/hle/service/am/applets/applet_cabinet.cpp b/src/core/hle/service/am/applets/applet_cabinet.cpp index 01f577ab9..d0969b0f1 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.cpp +++ b/src/core/hle/service/am/applets/applet_cabinet.cpp @@ -98,7 +98,7 @@ void Cabinet::Execute() { } } -void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_name) { +void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) { Service::Mii::MiiManager manager; ReturnValueForAmiiboSettings applet_output{}; @@ -118,7 +118,7 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam switch (applet_input_common.applet_mode) { case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: { Service::NFP::AmiiboName name{}; - memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); + std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1)); nfp_device->SetNicknameAndOwner(name); break; } @@ -142,12 +142,12 @@ void Cabinet::DisplayCompleted(bool apply_changes, const std::string& amiibo_nam const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info); nfp_device->Finalize(); - if (reg_result.IsSuccess() && tag_result.IsSuccess()) { - applet_output.result = CabinetResult::All; - } else if (reg_result.IsSuccess()) { - applet_output.result = CabinetResult::RegisterInfo; - } else if (tag_result.IsSuccess()) { - applet_output.result = CabinetResult::TagInfo; + if (reg_result.IsSuccess()) { + applet_output.result |= CabinetResult::RegisterInfo; + } + + if (tag_result.IsSuccess()) { + applet_output.result |= CabinetResult::TagInfo; } std::vector out_data(sizeof(ReturnValueForAmiiboSettings)); diff --git a/src/core/hle/service/am/applets/applet_cabinet.h b/src/core/hle/service/am/applets/applet_cabinet.h index 8466d5997..84197a807 100644 --- a/src/core/hle/service/am/applets/applet_cabinet.h +++ b/src/core/hle/service/am/applets/applet_cabinet.h @@ -25,16 +25,17 @@ class NfpDevice; namespace Service::AM::Applets { -enum class CabinetAppletVersion : s32 { +enum class CabinetAppletVersion : u32 { Version1 = 0x1, }; enum class CabinetResult : u8 { - Cancel, + Cancel = 0, TagInfo = 1 << 1, RegisterInfo = 1 << 2, All = TagInfo | RegisterInfo, }; +DECLARE_ENUM_FLAG_OPERATORS(CabinetResult) // This is nn::nfp::AmiiboSettingsStartParam struct AmiiboSettingsStartParam { @@ -45,7 +46,7 @@ struct AmiiboSettingsStartParam { static_assert(sizeof(AmiiboSettingsStartParam) == 0x30, "AmiiboSettingsStartParam is an invalid size"); -#pragma pack(1) +#pragma pack(push, 1) // This is nn::nfp::StartParamForAmiiboSettings struct StartParamForAmiiboSettings { u8 param_1; @@ -72,7 +73,7 @@ struct ReturnValueForAmiiboSettings { }; static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188, "ReturnValueForAmiiboSettings is an invalid size"); -#pragma pack() +#pragma pack(pop) class Cabinet final : public Applet { public: @@ -86,7 +87,7 @@ public: Result GetStatus() const override; void ExecuteInteractive() override; void Execute() override; - void DisplayCompleted(bool apply_changes, const std::string& amiibo_name); + void DisplayCompleted(bool apply_changes, std::string_view amiibo_name); void Cancel(); private: diff --git a/src/core/hle/service/nfp/nfp_device.cpp b/src/core/hle/service/nfp/nfp_device.cpp index 2f9dfa9c2..e1bf90d7c 100644 --- a/src/core/hle/service/nfp/nfp_device.cpp +++ b/src/core/hle/service/nfp/nfp_device.cpp @@ -148,7 +148,7 @@ void NfpDevice::Finalize() { device_state = DeviceState::Unavailable; } -Result NfpDevice::StartDetection([[maybe_unused]] TagProtocol allowed_protocol) { +Result NfpDevice::StartDetection(TagProtocol allowed_protocol) { if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); return WrongDeviceState; @@ -475,6 +475,8 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) { } Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const { + application_area_id = {}; + if (device_state != DeviceState::TagMounted) { LOG_ERROR(Service_NFP, "Wrong device state {}", device_state); if (device_state == DeviceState::TagRemoved) { -- cgit v1.2.3 From 6fa3faec658893c9fae19116232d24dac08babc7 Mon Sep 17 00:00:00 2001 From: Kyle Kienapfel Date: Fri, 11 Nov 2022 04:12:37 -0800 Subject: Add break for default cases Visual Studio has an option to search all files in a solution, so I did a search in there for "default:" looking for any missing break statements. I've left out default statements that return something, and that throw something, even if via ThrowInvalidType. UNREACHABLE leads towards throw R_THROW macro leads towards a return --- src/core/hle/kernel/init/init_slab_setup.cpp | 1 + src/core/hle/kernel/k_page_table.cpp | 3 +++ src/core/hle/kernel/k_process.cpp | 1 + src/core/hle/service/am/applets/applet_error.cpp | 1 + src/core/hle/service/am/applets/applet_general_backend.cpp | 2 ++ src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 5 ++--- src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 5 ++--- src/core/hle/service/service.cpp | 1 + src/core/hle/service/time/time_zone_manager.cpp | 1 + 9 files changed, 14 insertions(+), 6 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index bda098511..7b363eb1e 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -243,6 +243,7 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) { // If we somehow get an invalid type, abort. default: ASSERT_MSG(false, "Unknown slab type: {}", slab_types[i]); + break; } // If we've hit the end of a gap, free it. diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 5387bf5fe..612fc76fa 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -2301,6 +2301,7 @@ Result KPageTable::SetProcessMemoryPermission(VAddr addr, size_t size, break; default: ASSERT(false); + break; } } @@ -2803,6 +2804,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, const KPageGroup& page_ break; default: ASSERT(false); + break; } addr += size; @@ -2838,6 +2840,7 @@ Result KPageTable::Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, break; default: ASSERT(false); + break; } R_SUCCEED(); } diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 55a9c5fae..d1dc62401 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -395,6 +395,7 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std: default: ASSERT(false); + break; } // Create TLS region diff --git a/src/core/hle/service/am/applets/applet_error.cpp b/src/core/hle/service/am/applets/applet_error.cpp index fcf34bf7e..bae0d99a6 100644 --- a/src/core/hle/service/am/applets/applet_error.cpp +++ b/src/core/hle/service/am/applets/applet_error.cpp @@ -144,6 +144,7 @@ void Error::Initialize() { break; default: UNIMPLEMENTED_MSG("Unimplemented LibAppletError mode={:02X}!", mode); + break; } } diff --git a/src/core/hle/service/am/applets/applet_general_backend.cpp b/src/core/hle/service/am/applets/applet_general_backend.cpp index c34ef08b3..e50acdaf6 100644 --- a/src/core/hle/service/am/applets/applet_general_backend.cpp +++ b/src/core/hle/service/am/applets/applet_general_backend.cpp @@ -129,6 +129,7 @@ void Auth::Execute() { } default: unimplemented_log(); + break; } } @@ -192,6 +193,7 @@ void PhotoViewer::Execute() { break; default: UNIMPLEMENTED_MSG("Unimplemented PhotoViewer applet mode={:02X}!", mode); + break; } } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index ced57dfe6..b97813fbc 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -300,11 +300,10 @@ Kernel::KEvent* nvhost_ctrl_gpu::QueryEvent(u32 event_id) { return error_notifier_event; case 2: return unknown_event; - default: { + default: LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + return nullptr; } - } - return nullptr; } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 45a759fa8..e123564c6 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp @@ -364,11 +364,10 @@ Kernel::KEvent* nvhost_gpu::QueryEvent(u32 event_id) { return sm_exception_breakpoint_pause_report_event; case 3: return error_notifier_event; - default: { + default: LOG_CRITICAL(Service_NVDRV, "Unknown Ctrl GPU Event {}", event_id); + return nullptr; } - } - return nullptr; } } // namespace Service::Nvidia::Devices diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 5ab41c0c4..0de67f1e1 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -228,6 +228,7 @@ Result ServiceFrameworkBase::HandleSyncRequest(Kernel::KServerSession& session, } UNIMPLEMENTED_MSG("command_type={}", ctx.GetCommandType()); + break; } // If emulation was shutdown, we are closing service threads, do not write the response back to diff --git a/src/core/hle/service/time/time_zone_manager.cpp b/src/core/hle/service/time/time_zone_manager.cpp index 2aa675df9..f9ada7c93 100644 --- a/src/core/hle/service/time/time_zone_manager.cpp +++ b/src/core/hle/service/time/time_zone_manager.cpp @@ -280,6 +280,7 @@ static constexpr int TransitionTime(int year, Rule rule, int offset) { } default: ASSERT(false); + break; } return value + rule.transition_time + offset; } -- cgit v1.2.3 From 18fcc03b3ce10997ab1559b4e4887d6267d8486c Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Mon, 14 Nov 2022 18:10:04 -0600 Subject: core: Update result module --- src/core/hle/result.h | 76 ++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 75 insertions(+), 1 deletion(-) (limited to 'src/core') diff --git a/src/core/hle/result.h b/src/core/hle/result.h index 56c990728..240f06689 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -28,30 +28,49 @@ enum class ErrorModule : u32 { Loader = 9, CMIF = 10, HIPC = 11, + TMA = 12, + DMNT = 13, + GDS = 14, PM = 15, NS = 16, + BSDSockets = 17, HTC = 18, + TSC = 19, NCMContent = 20, SM = 21, RO = 22, + GC = 23, SDMMC = 24, OVLN = 25, SPL = 26, + Socket = 27, + HTCLOW = 29, + DDSF = 30, + HTCFS = 31, + Async = 32, + Util = 33, + TIPC = 35, + ANIF = 37, ETHC = 100, I2C = 101, GPIO = 102, UART = 103, + CPAD = 104, Settings = 105, + FTM = 106, WLAN = 107, XCD = 108, + TMP451 = 109, NIFM = 110, Hwopus = 111, + LSM6DS3 = 112, Bluetooth = 113, VI = 114, NFP = 115, Time = 116, FGM = 117, OE = 118, + BH1730FVC = 119, PCIe = 120, Friends = 121, BCAT = 122, @@ -65,7 +84,7 @@ enum class ErrorModule : u32 { AHID = 130, Qlaunch = 132, PCV = 133, - OMM = 134, + USBPD = 134, BPC = 135, PSM = 136, NIM = 137, @@ -75,18 +94,22 @@ enum class ErrorModule : u32 { NSD = 141, PCTL = 142, BTM = 143, + LA = 144, ETicket = 145, NGC = 146, ERPT = 147, APM = 148, + CEC = 149, Profiler = 150, ErrorUpload = 151, + LIDBE = 152, Audio = 153, NPNS = 154, NPNSHTTPSTREAM = 155, ARP = 157, SWKBD = 158, BOOT = 159, + NetDiag = 160, NFCMifare = 161, UserlandAssert = 162, Fatal = 163, @@ -94,17 +117,68 @@ enum class ErrorModule : u32 { SPSM = 165, BGTC = 167, UserlandCrash = 168, + SASBUS = 169, + PI = 170, + AudioCtrl = 172, + LBL = 173, + JIT = 175, + HDCP = 176, + OMM = 177, + PDM = 178, + OLSC = 179, SREPO = 180, Dauth = 181, + STDFU = 182, + DBG = 183, + DHCPS = 186, + SPI = 187, + AVM = 188, + PWM = 189, + RTC = 191, + Regulator = 192, + LED = 193, + SIO = 195, + PCM = 196, + CLKRST = 197, + POWCTL = 198, + AudioOld = 201, HID = 202, LDN = 203, + CS = 204, Irsensor = 205, Capture = 206, Manu = 208, ATK = 209, + WEB = 210, + LCS = 211, GRC = 212, + Repair = 213, + Album = 214, + RID = 215, Migration = 216, MigrationLdcServ = 217, + HIDBUS = 218, + ENS = 219, + WebSocket = 223, + DCDMTP = 227, + PGL = 228, + Notification = 229, + INS = 230, + LP2P = 231, + RCD = 232, + LCM40607 = 233, + PRC = 235, + TMAHTC = 237, + ECTX = 238, + MNPP = 239, + HSHL = 240, + CAPMTP = 242, + DP2HDMI = 244, + Cradle = 245, + SProfile = 246, + NDRM = 250, + TSPM = 499, + DevMenu = 500, GeneralWebApplet = 800, WifiWebAuthApplet = 809, WhitelistedApplet = 810, -- cgit v1.2.3 From cf202f371862ebe92dd88924a9f7b8cfbc7ad738 Mon Sep 17 00:00:00 2001 From: Liam Date: Mon, 14 Nov 2022 21:00:32 -0500 Subject: nvnflinger: fix lost wakeup --- src/core/hle/service/nvflinger/buffer_queue_core.cpp | 6 ++++-- src/core/hle/service/nvflinger/buffer_queue_core.h | 5 +++-- src/core/hle/service/nvflinger/buffer_queue_producer.cpp | 14 +++++++------- src/core/hle/service/nvflinger/buffer_queue_producer.h | 3 ++- 4 files changed, 16 insertions(+), 12 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.cpp b/src/core/hle/service/nvflinger/buffer_queue_core.cpp index ea4a14ea4..3d1338e66 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_core.cpp @@ -23,15 +23,17 @@ void BufferQueueCore::NotifyShutdown() { } void BufferQueueCore::SignalDequeueCondition() { + dequeue_possible.store(true); dequeue_condition.notify_all(); } -bool BufferQueueCore::WaitForDequeueCondition() { +bool BufferQueueCore::WaitForDequeueCondition(std::unique_lock& lk) { if (is_shutting_down) { return false; } - dequeue_condition.wait(mutex); + dequeue_condition.wait(lk, [&] { return dequeue_possible.load(); }); + dequeue_possible.store(false); return true; } diff --git a/src/core/hle/service/nvflinger/buffer_queue_core.h b/src/core/hle/service/nvflinger/buffer_queue_core.h index ca6baefaf..85b3bc4c1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_core.h +++ b/src/core/hle/service/nvflinger/buffer_queue_core.h @@ -38,7 +38,7 @@ public: private: void SignalDequeueCondition(); - bool WaitForDequeueCondition(); + bool WaitForDequeueCondition(std::unique_lock& lk); s32 GetMinUndequeuedBufferCountLocked(bool async) const; s32 GetMinMaxBufferCountLocked(bool async) const; @@ -60,7 +60,8 @@ private: BufferQueueDefs::SlotsType slots{}; std::vector queue; s32 override_max_buffer_count{}; - mutable std::condition_variable_any dequeue_condition; + std::condition_variable dequeue_condition; + std::atomic dequeue_possible{}; const bool use_async_buffer{}; // This is always disabled on HOS bool dequeue_buffer_cannot_block{}; PixelFormat default_buffer_format{PixelFormat::Rgba8888}; diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp index 41ba44b21..e601b5da1 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.cpp @@ -121,8 +121,8 @@ Status BufferQueueProducer::SetBufferCount(s32 buffer_count) { return Status::NoError; } -Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, - Status* return_flags) const { +Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, + std::unique_lock& lk) const { bool try_again = true; while (try_again) { @@ -214,7 +214,7 @@ Status BufferQueueProducer::WaitForFreeSlotThenRelock(bool async, s32* found, return Status::WouldBlock; } - if (!core->WaitForDequeueCondition()) { + if (!core->WaitForDequeueCondition(lk)) { // We are no longer running return Status::NoError; } @@ -237,7 +237,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool Status return_flags = Status::NoError; bool attached_by_consumer = false; { - std::scoped_lock lock{core->mutex}; + std::unique_lock lock{core->mutex}; core->WaitWhileAllocatingLocked(); if (format == PixelFormat::NoFormat) { @@ -248,7 +248,7 @@ Status BufferQueueProducer::DequeueBuffer(s32* out_slot, Fence* out_fence, bool usage |= core->consumer_usage_bit; s32 found{}; - Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags); + Status status = WaitForFreeSlotThenRelock(async, &found, &return_flags, lock); if (status != Status::NoError) { return status; } @@ -400,13 +400,13 @@ Status BufferQueueProducer::AttachBuffer(s32* out_slot, return Status::BadValue; } - std::scoped_lock lock{core->mutex}; + std::unique_lock lock{core->mutex}; core->WaitWhileAllocatingLocked(); Status return_flags = Status::NoError; s32 found{}; - const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags); + const auto status = WaitForFreeSlotThenRelock(false, &found, &return_flags, lock); if (status != Status::NoError) { return status; } diff --git a/src/core/hle/service/nvflinger/buffer_queue_producer.h b/src/core/hle/service/nvflinger/buffer_queue_producer.h index 7526bf8ec..1d380480f 100644 --- a/src/core/hle/service/nvflinger/buffer_queue_producer.h +++ b/src/core/hle/service/nvflinger/buffer_queue_producer.h @@ -70,7 +70,8 @@ public: private: BufferQueueProducer(const BufferQueueProducer&) = delete; - Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags) const; + Status WaitForFreeSlotThenRelock(bool async, s32* found, Status* return_flags, + std::unique_lock& lk) const; Kernel::KEvent* buffer_wait_event{}; Service::KernelHelpers::ServiceContext& service_context; -- cgit v1.2.3 From bc957531072ad1973a690cd6c4aa9aa821ca64b1 Mon Sep 17 00:00:00 2001 From: Fernando Sahmkow Date: Thu, 17 Nov 2022 16:59:41 +0100 Subject: Dynarmic: Remove inaccurate NaN from Auto CPU settings. --- src/core/arm/dynarmic/arm_dynarmic_64.cpp | 1 - 1 file changed, 1 deletion(-) (limited to 'src/core') diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index afb7fb3a0..cb53d64ba 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -348,7 +348,6 @@ std::shared_ptr ARM_Dynarmic_64::MakeJit(Common::PageTable* if (Settings::values.cpu_accuracy.GetValue() == Settings::CPUAccuracy::Auto) { config.unsafe_optimizations = true; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_UnfuseFMA; - config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_InaccurateNaN; config.fastmem_address_space_bits = 64; config.optimizations |= Dynarmic::OptimizationFlag::Unsafe_IgnoreGlobalMonitor; } -- cgit v1.2.3 From 38c48cf8d896f28f7424b28265110c34f69d2369 Mon Sep 17 00:00:00 2001 From: Narr the Reg Date: Sat, 5 Nov 2022 10:39:03 -0600 Subject: core: hid: Implement true multitouch support --- src/core/hid/emulated_console.cpp | 94 ++++++++++++++++++++++++++++++--------- src/core/hid/emulated_console.h | 15 +++++-- src/core/hid/input_converter.cpp | 3 -- 3 files changed, 83 insertions(+), 29 deletions(-) (limited to 'src/core') diff --git a/src/core/hid/emulated_console.cpp b/src/core/hid/emulated_console.cpp index aac45907d..fb7e5802a 100644 --- a/src/core/hid/emulated_console.cpp +++ b/src/core/hid/emulated_console.cpp @@ -19,27 +19,26 @@ void EmulatedConsole::ReloadFromSettings() { } void EmulatedConsole::SetTouchParams() { - // TODO(german77): Support any number of fingers std::size_t index = 0; - // Hardcode mouse, touchscreen and cemuhook parameters + // We can't use mouse as touch if native mouse is enabled if (!Settings::values.mouse_enabled) { - // We can't use mouse as touch if native mouse is enabled touch_params[index++] = Common::ParamPackage{"engine:mouse,axis_x:10,axis_y:11,button:0"}; } touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:0,axis_y:1,button:0,touch_id:0"}; + Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536"}; touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:2,axis_y:3,button:1,touch_id:1"}; - touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:4,axis_y:5,button:2,touch_id:2"}; - touch_params[index++] = - Common::ParamPackage{"engine:touch,axis_x:6,axis_y:7,button:3,touch_id:3"}; - touch_params[index++] = - Common::ParamPackage{"engine:cemuhookudp,axis_x:17,axis_y:18,button:65536,touch_id:0"}; - touch_params[index++] = - Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072,touch_id:1"}; + Common::ParamPackage{"engine:cemuhookudp,axis_x:19,axis_y:20,button:131072"}; + + for (int i = 0; i < static_cast(MaxActiveTouchInputs); i++) { + Common::ParamPackage touchscreen_param{}; + touchscreen_param.Set("engine", "touch"); + touchscreen_param.Set("axis_x", i * 2); + touchscreen_param.Set("axis_y", (i * 2) + 1); + touchscreen_param.Set("button", i); + touch_params[index++] = touchscreen_param; + } const auto button_index = static_cast(Settings::values.touch_from_button_map_index.GetValue()); @@ -47,7 +46,7 @@ void EmulatedConsole::SetTouchParams() { // Map the rest of the fingers from touch from button configuration for (const auto& config_entry : touch_buttons) { - if (index >= touch_params.size()) { + if (index >= MaxTouchDevices) { continue; } Common::ParamPackage params{config_entry}; @@ -60,7 +59,6 @@ void EmulatedConsole::SetTouchParams() { touch_button_params.Set("button", params.Serialize()); touch_button_params.Set("x", x); touch_button_params.Set("y", y); - touch_button_params.Set("touch_id", static_cast(index)); touch_params[index] = touch_button_params; index++; } @@ -178,12 +176,38 @@ void EmulatedConsole::SetMotion(const Common::Input::CallbackStatus& callback) { } void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index) { - if (index >= console.touch_values.size()) { + if (index >= MaxTouchDevices) { return; } std::unique_lock lock{mutex}; - console.touch_values[index] = TransformToTouch(callback); + const auto touch_input = TransformToTouch(callback); + auto touch_index = GetIndexFromFingerId(index); + bool is_new_input = false; + + if (!touch_index.has_value() && touch_input.pressed.value) { + touch_index = GetNextFreeIndex(); + is_new_input = true; + } + + // No free entries or invalid state. Ignore input + if (!touch_index.has_value()) { + return; + } + + auto& touch_value = console.touch_values[touch_index.value()]; + + if (is_new_input) { + touch_value.pressed.value = true; + touch_value.id = static_cast(index); + } + + touch_value.x = touch_input.x; + touch_value.y = touch_input.y; + + if (!touch_input.pressed.value) { + touch_value.pressed.value = false; + } if (is_configuring) { lock.unlock(); @@ -191,11 +215,15 @@ void EmulatedConsole::SetTouch(const Common::Input::CallbackStatus& callback, st return; } - // TODO(german77): Remap touch id in sequential order - console.touch_state[index] = { - .position = {console.touch_values[index].x.value, console.touch_values[index].y.value}, - .id = static_cast(console.touch_values[index].id), - .pressed = console.touch_values[index].pressed.value, + // Touch outside allowed range. Ignore input + if (touch_index.value() >= MaxActiveTouchInputs) { + return; + } + + console.touch_state[touch_index.value()] = { + .position = {touch_value.x.value, touch_value.y.value}, + .id = static_cast(touch_index.value()), + .pressed = touch_input.pressed.value, }; lock.unlock(); @@ -222,6 +250,28 @@ TouchFingerState EmulatedConsole::GetTouch() const { return console.touch_state; } +std::optional EmulatedConsole::GetIndexFromFingerId(std::size_t finger_id) const { + for (std::size_t index = 0; index < MaxTouchDevices; ++index) { + const auto& finger = console.touch_values[index]; + if (!finger.pressed.value) { + continue; + } + if (finger.id == static_cast(finger_id)) { + return index; + } + } + return std::nullopt; +} + +std::optional EmulatedConsole::GetNextFreeIndex() const { + for (std::size_t index = 0; index < MaxTouchDevices; ++index) { + if (!console.touch_values[index].pressed.value) { + return index; + } + } + return std::nullopt; +} + void EmulatedConsole::TriggerOnChange(ConsoleTriggerType type) { std::scoped_lock lock{callback_mutex}; for (const auto& poller_pair : callback_list) { diff --git a/src/core/hid/emulated_console.h b/src/core/hid/emulated_console.h index 1c510cd19..697ecd2d6 100644 --- a/src/core/hid/emulated_console.h +++ b/src/core/hid/emulated_console.h @@ -7,6 +7,7 @@ #include #include #include +#include #include #include "common/common_funcs.h" @@ -20,6 +21,8 @@ #include "core/hid/motion_input.h" namespace Core::HID { +static constexpr std::size_t MaxTouchDevices = 32; +static constexpr std::size_t MaxActiveTouchInputs = 16; struct ConsoleMotionInfo { Common::Input::MotionStatus raw_status{}; @@ -27,13 +30,13 @@ struct ConsoleMotionInfo { }; using ConsoleMotionDevices = std::unique_ptr; -using TouchDevices = std::array, 16>; +using TouchDevices = std::array, MaxTouchDevices>; using ConsoleMotionParams = Common::ParamPackage; -using TouchParams = std::array; +using TouchParams = std::array; using ConsoleMotionValues = ConsoleMotionInfo; -using TouchValues = std::array; +using TouchValues = std::array; struct TouchFinger { u64 last_touch{}; @@ -55,7 +58,7 @@ struct ConsoleMotion { bool is_at_rest{}; }; -using TouchFingerState = std::array; +using TouchFingerState = std::array; struct ConsoleStatus { // Data from input_common @@ -166,6 +169,10 @@ private: */ void SetTouch(const Common::Input::CallbackStatus& callback, std::size_t index); + std::optional GetIndexFromFingerId(std::size_t finger_id) const; + + std::optional GetNextFreeIndex() const; + /** * Triggers a callback that something has changed on the console status * @param type Input type of the event to trigger diff --git a/src/core/hid/input_converter.cpp b/src/core/hid/input_converter.cpp index 5d8b75b50..502692875 100644 --- a/src/core/hid/input_converter.cpp +++ b/src/core/hid/input_converter.cpp @@ -200,9 +200,6 @@ Common::Input::TouchStatus TransformToTouch(const Common::Input::CallbackStatus& x = std::clamp(x, 0.0f, 1.0f); y = std::clamp(y, 0.0f, 1.0f); - // Limit id to maximum number of fingers - status.id = std::clamp(status.id, 0, 16); - if (status.pressed.inverted) { status.pressed.value = !status.pressed.value; } -- cgit v1.2.3 From aa075a0c08335b1d145b2885eb0ba2f395b74f90 Mon Sep 17 00:00:00 2001 From: german77 Date: Sat, 5 Nov 2022 11:40:19 -0600 Subject: service: hid: Only overclock npad controllers --- src/core/hle/service/hid/hid.cpp | 32 +++++++++++++++++++++++++++----- src/core/hle/service/hid/hid.h | 4 +++- 2 files changed, 30 insertions(+), 6 deletions(-) (limited to 'src/core') diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 79375bd2f..bf28440c6 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp @@ -36,8 +36,9 @@ namespace Service::HID { // Updating period for each HID device. // Period time is obtained by measuring the number of samples in a second on HW using a homebrew -// Correct pad_update_ns is 4ms this is overclocked to lower input lag -constexpr auto pad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +// Correct npad_update_ns is 4ms this is overclocked to lower input lag +constexpr auto npad_update_ns = std::chrono::nanoseconds{1 * 1000 * 1000}; // (1ms, 1000Hz) +constexpr auto default_update_ns = std::chrono::nanoseconds{4 * 1000 * 1000}; // (4ms, 1000Hz) constexpr auto mouse_keyboard_update_ns = std::chrono::nanoseconds{8 * 1000 * 1000}; // (8ms, 125Hz) constexpr auto motion_update_ns = std::chrono::nanoseconds{5 * 1000 * 1000}; // (5ms, 200Hz) @@ -75,8 +76,16 @@ IAppletResource::IAppletResource(Core::System& system_, GetController(HidController::UniquePad).SetCommonHeaderOffset(0x5A00); // Register update callbacks - pad_update_event = Core::Timing::CreateEvent( + npad_update_event = Core::Timing::CreateEvent( "HID::UpdatePadCallback", + [this](std::uintptr_t user_data, s64 time, + std::chrono::nanoseconds ns_late) -> std::optional { + const auto guard = LockService(); + UpdateNpad(user_data, ns_late); + return std::nullopt; + }); + default_update_event = Core::Timing::CreateEvent( + "HID::UpdateDefaultCallback", [this](std::uintptr_t user_data, s64 time, std::chrono::nanoseconds ns_late) -> std::optional { const auto guard = LockService(); @@ -100,7 +109,9 @@ IAppletResource::IAppletResource(Core::System& system_, return std::nullopt; }); - system.CoreTiming().ScheduleLoopingEvent(pad_update_ns, pad_update_ns, pad_update_event); + system.CoreTiming().ScheduleLoopingEvent(npad_update_ns, npad_update_ns, npad_update_event); + system.CoreTiming().ScheduleLoopingEvent(default_update_ns, default_update_ns, + default_update_event); system.CoreTiming().ScheduleLoopingEvent(mouse_keyboard_update_ns, mouse_keyboard_update_ns, mouse_keyboard_update_event); system.CoreTiming().ScheduleLoopingEvent(motion_update_ns, motion_update_ns, @@ -118,7 +129,8 @@ void IAppletResource::DeactivateController(HidController controller) { } IAppletResource::~IAppletResource() { - system.CoreTiming().UnscheduleEvent(pad_update_event, 0); + system.CoreTiming().UnscheduleEvent(npad_update_event, 0); + system.CoreTiming().UnscheduleEvent(default_update_event, 0); system.CoreTiming().UnscheduleEvent(mouse_keyboard_update_event, 0); system.CoreTiming().UnscheduleEvent(motion_update_event, 0); } @@ -144,10 +156,20 @@ void IAppletResource::UpdateControllers(std::uintptr_t user_data, if (controller == controllers[static_cast(HidController::Mouse)]) { continue; } + // Npad has it's own update event + if (controller == controllers[static_cast(HidController::NPad)]) { + continue; + } controller->OnUpdate(core_timing); } } +void IAppletResource::UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { + auto& core_timing = system.CoreTiming(); + + controllers[static_cast(HidController::NPad)]->OnUpdate(core_timing); +} + void IAppletResource::UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late) { auto& core_timing = system.CoreTiming(); diff --git a/src/core/hle/service/hid/hid.h b/src/core/hle/service/hid/hid.h index 340d26fdc..b7c2a23ef 100644 --- a/src/core/hle/service/hid/hid.h +++ b/src/core/hle/service/hid/hid.h @@ -71,12 +71,14 @@ private: void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx); void UpdateControllers(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); + void UpdateNpad(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMouseKeyboard(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); void UpdateMotion(std::uintptr_t user_data, std::chrono::nanoseconds ns_late); KernelHelpers::ServiceContext& service_context; - std::shared_ptr pad_update_event; + std::shared_ptr npad_update_event; + std::shared_ptr default_update_event; std::shared_ptr mouse_keyboard_update_event; std::shared_ptr motion_update_event; -- cgit v1.2.3