2022-04-23 10:59:50 +02:00
|
|
|
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
|
|
|
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
2022-03-11 09:36:33 +01:00
|
|
|
|
|
|
|
#include "common/scope_exit.h"
|
2022-03-18 03:09:01 +01:00
|
|
|
#include "core/core.h"
|
2022-03-19 04:44:24 +01:00
|
|
|
|
2022-03-11 09:36:33 +01:00
|
|
|
#include "core/hle/kernel/k_memory_block.h"
|
2022-03-19 04:44:24 +01:00
|
|
|
#include "core/hle/kernel/k_page_buffer.h"
|
2022-03-11 09:36:33 +01:00
|
|
|
#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 {
|
|
|
|
|
2022-06-26 05:44:19 +02:00
|
|
|
Result KThreadLocalPage::Initialize(KernelCore& kernel, KProcess* process) {
|
2022-03-11 09:36:33 +01:00
|
|
|
// Set that this process owns us.
|
|
|
|
m_owner = process;
|
2023-03-07 18:01:07 +01:00
|
|
|
m_kernel = std::addressof(kernel);
|
2022-03-11 09:36:33 +01:00
|
|
|
|
|
|
|
// 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);
|
2023-07-15 03:43:15 +02:00
|
|
|
R_TRY(m_owner->GetPageTable().MapPages(std::addressof(m_virt_addr), 1, PageSize, phys_addr,
|
|
|
|
KMemoryState::ThreadLocal,
|
|
|
|
KMemoryPermission::UserReadWrite));
|
2022-03-11 09:36:33 +01:00
|
|
|
|
|
|
|
// We succeeded.
|
|
|
|
page_buf_guard.Cancel();
|
|
|
|
|
|
|
|
return ResultSuccess;
|
|
|
|
}
|
|
|
|
|
2022-06-26 05:44:19 +02:00
|
|
|
Result KThreadLocalPage::Finalize() {
|
2022-03-11 09:36:33 +01:00
|
|
|
// Get the physical address of the page.
|
2023-10-23 03:16:38 +02:00
|
|
|
KPhysicalAddress phys_addr{};
|
|
|
|
ASSERT(m_owner->GetPageTable().GetPhysicalAddress(std::addressof(phys_addr), m_virt_addr));
|
2022-03-11 09:36:33 +01:00
|
|
|
|
|
|
|
// Unmap the page.
|
2023-07-15 03:43:15 +02:00
|
|
|
R_TRY(m_owner->GetPageTable().UnmapPages(this->GetAddress(), 1, KMemoryState::ThreadLocal));
|
2022-03-11 09:36:33 +01:00
|
|
|
|
|
|
|
// Free the page.
|
|
|
|
KPageBuffer::Free(*m_kernel, KPageBuffer::FromPhysicalAddress(m_kernel->System(), phys_addr));
|
|
|
|
|
|
|
|
return ResultSuccess;
|
|
|
|
}
|
|
|
|
|
2023-03-18 02:26:04 +01:00
|
|
|
KProcessAddress KThreadLocalPage::Reserve() {
|
2022-03-11 09:36:33 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2023-03-18 02:26:04 +01:00
|
|
|
void KThreadLocalPage::Release(KProcessAddress addr) {
|
2022-03-11 09:36:33 +01:00
|
|
|
m_is_region_free[this->GetRegionIndex(addr)] = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
} // namespace Kernel
|