mirror of
				https://github.com/yuzu-emu/yuzu.git
				synced 2025-11-04 06:13:42 +00:00 
			
		
		
		
	core: hle: kernel: k_page_buffer: Add KThreadLocalPage primitive.
This commit is contained in:
		
							parent
							
								
									08434842b3
								
							
						
					
					
						commit
						91819726b1
					
				@ -245,6 +245,8 @@ add_library(core STATIC
 | 
				
			|||||||
    hle/kernel/k_system_control.h
 | 
					    hle/kernel/k_system_control.h
 | 
				
			||||||
    hle/kernel/k_thread.cpp
 | 
					    hle/kernel/k_thread.cpp
 | 
				
			||||||
    hle/kernel/k_thread.h
 | 
					    hle/kernel/k_thread.h
 | 
				
			||||||
 | 
					    hle/kernel/k_thread_local_page.cpp
 | 
				
			||||||
 | 
					    hle/kernel/k_thread_local_page.h
 | 
				
			||||||
    hle/kernel/k_thread_queue.cpp
 | 
					    hle/kernel/k_thread_queue.cpp
 | 
				
			||||||
    hle/kernel/k_thread_queue.h
 | 
					    hle/kernel/k_thread_queue.h
 | 
				
			||||||
    hle/kernel/k_trace.h
 | 
					    hle/kernel/k_trace.h
 | 
				
			||||||
 | 
				
			|||||||
							
								
								
									
										65
									
								
								src/core/hle/kernel/k_thread_local_page.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										65
									
								
								src/core/hle/kernel/k_thread_local_page.cpp
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,65 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 yuzu Emulator Project
 | 
				
			||||||
 | 
					// Licensed under GPLv2 or any later version
 | 
				
			||||||
 | 
					// Refer to the license.txt file included.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/scope_exit.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/k_memory_block.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/k_page_table.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/k_process.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/k_thread_local_page.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/kernel.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ResultCode KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
 | 
				
			||||||
 | 
					    // Set that this process owns us.
 | 
				
			||||||
 | 
					    m_owner = process;
 | 
				
			||||||
 | 
					    m_kernel = &kernel;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Allocate a new page.
 | 
				
			||||||
 | 
					    KPageBuffer* page_buf = KPageBuffer::Allocate(kernel);
 | 
				
			||||||
 | 
					    R_UNLESS(page_buf != nullptr, ResultOutOfMemory);
 | 
				
			||||||
 | 
					    auto page_buf_guard = SCOPE_GUARD({ KPageBuffer::Free(kernel, page_buf); });
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Map the address in.
 | 
				
			||||||
 | 
					    const auto phys_addr = kernel.System().DeviceMemory().GetPhysicalAddr(page_buf);
 | 
				
			||||||
 | 
					    R_TRY(m_owner->PageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr,
 | 
				
			||||||
 | 
					                                        KMemoryState::ThreadLocal,
 | 
				
			||||||
 | 
					                                        KMemoryPermission::UserReadWrite));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // We succeeded.
 | 
				
			||||||
 | 
					    page_buf_guard.Cancel();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ResultSuccess;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ResultCode KThreadLocalPage::Finalize() {
 | 
				
			||||||
 | 
					    // Get the physical address of the page.
 | 
				
			||||||
 | 
					    const PAddr phys_addr = m_owner->PageTable().GetPhysicalAddr(m_virt_addr);
 | 
				
			||||||
 | 
					    ASSERT(phys_addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Unmap the page.
 | 
				
			||||||
 | 
					    R_TRY(m_owner->PageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    // Free the page.
 | 
				
			||||||
 | 
					    KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return ResultSuccess;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					VAddr KThreadLocalPage::Reserve() {
 | 
				
			||||||
 | 
					    for (size_t i = 0; i < m_is_region_free.size(); i++) {
 | 
				
			||||||
 | 
					        if (m_is_region_free[i]) {
 | 
				
			||||||
 | 
					            m_is_region_free[i] = false;
 | 
				
			||||||
 | 
					            return this->GetRegionAddress(i);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void KThreadLocalPage::Release(VAddr addr) {
 | 
				
			||||||
 | 
					    m_is_region_free[this->GetRegionIndex(addr)] = true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Kernel
 | 
				
			||||||
							
								
								
									
										112
									
								
								src/core/hle/kernel/k_thread_local_page.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										112
									
								
								src/core/hle/kernel/k_thread_local_page.h
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,112 @@
 | 
				
			|||||||
 | 
					// Copyright 2022 yuzu Emulator Project
 | 
				
			||||||
 | 
					// Licensed under GPLv2 or any later version
 | 
				
			||||||
 | 
					// Refer to the license.txt file included.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <algorithm>
 | 
				
			||||||
 | 
					#include <array>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "common/alignment.h"
 | 
				
			||||||
 | 
					#include "common/assert.h"
 | 
				
			||||||
 | 
					#include "common/common_types.h"
 | 
				
			||||||
 | 
					#include "common/intrusive_red_black_tree.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/k_page_buffer.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/memory_types.h"
 | 
				
			||||||
 | 
					#include "core/hle/kernel/slab_helpers.h"
 | 
				
			||||||
 | 
					#include "core/hle/result.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace Kernel {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KernelCore;
 | 
				
			||||||
 | 
					class KProcess;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class KThreadLocalPage final : public Common::IntrusiveRedBlackTreeBaseNode<KThreadLocalPage>,
 | 
				
			||||||
 | 
					                               public KSlabAllocated<KThreadLocalPage> {
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    static constexpr size_t RegionsPerPage = PageSize / Svc::ThreadLocalRegionSize;
 | 
				
			||||||
 | 
					    static_assert(RegionsPerPage > 0);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    constexpr explicit KThreadLocalPage(VAddr addr = {}) : m_virt_addr(addr) {
 | 
				
			||||||
 | 
					        m_is_region_free.fill(true);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr VAddr GetAddress() const {
 | 
				
			||||||
 | 
					        return m_virt_addr;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ResultCode Initialize(KernelCore& kernel, KProcess* process);
 | 
				
			||||||
 | 
					    ResultCode Finalize();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    VAddr Reserve();
 | 
				
			||||||
 | 
					    void Release(VAddr addr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsAllUsed() const {
 | 
				
			||||||
 | 
					        return std::ranges::all_of(m_is_region_free.begin(), m_is_region_free.end(),
 | 
				
			||||||
 | 
					                                   [](bool is_free) { return !is_free; });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsAllFree() const {
 | 
				
			||||||
 | 
					        return std::ranges::all_of(m_is_region_free.begin(), m_is_region_free.end(),
 | 
				
			||||||
 | 
					                                   [](bool is_free) { return is_free; });
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsAnyUsed() const {
 | 
				
			||||||
 | 
					        return !this->IsAllFree();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsAnyFree() const {
 | 
				
			||||||
 | 
					        return !this->IsAllUsed();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					    using RedBlackKeyType = VAddr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    static constexpr RedBlackKeyType GetRedBlackKey(const RedBlackKeyType& v) {
 | 
				
			||||||
 | 
					        return v;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    static constexpr RedBlackKeyType GetRedBlackKey(const KThreadLocalPage& v) {
 | 
				
			||||||
 | 
					        return v.GetAddress();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    template <typename T>
 | 
				
			||||||
 | 
					    requires(std::same_as<T, KThreadLocalPage> ||
 | 
				
			||||||
 | 
					             std::same_as<T, RedBlackKeyType>) static constexpr int Compare(const T& lhs,
 | 
				
			||||||
 | 
					                                                                            const KThreadLocalPage&
 | 
				
			||||||
 | 
					                                                                                rhs) {
 | 
				
			||||||
 | 
					        const VAddr lval = GetRedBlackKey(lhs);
 | 
				
			||||||
 | 
					        const VAddr rval = GetRedBlackKey(rhs);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        if (lval < rval) {
 | 
				
			||||||
 | 
					            return -1;
 | 
				
			||||||
 | 
					        } else if (lval == rval) {
 | 
				
			||||||
 | 
					            return 0;
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            return 1;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    constexpr VAddr GetRegionAddress(size_t i) const {
 | 
				
			||||||
 | 
					        return this->GetAddress() + i * Svc::ThreadLocalRegionSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr bool Contains(VAddr addr) const {
 | 
				
			||||||
 | 
					        return this->GetAddress() <= addr && addr < this->GetAddress() + PageSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    constexpr size_t GetRegionIndex(VAddr addr) const {
 | 
				
			||||||
 | 
					        ASSERT(Common::IsAligned(addr, Svc::ThreadLocalRegionSize));
 | 
				
			||||||
 | 
					        ASSERT(this->Contains(addr));
 | 
				
			||||||
 | 
					        return (addr - this->GetAddress()) / Svc::ThreadLocalRegionSize;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					private:
 | 
				
			||||||
 | 
					    VAddr m_virt_addr{};
 | 
				
			||||||
 | 
					    KProcess* m_owner{};
 | 
				
			||||||
 | 
					    KernelCore* m_kernel{};
 | 
				
			||||||
 | 
					    std::array<bool, RegionsPerPage> m_is_region_free{};
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					} // namespace Kernel
 | 
				
			||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user