mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	kernel: add KDeviceAddressSpace
This commit is contained in:
		@@ -195,6 +195,8 @@ add_library(core STATIC
 | 
			
		||||
    hle/kernel/k_condition_variable.cpp
 | 
			
		||||
    hle/kernel/k_condition_variable.h
 | 
			
		||||
    hle/kernel/k_debug.h
 | 
			
		||||
    hle/kernel/k_device_address_space.cpp
 | 
			
		||||
    hle/kernel/k_device_address_space.h
 | 
			
		||||
    hle/kernel/k_dynamic_page_manager.h
 | 
			
		||||
    hle/kernel/k_dynamic_resource_manager.h
 | 
			
		||||
    hle/kernel/k_dynamic_slab_heap.h
 | 
			
		||||
 
 | 
			
		||||
@@ -11,6 +11,7 @@
 | 
			
		||||
#include "core/hle/kernel/init/init_slab_setup.h"
 | 
			
		||||
#include "core/hle/kernel/k_code_memory.h"
 | 
			
		||||
#include "core/hle/kernel/k_debug.h"
 | 
			
		||||
#include "core/hle/kernel/k_device_address_space.h"
 | 
			
		||||
#include "core/hle/kernel/k_event.h"
 | 
			
		||||
#include "core/hle/kernel/k_event_info.h"
 | 
			
		||||
#include "core/hle/kernel/k_memory_layout.h"
 | 
			
		||||
@@ -43,6 +44,7 @@ namespace Kernel::Init {
 | 
			
		||||
    HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__)                     \
 | 
			
		||||
    HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__)                         \
 | 
			
		||||
    HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__)                                 \
 | 
			
		||||
    HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__)                 \
 | 
			
		||||
    HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__)                                       \
 | 
			
		||||
    HANDLER(KThreadLocalPage,                                                                      \
 | 
			
		||||
            (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8),             \
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										150
									
								
								src/core/hle/kernel/k_device_address_space.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										150
									
								
								src/core/hle/kernel/k_device_address_space.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,150 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#include "common/assert.h"
 | 
			
		||||
#include "core/core.h"
 | 
			
		||||
#include "core/hle/kernel/k_device_address_space.h"
 | 
			
		||||
#include "core/hle/kernel/kernel.h"
 | 
			
		||||
#include "core/hle/kernel/svc_results.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_)
 | 
			
		||||
    : KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {}
 | 
			
		||||
KDeviceAddressSpace::~KDeviceAddressSpace() = default;
 | 
			
		||||
 | 
			
		||||
void KDeviceAddressSpace::Initialize() {
 | 
			
		||||
    // This just forwards to the device page table manager.
 | 
			
		||||
    // KDevicePageTable::Initialize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Member functions.
 | 
			
		||||
Result KDeviceAddressSpace::Initialize(u64 address, u64 size) {
 | 
			
		||||
    // Initialize the device page table.
 | 
			
		||||
    // R_TRY(m_table.Initialize(address, size));
 | 
			
		||||
 | 
			
		||||
    // Set member variables.
 | 
			
		||||
    m_space_address = address;
 | 
			
		||||
    m_space_size = size;
 | 
			
		||||
    m_is_initialized = true;
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void KDeviceAddressSpace::Finalize() {
 | 
			
		||||
    // Finalize the table.
 | 
			
		||||
    // m_table.Finalize();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) {
 | 
			
		||||
    // Lock the address space.
 | 
			
		||||
    KScopedLightLock lk(m_lock);
 | 
			
		||||
 | 
			
		||||
    // Attach.
 | 
			
		||||
    // R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size));
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) {
 | 
			
		||||
    // Lock the address space.
 | 
			
		||||
    KScopedLightLock lk(m_lock);
 | 
			
		||||
 | 
			
		||||
    // Detach.
 | 
			
		||||
    // R_RETURN(m_table.Detach(device_name));
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size,
 | 
			
		||||
                                u64 device_address, u32 option, bool is_aligned) {
 | 
			
		||||
    // Check that the address falls within the space.
 | 
			
		||||
    R_UNLESS((m_space_address <= device_address &&
 | 
			
		||||
              device_address + size - 1 <= m_space_address + m_space_size - 1),
 | 
			
		||||
             ResultInvalidCurrentMemory);
 | 
			
		||||
 | 
			
		||||
    // Decode the option.
 | 
			
		||||
    const Svc::MapDeviceAddressSpaceOption option_pack{option};
 | 
			
		||||
    const auto device_perm = option_pack.permission.Value();
 | 
			
		||||
    const auto flags = option_pack.flags.Value();
 | 
			
		||||
    const auto reserved = option_pack.reserved.Value();
 | 
			
		||||
 | 
			
		||||
    // Validate the option.
 | 
			
		||||
    // TODO: It is likely that this check for flags == none is only on NX board.
 | 
			
		||||
    R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue);
 | 
			
		||||
    R_UNLESS(reserved == 0, ResultInvalidEnumValue);
 | 
			
		||||
 | 
			
		||||
    // Lock the address space.
 | 
			
		||||
    KScopedLightLock lk(m_lock);
 | 
			
		||||
 | 
			
		||||
    // Lock the page table to prevent concurrent device mapping operations.
 | 
			
		||||
    // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
 | 
			
		||||
 | 
			
		||||
    // Lock the pages.
 | 
			
		||||
    bool is_io{};
 | 
			
		||||
    R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size,
 | 
			
		||||
                                                   ConvertToKMemoryPermission(device_perm),
 | 
			
		||||
                                                   is_aligned, true));
 | 
			
		||||
 | 
			
		||||
    // Ensure that if we fail, we don't keep unmapped pages locked.
 | 
			
		||||
    ON_RESULT_FAILURE {
 | 
			
		||||
        ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    // Check that the io status is allowable.
 | 
			
		||||
    if (is_io) {
 | 
			
		||||
        R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0,
 | 
			
		||||
                 ResultInvalidCombination);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Map the pages.
 | 
			
		||||
    {
 | 
			
		||||
        // Perform the mapping.
 | 
			
		||||
        // R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm,
 | 
			
		||||
        //                   is_aligned, is_io));
 | 
			
		||||
 | 
			
		||||
        // Ensure that we unmap the pages if we fail to update the protections.
 | 
			
		||||
        // NOTE: Nintendo does not check the result of this unmap call.
 | 
			
		||||
        // ON_RESULT_FAILURE { m_table.Unmap(device_address, size); };
 | 
			
		||||
 | 
			
		||||
        // Update the protections in accordance with how much we mapped.
 | 
			
		||||
        // R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // We succeeded.
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size,
 | 
			
		||||
                                  u64 device_address) {
 | 
			
		||||
    // Check that the address falls within the space.
 | 
			
		||||
    R_UNLESS((m_space_address <= device_address &&
 | 
			
		||||
              device_address + size - 1 <= m_space_address + m_space_size - 1),
 | 
			
		||||
             ResultInvalidCurrentMemory);
 | 
			
		||||
 | 
			
		||||
    // Lock the address space.
 | 
			
		||||
    KScopedLightLock lk(m_lock);
 | 
			
		||||
 | 
			
		||||
    // Lock the page table to prevent concurrent device mapping operations.
 | 
			
		||||
    // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock();
 | 
			
		||||
 | 
			
		||||
    // Lock the pages.
 | 
			
		||||
    R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true));
 | 
			
		||||
 | 
			
		||||
    // Unmap the pages.
 | 
			
		||||
    {
 | 
			
		||||
        // If we fail to unmap, we want to do a partial unlock.
 | 
			
		||||
        // ON_RESULT_FAILURE {
 | 
			
		||||
        //     ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) ==
 | 
			
		||||
        //            ResultSuccess);
 | 
			
		||||
        // };
 | 
			
		||||
 | 
			
		||||
        // Perform the unmap.
 | 
			
		||||
        // R_TRY(m_table.Unmap(page_table, process_address, size, device_address));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    // Unlock the pages.
 | 
			
		||||
    ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess);
 | 
			
		||||
 | 
			
		||||
    R_SUCCEED();
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
							
								
								
									
										60
									
								
								src/core/hle/kernel/k_device_address_space.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										60
									
								
								src/core/hle/kernel/k_device_address_space.h
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,60 @@
 | 
			
		||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
 | 
			
		||||
// SPDX-License-Identifier: GPL-2.0-or-later
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <string>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "core/hle/kernel/k_page_table.h"
 | 
			
		||||
#include "core/hle/kernel/slab_helpers.h"
 | 
			
		||||
#include "core/hle/result.h"
 | 
			
		||||
 | 
			
		||||
namespace Kernel {
 | 
			
		||||
 | 
			
		||||
class KDeviceAddressSpace final
 | 
			
		||||
    : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> {
 | 
			
		||||
    KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject);
 | 
			
		||||
 | 
			
		||||
public:
 | 
			
		||||
    explicit KDeviceAddressSpace(KernelCore& kernel);
 | 
			
		||||
    ~KDeviceAddressSpace();
 | 
			
		||||
 | 
			
		||||
    Result Initialize(u64 address, u64 size);
 | 
			
		||||
    void Finalize();
 | 
			
		||||
 | 
			
		||||
    bool IsInitialized() const {
 | 
			
		||||
        return m_is_initialized;
 | 
			
		||||
    }
 | 
			
		||||
    static void PostDestroy(uintptr_t arg) {}
 | 
			
		||||
 | 
			
		||||
    Result Attach(Svc::DeviceName device_name);
 | 
			
		||||
    Result Detach(Svc::DeviceName device_name);
 | 
			
		||||
 | 
			
		||||
    Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size,
 | 
			
		||||
                      u64 device_address, u32 option) {
 | 
			
		||||
        R_RETURN(this->Map(page_table, process_address, size, device_address, option, false));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size,
 | 
			
		||||
                      u64 device_address, u32 option) {
 | 
			
		||||
        R_RETURN(this->Map(page_table, process_address, size, device_address, option, true));
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address);
 | 
			
		||||
 | 
			
		||||
    static void Initialize();
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address,
 | 
			
		||||
               u32 option, bool is_aligned);
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    KLightLock m_lock;
 | 
			
		||||
    // KDevicePageTable m_table;
 | 
			
		||||
    u64 m_space_address{};
 | 
			
		||||
    u64 m_space_size{};
 | 
			
		||||
    bool m_is_initialized{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace Kernel
 | 
			
		||||
@@ -35,6 +35,7 @@ class GlobalSchedulerContext;
 | 
			
		||||
class KAutoObjectWithListContainer;
 | 
			
		||||
class KClientSession;
 | 
			
		||||
class KDebug;
 | 
			
		||||
class KDeviceAddressSpace;
 | 
			
		||||
class KDynamicPageManager;
 | 
			
		||||
class KEvent;
 | 
			
		||||
class KEventInfo;
 | 
			
		||||
@@ -359,6 +360,8 @@ public:
 | 
			
		||||
            return slab_heap_container->transfer_memory;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KCodeMemory>) {
 | 
			
		||||
            return slab_heap_container->code_memory;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) {
 | 
			
		||||
            return slab_heap_container->device_address_space;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KPageBuffer>) {
 | 
			
		||||
            return slab_heap_container->page_buffer;
 | 
			
		||||
        } else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
 | 
			
		||||
