kernel: add KDeviceAddressSpace
This commit is contained in:
parent
92c5ab33b7
commit
7d1c3a3f59
|
@ -195,6 +195,8 @@ add_library(core STATIC
|
||||||
hle/kernel/k_condition_variable.cpp
|
hle/kernel/k_condition_variable.cpp
|
||||||
hle/kernel/k_condition_variable.h
|
hle/kernel/k_condition_variable.h
|
||||||
hle/kernel/k_debug.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_page_manager.h
|
||||||
hle/kernel/k_dynamic_resource_manager.h
|
hle/kernel/k_dynamic_resource_manager.h
|
||||||
hle/kernel/k_dynamic_slab_heap.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/init/init_slab_setup.h"
|
||||||
#include "core/hle/kernel/k_code_memory.h"
|
#include "core/hle/kernel/k_code_memory.h"
|
||||||
#include "core/hle/kernel/k_debug.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.h"
|
||||||
#include "core/hle/kernel/k_event_info.h"
|
#include "core/hle/kernel/k_event_info.h"
|
||||||
#include "core/hle/kernel/k_memory_layout.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(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \
|
||||||
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \
|
||||||
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
|
HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \
|
||||||
|
HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__) \
|
||||||
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
|
HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \
|
||||||
HANDLER(KThreadLocalPage, \
|
HANDLER(KThreadLocalPage, \
|
||||||
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
|
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
|
||||||
|
|
|
@ -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
|
|
@ -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 KAutoObjectWithListContainer;
|
||||||
class KClientSession;
|
class KClientSession;
|
||||||
class KDebug;
|
class KDebug;
|
||||||
|
class KDeviceAddressSpace;
|
||||||
class KDynamicPageManager;
|
class KDynamicPageManager;
|
||||||
class KEvent;
|
class KEvent;
|
||||||
class KEventInfo;
|
class KEventInfo;
|
||||||
|
@ -359,6 +360,8 @@ public:
|
||||||
return slab_heap_container->transfer_memory;
|
return slab_heap_container->transfer_memory;
|
||||||
} else if constexpr (std::is_same_v<T, KCodeMemory>) {
|
} else if constexpr (std::is_same_v<T, KCodeMemory>) {
|
||||||
return slab_heap_container->code_memory;
|
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>) {
|
} else if constexpr (std::is_same_v<T, KPageBuffer>) {
|
||||||
return slab_heap_container->page_buffer;
|
return slab_heap_container->page_buffer;
|
||||||
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
|
} else if constexpr (std::is_same_v<T, KThreadLocalPage>) {
|
||||||
|
@ -431,6 +434,7 @@ private:
|
||||||
KSlabHeap<KThread> thread;
|
KSlabHeap<KThread> thread;
|
||||||
KSlabHeap<KTransferMemory> transfer_memory;
|
KSlabHeap<KTransferMemory> transfer_memory;
|
||||||
KSlabHeap<KCodeMemory> code_memory;
|
KSlabHeap<KCodeMemory> code_memory;
|
||||||
|
KSlabHeap<KDeviceAddressSpace> device_address_space;
|
||||||
KSlabHeap<KPageBuffer> page_buffer;
|
KSlabHeap<KPageBuffer> page_buffer;
|
||||||
KSlabHeap<KThreadLocalPage> thread_local_page;
|
KSlabHeap<KThreadLocalPage> thread_local_page;
|
||||||
KSlabHeap<KSessionRequest> session_request;
|
KSlabHeap<KSessionRequest> session_request;
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
|
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
||||||
|
#include "common/bit_field.h"
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
@ -498,6 +499,19 @@ enum class MemoryMapping : u32 {
|
||||||
Memory = 2,
|
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 {
|
enum class KernelDebugType : u32 {
|
||||||
Thread = 0,
|
Thread = 0,
|
||||||
ThreadCallStack = 1,
|
ThreadCallStack = 1,
|
||||||
|
|
Reference in New Issue