diff options
Diffstat (limited to '')
32 files changed, 376 insertions, 432 deletions
diff --git a/src/core/hle/ipc_helpers.h b/src/core/hle/ipc_helpers.h index 497f35d23..61bda3786 100644 --- a/src/core/hle/ipc_helpers.h +++ b/src/core/hle/ipc_helpers.h @@ -80,16 +80,12 @@ public: memset(cmdbuf, 0, sizeof(u32) * IPC::COMMAND_BUFFER_LENGTH); - ctx.ClearIncomingObjects(); - IPC::CommandHeader header{}; // The entire size of the raw data section in u32 units, including the 16 bytes of mandatory // padding. - u32 raw_data_size = ctx.IsTipc() - ? normal_params_size - 1 - : sizeof(IPC::DataPayloadHeader) / 4 + 4 + normal_params_size; - + u32 raw_data_size = ctx.write_size = + ctx.IsTipc() ? normal_params_size - 1 : normal_params_size; u32 num_handles_to_move{}; u32 num_domain_objects{}; const bool always_move_handles{ @@ -101,16 +97,20 @@ public: } if (ctx.Session()->IsDomain()) { - raw_data_size += static_cast<u32>(sizeof(DomainMessageHeader) / 4 + num_domain_objects); + raw_data_size += + static_cast<u32>(sizeof(DomainMessageHeader) / sizeof(u32) + num_domain_objects); + ctx.write_size += num_domain_objects; } if (ctx.IsTipc()) { header.type.Assign(ctx.GetCommandType()); + } else { + raw_data_size += static_cast<u32>(sizeof(IPC::DataPayloadHeader) / sizeof(u32) + 4 + + normal_params_size); } - ctx.data_size = static_cast<u32>(raw_data_size); - header.data_size.Assign(static_cast<u32>(raw_data_size)); - if (num_handles_to_copy != 0 || num_handles_to_move != 0) { + header.data_size.Assign(raw_data_size); + if (num_handles_to_copy || num_handles_to_move) { header.enable_handle_descriptor.Assign(1); } PushRaw(header); @@ -143,7 +143,8 @@ public: data_payload_index = index; ctx.data_payload_offset = index; - ctx.domain_offset = index + raw_data_size / 4; + ctx.write_size += index; + ctx.domain_offset = static_cast<u32>(index + raw_data_size / sizeof(u32)); } template <class T> @@ -151,8 +152,8 @@ public: if (context->Session()->IsDomain()) { context->AddDomainObject(std::move(iface)); } else { - // kernel.CurrentProcess()->GetResourceLimit()->Reserve( - // Kernel::LimitableResource::Sessions, 1); + kernel.CurrentProcess()->GetResourceLimit()->Reserve( + Kernel::LimitableResource::Sessions, 1); auto* session = Kernel::KSession::Create(kernel); session->Initialize(nullptr, iface->GetServiceName()); @@ -167,24 +168,6 @@ public: PushIpcInterface<T>(std::make_shared<T>(std::forward<Args>(args)...)); } - void ValidateHeader() { - const std::size_t num_domain_objects = context->NumDomainObjects(); - const std::size_t num_move_objects = context->NumMoveObjects(); - ASSERT_MSG(!num_domain_objects || !num_move_objects, - "cannot move normal handles and domain objects"); - ASSERT_MSG((index - data_payload_index) == normal_params_size, - "normal_params_size value is incorrect"); - ASSERT_MSG((num_domain_objects + num_move_objects) == num_objects_to_move, - "num_objects_to_move value is incorrect"); - ASSERT_MSG(context->NumCopyObjects() == num_handles_to_copy, - "num_handles_to_copy value is incorrect"); - } - - // Validate on destruction, as there shouldn't be any case where we don't want it - ~ResponseBuilder() { - ValidateHeader(); - } - void PushImpl(s8 value); void PushImpl(s16 value); void PushImpl(s32 value); @@ -404,7 +387,7 @@ public: std::shared_ptr<T> PopIpcInterface() { ASSERT(context->Session()->IsDomain()); ASSERT(context->GetDomainMessageHeader().input_object_count > 0); - return context->GetDomainRequestHandler<T>(Pop<u32>() - 1); + return context->GetDomainHandler<T>(Pop<u32>() - 1); } }; diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index ce3466df8..9d069a78f 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp @@ -35,11 +35,11 @@ SessionRequestHandler::SessionRequestHandler() = default; SessionRequestHandler::~SessionRequestHandler() = default; void SessionRequestHandler::ClientConnected(KServerSession* session) { - session->SetHleHandler(shared_from_this()); + session->SetSessionHandler(shared_from_this()); } void SessionRequestHandler::ClientDisconnected(KServerSession* session) { - session->SetHleHandler(nullptr); + session->SetSessionHandler(nullptr); } HLERequestContext::HLERequestContext(KernelCore& kernel_, Core::Memory::Memory& memory_, @@ -64,19 +64,15 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 if (command_header->enable_handle_descriptor) { handle_descriptor_header = rp.PopRaw<IPC::HandleDescriptorHeader>(); if (handle_descriptor_header->send_current_pid) { - rp.Skip(2, false); + pid = rp.Pop<u64>(); } if (incoming) { // Populate the object lists with the data in the IPC request. for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { - const u32 copy_handle{rp.Pop<Handle>()}; - copy_handles.push_back(copy_handle); - copy_objects.push_back(handle_table.GetObject(copy_handle).GetPointerUnsafe()); + incoming_copy_handles.push_back(rp.Pop<Handle>()); } for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_move; ++handle) { - const u32 move_handle{rp.Pop<Handle>()}; - move_handles.push_back(move_handle); - move_objects.push_back(handle_table.GetObject(move_handle).GetPointerUnsafe()); + incoming_move_handles.push_back(rp.Pop<Handle>()); } } else { // For responses we just ignore the handles, they're empty and will be populated when @@ -86,16 +82,16 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 } } - for (unsigned i = 0; i < command_header->num_buf_x_descriptors; ++i) { + for (u32 i = 0; i < command_header->num_buf_x_descriptors; ++i) { buffer_x_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorX>()); } - for (unsigned i = 0; i < command_header->num_buf_a_descriptors; ++i) { + for (u32 i = 0; i < command_header->num_buf_a_descriptors; ++i) { buffer_a_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } - for (unsigned i = 0; i < command_header->num_buf_b_descriptors; ++i) { + for (u32 i = 0; i < command_header->num_buf_b_descriptors; ++i) { buffer_b_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } - for (unsigned i = 0; i < command_header->num_buf_w_descriptors; ++i) { + for (u32 i = 0; i < command_header->num_buf_w_descriptors; ++i) { buffer_w_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorABW>()); } @@ -148,14 +144,14 @@ void HLERequestContext::ParseCommandBuffer(const KHandleTable& handle_table, u32 IPC::CommandHeader::BufferDescriptorCFlag::OneDescriptor) { buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); } else { - unsigned num_buf_c_descriptors = - static_cast<unsigned>(command_header->buf_c_descriptor_flags.Value()) - 2; + u32 num_buf_c_descriptors = + static_cast<u32>(command_header->buf_c_descriptor_flags.Value()) - 2; // This is used to detect possible underflows, in case something is broken // with the two ifs above and the flags value is == 0 || == 1. ASSERT(num_buf_c_descriptors < 14); - for (unsigned i = 0; i < num_buf_c_descriptors; ++i) { + for (u32 i = 0; i < num_buf_c_descriptors; ++i) { buffer_c_desciptors.push_back(rp.PopRaw<IPC::BufferDescriptorC>()); } } @@ -186,26 +182,14 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t auto& owner_process = *requesting_thread.GetOwnerProcess(); auto& handle_table = owner_process.GetHandleTable(); - // The data_size already includes the payload header, the padding and the domain header. - std::size_t size{}; - - if (IsTipc()) { - size = cmd_buf.size(); - } else { - size = data_payload_offset + data_size - sizeof(IPC::DataPayloadHeader) / sizeof(u32) - 4; - if (Session()->IsDomain()) { - size -= sizeof(IPC::DomainMessageHeader) / sizeof(u32); - } - } - - for (auto& object : copy_objects) { + for (auto& object : outgoing_copy_objects) { Handle handle{}; if (object) { R_TRY(handle_table.Add(&handle, object)); } cmd_buf[current_offset++] = handle; } - for (auto& object : move_objects) { + for (auto& object : outgoing_move_objects) { Handle handle{}; if (object) { R_TRY(handle_table.Add(&handle, object)); @@ -220,9 +204,9 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t // TODO(Subv): This completely ignores C buffers. if (Session()->IsDomain()) { - current_offset = domain_offset - static_cast<u32>(domain_objects.size()); - for (const auto& object : domain_objects) { - server_session->AppendDomainRequestHandler(object); + current_offset = domain_offset - static_cast<u32>(outgoing_domain_objects.size()); + for (const auto& object : outgoing_domain_objects) { + server_session->AppendDomainHandler(object); cmd_buf[current_offset++] = static_cast<u32_le>(server_session->NumDomainRequestHandlers()); } @@ -230,7 +214,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(KThread& requesting_t // Copy the translated command buffer back into the thread's command buffer area. memory.WriteBlock(owner_process, requesting_thread.GetTLSAddress(), cmd_buf.data(), - size * sizeof(u32)); + write_size * sizeof(u32)); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 4fba300dc..b47e363cc 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h @@ -11,7 +11,8 @@ #include <string> #include <type_traits> #include <vector> -#include <boost/container/small_vector.hpp> + +#include "common/assert.h" #include "common/common_types.h" #include "common/concepts.h" #include "common/swap.h" @@ -84,6 +85,69 @@ public: void ClientDisconnected(KServerSession* session); }; +using SessionRequestHandlerPtr = std::shared_ptr<SessionRequestHandler>; + +/** + * Manages the underlying HLE requests for a session, and whether (or not) the session should be + * treated as a domain. This is managed separately from server sessions, as this state is shared + * when objects are cloned. + */ +class SessionRequestManager final { +public: + SessionRequestManager() = default; + + bool IsDomain() const { + return is_domain; + } + + void ConvertToDomain() { + domain_handlers = {session_handler}; + is_domain = true; + } + + std::size_t DomainHandlerCount() const { + return domain_handlers.size(); + } + + bool HasSessionHandler() const { + return session_handler != nullptr; + } + + SessionRequestHandler& SessionHandler() { + return *session_handler; + } + + const SessionRequestHandler& SessionHandler() const { + return *session_handler; + } + + void CloseDomainHandler(std::size_t index) { + if (index < DomainHandlerCount()) { + domain_handlers[index] = nullptr; + } else { + UNREACHABLE_MSG("Unexpected handler index {}", index); + } + } + + SessionRequestHandlerPtr DomainHandler(std::size_t index) const { + ASSERT_MSG(index < DomainHandlerCount(), "Unexpected handler index {}", index); + return domain_handlers.at(index); + } + + void AppendDomainHandler(SessionRequestHandlerPtr&& handler) { + domain_handlers.emplace_back(std::move(handler)); + } + + void SetSessionHandler(SessionRequestHandlerPtr&& handler) { + session_handler = std::move(handler); + } + +private: + bool is_domain{}; + SessionRequestHandlerPtr session_handler; + std::vector<SessionRequestHandlerPtr> domain_handlers; +}; + /** * Class containing information about an in-flight IPC request being handled by an HLE service * implementation. Services should avoid using old global APIs (e.g. Kernel::GetCommandBuffer()) and @@ -150,6 +214,10 @@ public: return command_header->type; } + u64 GetPID() const { + return pid; + } + u32 GetDataPayloadOffset() const { return data_payload_offset; } @@ -220,53 +288,32 @@ public: bool CanWriteBuffer(std::size_t buffer_index = 0) const; Handle GetCopyHandle(std::size_t index) const { - return copy_handles.at(index); + return incoming_copy_handles.at(index); } Handle GetMoveHandle(std::size_t index) const { - return move_handles.at(index); + return incoming_move_handles.at(index); } void AddMoveObject(KAutoObject* object) { - move_objects.emplace_back(object); + outgoing_move_objects.emplace_back(object); } void AddCopyObject(KAutoObject* object) { - copy_objects.emplace_back(object); + outgoing_copy_objects.emplace_back(object); } - void AddDomainObject(std::shared_ptr<SessionRequestHandler> object) { - domain_objects.emplace_back(std::move(object)); + void AddDomainObject(SessionRequestHandlerPtr object) { + outgoing_domain_objects.emplace_back(std::move(object)); } template <typename T> - std::shared_ptr<T> GetDomainRequestHandler(std::size_t index) const { - return std::static_pointer_cast<T>(domain_request_handlers.at(index)); + std::shared_ptr<T> GetDomainHandler(std::size_t index) const { + return std::static_pointer_cast<T>(manager->DomainHandler(index)); } - void SetDomainRequestHandlers( - const std::vector<std::shared_ptr<SessionRequestHandler>>& handlers) { - domain_request_handlers = handlers; - } - - /// Clears the list of objects so that no lingering objects are written accidentally to the - /// response buffer. - void ClearIncomingObjects() { - move_objects.clear(); - copy_objects.clear(); - domain_objects.clear(); - } - - std::size_t NumMoveObjects() const { - return move_objects.size(); - } - - std::size_t NumCopyObjects() const { - return copy_objects.size(); - } - - std::size_t NumDomainObjects() const { - return domain_objects.size(); + void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { + manager = std::move(manager_); } std::string Description() const; @@ -288,12 +335,12 @@ private: Kernel::KServerSession* server_session{}; KThread* thread; - // TODO(yuriks): Check common usage of this and optimize size accordingly - boost::container::small_vector<Handle, 8> move_handles; - boost::container::small_vector<Handle, 8> copy_handles; - boost::container::small_vector<KAutoObject*, 8> move_objects; - boost::container::small_vector<KAutoObject*, 8> copy_objects; - boost::container::small_vector<std::shared_ptr<SessionRequestHandler>, 8> domain_objects; + std::vector<Handle> incoming_move_handles; + std::vector<Handle> incoming_copy_handles; + + std::vector<KAutoObject*> outgoing_move_objects; + std::vector<KAutoObject*> outgoing_copy_objects; + std::vector<SessionRequestHandlerPtr> outgoing_domain_objects; std::optional<IPC::CommandHeader> command_header; std::optional<IPC::HandleDescriptorHeader> handle_descriptor_header; @@ -305,13 +352,14 @@ private: std::vector<IPC::BufferDescriptorABW> buffer_w_desciptors; std::vector<IPC::BufferDescriptorC> buffer_c_desciptors; + u32_le command{}; + u64 pid{}; + u32 write_size{}; u32 data_payload_offset{}; u32 handles_offset{}; u32 domain_offset{}; - u32 data_size{}; - u32_le command{}; - std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + std::shared_ptr<SessionRequestManager> manager; bool is_thread_waiting{}; KernelCore& kernel; diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 69ae405e6..10edede17 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp @@ -70,14 +70,22 @@ constexpr size_t SlabCountExtraKThread = 160; template <typename T> VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAddr address, size_t num_objects) { + // TODO(bunnei): This is just a place holder. We should initialize the appropriate KSlabHeap for + // kernel object type T with the backing kernel memory pointer once we emulate kernel memory. + const size_t size = Common::AlignUp(sizeof(T) * num_objects, alignof(void*)); VAddr start = Common::AlignUp(address, alignof(T)); + // This is intentionally empty. Once KSlabHeap is fully implemented, we can replace this with + // the pointer to emulated memory to pass along. Until then, KSlabHeap will just allocate/free + // host memory. + void* backing_kernel_memory{}; + if (size > 0) { const KMemoryRegion* region = memory_layout.FindVirtual(start + size - 1); ASSERT(region != nullptr); ASSERT(region->IsDerivedFrom(KMemoryRegionType_KernelSlab)); - T::InitializeSlabHeap(system.Kernel(), system.Memory().GetKernelBuffer(start, size), size); + T::InitializeSlabHeap(system.Kernel(), backing_kernel_memory, size); } return start + size; diff --git a/src/core/hle/kernel/k_client_port.cpp b/src/core/hle/kernel/k_client_port.cpp index ad01cf67e..4a12dee10 100644 --- a/src/core/hle/kernel/k_client_port.cpp +++ b/src/core/hle/kernel/k_client_port.cpp @@ -58,9 +58,9 @@ bool KClientPort::IsSignaled() const { ResultCode KClientPort::CreateSession(KClientSession** out) { // Reserve a new session from the resource limit. - // KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), - // LimitableResource::Sessions); - // R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); + KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(), + LimitableResource::Sessions); + R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); // Update the session counts. { @@ -104,7 +104,7 @@ ResultCode KClientPort::CreateSession(KClientSession** out) { session->Initialize(this, parent->GetName()); // Commit the session reservation. - // session_reservation.Commit(); + session_reservation.Commit(); // Register the session. KSession::Register(kernel, session); diff --git a/src/core/hle/kernel/k_client_port.h b/src/core/hle/kernel/k_client_port.h index d00ce3ddd..8501156e8 100644 --- a/src/core/hle/kernel/k_client_port.h +++ b/src/core/hle/kernel/k_client_port.h @@ -31,6 +31,9 @@ public: const KPort* GetParent() const { return parent; } + KPort* GetParent() { + return parent; + } s32 GetNumSessions() const { return num_sessions; diff --git a/src/core/hle/kernel/k_port.cpp b/src/core/hle/kernel/k_port.cpp index feb2bb11f..223c0b205 100644 --- a/src/core/hle/kernel/k_port.cpp +++ b/src/core/hle/kernel/k_port.cpp @@ -56,11 +56,8 @@ ResultCode KPort::EnqueueSession(KServerSession* session) { R_UNLESS(state == State::Normal, ResultPortClosed); - if (server.HasHLEHandler()) { - server.GetHLEHandler()->ClientConnected(session); - } else { - server.EnqueueSession(session); - } + server.EnqueueSession(session); + server.GetSessionRequestHandler()->ClientConnected(server.AcceptSession()); return RESULT_SUCCESS; } diff --git a/src/core/hle/kernel/k_server_port.h b/src/core/hle/kernel/k_server_port.h index e76792253..d1a757ec3 100644 --- a/src/core/hle/kernel/k_server_port.h +++ b/src/core/hle/kernel/k_server_port.h @@ -32,26 +32,24 @@ public: explicit KServerPort(KernelCore& kernel_); virtual ~KServerPort() override; - using HLEHandler = std::shared_ptr<SessionRequestHandler>; - void Initialize(KPort* parent_, std::string&& name_); /// Whether or not this server port has an HLE handler available. - bool HasHLEHandler() const { - return hle_handler != nullptr; + bool HasSessionRequestHandler() const { + return session_handler != nullptr; } /// Gets the HLE handler for this port. - HLEHandler GetHLEHandler() const { - return hle_handler; + SessionRequestHandlerPtr GetSessionRequestHandler() const { + return session_handler; } /** * Sets the HLE handler template for the port. ServerSessions crated by connecting to this port * will inherit a reference to this handler. */ - void SetHleHandler(HLEHandler hle_handler_) { - hle_handler = std::move(hle_handler_); + void SetSessionHandler(SessionRequestHandlerPtr&& handler) { + session_handler = std::move(handler); } void EnqueueSession(KServerSession* pending_session); @@ -73,7 +71,7 @@ private: private: SessionList session_list; - HLEHandler hle_handler; + SessionRequestHandlerPtr session_handler; KPort* parent{}; }; diff --git a/src/core/hle/kernel/k_server_session.cpp b/src/core/hle/kernel/k_server_session.cpp index 8850d9af5..457fdfd60 100644 --- a/src/core/hle/kernel/k_server_session.cpp +++ b/src/core/hle/kernel/k_server_session.cpp @@ -23,7 +23,8 @@ namespace Kernel { -KServerSession::KServerSession(KernelCore& kernel_) : KSynchronizationObject{kernel_} {} +KServerSession::KServerSession(KernelCore& kernel_) + : KSynchronizationObject{kernel_}, manager{std::make_shared<SessionRequestManager>()} {} KServerSession::~KServerSession() { kernel.ReleaseServiceThread(service_thread); @@ -43,14 +44,8 @@ void KServerSession::Destroy() { } void KServerSession::OnClientClosed() { - // We keep a shared pointer to the hle handler to keep it alive throughout - // the call to ClientDisconnected, as ClientDisconnected invalidates the - // hle_handler member itself during the course of the function executing. - std::shared_ptr<SessionRequestHandler> handler = hle_handler; - if (handler) { - // Note that after this returns, this server session's hle_handler is - // invalidated (set to null). - handler->ClientDisconnected(this); + if (manager->HasSessionHandler()) { + manager->SessionHandler().ClientDisconnected(this); } } @@ -66,12 +61,12 @@ bool KServerSession::IsSignaled() const { return false; } -void KServerSession::AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler) { - domain_request_handlers.push_back(std::move(handler)); +void KServerSession::AppendDomainHandler(SessionRequestHandlerPtr handler) { + manager->AppendDomainHandler(std::move(handler)); } std::size_t KServerSession::NumDomainRequestHandlers() const { - return domain_request_handlers.size(); + return manager->DomainHandlerCount(); } ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& context) { @@ -80,14 +75,14 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co } // Set domain handlers in HLE context, used for domain objects (IPC interfaces) as inputs - context.SetDomainRequestHandlers(domain_request_handlers); + context.SetSessionRequestManager(manager); // If there is a DomainMessageHeader, then this is CommandType "Request" const auto& domain_message_header = context.GetDomainMessageHeader(); const u32 object_id{domain_message_header.object_id}; switch (domain_message_header.command) { case IPC::DomainMessageHeader::CommandType::SendMessage: - if (object_id > domain_request_handlers.size()) { + if (object_id > manager->DomainHandlerCount()) { LOG_CRITICAL(IPC, "object_id {} is too big! This probably means a recent service call " "to {} needed to return a new interface!", @@ -95,12 +90,12 @@ ResultCode KServerSession::HandleDomainSyncRequest(Kernel::HLERequestContext& co UNREACHABLE(); return RESULT_SUCCESS; // Ignore error if asserts are off } - return domain_request_handlers[object_id - 1]->HandleSyncRequest(*this, context); + return manager->DomainHandler(object_id - 1)->HandleSyncRequest(*this, context); case IPC::DomainMessageHeader::CommandType::CloseVirtualHandle: { LOG_DEBUG(IPC, "CloseVirtualHandle, object_id=0x{:08X}", object_id); - domain_request_handlers[object_id - 1] = nullptr; + manager->CloseDomainHandler(object_id - 1); IPC::ResponseBuilder rb{context, 2}; rb.Push(RESULT_SUCCESS); @@ -133,14 +128,14 @@ ResultCode KServerSession::CompleteSyncRequest(HLERequestContext& context) { if (IsDomain() && context.HasDomainMessageHeader()) { result = HandleDomainSyncRequest(context); // If there is no domain header, the regular session handler is used - } else if (hle_handler != nullptr) { + } else if (manager->HasSessionHandler()) { // If this ServerSession has an associated HLE handler, forward the request to it. - result = hle_handler->HandleSyncRequest(*this, context); + result = manager->SessionHandler().HandleSyncRequest(*this, context); } if (convert_to_domain) { - ASSERT_MSG(IsSession(), "ServerSession is already a domain instance."); - domain_request_handlers = {hle_handler}; + ASSERT_MSG(!IsDomain(), "ServerSession is already a domain instance."); + manager->ConvertToDomain(); convert_to_domain = false; } diff --git a/src/core/hle/kernel/k_server_session.h b/src/core/hle/kernel/k_server_session.h index 597d76d38..dd4de2904 100644 --- a/src/core/hle/kernel/k_server_session.h +++ b/src/core/hle/kernel/k_server_session.h @@ -12,6 +12,7 @@ #include <boost/intrusive/list.hpp> #include "common/threadsafe_queue.h" +#include "core/hle/kernel/hle_ipc.h" #include "core/hle/kernel/k_synchronization_object.h" #include "core/hle/kernel/service_thread.h" #include "core/hle/result.h" @@ -64,8 +65,8 @@ public: * instead of the regular IPC machinery. (The regular IPC machinery is currently not * implemented.) */ - void SetHleHandler(std::shared_ptr<SessionRequestHandler> hle_handler_) { - hle_handler = std::move(hle_handler_); + void SetSessionHandler(SessionRequestHandlerPtr handler) { + manager->SetSessionHandler(std::move(handler)); } /** @@ -82,7 +83,7 @@ public: /// Adds a new domain request handler to the collection of request handlers within /// this ServerSession instance. - void AppendDomainRequestHandler(std::shared_ptr<SessionRequestHandler> handler); + void AppendDomainHandler(SessionRequestHandlerPtr handler); /// Retrieves the total number of domain request handlers that have been /// appended to this ServerSession instance. @@ -90,12 +91,7 @@ public: /// Returns true if the session has been converted to a domain, otherwise False bool IsDomain() const { - return !IsSession(); - } - - /// Returns true if this session has not been converted to a domain, otherwise false. - bool IsSession() const { - return domain_request_handlers.empty(); + return manager->IsDomain(); } /// Converts the session to a domain at the end of the current command @@ -103,6 +99,21 @@ public: convert_to_domain = true; } + /// Gets the session request manager, which forwards requests to the underlying service + std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() { + return manager; + } + + /// Gets the session request manager, which forwards requests to the underlying service + const std::shared_ptr<SessionRequestManager>& GetSessionRequestManager() const { + return manager; + } + + /// Sets the session request manager, which forwards requests to the underlying service + void SetSessionRequestManager(std::shared_ptr<SessionRequestManager> manager_) { + manager = std::move(manager_); + } + private: /// Queues a sync request from the emulated application. ResultCode QueueSyncRequest(KThread* thread, Core::Memory::Memory& memory); @@ -114,11 +125,8 @@ private: /// object handle. ResultCode HandleDomainSyncRequest(Kernel::HLERequestContext& context); - /// This session's HLE request handler (applicable when not a domain) - std::shared_ptr<SessionRequestHandler> hle_handler; - - /// This is the list of domain request handlers (after conversion to a domain) - std::vector<std::shared_ptr<SessionRequestHandler>> domain_request_handlers; + /// This session's HLE request handlers + std::shared_ptr<SessionRequestManager> manager; /// When set to True, converts the session to a domain at the end of the command bool convert_to_domain{}; diff --git a/src/core/hle/kernel/k_session.cpp b/src/core/hle/kernel/k_session.cpp index b7ce27a0b..025b8b555 100644 --- a/src/core/hle/kernel/k_session.cpp +++ b/src/core/hle/kernel/k_session.cpp @@ -78,7 +78,7 @@ void KSession::OnClientClosed() { void KSession::PostDestroy(uintptr_t arg) { // Release the session count resource the owner process holds. KProcess* owner = reinterpret_cast<KProcess*>(arg); - // owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); + owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1); owner->Close(); } diff --git a/src/core/hle/kernel/k_session.h b/src/core/hle/kernel/k_session.h index 16901e19c..a981fd1f6 100644 --- a/src/core/hle/kernel/k_session.h +++ b/src/core/hle/kernel/k_session.h @@ -66,6 +66,10 @@ public: return port; } + KClientPort* GetParent() { + return port; + } + private: enum class State : u8 { Invalid = 0, diff --git a/src/core/hle/kernel/k_slab_heap.h b/src/core/hle/kernel/k_slab_heap.h index 5ce9a1d7c..81d472a3e 100644 --- a/src/core/hle/kernel/k_slab_heap.h +++ b/src/core/hle/kernel/k_slab_heap.h @@ -4,165 +4,33 @@ #pragma once -#include <atomic> - -#include "common/assert.h" -#include "common/common_types.h" - namespace Kernel { -namespace impl { - -class KSlabHeapImpl final : NonCopyable { -public: - struct Node { - Node* next{}; - }; - - constexpr KSlabHeapImpl() = default; - - void Initialize(std::size_t size) { - ASSERT(head == nullptr); - obj_size = size; - } - - constexpr std::size_t GetObjectSize() const { - return obj_size; - } - - Node* GetHead() const { - return head; - } - - void* Allocate() { - Node* ret = head.load(); - - do { - if (ret == nullptr) { - break; - } - } while (!head.compare_exchange_weak(ret, ret->next)); - - return ret; - } - - void Free(void* obj) { - Node* node = static_cast<Node*>(obj); - - Node* cur_head = head.load(); - do { - node->next = cur_head; - } while (!head.compare_exchange_weak(cur_head, node)); - } - -private: - std::atomic<Node*> head{}; - std::size_t obj_size{}; -}; - -} // namespace impl - -class KSlabHeapBase : NonCopyable { -public: - constexpr KSlabHeapBase() = default; - - constexpr bool Contains(uintptr_t addr) const { - return start <= addr && addr < end; - } - - constexpr std::size_t GetSlabHeapSize() const { - return (end - start) / GetObjectSize(); - } - - constexpr std::size_t GetObjectSize() const { - return impl.GetObjectSize(); - } +class KernelCore; - constexpr uintptr_t GetSlabHeapAddress() const { - return start; - } - - std::size_t GetObjectIndexImpl(const void* obj) const { - return (reinterpret_cast<uintptr_t>(obj) - start) / GetObjectSize(); - } - - std::size_t GetPeakIndex() const { - return GetObjectIndexImpl(reinterpret_cast<const void*>(peak)); - } - - void* AllocateImpl() { - return impl.Allocate(); - } - - void FreeImpl(void* obj) { - // Don't allow freeing an object that wasn't allocated from this heap - ASSERT(Contains(reinterpret_cast<uintptr_t>(obj))); - - impl.Free(obj); - } - - void InitializeImpl(std::size_t obj_size, void* memory, std::size_t memory_size) { - // Ensure we don't initialize a slab using null memory - ASSERT(memory != nullptr); - - // Initialize the base allocator - impl.Initialize(obj_size); - - // Set our tracking variables - const std::size_t num_obj = (memory_size / obj_size); - start = reinterpret_cast<uintptr_t>(memory); - end = start + num_obj * obj_size; - peak = start; - - // Free the objects - u8* cur = reinterpret_cast<u8*>(end); - - for (std::size_t i{}; i < num_obj; i++) { - cur -= obj_size; - impl.Free(cur); - } - } - -private: - using Impl = impl::KSlabHeapImpl; - - Impl impl; - uintptr_t peak{}; - uintptr_t start{}; - uintptr_t end{}; -}; +/// This is a placeholder class to manage slab heaps for kernel objects. For now, we just allocate +/// these with new/delete, but this can be re-implemented later to allocate these in emulated +/// memory. template <typename T> -class KSlabHeap final : public KSlabHeapBase { +class KSlabHeap final : NonCopyable { public: - constexpr KSlabHeap() : KSlabHeapBase() {} + KSlabHeap() = default; - void Initialize(void* memory, std::size_t memory_size) { - InitializeImpl(sizeof(T), memory, memory_size); + void Initialize([[maybe_unused]] void* memory, [[maybe_unused]] std::size_t memory_size) { + // Placeholder that should initialize the backing slab heap implementation. } T* Allocate() { - T* obj = static_cast<T*>(AllocateImpl()); - if (obj != nullptr) { - new (obj) T(); - } - return obj; + return new T(); } T* AllocateWithKernel(KernelCore& kernel) { - T* obj = static_cast<T*>(AllocateImpl()); - if (obj != nullptr) { - new (obj) T(kernel); - } - return obj; + return new T(kernel); } void Free(T* obj) { - FreeImpl(obj); - } - - constexpr std::size_t GetObjectIndex(const T* obj) const { - return GetObjectIndexImpl(obj); + delete obj; } }; diff --git a/src/core/hle/kernel/k_transfer_memory.h b/src/core/hle/kernel/k_transfer_memory.h index 838fd2b18..c2d0f1eaf 100644 --- a/src/core/hle/kernel/k_transfer_memory.h +++ b/src/core/hle/kernel/k_transfer_memory.h @@ -52,7 +52,7 @@ public: } size_t GetSize() const { - return is_initialized ? size * PageSize : 0; + return is_initialized ? size : 0; } private: diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index fcb8b1ea5..b2ceeceb3 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -22,6 +22,7 @@ enum : u32 { CapabilityOffset_Syscall = 4, CapabilityOffset_MapPhysical = 6, CapabilityOffset_MapIO = 7, + CapabilityOffset_MapRegion = 10, CapabilityOffset_Interrupt = 11, CapabilityOffset_ProgramType = 13, CapabilityOffset_KernelVersion = 14, @@ -46,6 +47,7 @@ enum class CapabilityType : u32 { Syscall = (1U << CapabilityOffset_Syscall) - 1, MapPhysical = (1U << CapabilityOffset_MapPhysical) - 1, MapIO = (1U << CapabilityOffset_MapIO) - 1, + MapRegion = (1U << CapabilityOffset_MapRegion) - 1, Interrupt = (1U << CapabilityOffset_Interrupt) - 1, ProgramType = (1U << CapabilityOffset_ProgramType) - 1, KernelVersion = (1U << CapabilityOffset_KernelVersion) - 1, @@ -187,6 +189,8 @@ ResultCode ProcessCapabilities::ParseSingleFlagCapability(u32& set_flags, u32& s return HandleSyscallFlags(set_svc_bits, flag); case CapabilityType::MapIO: return HandleMapIOFlags(flag, page_table); + case CapabilityType::MapRegion: + return HandleMapRegionFlags(flag, page_table); case CapabilityType::Interrupt: return HandleInterruptFlags(flag); case CapabilityType::ProgramType: @@ -298,6 +302,11 @@ ResultCode ProcessCapabilities::HandleMapIOFlags(u32 flags, KPageTable& page_tab return RESULT_SUCCESS; } +ResultCode ProcessCapabilities::HandleMapRegionFlags(u32 flags, KPageTable& page_table) { + // TODO(Lioncache): Implement once the memory manager can handle this. + return RESULT_SUCCESS; +} + ResultCode ProcessCapabilities::HandleInterruptFlags(u32 flags) { constexpr u32 interrupt_ignore_value = 0x3FF; const u32 interrupt0 = (flags >> 12) & 0x3FF; diff --git a/src/core/hle/kernel/process_capability.h b/src/core/hle/kernel/process_capability.h index b7a9b2e45..2a7bf5505 100644 --- a/src/core/hle/kernel/process_capability.h +++ b/src/core/hle/kernel/process_capability.h @@ -231,6 +231,9 @@ private: /// Handles flags related to mapping IO pages. ResultCode HandleMapIOFlags(u32 flags, KPageTable& page_table); + /// Handles flags related to mapping physical memory regions. + ResultCode HandleMapRegionFlags(u32 flags, KPageTable& page_table); + /// Handles flags related to the interrupt capability flags. ResultCode HandleInterruptFlags(u32 flags); diff --git a/src/core/hle/kernel/service_thread.cpp b/src/core/hle/kernel/service_thread.cpp index 04be8a502..2ae80beca 100644 --- a/src/core/hle/kernel/service_thread.cpp +++ b/src/core/hle/kernel/service_thread.cpp @@ -74,21 +74,17 @@ void ServiceThread::Impl::QueueSyncRequest(KSession& session, { std::unique_lock lock{queue_mutex}; + auto* server_session{&session.GetServerSession()}; + // Open a reference to the session to ensure it is not closes while the service request // completes asynchronously. - session.Open(); + server_session->Open(); - requests.emplace([session_ptr{&session}, context{std::move(context)}]() { + requests.emplace([server_session, context{std::move(context)}]() { // Close the reference. - SCOPE_EXIT({ session_ptr->Close(); }); - - // If the session has been closed, we are done. - if (session_ptr->IsServerClosed()) { - return; - } + SCOPE_EXIT({ server_session->Close(); }); // Complete the service request. - KScopedAutoObject server_session{&session_ptr->GetServerSession()}; server_session->CompleteSyncRequest(*context); }); } diff --git a/src/core/hle/kernel/slab_helpers.h b/src/core/hle/kernel/slab_helpers.h index d0f7f084b..0c5995db0 100644 --- a/src/core/hle/kernel/slab_helpers.h +++ b/src/core/hle/kernel/slab_helpers.h @@ -67,11 +67,11 @@ class KAutoObjectWithSlabHeapAndContainer : public Base { private: static Derived* Allocate(KernelCore& kernel) { - return new Derived(kernel); + return kernel.SlabHeap<Derived>().AllocateWithKernel(kernel); } static void Free(KernelCore& kernel, Derived* obj) { - delete obj; + kernel.SlabHeap<Derived>().Free(obj); } public: diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 49c09a570..39cd1efc1 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp @@ -4,9 +4,9 @@ #include <algorithm> #include <array> -#include "common/common_paths.h" #include "common/common_types.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "common/swap.h" @@ -41,9 +41,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::string GetImagePath(Common::UUID uuid) { - return Common::FS::GetUserPath(Common::FS::UserPath::NANDDir) + - "/system/save/8000000000000010/su/avators/" + uuid.FormatSwitch() + ".jpg"; +static std::filesystem::path GetImagePath(Common::UUID uuid) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::NANDDir) / + fmt::format("system/save/8000000000000010/su/avators/{}.jpg", uuid.FormatSwitch()); } static constexpr u32 SanitizeJPEGSize(std::size_t size) { @@ -328,7 +328,8 @@ protected: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - const Common::FS::IOFile image(GetImagePath(user_id), "rb"); + const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile); if (!image.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load user provided image! Falling back to built-in backup..."); @@ -339,7 +340,10 @@ protected: const u32 size = SanitizeJPEGSize(image.GetSize()); std::vector<u8> buffer(size); - image.ReadBytes(buffer.data(), buffer.size()); + + if (image.Read(buffer) != buffer.size()) { + LOG_ERROR(Service_ACC, "Failed to read all the bytes in the user provided image."); + } ctx.WriteBuffer(buffer); rb.Push<u32>(size); @@ -350,7 +354,8 @@ protected: IPC::ResponseBuilder rb{ctx, 3}; rb.Push(RESULT_SUCCESS); - const Common::FS::IOFile image(GetImagePath(user_id), "rb"); + const Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile); if (!image.IsOpen()) { LOG_WARNING(Service_ACC, @@ -415,10 +420,11 @@ protected: ProfileData data; std::memcpy(&data, user_data.data(), sizeof(ProfileData)); - Common::FS::IOFile image(GetImagePath(user_id), "wb"); + Common::FS::IOFile image(GetImagePath(user_id), Common::FS::FileAccessMode::Write, + Common::FS::FileType::BinaryFile); - if (!image.IsOpen() || !image.Resize(image_data.size()) || - image.WriteBytes(image_data.data(), image_data.size()) != image_data.size() || + if (!image.IsOpen() || !image.SetSize(image_data.size()) || + image.Write(image_data) != image_data.size() || !profile_manager.SetProfileBaseAndData(user_id, base, data)) { LOG_ERROR(Service_ACC, "Failed to update profile data, base, and image!"); IPC::ResponseBuilder rb{ctx, 2}; diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index de83d82a4..77510489c 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp @@ -7,7 +7,9 @@ #include <fmt/format.h> -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/settings.h" #include "core/hle/service/acc/profile_manager.h" @@ -36,7 +38,7 @@ constexpr ResultCode ERROR_TOO_MANY_USERS(ErrorModule::Account, u32(-1)); constexpr ResultCode ERROR_USER_ALREADY_EXISTS(ErrorModule::Account, u32(-2)); constexpr ResultCode ERROR_ARGUMENT_IS_NULL(ErrorModule::Account, 20); -constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "/system/save/8000000000000010/su/avators/"; +constexpr char ACC_SAVE_AVATORS_BASE_PATH[] = "system/save/8000000000000010/su/avators"; ProfileManager::ProfileManager() { ParseUserSaveFile(); @@ -325,8 +327,9 @@ bool ProfileManager::SetProfileBaseAndData(Common::UUID uuid, const ProfileBase& } void ProfileManager::ParseUserSaveFile() { - const FS::IOFile save( - FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat", "rb"); + const auto save_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH / + "profiles.dat"); + const FS::IOFile save(save_path, FS::FileAccessMode::Read, FS::FileType::BinaryFile); if (!save.IsOpen()) { LOG_WARNING(Service_ACC, "Failed to load profile data from save data... Generating new " @@ -335,7 +338,7 @@ void ProfileManager::ParseUserSaveFile() { } ProfileDataRaw data; - if (save.ReadBytes(&data, sizeof(ProfileDataRaw)) != sizeof(ProfileDataRaw)) { + if (!save.ReadObject(data)) { LOG_WARNING(Service_ACC, "profiles.dat is smaller than expected... Generating new user " "'yuzu' with random UUID."); return; @@ -372,31 +375,27 @@ void ProfileManager::WriteUserSaveFile() { }; } - const auto raw_path = FS::GetUserPath(FS::UserPath::NANDDir) + "/system/save/8000000000000010"; - if (FS::Exists(raw_path) && !FS::IsDirectory(raw_path)) { - FS::Delete(raw_path); + const auto raw_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / "system/save/8000000000000010"); + if (FS::IsFile(raw_path) && !FS::RemoveFile(raw_path)) { + return; } - const auto path = - FS::GetUserPath(FS::UserPath::NANDDir) + ACC_SAVE_AVATORS_BASE_PATH + "profiles.dat"; + const auto save_path(FS::GetYuzuPath(FS::YuzuPath::NANDDir) / ACC_SAVE_AVATORS_BASE_PATH / + "profiles.dat"); - if (!FS::CreateFullPath(path)) { + if (!FS::CreateParentDirs(save_path)) { LOG_WARNING(Service_ACC, "Failed to create full path of profiles.dat. Create the directory " "nand/system/save/8000000000000010/su/avators to mitigate this " "issue."); return; } - FS::IOFile save(path, "wb"); + FS::IOFile save(save_path, FS::FileAccessMode::Write, FS::FileType::BinaryFile); - if (!save.IsOpen()) { + if (!save.IsOpen() || !save.SetSize(sizeof(ProfileDataRaw)) || !save.WriteObject(raw)) { LOG_WARNING(Service_ACC, "Failed to write save data to file... No changes to user data " "made in current session will be saved."); - return; } - - save.Resize(sizeof(ProfileDataRaw)); - save.WriteBytes(&raw, sizeof(ProfileDataRaw)); } }; // namespace Service::Account diff --git a/src/core/hle/service/am/applets/web_browser.cpp b/src/core/hle/service/am/applets/web_browser.cpp index e5f4a4485..3b28e829b 100644 --- a/src/core/hle/service/am/applets/web_browser.cpp +++ b/src/core/hle/service/am/applets/web_browser.cpp @@ -3,8 +3,9 @@ // Refer to the license.txt file included. #include "common/assert.h" -#include "common/common_paths.h" -#include "common/file_util.h" +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/logging/log.h" #include "common/string_util.h" #include "core/core.h" @@ -135,14 +136,10 @@ void ExtractSharedFonts(Core::System& system) { "FontNintendoExtended2.ttf", }; - for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { - const auto fonts_dir = Common::FS::SanitizePath( - fmt::format("{}/fonts", Common::FS::GetUserPath(Common::FS::UserPath::CacheDir)), - Common::FS::DirectorySeparator::PlatformDefault); + const auto fonts_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "fonts"; - const auto font_file_path = - Common::FS::SanitizePath(fmt::format("{}/{}", fonts_dir, DECRYPTED_SHARED_FONTS[i]), - Common::FS::DirectorySeparator::PlatformDefault); + for (std::size_t i = 0; i < NS::SHARED_FONTS.size(); ++i) { + const auto font_file_path = fonts_dir / DECRYPTED_SHARED_FONTS[i]; if (Common::FS::Exists(font_file_path)) { continue; @@ -197,8 +194,8 @@ void ExtractSharedFonts(Core::System& system) { FileSys::VirtualFile decrypted_font = std::make_shared<FileSys::VectorVfsFile>( std::move(decrypted_data), DECRYPTED_SHARED_FONTS[i]); - const auto temp_dir = - system.GetFilesystem()->CreateDirectory(fonts_dir, FileSys::Mode::ReadWrite); + const auto temp_dir = system.GetFilesystem()->CreateDirectory( + Common::FS::PathToUTF8String(fonts_dir), FileSys::Mode::ReadWrite); const auto out_file = temp_dir->CreateFile(DECRYPTED_SHARED_FONTS[i]); @@ -312,13 +309,14 @@ void WebBrowser::Execute() { } void WebBrowser::ExtractOfflineRomFS() { - LOG_DEBUG(Service_AM, "Extracting RomFS to {}", offline_cache_dir); + LOG_DEBUG(Service_AM, "Extracting RomFS to {}", + Common::FS::PathToUTF8String(offline_cache_dir)); const auto extracted_romfs_dir = FileSys::ExtractRomFS(offline_romfs, FileSys::RomFSExtractionType::SingleDiscard); - const auto temp_dir = - system.GetFilesystem()->CreateDirectory(offline_cache_dir, FileSys::Mode::ReadWrite); + const auto temp_dir = system.GetFilesystem()->CreateDirectory( + Common::FS::PathToUTF8String(offline_cache_dir), FileSys::Mode::ReadWrite); FileSys::VfsRawCopyD(extracted_romfs_dir, temp_dir); } @@ -397,15 +395,12 @@ void WebBrowser::InitializeOffline() { "system_data", }; - offline_cache_dir = Common::FS::SanitizePath( - fmt::format("{}/offline_web_applet_{}/{:016X}", - Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), - RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id), - Common::FS::DirectorySeparator::PlatformDefault); + offline_cache_dir = Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / + fmt::format("offline_web_applet_{}/{:016X}", + RESOURCE_TYPES[static_cast<u32>(document_kind) - 1], title_id); - offline_document = Common::FS::SanitizePath( - fmt::format("{}/{}/{}", offline_cache_dir, additional_paths, document_path), - Common::FS::DirectorySeparator::PlatformDefault); + offline_document = Common::FS::ConcatPathSafe( + offline_cache_dir, fmt::format("{}/{}", additional_paths, document_path)); } void WebBrowser::InitializeShare() {} @@ -429,8 +424,7 @@ void WebBrowser::ExecuteLogin() { } void WebBrowser::ExecuteOffline() { - const auto main_url = Common::FS::SanitizePath(GetMainURL(offline_document), - Common::FS::DirectorySeparator::PlatformDefault); + const auto main_url = GetMainURL(Common::FS::PathToUTF8String(offline_document)); if (!Common::FS::Exists(main_url)) { offline_romfs = GetOfflineRomFS(system, title_id, nca_type); @@ -444,10 +438,11 @@ void WebBrowser::ExecuteOffline() { } } - LOG_INFO(Service_AM, "Opening offline document at {}", offline_document); + LOG_INFO(Service_AM, "Opening offline document at {}", + Common::FS::PathToUTF8String(offline_document)); frontend.OpenLocalWebPage( - offline_document, [this] { ExtractOfflineRomFS(); }, + Common::FS::PathToUTF8String(offline_document), [this] { ExtractOfflineRomFS(); }, [this](WebExitReason exit_reason, std::string last_url) { WebBrowserExit(exit_reason, last_url); }); diff --git a/src/core/hle/service/am/applets/web_browser.h b/src/core/hle/service/am/applets/web_browser.h index 1e1812f36..cdeaf2c40 100644 --- a/src/core/hle/service/am/applets/web_browser.h +++ b/src/core/hle/service/am/applets/web_browser.h @@ -4,6 +4,7 @@ #pragma once +#include <filesystem> #include <optional> #include "common/common_funcs.h" @@ -75,8 +76,8 @@ private: u64 title_id{}; FileSys::ContentRecordType nca_type{}; - std::string offline_cache_dir; - std::string offline_document; + std::filesystem::path offline_cache_dir; + std::filesystem::path offline_document; FileSys::VirtualFile offline_romfs; std::string external_url; diff --git a/src/core/hle/service/bcat/backend/boxcat.cpp b/src/core/hle/service/bcat/backend/boxcat.cpp index d6d2f52e5..3cc397604 100644 --- a/src/core/hle/service/bcat/backend/boxcat.cpp +++ b/src/core/hle/service/bcat/backend/boxcat.cpp @@ -15,6 +15,9 @@ #pragma GCC diagnostic pop #endif +#include "common/fs/file.h" +#include "common/fs/fs.h" +#include "common/fs/path_util.h" #include "common/hex_util.h" #include "common/logging/backend.h" #include "common/logging/log.h" @@ -96,14 +99,14 @@ constexpr u32 PORT = 443; constexpr u32 TIMEOUT_SECONDS = 30; [[maybe_unused]] constexpr u64 VFS_COPY_BLOCK_SIZE = 1ULL << 24; // 4MB -std::string GetBINFilePath(u64 title_id) { - return fmt::format("{}bcat/{:016X}/launchparam.bin", - Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id); +std::filesystem::path GetBINFilePath(u64 title_id) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" / + fmt::format("{:016X}/launchparam.bin", title_id); } -std::string GetZIPFilePath(u64 title_id) { - return fmt::format("{}bcat/{:016X}/data.zip", - Common::FS::GetUserPath(Common::FS::UserPath::CacheDir), title_id); +std::filesystem::path GetZIPFilePath(u64 title_id) { + return Common::FS::GetYuzuPath(Common::FS::YuzuPath::CacheDir) / "bcat" / + fmt::format("{:016X}/data.zip", title_id); } // If the error is something the user should know about (build ID mismatch, bad client version), @@ -187,7 +190,7 @@ bool VfsRawCopyDProgress(FileSys::VirtualDir src, FileSys::VirtualDir dest, class Boxcat::Client { public: - Client(std::string path_, u64 title_id_, u64 build_id_) + Client(std::filesystem::path path_, u64 title_id_, u64 build_id_) : path(std::move(path_)), title_id(title_id_), build_id(build_id_) {} DownloadResult DownloadDataZip() { @@ -217,10 +220,11 @@ private: }; if (Common::FS::Exists(path)) { - Common::FS::IOFile file{path, "rb"}; + Common::FS::IOFile file{path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; if (file.IsOpen()) { std::vector<u8> bytes(file.GetSize()); - file.ReadBytes(bytes.data(), bytes.size()); + void(file.Read(bytes)); const auto digest = DigestFile(bytes); headers.insert({std::string("If-None-Match"), Common::HexToString(digest, false)}); } @@ -247,14 +251,23 @@ private: return DownloadResult::InvalidContentType; } - Common::FS::CreateFullPath(path); - Common::FS::IOFile file{path, "wb"}; - if (!file.IsOpen()) + if (!Common::FS::CreateDirs(path)) { return DownloadResult::GeneralFSError; - if (!file.Resize(response->body.size())) + } + + Common::FS::IOFile file{path, Common::FS::FileAccessMode::Append, + Common::FS::FileType::BinaryFile}; + if (!file.IsOpen()) { + return DownloadResult::GeneralFSError; + } + + if (!file.SetSize(response->body.size())) { return DownloadResult::GeneralFSError; - if (file.WriteBytes(response->body.data(), response->body.size()) != response->body.size()) + } + + if (file.Write(response->body) != response->body.size()) { return DownloadResult::GeneralFSError; + } return DownloadResult::Success; } @@ -267,7 +280,7 @@ private: } std::unique_ptr<httplib::SSLClient> client; - std::string path; + std::filesystem::path path; u64 title_id; u64 build_id; }; @@ -291,7 +304,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe return; } - const auto zip_path{GetZIPFilePath(title.title_id)}; + const auto zip_path = GetZIPFilePath(title.title_id); Boxcat::Client client{zip_path, title.title_id, title.build_id}; progress.StartConnecting(); @@ -301,7 +314,7 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { - Common::FS::Delete(zip_path); + void(Common::FS::RemoveFile(zip_path)); } HandleDownloadDisplayResult(applet_manager, res); @@ -311,11 +324,13 @@ void SynchronizeInternal(AM::Applets::AppletManager& applet_manager, DirectoryGe progress.StartProcessingDataList(); - Common::FS::IOFile zip{zip_path, "rb"}; + Common::FS::IOFile zip{zip_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; const auto size = zip.GetSize(); std::vector<u8> bytes(size); - if (!zip.IsOpen() || size == 0 || zip.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { - LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", zip_path); + if (!zip.IsOpen() || size == 0 || zip.Read(bytes) != bytes.size()) { + LOG_ERROR(Service_BCAT, "Boxcat failed to read ZIP file at path '{}'!", + Common::FS::PathToUTF8String(zip_path)); progress.FinishDownload(ERROR_GENERAL_BCAT_FAILURE); return; } @@ -419,19 +434,19 @@ void Boxcat::SetPassphrase(u64 title_id, const Passphrase& passphrase) { } std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) { - const auto path{GetBINFilePath(title.title_id)}; + const auto bin_file_path = GetBINFilePath(title.title_id); if (Settings::values.bcat_boxcat_local) { LOG_INFO(Service_BCAT, "Boxcat using local data by override, skipping download."); } else { - Client launch_client{path, title.title_id, title.build_id}; + Client launch_client{bin_file_path, title.title_id, title.build_id}; const auto res = launch_client.DownloadLaunchParam(); if (res != DownloadResult::Success) { LOG_ERROR(Service_BCAT, "Boxcat synchronization failed with error '{}'!", res); if (res == DownloadResult::NoMatchBuildId || res == DownloadResult::NoMatchTitleId) { - Common::FS::Delete(path); + void(Common::FS::RemoveFile(bin_file_path)); } HandleDownloadDisplayResult(applet_manager, res); @@ -439,12 +454,13 @@ std::optional<std::vector<u8>> Boxcat::GetLaunchParameter(TitleIDVersion title) } } - Common::FS::IOFile bin{path, "rb"}; + Common::FS::IOFile bin{bin_file_path, Common::FS::FileAccessMode::Read, + Common::FS::FileType::BinaryFile}; const auto size = bin.GetSize(); std::vector<u8> bytes(size); - if (!bin.IsOpen() || size == 0 || bin.ReadBytes(bytes.data(), bytes.size()) != bytes.size()) { + if (!bin.IsOpen() || size == 0 || bin.Read(bytes) != bytes.size()) { LOG_ERROR(Service_BCAT, "Boxcat failed to read launch parameter binary at path '{}'!", - path); + Common::FS::PathToUTF8String(bin_file_path)); return std::nullopt; } diff --git a/src/core/hle/service/fatal/fatal.cpp b/src/core/hle/service/fatal/fatal.cpp index 432abde76..b7666e95a 100644 --- a/src/core/hle/service/fatal/fatal.cpp +++ b/src/core/hle/service/fatal/fatal.cpp @@ -6,7 +6,6 @@ #include <cstring> #include <ctime> #include <fmt/chrono.h> -#include "common/file_util.h" #include "common/logging/log.h" #include "common/scm_rev.h" #include "common/swap.h" diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 67baaee9b..78664439d 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp @@ -5,7 +5,7 @@ #include <utility> #include "common/assert.h" -#include "common/file_util.h" +#include "common/fs/path_util.h" #include "common/settings.h" #include "core/core.h" #include "core/file_sys/bis_factory.h" @@ -728,14 +728,17 @@ void FileSystemController::CreateFactories(FileSys::VfsFilesystem& vfs, bool ove sdmc_factory = nullptr; } - auto nand_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::NANDDir), - FileSys::Mode::ReadWrite); - auto sd_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir), - FileSys::Mode::ReadWrite); - auto load_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::LoadDir), - FileSys::Mode::ReadWrite); - auto dump_directory = vfs.OpenDirectory(Common::FS::GetUserPath(Common::FS::UserPath::DumpDir), - FileSys::Mode::ReadWrite); + using YuzuPath = Common::FS::YuzuPath; + const auto rw_mode = FileSys::Mode::ReadWrite; + + auto nand_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::NANDDir), rw_mode); + auto sd_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::SDMCDir), rw_mode); + auto load_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::LoadDir), FileSys::Mode::Read); + auto dump_directory = + vfs.OpenDirectory(Common::FS::GetYuzuPathString(YuzuPath::DumpDir), rw_mode); if (bis_factory == nullptr) { bis_factory = diff --git a/src/core/hle/service/mii/manager.cpp b/src/core/hle/service/mii/manager.cpp index 70350a2a3..114aff31c 100644 --- a/src/core/hle/service/mii/manager.cpp +++ b/src/core/hle/service/mii/manager.cpp @@ -6,7 +6,6 @@ #include <random> #include "common/assert.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "common/string_util.h" diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index e14acce58..90ba5c752 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp @@ -7,9 +7,7 @@ #include <vector> #include "common/assert.h" -#include "common/common_paths.h" #include "common/common_types.h" -#include "common/file_util.h" #include "common/logging/log.h" #include "common/swap.h" #include "core/core.h" diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp index bbef04a29..2cc0da124 100644 --- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp +++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp @@ -52,7 +52,6 @@ void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u3 addr, offset, width, height, stride, static_cast<PixelFormat>(format), transform, crop_rect}; - system.GetPerfStats().EndGameFrame(); system.GetPerfStats().EndSystemFrame(); system.GPU().SwapBuffers(&framebuffer); system.FrameLimiter().DoFrameLimiting(system.CoreTiming().GetGlobalTimeUs()); diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 2c9b2ce6d..fa61a5c7b 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp @@ -107,7 +107,7 @@ void ServiceFrameworkBase::InstallAsService(SM::ServiceManager& service_manager) ASSERT(!port_installed); auto port = service_manager.RegisterService(service_name, max_sessions).Unwrap(); - port->SetHleHandler(shared_from_this()); + port->SetSessionHandler(shared_from_this()); port_installed = true; } @@ -118,7 +118,7 @@ Kernel::KClientPort& ServiceFrameworkBase::CreatePort(Kernel::KernelCore& kernel auto* port = Kernel::KPort::Create(kernel); port->Initialize(max_sessions, false, service_name); - port->GetServerPort().SetHleHandler(shared_from_this()); + port->GetServerPort().SetSessionHandler(shared_from_this()); port_installed = true; diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index de530cbfb..147f12147 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp @@ -4,8 +4,13 @@ #include "common/assert.h" #include "common/logging/log.h" +#include "core/core.h" #include "core/hle/ipc_helpers.h" +#include "core/hle/kernel/k_client_port.h" #include "core/hle/kernel/k_client_session.h" +#include "core/hle/kernel/k_port.h" +#include "core/hle/kernel/k_scoped_resource_reservation.h" +#include "core/hle/kernel/k_server_port.h" #include "core/hle/kernel/k_server_session.h" #include "core/hle/kernel/k_session.h" #include "core/hle/service/sm/controller.h" @@ -13,7 +18,7 @@ namespace Service::SM { void Controller::ConvertCurrentObjectToDomain(Kernel::HLERequestContext& ctx) { - ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); + ASSERT_MSG(!ctx.Session()->IsDomain(), "Session is already a domain"); LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetId()); ctx.Session()->ConvertToDomain(); @@ -29,16 +34,36 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) { LOG_DEBUG(Service, "called"); - auto session = ctx.Session()->GetParent(); + auto& kernel = system.Kernel(); + auto* session = ctx.Session()->GetParent(); + auto* port = session->GetParent()->GetParent(); - // Open a reference to the session to simulate a new one being created. - session->Open(); - session->GetClientSession().Open(); - session->GetServerSession().Open(); + // Reserve a new session from the process resource limit. + Kernel::KScopedResourceReservation session_reservation( + kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); + if (!session_reservation.Succeeded()) { + IPC::ResponseBuilder rb{ctx, 2}; + rb.Push(Kernel::ResultLimitReached); + } + // Create a new session. + auto* clone = Kernel::KSession::Create(kernel); + clone->Initialize(&port->GetClientPort(), session->GetName()); + + // Commit the session reservation. + session_reservation.Commit(); + + // Enqueue the session with the named port. + port->EnqueueSession(&clone->GetServerSession()); + + // Set the session request manager. + clone->GetServerSession().SetSessionRequestManager( + session->GetServerSession().GetSessionRequestManager()); + + // We succeeded. IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; rb.Push(RESULT_SUCCESS); - rb.PushMoveObjects(session->GetClientSession()); + rb.PushMoveObjects(clone->GetClientSession()); } void Controller::CloneCurrentObjectEx(Kernel::HLERequestContext& ctx) { diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 8cc9aee8a..a9bc7da74 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp @@ -150,31 +150,31 @@ ResultVal<Kernel::KClientSession*> SM::GetServiceImpl(Kernel::HLERequestContext& IPC::RequestParser rp{ctx}; std::string name(PopServiceName(rp)); + // Find the named port. auto result = service_manager.GetServicePort(name); if (result.Failed()) { LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.Code().raw); return result.Code(); } - auto* port = result.Unwrap(); - // Kernel::KScopedResourceReservation session_reservation( - // kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); - // R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); + // Reserve a new session from the process resource limit. + Kernel::KScopedResourceReservation session_reservation( + kernel.CurrentProcess()->GetResourceLimit(), Kernel::LimitableResource::Sessions); + R_UNLESS(session_reservation.Succeeded(), Kernel::ResultLimitReached); + // Create a new session. auto* session = Kernel::KSession::Create(kernel); session->Initialize(&port->GetClientPort(), std::move(name)); // Commit the session reservation. - // session_reservation.Commit(); + session_reservation.Commit(); - if (port->GetServerPort().GetHLEHandler()) { - port->GetServerPort().GetHLEHandler()->ClientConnected(&session->GetServerSession()); - } else { - port->EnqueueSession(&session->GetServerSession()); - } + // Enqueue the session with the named port. + port->EnqueueSession(&session->GetServerSession()); LOG_DEBUG(Service_SM, "called service={} -> session={}", name, session->GetId()); + return MakeResult(&session->GetClientSession()); } diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 60f0b3f8a..ea37f11d4 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h @@ -73,7 +73,7 @@ public: if (port == nullptr) { return nullptr; } - return std::static_pointer_cast<T>(port->GetServerPort().GetHLEHandler()); + return std::static_pointer_cast<T>(port->GetServerPort().GetSessionRequestHandler()); } void InvokeControlRequest(Kernel::HLERequestContext& context); |