diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/init/init_slab_setup.cpp | 2 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_device_address_space.cpp | 150 | ||||
| -rw-r--r-- | src/core/hle/kernel/k_device_address_space.h | 60 | ||||
| -rw-r--r-- | src/core/hle/kernel/kernel.h | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/svc_types.h | 14 |
6 files changed, 232 insertions, 0 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 3eee1cfbe..112c61b80 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -195,6 +195,8 @@ add_library(core STATIC | |||
| 195 | hle/kernel/k_condition_variable.cpp | 195 | hle/kernel/k_condition_variable.cpp |
| 196 | hle/kernel/k_condition_variable.h | 196 | hle/kernel/k_condition_variable.h |
| 197 | hle/kernel/k_debug.h | 197 | hle/kernel/k_debug.h |
| 198 | hle/kernel/k_device_address_space.cpp | ||
| 199 | hle/kernel/k_device_address_space.h | ||
| 198 | hle/kernel/k_dynamic_page_manager.h | 200 | hle/kernel/k_dynamic_page_manager.h |
| 199 | hle/kernel/k_dynamic_resource_manager.h | 201 | hle/kernel/k_dynamic_resource_manager.h |
| 200 | hle/kernel/k_dynamic_slab_heap.h | 202 | hle/kernel/k_dynamic_slab_heap.h |
diff --git a/src/core/hle/kernel/init/init_slab_setup.cpp b/src/core/hle/kernel/init/init_slab_setup.cpp index 7b363eb1e..571acf4b2 100644 --- a/src/core/hle/kernel/init/init_slab_setup.cpp +++ b/src/core/hle/kernel/init/init_slab_setup.cpp | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include "core/hle/kernel/init/init_slab_setup.h" | 11 | #include "core/hle/kernel/init/init_slab_setup.h" |
| 12 | #include "core/hle/kernel/k_code_memory.h" | 12 | #include "core/hle/kernel/k_code_memory.h" |
| 13 | #include "core/hle/kernel/k_debug.h" | 13 | #include "core/hle/kernel/k_debug.h" |
| 14 | #include "core/hle/kernel/k_device_address_space.h" | ||
| 14 | #include "core/hle/kernel/k_event.h" | 15 | #include "core/hle/kernel/k_event.h" |
| 15 | #include "core/hle/kernel/k_event_info.h" | 16 | #include "core/hle/kernel/k_event_info.h" |
| 16 | #include "core/hle/kernel/k_memory_layout.h" | 17 | #include "core/hle/kernel/k_memory_layout.h" |
| @@ -43,6 +44,7 @@ namespace Kernel::Init { | |||
| 43 | HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \ | 44 | HANDLER(KSharedMemoryInfo, (SLAB_COUNT(KSharedMemory) * 8), ##__VA_ARGS__) \ |
| 44 | HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ | 45 | HANDLER(KTransferMemory, (SLAB_COUNT(KTransferMemory)), ##__VA_ARGS__) \ |
| 45 | HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \ | 46 | HANDLER(KCodeMemory, (SLAB_COUNT(KCodeMemory)), ##__VA_ARGS__) \ |
| 47 | HANDLER(KDeviceAddressSpace, (SLAB_COUNT(KDeviceAddressSpace)), ##__VA_ARGS__) \ | ||
| 46 | HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ | 48 | HANDLER(KSession, (SLAB_COUNT(KSession)), ##__VA_ARGS__) \ |
| 47 | HANDLER(KThreadLocalPage, \ | 49 | HANDLER(KThreadLocalPage, \ |
| 48 | (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \ | 50 | (SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \ |
diff --git a/src/core/hle/kernel/k_device_address_space.cpp b/src/core/hle/kernel/k_device_address_space.cpp new file mode 100644 index 000000000..27659ea3b --- /dev/null +++ b/src/core/hle/kernel/k_device_address_space.cpp | |||
| @@ -0,0 +1,150 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #include "common/assert.h" | ||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/hle/kernel/k_device_address_space.h" | ||
| 7 | #include "core/hle/kernel/kernel.h" | ||
| 8 | #include "core/hle/kernel/svc_results.h" | ||
| 9 | |||
| 10 | namespace Kernel { | ||
| 11 | |||
| 12 | KDeviceAddressSpace::KDeviceAddressSpace(KernelCore& kernel_) | ||
| 13 | : KAutoObjectWithSlabHeapAndContainer(kernel_), m_lock(kernel_), m_is_initialized(false) {} | ||
| 14 | KDeviceAddressSpace::~KDeviceAddressSpace() = default; | ||
| 15 | |||
| 16 | void KDeviceAddressSpace::Initialize() { | ||
| 17 | // This just forwards to the device page table manager. | ||
| 18 | // KDevicePageTable::Initialize(); | ||
| 19 | } | ||
| 20 | |||
| 21 | // Member functions. | ||
| 22 | Result KDeviceAddressSpace::Initialize(u64 address, u64 size) { | ||
| 23 | // Initialize the device page table. | ||
| 24 | // R_TRY(m_table.Initialize(address, size)); | ||
| 25 | |||
| 26 | // Set member variables. | ||
| 27 | m_space_address = address; | ||
| 28 | m_space_size = size; | ||
| 29 | m_is_initialized = true; | ||
| 30 | |||
| 31 | R_SUCCEED(); | ||
| 32 | } | ||
| 33 | |||
| 34 | void KDeviceAddressSpace::Finalize() { | ||
| 35 | // Finalize the table. | ||
| 36 | // m_table.Finalize(); | ||
| 37 | } | ||
| 38 | |||
| 39 | Result KDeviceAddressSpace::Attach(Svc::DeviceName device_name) { | ||
| 40 | // Lock the address space. | ||
| 41 | KScopedLightLock lk(m_lock); | ||
| 42 | |||
| 43 | // Attach. | ||
| 44 | // R_RETURN(m_table.Attach(device_name, m_space_address, m_space_size)); | ||
| 45 | R_SUCCEED(); | ||
| 46 | } | ||
| 47 | |||
| 48 | Result KDeviceAddressSpace::Detach(Svc::DeviceName device_name) { | ||
| 49 | // Lock the address space. | ||
| 50 | KScopedLightLock lk(m_lock); | ||
| 51 | |||
| 52 | // Detach. | ||
| 53 | // R_RETURN(m_table.Detach(device_name)); | ||
| 54 | R_SUCCEED(); | ||
| 55 | } | ||
| 56 | |||
| 57 | Result KDeviceAddressSpace::Map(KPageTable* page_table, VAddr process_address, size_t size, | ||
| 58 | u64 device_address, u32 option, bool is_aligned) { | ||
| 59 | // Check that the address falls within the space. | ||
| 60 | R_UNLESS((m_space_address <= device_address && | ||
| 61 | device_address + size - 1 <= m_space_address + m_space_size - 1), | ||
| 62 | ResultInvalidCurrentMemory); | ||
| 63 | |||
| 64 | // Decode the option. | ||
| 65 | const Svc::MapDeviceAddressSpaceOption option_pack{option}; | ||
| 66 | const auto device_perm = option_pack.permission.Value(); | ||
| 67 | const auto flags = option_pack.flags.Value(); | ||
| 68 | const auto reserved = option_pack.reserved.Value(); | ||
| 69 | |||
| 70 | // Validate the option. | ||
| 71 | // TODO: It is likely that this check for flags == none is only on NX board. | ||
| 72 | R_UNLESS(flags == Svc::MapDeviceAddressSpaceFlag::None, ResultInvalidEnumValue); | ||
| 73 | R_UNLESS(reserved == 0, ResultInvalidEnumValue); | ||
| 74 | |||
| 75 | // Lock the address space. | ||
| 76 | KScopedLightLock lk(m_lock); | ||
| 77 | |||
| 78 | // Lock the page table to prevent concurrent device mapping operations. | ||
| 79 | // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); | ||
| 80 | |||
| 81 | // Lock the pages. | ||
| 82 | bool is_io{}; | ||
| 83 | R_TRY(page_table->LockForMapDeviceAddressSpace(std::addressof(is_io), process_address, size, | ||
| 84 | ConvertToKMemoryPermission(device_perm), | ||
| 85 | is_aligned, true)); | ||
| 86 | |||
| 87 | // Ensure that if we fail, we don't keep unmapped pages locked. | ||
| 88 | ON_RESULT_FAILURE { | ||
| 89 | ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess); | ||
| 90 | }; | ||
| 91 | |||
| 92 | // Check that the io status is allowable. | ||
| 93 | if (is_io) { | ||
| 94 | R_UNLESS(static_cast<u32>(flags & Svc::MapDeviceAddressSpaceFlag::NotIoRegister) == 0, | ||
| 95 | ResultInvalidCombination); | ||
| 96 | } | ||
| 97 | |||
| 98 | // Map the pages. | ||
| 99 | { | ||
| 100 | // Perform the mapping. | ||
| 101 | // R_TRY(m_table.Map(page_table, process_address, size, device_address, device_perm, | ||
| 102 | // is_aligned, is_io)); | ||
| 103 | |||
| 104 | // Ensure that we unmap the pages if we fail to update the protections. | ||
| 105 | // NOTE: Nintendo does not check the result of this unmap call. | ||
| 106 | // ON_RESULT_FAILURE { m_table.Unmap(device_address, size); }; | ||
| 107 | |||
| 108 | // Update the protections in accordance with how much we mapped. | ||
| 109 | // R_TRY(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size)); | ||
| 110 | } | ||
| 111 | |||
| 112 | // We succeeded. | ||
| 113 | R_SUCCEED(); | ||
| 114 | } | ||
| 115 | |||
| 116 | Result KDeviceAddressSpace::Unmap(KPageTable* page_table, VAddr process_address, size_t size, | ||
| 117 | u64 device_address) { | ||
| 118 | // Check that the address falls within the space. | ||
| 119 | R_UNLESS((m_space_address <= device_address && | ||
| 120 | device_address + size - 1 <= m_space_address + m_space_size - 1), | ||
| 121 | ResultInvalidCurrentMemory); | ||
| 122 | |||
| 123 | // Lock the address space. | ||
| 124 | KScopedLightLock lk(m_lock); | ||
| 125 | |||
| 126 | // Lock the page table to prevent concurrent device mapping operations. | ||
| 127 | // KScopedLightLock pt_lk = page_table->AcquireDeviceMapLock(); | ||
| 128 | |||
| 129 | // Lock the pages. | ||
| 130 | R_TRY(page_table->LockForUnmapDeviceAddressSpace(process_address, size, true)); | ||
| 131 | |||
| 132 | // Unmap the pages. | ||
| 133 | { | ||
| 134 | // If we fail to unmap, we want to do a partial unlock. | ||
| 135 | // ON_RESULT_FAILURE { | ||
| 136 | // ASSERT(page_table->UnlockForDeviceAddressSpacePartialMap(process_address, size) == | ||
| 137 | // ResultSuccess); | ||
| 138 | // }; | ||
| 139 | |||
| 140 | // Perform the unmap. | ||
| 141 | // R_TRY(m_table.Unmap(page_table, process_address, size, device_address)); | ||
| 142 | } | ||
| 143 | |||
| 144 | // Unlock the pages. | ||
| 145 | ASSERT(page_table->UnlockForDeviceAddressSpace(process_address, size) == ResultSuccess); | ||
| 146 | |||
| 147 | R_SUCCEED(); | ||
| 148 | } | ||
| 149 | |||
| 150 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/k_device_address_space.h b/src/core/hle/kernel/k_device_address_space.h new file mode 100644 index 000000000..4709df995 --- /dev/null +++ b/src/core/hle/kernel/k_device_address_space.h | |||
| @@ -0,0 +1,60 @@ | |||
| 1 | // SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project | ||
| 2 | // SPDX-License-Identifier: GPL-2.0-or-later | ||
| 3 | |||
| 4 | #pragma once | ||
| 5 | |||
| 6 | #include <string> | ||
| 7 | |||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/hle/kernel/k_page_table.h" | ||
| 10 | #include "core/hle/kernel/slab_helpers.h" | ||
| 11 | #include "core/hle/result.h" | ||
| 12 | |||
| 13 | namespace Kernel { | ||
| 14 | |||
| 15 | class KDeviceAddressSpace final | ||
| 16 | : public KAutoObjectWithSlabHeapAndContainer<KDeviceAddressSpace, KAutoObjectWithList> { | ||
| 17 | KERNEL_AUTOOBJECT_TRAITS(KDeviceAddressSpace, KAutoObject); | ||
| 18 | |||
| 19 | public: | ||
| 20 | explicit KDeviceAddressSpace(KernelCore& kernel); | ||
| 21 | ~KDeviceAddressSpace(); | ||
| 22 | |||
| 23 | Result Initialize(u64 address, u64 size); | ||
| 24 | void Finalize(); | ||
| 25 | |||
| 26 | bool IsInitialized() const { | ||
| 27 | return m_is_initialized; | ||
| 28 | } | ||
| 29 | static void PostDestroy(uintptr_t arg) {} | ||
| 30 | |||
| 31 | Result Attach(Svc::DeviceName device_name); | ||
| 32 | Result Detach(Svc::DeviceName device_name); | ||
| 33 | |||
| 34 | Result MapByForce(KPageTable* page_table, VAddr process_address, size_t size, | ||
| 35 | u64 device_address, u32 option) { | ||
| 36 | R_RETURN(this->Map(page_table, process_address, size, device_address, option, false)); | ||
| 37 | } | ||
| 38 | |||
| 39 | Result MapAligned(KPageTable* page_table, VAddr process_address, size_t size, | ||
| 40 | u64 device_address, u32 option) { | ||
| 41 | R_RETURN(this->Map(page_table, process_address, size, device_address, option, true)); | ||
| 42 | } | ||
| 43 | |||
| 44 | Result Unmap(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address); | ||
| 45 | |||
| 46 | static void Initialize(); | ||
| 47 | |||
| 48 | private: | ||
| 49 | Result Map(KPageTable* page_table, VAddr process_address, size_t size, u64 device_address, | ||
| 50 | u32 option, bool is_aligned); | ||
| 51 | |||
| 52 | private: | ||
| 53 | KLightLock m_lock; | ||
| 54 | // KDevicePageTable m_table; | ||
| 55 | u64 m_space_address{}; | ||
| 56 | u64 m_space_size{}; | ||
| 57 | bool m_is_initialized{}; | ||
| 58 | }; | ||
| 59 | |||
| 60 | } // namespace Kernel | ||
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h index 8d22f8d2c..5f52e1e95 100644 --- a/src/core/hle/kernel/kernel.h +++ b/src/core/hle/kernel/kernel.h | |||
| @@ -35,6 +35,7 @@ class GlobalSchedulerContext; | |||
| 35 | class KAutoObjectWithListContainer; | 35 | class KAutoObjectWithListContainer; |
| 36 | class KClientSession; | 36 | class KClientSession; |
| 37 | class KDebug; | 37 | class KDebug; |
| 38 | class KDeviceAddressSpace; | ||
| 38 | class KDynamicPageManager; | 39 | class KDynamicPageManager; |
| 39 | class KEvent; | 40 | class KEvent; |
| 40 | class KEventInfo; | 41 | class KEventInfo; |
| @@ -359,6 +360,8 @@ public: | |||
| 359 | return slab_heap_container->transfer_memory; | 360 | return slab_heap_container->transfer_memory; |
| 360 | } else if constexpr (std::is_same_v<T, KCodeMemory>) { | 361 | } else if constexpr (std::is_same_v<T, KCodeMemory>) { |
| 361 | return slab_heap_container->code_memory; | 362 | return slab_heap_container->code_memory; |
| 363 | } else if constexpr (std::is_same_v<T, KDeviceAddressSpace>) { | ||
| 364 | return slab_heap_container->device_address_space; | ||
| 362 | } else if constexpr (std::is_same_v<T, KPageBuffer>) { | 365 | } else if constexpr (std::is_same_v<T, KPageBuffer>) { |
| 363 | return slab_heap_container->page_buffer; | 366 | return slab_heap_container->page_buffer; |
| 364 | } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { | 367 | } else if constexpr (std::is_same_v<T, KThreadLocalPage>) { |
| @@ -431,6 +434,7 @@ private: | |||
| 431 | KSlabHeap<KThread> thread; | 434 | KSlabHeap<KThread> thread; |
| 432 | KSlabHeap<KTransferMemory> transfer_memory; | 435 | KSlabHeap<KTransferMemory> transfer_memory; |
| 433 | KSlabHeap<KCodeMemory> code_memory; | 436 | KSlabHeap<KCodeMemory> code_memory; |
| 437 | KSlabHeap<KDeviceAddressSpace> device_address_space; | ||
| 434 | KSlabHeap<KPageBuffer> page_buffer; | 438 | KSlabHeap<KPageBuffer> page_buffer; |
| 435 | KSlabHeap<KThreadLocalPage> thread_local_page; | 439 | KSlabHeap<KThreadLocalPage> thread_local_page; |
| 436 | KSlabHeap<KSessionRequest> session_request; | 440 | KSlabHeap<KSessionRequest> session_request; |
diff --git a/src/core/hle/kernel/svc_types.h b/src/core/hle/kernel/svc_types.h index 9c2f9998a..e90c35601 100644 --- a/src/core/hle/kernel/svc_types.h +++ b/src/core/hle/kernel/svc_types.h | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | 5 | ||
| 6 | #include <bitset> | 6 | #include <bitset> |
| 7 | 7 | ||
| 8 | #include "common/bit_field.h" | ||
| 8 | #include "common/common_funcs.h" | 9 | #include "common/common_funcs.h" |
| 9 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 10 | 11 | ||
| @@ -498,6 +499,19 @@ enum class MemoryMapping : u32 { | |||
| 498 | Memory = 2, | 499 | Memory = 2, |
| 499 | }; | 500 | }; |
| 500 | 501 | ||
| 502 | enum class MapDeviceAddressSpaceFlag : u32 { | ||
| 503 | None = (0U << 0), | ||
| 504 | NotIoRegister = (1U << 0), | ||
| 505 | }; | ||
| 506 | DECLARE_ENUM_FLAG_OPERATORS(MapDeviceAddressSpaceFlag); | ||
| 507 | |||
| 508 | union MapDeviceAddressSpaceOption { | ||
| 509 | u32 raw; | ||
| 510 | BitField<0, 16, MemoryPermission> permission; | ||
| 511 | BitField<16, 1, MapDeviceAddressSpaceFlag> flags; | ||
| 512 | BitField<17, 15, u32> reserved; | ||
| 513 | }; | ||
| 514 | |||
| 501 | enum class KernelDebugType : u32 { | 515 | enum class KernelDebugType : u32 { |
| 502 | Thread = 0, | 516 | Thread = 0, |
| 503 | ThreadCallStack = 1, | 517 | ThreadCallStack = 1, |