diff options
| author | 2019-07-04 15:32:32 -0400 | |
|---|---|---|
| committer | 2019-07-04 15:32:32 -0400 | |
| commit | 54a02d14fd38282e446a56892a1c45f558ee0e42 (patch) | |
| tree | 79a86a51973712ee8307071a6c5dc471289746eb /src | |
| parent | Merge pull request #2670 from DarkLordZach/fix-merge-discrep-1 (diff) | |
| parent | kernel/process: Default initialize all member variables (diff) | |
| download | yuzu-54a02d14fd38282e446a56892a1c45f558ee0e42.tar.gz yuzu-54a02d14fd38282e446a56892a1c45f558ee0e42.tar.xz yuzu-54a02d14fd38282e446a56892a1c45f558ee0e42.zip | |
Merge pull request #2555 from lioncash/tls
kernel/process: Decouple TLS handling from threads
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/kernel/process.cpp | 135 | ||||
| -rw-r--r-- | src/core/hle/kernel/process.h | 12 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.cpp | 4 | ||||
| -rw-r--r-- | src/core/hle/kernel/thread.h | 16 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.cpp | 31 | ||||
| -rw-r--r-- | src/core/hle/kernel/vm_manager.h | 31 |
6 files changed, 148 insertions, 81 deletions
diff --git a/src/core/hle/kernel/process.cpp b/src/core/hle/kernel/process.cpp index 7cfc513a1..f45ef05f6 100644 --- a/src/core/hle/kernel/process.cpp +++ b/src/core/hle/kernel/process.cpp | |||
| @@ -3,6 +3,7 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <bitset> | ||
| 6 | #include <memory> | 7 | #include <memory> |
| 7 | #include <random> | 8 | #include <random> |
| 8 | #include "common/alignment.h" | 9 | #include "common/alignment.h" |
| @@ -48,8 +49,58 @@ void SetupMainThread(Process& owner_process, KernelCore& kernel, u32 priority) { | |||
| 48 | } | 49 | } |
| 49 | } // Anonymous namespace | 50 | } // Anonymous namespace |
| 50 | 51 | ||
| 51 | SharedPtr<Process> Process::Create(Core::System& system, std::string name, | 52 | // Represents a page used for thread-local storage. |
| 52 | Process::ProcessType type) { | 53 | // |
| 54 | // Each TLS page contains slots that may be used by processes and threads. | ||
| 55 | // Every process and thread is created with a slot in some arbitrary page | ||
| 56 | // (whichever page happens to have an available slot). | ||
| 57 | class TLSPage { | ||
| 58 | public: | ||
| 59 | static constexpr std::size_t num_slot_entries = Memory::PAGE_SIZE / Memory::TLS_ENTRY_SIZE; | ||
| 60 | |||
| 61 | explicit TLSPage(VAddr address) : base_address{address} {} | ||
| 62 | |||
| 63 | bool HasAvailableSlots() const { | ||
| 64 | return !is_slot_used.all(); | ||
| 65 | } | ||
| 66 | |||
| 67 | VAddr GetBaseAddress() const { | ||
| 68 | return base_address; | ||
| 69 | } | ||
| 70 | |||
| 71 | std::optional<VAddr> ReserveSlot() { | ||
| 72 | for (std::size_t i = 0; i < is_slot_used.size(); i++) { | ||
| 73 | if (is_slot_used[i]) { | ||
| 74 | continue; | ||
| 75 | } | ||
| 76 | |||
| 77 | is_slot_used[i] = true; | ||
| 78 | return base_address + (i * Memory::TLS_ENTRY_SIZE); | ||
| 79 | } | ||
| 80 | |||
| 81 | return std::nullopt; | ||
| 82 | } | ||
| 83 | |||
| 84 | void ReleaseSlot(VAddr address) { | ||
| 85 | // Ensure that all given addresses are consistent with how TLS pages | ||
| 86 | // are intended to be used when releasing slots. | ||
| 87 | ASSERT(IsWithinPage(address)); | ||
| 88 | ASSERT((address % Memory::TLS_ENTRY_SIZE) == 0); | ||
| 89 | |||
| 90 | const std::size_t index = (address - base_address) / Memory::TLS_ENTRY_SIZE; | ||
| 91 | is_slot_used[index] = false; | ||
| 92 | } | ||
| 93 | |||
| 94 | private: | ||
| 95 | bool IsWithinPage(VAddr address) const { | ||
| 96 | return base_address <= address && address < base_address + Memory::PAGE_SIZE; | ||
| 97 | } | ||
| 98 | |||
| 99 | VAddr base_address; | ||
| 100 | std::bitset<num_slot_entries> is_slot_used; | ||
| 101 | }; | ||
| 102 | |||
| 103 | SharedPtr<Process> Process::Create(Core::System& system, std::string name, ProcessType type) { | ||
| 53 | auto& kernel = system.Kernel(); | 104 | auto& kernel = system.Kernel(); |
| 54 | 105 | ||
| 55 | SharedPtr<Process> process(new Process(system)); | 106 | SharedPtr<Process> process(new Process(system)); |
| @@ -181,61 +232,55 @@ void Process::PrepareForTermination() { | |||
| 181 | } | 232 | } |
| 182 | 233 | ||
| 183 | /** | 234 | /** |
| 184 | * Finds a free location for the TLS section of a thread. | 235 | * Attempts to find a TLS page that contains a free slot for |
| 185 | * @param tls_slots The TLS page array of the thread's owner process. | 236 | * use by a thread. |
| 186 | * Returns a tuple of (page, slot, alloc_needed) where: | 237 | * |
| 187 | * page: The index of the first allocated TLS page that has free slots. | 238 | * @returns If a page with an available slot is found, then an iterator |
| 188 | * slot: The index of the first free slot in the indicated page. | 239 | * pointing to the page is returned. Otherwise the end iterator |
| 189 | * alloc_needed: Whether there's a need to allocate a new TLS page (All pages are full). | 240 | * is returned instead. |
| 190 | */ | 241 | */ |
| 191 | static std::tuple<std::size_t, std::size_t, bool> FindFreeThreadLocalSlot( | 242 | static auto FindTLSPageWithAvailableSlots(std::vector<TLSPage>& tls_pages) { |
| 192 | const std::vector<std::bitset<8>>& tls_slots) { | 243 | return std::find_if(tls_pages.begin(), tls_pages.end(), |
| 193 | // Iterate over all the allocated pages, and try to find one where not all slots are used. | 244 | [](const auto& page) { return page.HasAvailableSlots(); }); |
| 194 | for (std::size_t page = 0; page < tls_slots.size(); ++page) { | ||
| 195 | const auto& page_tls_slots = tls_slots[page]; | ||
| 196 | if (!page_tls_slots.all()) { | ||
| 197 | // We found a page with at least one free slot, find which slot it is | ||
| 198 | for (std::size_t slot = 0; slot < page_tls_slots.size(); ++slot) { | ||
| 199 | if (!page_tls_slots.test(slot)) { | ||
| 200 | return std::make_tuple(page, slot, false); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | } | ||
| 204 | } | ||
| 205 | |||
| 206 | return std::make_tuple(0, 0, true); | ||
| 207 | } | 245 | } |
| 208 | 246 | ||
| 209 | VAddr Process::MarkNextAvailableTLSSlotAsUsed(Thread& thread) { | 247 | VAddr Process::CreateTLSRegion() { |
| 210 | auto [available_page, available_slot, needs_allocation] = FindFreeThreadLocalSlot(tls_slots); | 248 | auto tls_page_iter = FindTLSPageWithAvailableSlots(tls_pages); |
| 211 | const VAddr tls_begin = vm_manager.GetTLSIORegionBaseAddress(); | ||
| 212 | 249 | ||
| 213 | if (needs_allocation) { | 250 | if (tls_page_iter == tls_pages.cend()) { |
| 214 | tls_slots.emplace_back(0); // The page is completely available at the start | 251 | const auto region_address = |
| 215 | available_page = tls_slots.size() - 1; | 252 | vm_manager.FindFreeRegion(vm_manager.GetTLSIORegionBaseAddress(), |
| 216 | available_slot = 0; // Use the first slot in the new page | 253 | vm_manager.GetTLSIORegionEndAddress(), Memory::PAGE_SIZE); |
| 254 | ASSERT(region_address.Succeeded()); | ||
| 217 | 255 | ||
| 218 | // Allocate some memory from the end of the linear heap for this region. | 256 | const auto map_result = vm_manager.MapMemoryBlock( |
| 219 | auto& tls_memory = thread.GetTLSMemory(); | 257 | *region_address, std::make_shared<std::vector<u8>>(Memory::PAGE_SIZE), 0, |
| 220 | tls_memory->insert(tls_memory->end(), Memory::PAGE_SIZE, 0); | 258 | Memory::PAGE_SIZE, MemoryState::ThreadLocal); |
| 259 | ASSERT(map_result.Succeeded()); | ||
| 221 | 260 | ||
| 222 | vm_manager.RefreshMemoryBlockMappings(tls_memory.get()); | 261 | tls_pages.emplace_back(*region_address); |
| 223 | 262 | ||
| 224 | vm_manager.MapMemoryBlock(tls_begin + available_page * Memory::PAGE_SIZE, tls_memory, 0, | 263 | const auto reserve_result = tls_pages.back().ReserveSlot(); |
| 225 | Memory::PAGE_SIZE, MemoryState::ThreadLocal); | 264 | ASSERT(reserve_result.has_value()); |
| 226 | } | ||
| 227 | 265 | ||
| 228 | tls_slots[available_page].set(available_slot); | 266 | return *reserve_result; |
| 267 | } | ||
| 229 | 268 | ||
| 230 | return tls_begin + available_page * Memory::PAGE_SIZE + available_slot * Memory::TLS_ENTRY_SIZE; | 269 | return *tls_page_iter->ReserveSlot(); |
| 231 | } | 270 | } |
| 232 | 271 | ||
| 233 | void Process::FreeTLSSlot(VAddr tls_address) { | 272 | void Process::FreeTLSRegion(VAddr tls_address) { |
| 234 | const VAddr tls_base = tls_address - vm_manager.GetTLSIORegionBaseAddress(); | 273 | const VAddr aligned_address = Common::AlignDown(tls_address, Memory::PAGE_SIZE); |
| 235 | const VAddr tls_page = tls_base / Memory::PAGE_SIZE; | 274 | auto iter = |
| 236 | const VAddr tls_slot = (tls_base % Memory::PAGE_SIZE) / Memory::TLS_ENTRY_SIZE; | 275 | std::find_if(tls_pages.begin(), tls_pages.end(), [aligned_address](const auto& page) { |
| 276 | return page.GetBaseAddress() == aligned_address; | ||
| 277 | }); | ||
| 278 | |||
| 279 | // Something has gone very wrong if we're freeing a region | ||
| 280 | // with no actual page available. | ||
| 281 | ASSERT(iter != tls_pages.cend()); | ||
| 237 | 282 | ||
| 238 | tls_slots[tls_page].reset(tls_slot); | 283 | iter->ReleaseSlot(tls_address); |
| 239 | } | 284 | } |
| 240 | 285 | ||
| 241 | void Process::LoadModule(CodeSet module_, VAddr base_addr) { | 286 | void Process::LoadModule(CodeSet module_, VAddr base_addr) { |
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h index 248fd3840..83ea02bee 100644 --- a/src/core/hle/kernel/process.h +++ b/src/core/hle/kernel/process.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <bitset> | ||
| 9 | #include <cstddef> | 8 | #include <cstddef> |
| 10 | #include <list> | 9 | #include <list> |
| 11 | #include <string> | 10 | #include <string> |
| @@ -32,6 +31,7 @@ namespace Kernel { | |||
| 32 | class KernelCore; | 31 | class KernelCore; |
| 33 | class ResourceLimit; | 32 | class ResourceLimit; |
| 34 | class Thread; | 33 | class Thread; |
| 34 | class TLSPage; | ||
| 35 | 35 | ||
| 36 | struct CodeSet; | 36 | struct CodeSet; |
| 37 | 37 | ||
| @@ -260,10 +260,10 @@ public: | |||
| 260 | // Thread-local storage management | 260 | // Thread-local storage management |
| 261 | 261 | ||
| 262 | // Marks the next available region as used and returns the address of the slot. | 262 | // Marks the next available region as used and returns the address of the slot. |
| 263 | VAddr MarkNextAvailableTLSSlotAsUsed(Thread& thread); | 263 | [[nodiscard]] VAddr CreateTLSRegion(); |
| 264 | 264 | ||
| 265 | // Frees a used TLS slot identified by the given address | 265 | // Frees a used TLS slot identified by the given address |
| 266 | void FreeTLSSlot(VAddr tls_address); | 266 | void FreeTLSRegion(VAddr tls_address); |
| 267 | 267 | ||
| 268 | private: | 268 | private: |
| 269 | explicit Process(Core::System& system); | 269 | explicit Process(Core::System& system); |
| @@ -290,7 +290,7 @@ private: | |||
| 290 | u64 code_memory_size = 0; | 290 | u64 code_memory_size = 0; |
| 291 | 291 | ||
| 292 | /// Current status of the process | 292 | /// Current status of the process |
| 293 | ProcessStatus status; | 293 | ProcessStatus status{}; |
| 294 | 294 | ||
| 295 | /// The ID of this process | 295 | /// The ID of this process |
| 296 | u64 process_id = 0; | 296 | u64 process_id = 0; |
| @@ -310,7 +310,7 @@ private: | |||
| 310 | /// holds the TLS for a specific thread. This vector contains which parts are in use for each | 310 | /// holds the TLS for a specific thread. This vector contains which parts are in use for each |
| 311 | /// page as a bitmask. | 311 | /// page as a bitmask. |
| 312 | /// This vector will grow as more pages are allocated for new threads. | 312 | /// This vector will grow as more pages are allocated for new threads. |
| 313 | std::vector<std::bitset<8>> tls_slots; | 313 | std::vector<TLSPage> tls_pages; |
| 314 | 314 | ||
| 315 | /// Contains the parsed process capability descriptors. | 315 | /// Contains the parsed process capability descriptors. |
| 316 | ProcessCapabilities capabilities; | 316 | ProcessCapabilities capabilities; |
| @@ -339,7 +339,7 @@ private: | |||
| 339 | Mutex mutex; | 339 | Mutex mutex; |
| 340 | 340 | ||
| 341 | /// Random values for svcGetInfo RandomEntropy | 341 | /// Random values for svcGetInfo RandomEntropy |
| 342 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy; | 342 | std::array<u64, RANDOM_ENTROPY_SIZE> random_entropy{}; |
| 343 | 343 | ||
| 344 | /// List of threads that are running with this process as their owner. | 344 | /// List of threads that are running with this process as their owner. |
| 345 | std::list<const Thread*> thread_list; | 345 | std::list<const Thread*> thread_list; |
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp index a055a5002..ec529e7f2 100644 --- a/src/core/hle/kernel/thread.cpp +++ b/src/core/hle/kernel/thread.cpp | |||
| @@ -65,7 +65,7 @@ void Thread::Stop() { | |||
| 65 | owner_process->UnregisterThread(this); | 65 | owner_process->UnregisterThread(this); |
| 66 | 66 | ||
| 67 | // Mark the TLS slot in the thread's page as free. | 67 | // Mark the TLS slot in the thread's page as free. |
| 68 | owner_process->FreeTLSSlot(tls_address); | 68 | owner_process->FreeTLSRegion(tls_address); |
| 69 | } | 69 | } |
| 70 | 70 | ||
| 71 | void Thread::WakeAfterDelay(s64 nanoseconds) { | 71 | void Thread::WakeAfterDelay(s64 nanoseconds) { |
| @@ -205,9 +205,9 @@ ResultVal<SharedPtr<Thread>> Thread::Create(KernelCore& kernel, std::string name | |||
| 205 | thread->name = std::move(name); | 205 | thread->name = std::move(name); |
| 206 | thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); | 206 | thread->callback_handle = kernel.ThreadWakeupCallbackHandleTable().Create(thread).Unwrap(); |
| 207 | thread->owner_process = &owner_process; | 207 | thread->owner_process = &owner_process; |
| 208 | thread->tls_address = thread->owner_process->CreateTLSRegion(); | ||
| 208 | thread->scheduler = &system.Scheduler(processor_id); | 209 | thread->scheduler = &system.Scheduler(processor_id); |
| 209 | thread->scheduler->AddThread(thread); | 210 | thread->scheduler->AddThread(thread); |
| 210 | thread->tls_address = thread->owner_process->MarkNextAvailableTLSSlotAsUsed(*thread); | ||
| 211 | 211 | ||
| 212 | thread->owner_process->RegisterThread(thread.get()); | 212 | thread->owner_process->RegisterThread(thread.get()); |
| 213 | 213 | ||
diff --git a/src/core/hle/kernel/thread.h b/src/core/hle/kernel/thread.h index b4b9cda7c..07e989637 100644 --- a/src/core/hle/kernel/thread.h +++ b/src/core/hle/kernel/thread.h | |||
| @@ -5,7 +5,6 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <functional> | 7 | #include <functional> |
| 8 | #include <memory> | ||
| 9 | #include <string> | 8 | #include <string> |
| 10 | #include <vector> | 9 | #include <vector> |
| 11 | 10 | ||
| @@ -78,9 +77,6 @@ enum class ThreadActivity : u32 { | |||
| 78 | 77 | ||
| 79 | class Thread final : public WaitObject { | 78 | class Thread final : public WaitObject { |
| 80 | public: | 79 | public: |
| 81 | using TLSMemory = std::vector<u8>; | ||
| 82 | using TLSMemoryPtr = std::shared_ptr<TLSMemory>; | ||
| 83 | |||
| 84 | using MutexWaitingThreads = std::vector<SharedPtr<Thread>>; | 80 | using MutexWaitingThreads = std::vector<SharedPtr<Thread>>; |
| 85 | 81 | ||
| 86 | using ThreadContext = Core::ARM_Interface::ThreadContext; | 82 | using ThreadContext = Core::ARM_Interface::ThreadContext; |
| @@ -169,14 +165,6 @@ public: | |||
| 169 | return thread_id; | 165 | return thread_id; |
| 170 | } | 166 | } |
| 171 | 167 | ||
| 172 | TLSMemoryPtr& GetTLSMemory() { | ||
| 173 | return tls_memory; | ||
| 174 | } | ||
| 175 | |||
| 176 | const TLSMemoryPtr& GetTLSMemory() const { | ||
| 177 | return tls_memory; | ||
| 178 | } | ||
| 179 | |||
| 180 | /// Resumes a thread from waiting | 168 | /// Resumes a thread from waiting |
| 181 | void ResumeFromWait(); | 169 | void ResumeFromWait(); |
| 182 | 170 | ||
| @@ -463,11 +451,9 @@ private: | |||
| 463 | u32 ideal_core{0xFFFFFFFF}; | 451 | u32 ideal_core{0xFFFFFFFF}; |
| 464 | u64 affinity_mask{0x1}; | 452 | u64 affinity_mask{0x1}; |
| 465 | 453 | ||
| 466 | TLSMemoryPtr tls_memory = std::make_shared<TLSMemory>(); | 454 | ThreadActivity activity = ThreadActivity::Normal; |
| 467 | 455 | ||
| 468 | std::string name; | 456 | std::string name; |
| 469 | |||
| 470 | ThreadActivity activity = ThreadActivity::Normal; | ||
| 471 | }; | 457 | }; |
| 472 | 458 | ||
| 473 | /** | 459 | /** |
diff --git a/src/core/hle/kernel/vm_manager.cpp b/src/core/hle/kernel/vm_manager.cpp index c929c2a52..3df5ccb7f 100644 --- a/src/core/hle/kernel/vm_manager.cpp +++ b/src/core/hle/kernel/vm_manager.cpp | |||
| @@ -152,22 +152,33 @@ ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* me | |||
| 152 | } | 152 | } |
| 153 | 153 | ||
| 154 | ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { | 154 | ResultVal<VAddr> VMManager::FindFreeRegion(u64 size) const { |
| 155 | // Find the first Free VMA. | 155 | return FindFreeRegion(GetASLRRegionBaseAddress(), GetASLRRegionEndAddress(), size); |
| 156 | const VAddr base = GetASLRRegionBaseAddress(); | 156 | } |
| 157 | const VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { | ||
| 158 | if (vma.second.type != VMAType::Free) | ||
| 159 | return false; | ||
| 160 | 157 | ||
| 161 | const VAddr vma_end = vma.second.base + vma.second.size; | 158 | ResultVal<VAddr> VMManager::FindFreeRegion(VAddr begin, VAddr end, u64 size) const { |
| 162 | return vma_end > base && vma_end >= base + size; | 159 | ASSERT(begin < end); |
| 163 | }); | 160 | ASSERT(size <= end - begin); |
| 164 | 161 | ||
| 165 | if (vma_handle == vma_map.end()) { | 162 | const VMAHandle vma_handle = |
| 163 | std::find_if(vma_map.begin(), vma_map.end(), [begin, end, size](const auto& vma) { | ||
| 164 | if (vma.second.type != VMAType::Free) { | ||
| 165 | return false; | ||
| 166 | } | ||
| 167 | const VAddr vma_base = vma.second.base; | ||
| 168 | const VAddr vma_end = vma_base + vma.second.size; | ||
| 169 | const VAddr assumed_base = (begin < vma_base) ? vma_base : begin; | ||
| 170 | const VAddr used_range = assumed_base + size; | ||
| 171 | |||
| 172 | return vma_base <= assumed_base && assumed_base < used_range && used_range < end && | ||
| 173 | used_range <= vma_end; | ||
| 174 | }); | ||
| 175 | |||
| 176 | if (vma_handle == vma_map.cend()) { | ||
| 166 | // TODO(Subv): Find the correct error code here. | 177 | // TODO(Subv): Find the correct error code here. |
| 167 | return ResultCode(-1); | 178 | return ResultCode(-1); |
| 168 | } | 179 | } |
| 169 | 180 | ||
| 170 | const VAddr target = std::max(base, vma_handle->second.base); | 181 | const VAddr target = std::max(begin, vma_handle->second.base); |
| 171 | return MakeResult<VAddr>(target); | 182 | return MakeResult<VAddr>(target); |
| 172 | } | 183 | } |
| 173 | 184 | ||
diff --git a/src/core/hle/kernel/vm_manager.h b/src/core/hle/kernel/vm_manager.h index dfbf7a894..752ae62f9 100644 --- a/src/core/hle/kernel/vm_manager.h +++ b/src/core/hle/kernel/vm_manager.h | |||
| @@ -362,14 +362,39 @@ public: | |||
| 362 | ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); | 362 | ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u64 size, MemoryState state); |
| 363 | 363 | ||
| 364 | /** | 364 | /** |
| 365 | * Finds the first free address that can hold a region of the desired size. | 365 | * Finds the first free memory region of the given size within |
| 366 | * the user-addressable ASLR memory region. | ||
| 366 | * | 367 | * |
| 367 | * @param size Size of the desired region. | 368 | * @param size The size of the desired region in bytes. |
| 368 | * @return The found free address. | 369 | * |
| 370 | * @returns If successful, the base address of the free region with | ||
| 371 | * the given size. | ||
| 369 | */ | 372 | */ |
| 370 | ResultVal<VAddr> FindFreeRegion(u64 size) const; | 373 | ResultVal<VAddr> FindFreeRegion(u64 size) const; |
| 371 | 374 | ||
| 372 | /** | 375 | /** |
| 376 | * Finds the first free address range that can hold a region of the desired size | ||
| 377 | * | ||
| 378 | * @param begin The starting address of the range. | ||
| 379 | * This is treated as an inclusive beginning address. | ||
| 380 | * | ||
| 381 | * @param end The ending address of the range. | ||
| 382 | * This is treated as an exclusive ending address. | ||
| 383 | * | ||
| 384 | * @param size The size of the free region to attempt to locate, | ||
| 385 | * in bytes. | ||
| 386 | * | ||
| 387 | * @returns If successful, the base address of the free region with | ||
| 388 | * the given size. | ||
| 389 | * | ||
| 390 | * @returns If unsuccessful, a result containing an error code. | ||
| 391 | * | ||
| 392 | * @pre The starting address must be less than the ending address. | ||
| 393 | * @pre The size must not exceed the address range itself. | ||
| 394 | */ | ||
| 395 | ResultVal<VAddr> FindFreeRegion(VAddr begin, VAddr end, u64 size) const; | ||
| 396 | |||
| 397 | /** | ||
| 373 | * Maps a memory-mapped IO region at a given address. | 398 | * Maps a memory-mapped IO region at a given address. |
| 374 | * | 399 | * |
| 375 | * @param target The guest address to start the mapping at. | 400 | * @param target The guest address to start the mapping at. |