mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	kernel: add KObjectName
This commit is contained in:
		@@ -225,6 +225,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/kernel/k_memory_manager.h
 | 
			
		||||
    hle/kernel/k_memory_region.h
 | 
			
		||||
    hle/kernel/k_memory_region_type.h
 | 
			
		||||
    hle/kernel/k_object_name.cpp
 | 
			
		||||
    hle/kernel/k_object_name.h
 | 
			
		||||
    hle/kernel/k_page_bitmap.h
 | 
			
		||||
    hle/kernel/k_page_buffer.cpp
 | 
			
		||||
    hle/kernel/k_page_buffer.h
 | 
			
		||||
 
 | 
			
		||||
@@ -16,6 +16,7 @@
 | 
			
		||||
#include "core/hle/kernel/k_event_info.h"
 | 
			
		||||
#include "core/hle/kernel/k_memory_layout.h"
 | 
			
		||||
#include "core/hle/kernel/k_memory_manager.h"
 | 
			
		||||
#include "core/hle/kernel/k_object_name.h"
 | 
			
		||||
#include "core/hle/kernel/k_page_buffer.h"
 | 
			
		||||
#include "core/hle/kernel/k_port.h"
 | 
			
		||||
#include "core/hle/kernel/k_process.h"
 | 
			
		||||
@@ -49,6 +50,7 @@ namespace Kernel::Init {
 | 
			
		||||
    HANDLER(KThreadLocalPage,                                                                      \
 | 
			
		||||
            (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8),             \
 | 
			
		||||
            ##__VA_ARGS__)                                                                         \
 | 
			
		||||
    HANDLER(KObjectName, (SLAB_COUNT(KObjectName)), ##__VA_ARGS__)                                 \
 | 
			
		||||
    HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)                           \
 | 
			
		||||
    HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__)                 \
 | 
			
		||||
    HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__)                                           \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										102
									
								
								src/core/hle/kernel/k_object_name.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										102
									
								
								src/core/hle/kernel/k_object_name.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,102 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "core/hle/kernel/k_object_name.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
KObjectNameGlobalData::KObjectNameGlobalData(KernelCore& kernel) : m_object_list_lock{kernel} {}
 | 
			
		||||
KObjectNameGlobalData::~KObjectNameGlobalData() = default;
 | 
			
		||||
 | 
			
		||||