@@ -431,6 +434,7 @@ private:
 | 
			
		||||
        KSlabHeap<KThread> thread;
 | 
			
		||||
        KSlabHeap<KTransferMemory> transfer_memory;
 | 
			
		||||
        KSlabHeap<KCodeMemory> code_memory;
 | 
			
		||||
        KSlabHeap<KDeviceAddressSpace> device_address_space;
 | 
			
		||||
        KSlabHeap<KPageBuffer> page_buffer;
 | 
			
		||||
        KSlabHeap<KThreadLocalPage> thread_local_page;
 | 
			
		||||
        KSlabHeap<KSessionRequest> session_request;
 | 
			
		||||
 
 | 
			
		||||
@@ -5,6 +5,7 @@
 | 
			
		||||
 | 
			
		||||
#include <bitset>
 | 
			
		||||
 | 
			
		||||
#include "common/bit_field.h"
 | 
			
		||||
#include "common/common_funcs.h"
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
 | 
			
		||||
@@ -498,6 +499,19 @@ enum class MemoryMapping : u32 {
 | 
			
		||||
    Memory = 2,
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class MapDeviceAddressSpaceFlag : u32 {
 | 
			
		||||
    None = (0U << 0),
 | 
			
		||||
    NotIoRegister = (1U << 0),
 | 
			
		||||
};
 | 
			
		||||
DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag);
 | 
			
		||||
 | 
			
		||||
union MapDeviceAddressSpaceOption {
 | 
			
		||||
    u32 raw;
 | 
			
		||||
    BitField<0, 16, MemoryPermission> permission;
 | 
			
		||||
    BitField<16, 1, MapDeviceAddressSpaceFlag> flags;
 | 
			
		||||
    BitField<17, 15, u32> reserved;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
enum class KernelDebugType : u32 {
 | 
			
		||||
    Thread = 0,
 | 
			
		||||
    ThreadCallStack = 1,
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user