void KObjectName::Initialize(KAutoObject* obj, const char* name) {
 | 
			
		||||
    // Set member variables.
 | 
			
		||||
    m_object = obj;
 | 
			
		||||
    std::strncpy(m_name.data(), name, sizeof(m_name) - 1);
 | 
			
		||||
    m_name[sizeof(m_name) - 1] = '\x00';
 | 
			
		||||
 | 
			
		||||
    // Open a reference to the object we hold.
 | 
			
		||||
    m_object->Open();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
bool KObjectName::MatchesName(const char* name) const {
 | 
			
		||||
    return std::strncmp(m_name.data(), name, sizeof(m_name)) == 0;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result KObjectName::NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name) {
 | 
			
		||||
    // Create a new object name.
 | 
			
		||||
    KObjectName* new_name = KObjectName::Allocate(kernel);
 | 
			
		||||
    R_UNLESS(new_name != nullptr, ResultOutOfResource);
 | 
			
		||||
 | 
			
		||||
    // Initialize the new name.
 | 
			
		||||
    new_name->Initialize(obj, name);
 | 
			
		||||
 | 
			
		||||
    // Check if there's an existing name.
 | 
			
		||||
    {
 | 
			
		||||
        // Get the global data.
 | 
			
		||||
        KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
 | 
			
		||||
 | 
			
		||||
        // Ensure we have exclusive access to the global list.
 | 
			
		||||
        KScopedLightLock lk{gd.GetObjectListLock()};
 | 
			
		||||
 | 
			
		||||
        // If the object doesn't exist, put it into the list.
 | 
			
		||||
        KScopedAutoObject existing_object = FindImpl(kernel, name);
 | 
			
		||||
        if (existing_object.IsNull()) {
 | 
			
		||||
            gd.GetObjectList().push_back(*new_name);
 | 
			
		||||
            R_SUCCEED();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // The object already exists, which is an error condition. Perform cleanup.
 | 
			
		||||
    obj->Close();
 | 
			
		||||
    KObjectName::Free(kernel, new_name);
 | 
			
		||||
    R_THROW(ResultInvalidState);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result KObjectName::Delete(KernelCore& kernel, KAutoObject* obj, const char* compare_name) {
 | 
			
		||||
    // Get the global data.
 | 
			
		||||
    KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
 | 
			
		||||
 | 
			
		||||
    // Ensure we have exclusive access to the global list.
 | 
			
		||||
    KScopedLightLock lk{gd.GetObjectListLock()};
 | 
			
		||||
 | 
			
		||||
    // Find a matching entry in the list, and delete it.
 | 
			
		||||
    for (auto& name : gd.GetObjectList()) {
 | 
			
		||||
        if (name.MatchesName(compare_name) && obj == name.GetObject()) {
 | 
			
		||||
            // We found a match, clean up its resources.
 | 
			
		||||
            obj->Close();
 | 
			
		||||
            gd.GetObjectList().erase(gd.GetObjectList().iterator_to(name));
 | 
			
		||||
            KObjectName::Free(kernel, std::addressof(name));
 | 
			
		||||
            R_SUCCEED();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We didn't find the object in the list.
 | 
			
		||||
    R_THROW(ResultNotFound);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KScopedAutoObject<KAutoObject> KObjectName::Find(KernelCore& kernel, const char* name) {
 | 
			
		||||
    // Get the global data.
 | 
			
		||||
    KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
 | 
			
		||||
 | 
			
		||||
    // Ensure we have exclusive access to the global list.
 | 
			
		||||
    KScopedLightLock lk{gd.GetObjectListLock()};
 | 
			
		||||
 | 
			
		||||
    return FindImpl(kernel, name);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KScopedAutoObject<KAutoObject> KObjectName::FindImpl(KernelCore& kernel, const char* compare_name) {
 | 
			
		||||
    // Get the global data.
 | 
			
		||||
    KObjectNameGlobalData& gd{kernel.ObjectNameGlobalData()};
 | 
			
		||||
 | 
			
		||||
    // Try to find a matching object in the global list.
 | 
			
		||||
    for (const auto& name : gd.GetObjectList()) {
 | 
			
		||||
        if (name.MatchesName(compare_name)) {
 | 
			
		||||
            return name.GetObject();
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // There's no matching entry in the list.
 | 
			
		||||
    return nullptr;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
							
								
								
									
										86
									
								
								src/core/hle/kernel/k_object_name.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										86
									
								
								src/core/hle/kernel/k_object_name.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,86 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <boost/intrusive/list.hpp>
 | 
			
		||||
 | 
			
		||||
#include "core/hle/kernel/k_light_lock.h"
 | 
			
		||||
#include "core/hle/kernel/slab_helpers.h"
 | 
			
		||||
#include "core/hle/kernel/svc_results.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
class KObjectNameGlobalData;
 | 
			
		||||
 | 
			
		||||
class KObjectName : public KSlabAllocated<KObjectName>, public boost::intrusive::list_base_hook<> {
 | 
			
		||||
public:
 | 
			
		||||
    explicit KObjectName(KernelCore&) {}
 | 
			
		||||
    virtual ~KObjectName() = default;
 | 
			
		||||
 | 
			
		||||
    static constexpr size_t NameLengthMax = 12;
 | 
			
		||||
    using List = boost::intrusive::list<KObjectName>;
 | 
			
		||||
 | 
			
		||||
    static Result NewFromName(KernelCore& kernel, KAutoObject* obj, const char* name);
 | 
			
		||||
    static Result Delete(KernelCore& kernel, KAutoObject* obj, const char* name);
 | 
			
		||||
 | 
			
		||||
    static KScopedAutoObject<KAutoObject> Find(KernelCore& kernel, const char* name);
 | 
			
		||||
 | 
			
		||||
    template <typename Derived>
 | 
			
		||||
    static Result Delete(KernelCore& kernel, const char* name) {
 | 
			
		||||
        // Find the object.
 | 
			
		||||
        KScopedAutoObject obj = Find(kernel, name);
 | 
			
		||||
        R_UNLESS(obj.IsNotNull(), ResultNotFound);
 | 
			
		||||
 | 
			
		||||
        // Cast the object to the desired type.
 | 
			
		||||
        Derived* derived = obj->DynamicCast<Derived*>();
 | 
			
		||||
        R_UNLESS(derived != nullptr, ResultNotFound);
 | 
			
		||||
 | 
			
		||||
        // Check that the object is closed.
 | 
			
		||||
        R_UNLESS(derived->IsServerClosed(), ResultInvalidState);
 | 
			
		||||
 | 
			
		||||
        return Delete(kernel, obj.GetPointerUnsafe(), name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    template <typename Derived>
 | 
			
		||||
        requires(std::derived_from<Derived, KAutoObject>)
 | 
			
		||||
    static KScopedAutoObject<Derived> Find(KernelCore& kernel, const char* name) {
 | 
			
		||||
        return Find(kernel, name);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    static KScopedAutoObject<KAutoObject> FindImpl(KernelCore& kernel, const char* name);
 | 
			
		||||
 | 
			
		||||
    void Initialize(KAutoObject* obj, const char* name);
 | 
			
		||||
 | 
			
		||||
    bool MatchesName(const char* name) const;
 | 
			
		||||
    KAutoObject* GetObject() const {
 | 
			
		||||
        return m_object;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    std::array<char, NameLengthMax> m_name{};
 | 
			
		||||
    KAutoObject* m_object{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class KObjectNameGlobalData {
 | 
			
		||||
public:
 | 
			
		||||
    explicit KObjectNameGlobalData(KernelCore& kernel);
 | 
			
		||||
    ~KObjectNameGlobalData();
 | 
			
		||||
 | 
			
		||||
    KLightLock& GetObjectListLock() {
 | 
			
		||||
        return m_object_list_lock;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    KObjectName::List& GetObjectList() {
 | 
			
		||||
        return m_object_list;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KLightLock m_object_list_lock;
 | 
			
		||||
    KObjectName::List m_object_list;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
@@ -29,6 +29,7 @@
 | 
			
		||||
#include "core/hle/kernel/k_hardware_timer.h"
 | 
			
		||||
#include "core/hle/kernel/k_memory_layout.h"
 | 
			
		||||
#include "core/hle/kernel/k_memory_manager.h"
 | 
			
		||||
#include "core/hle/kernel/k_object_name.h"
 | 
			
		||||
#include "core/hle/kernel/k_page_buffer.h"
 | 
			
		||||
#include "core/hle/kernel/k_process.h"
 | 
			
		||||
#include "core/hle/kernel/k_resource_limit.h"
 | 
			
		||||
@@ -84,6 +85,7 @@ struct KernelCore::Impl {
 | 
			
		||||
        InitializeShutdownThreads();
 | 
			
		||||
        InitializePhysicalCores();
 | 
			
		||||
        InitializePreemption(kernel);
 | 
			
		||||
        InitializeGlobalData(kernel);
 | 
			
		||||
 | 
			
		||||
        // Initialize the Dynamic Slab Heaps.
 | 
			
		||||
        {
 | 
			
		||||
@@ -194,6 +196,8 @@ struct KernelCore::Impl {
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        object_name_global_data.reset();
 | 
			
		||||
 | 
			
		||||
        // Ensure that the object list container is finalized and properly shutdown.
 | 
			
		||||
        global_object_list_container->Finalize();
 | 
			
		||||
        global_object_list_container.reset();
 | 
			
		||||
@@ -363,6 +367,10 @@ struct KernelCore::Impl {
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void InitializeGlobalData(KernelCore& kernel) {
 | 
			
		||||
        object_name_global_data = std::make_unique<KObjectNameGlobalData>(kernel);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MakeApplicationProcess(KProcess* process) {
 | 
			
		||||
        application_process = process;
 | 
			
		||||
    }
 | 
			
		||||
@@ -838,6 +846,8 @@ struct KernelCore::Impl {
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
 | 
			
		||||
 | 
			
		||||
    std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
 | 
			
		||||
 | 
			
		||||
    /// Map of named ports managed by the kernel, which can be retrieved using
 | 
			
		||||
    /// the ConnectToPort SVC.
 | 
			
		||||
    std::unordered_map<std::string, ServiceInterfaceFactory> service_interface_factory;
 | 
			
		||||
@@ -1138,6 +1148,10 @@ void KernelCore::SetCurrentEmuThread(KThread* thread) {
 | 
			
		||||
    impl->SetCurrentEmuThread(thread);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KObjectNameGlobalData& KernelCore::ObjectNameGlobalData() {
 | 
			
		||||
    return *impl->object_name_global_data;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
KMemoryManager& KernelCore::MemoryManager() {
 | 
			
		||||
    return *impl->memory_manager;
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -44,6 +44,8 @@ class KHardwareTimer;
 | 
			
		||||
class KLinkedListNode;
 | 
			
		||||
class KMemoryLayout;
 | 
			
		||||
class KMemoryManager;
 | 
			
		||||
class KObjectName;
 | 
			
		||||
class KObjectNameGlobalData;
 | 
			
		||||
class KPageBuffer;
 | 
			
		||||
class KPageBufferSlabHeap;
 | 
			
		||||
class KPort;
 | 
			
		||||
@@ -240,6 +242,9 @@ public:
 | 
			
		||||
    /// Register the current thread as a non CPU core thread.
 | 
			
		||||
    void RegisterHostThread(KThread* existing_thread = nullptr);
 | 
			
		||||
 | 
			
		||||
    /// Gets global data for KObjectName.
 | 
			
		||||
    KObjectNameGlobalData& ObjectNameGlobalData();
 | 
			
		||||
 | 
			
		||||
    /// Gets the virtual memory manager for the kernel.
 | 
			
		||||
    KMemoryManager& MemoryManager();
 | 
			
		||||
 | 
			
		||||
@@ -372,6 +377,8 @@ public:
 | 
			
		||||
            return slab_heap_container->page_buffer;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
 | 
			
		||||
            return slab_heap_container->thread_local_page;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KObjectName>) {
 | 
			
		||||
            return slab_heap_container->object_name;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KSessionRequest>) {
 | 
			
		||||
            return slab_heap_container->session_request;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
 | 
			
		||||
@@ -443,6 +450,7 @@ private:
 | 
			
		||||
        KSlabHeap<KDeviceAddressSpace> device_address_space;
 | 
			
		||||
        KSlabHeap<KPageBuffer> page_buffer;
 | 
			
		||||
        KSlabHeap<KThreadLocalPage> thread_local_page;
 | 
			
		||||
        KSlabHeap<KObjectName> object_name;
 | 
			
		||||
        KSlabHeap<KSessionRequest> session_request;
 | 
			
		||||
        KSlabHeap<KSecureSystemResource> secure_system_resource;
 | 
			
		||||
        KSlabHeap<KEventInfo> event_info;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/kernel/k_client_port.h"
 | 
			
		||||
#include "core/hle/kernel/k_client_session.h"
 | 
			
		||||
#include "core/hle/kernel/k_object_name.h"
 | 
			
		||||
#include "core/hle/kernel/k_port.h"
 | 
			
		||||
#include "core/hle/kernel/k_process.h"
 | 
			
		||||
#include "core/hle/kernel/svc.h"
 | 
			
		||||
@@ -74,10 +75,57 @@ Result ConnectToPort(Core::System& system, Handle* out_handle, Handle port) {
 | 
			
		||||
    R_THROW(ResultNotImplemented);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t name,
 | 
			
		||||
Result ManageNamedPort(Core::System& system, Handle* out_server_handle, uint64_t user_name,
 | 
			
		||||
                       int32_t max_sessions) {
 | 
			
		||||
    UNIMPLEMENTED();
 | 
			
		||||
    R_THROW(ResultNotImplemented);
 | 
			
		||||
    // Copy the provided name from user memory to kernel memory.
 | 
			
		||||
    std::array<char, KObjectName::NameLengthMax> name{};
 | 
			
		||||
    system.Memory().ReadBlock(user_name, name.data(), sizeof(name));
 | 
			
		||||
 | 
			
		||||
    // Validate that sessions and name are valid.
 | 
			
		||||
    R_UNLESS(max_sessions >= 0, ResultOutOfRange);
 | 
			
		||||
    R_UNLESS(name[sizeof(name) - 1] == '\x00', ResultOutOfRange);
 | 
			
		||||
 | 
			
		||||
    if (max_sessions > 0) {
 | 
			
		||||
        // Get the current handle table.
 | 
			
		||||
        auto& handle_table = GetCurrentProcess(system.Kernel()).GetHandleTable();
 | 
			
		||||
 | 
			
		||||
        // Create a new port.
 | 
			
		||||
        KPort* port = KPort::Create(system.Kernel());
 | 
			
		||||
        R_UNLESS(port != nullptr, ResultOutOfResource);
 | 
			
		||||
 | 
			
		||||
        // Initialize the new port.
 | 
			
		||||
        port->Initialize(max_sessions, false, "");
 | 
			
		||||
 | 
			
		||||
        // Register the port.
 | 
			
		||||
        KPort::Register(system.Kernel(), port);
 | 
			
		||||
 | 
			
		||||
        // Ensure that our only reference to the port is in the handle table when we're done.
 | 
			
		||||
        SCOPE_EXIT({
 | 
			
		||||
            port->GetClientPort().Close();
 | 
			
		||||
            port->GetServerPort().Close();
 | 
			
		||||
        });
 | 
			
		||||
 | 
			
		||||
        // Register the handle in the table.
 | 
			
		||||
        R_TRY(handle_table.Add(out_server_handle, std::addressof(port->GetServerPort())));
 | 
			
		||||
        ON_RESULT_FAILURE {
 | 
			
		||||
            handle_table.Remove(*out_server_handle);
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        // Create a new object name.
 | 
			
		||||
        R_TRY(KObjectName::NewFromName(system.Kernel(), std::addressof(port->GetClientPort()),
 | 
			
		||||
                                       name.data()));
 | 
			
		||||
    } else /* if (max_sessions == 0) */ {
 | 
			
		||||
        // Ensure that this else case is correct.
 | 
			
		||||
        ASSERT(max_sessions == 0);
 | 
			
		||||
 | 
			
		||||
        // If we're closing, there's no server handle.
 | 
			
		||||
        *out_server_handle = InvalidHandle;
 | 
			
		||||
 | 
			
		||||
        // Delete the object.
 | 
			
		||||
        R_TRY(KObjectName::Delete<KClientPort>(system.Kernel(), name.data()));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result ConnectToNamedPort64(Core::System& system, Handle* out_handle, uint64_t name) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user