early-access version 3324
This commit is contained in:
parent
ff3e8aa9d0
commit
13810b8a83
24 changed files with 509 additions and 244 deletions
|
@ -3,12 +3,14 @@
|
||||||
|
|
||||||
cmake_minimum_required(VERSION 3.22)
|
cmake_minimum_required(VERSION 3.22)
|
||||||
|
|
||||||
|
project(yuzu)
|
||||||
|
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/CMakeModules")
|
||||||
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
list(APPEND CMAKE_MODULE_PATH "${CMAKE_CURRENT_SOURCE_DIR}/externals/cmake-modules")
|
||||||
|
|
||||||
include(DownloadExternals)
|
include(DownloadExternals)
|
||||||
include(CMakeDependentOption)
|
include(CMakeDependentOption)
|
||||||
|
include(CTest)
|
||||||
project(yuzu)
|
|
||||||
|
|
||||||
# Set bundled sdl2/qt as dependent options.
|
# Set bundled sdl2/qt as dependent options.
|
||||||
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
# OFF by default, but if ENABLE_SDL2 and MSVC are true then ON
|
||||||
|
@ -42,7 +44,7 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||||
|
|
||||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
||||||
|
|
||||||
option(YUZU_TESTS "Compile tests" ON)
|
option(YUZU_TESTS "Compile tests" "${BUILD_TESTING}")
|
||||||
|
|
||||||
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
option(YUZU_USE_PRECOMPILED_HEADERS "Use precompiled headers" ON)
|
||||||
|
|
||||||
|
@ -242,7 +244,7 @@ if (ENABLE_WEB_SERVICE)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
if (YUZU_TESTS)
|
if (YUZU_TESTS)
|
||||||
find_package(Catch2 2.13.7 REQUIRED)
|
find_package(Catch2 3.0.1 REQUIRED)
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
find_package(Boost 1.73.0 COMPONENTS context)
|
find_package(Boost 1.73.0 COMPONENTS context)
|
||||||
|
@ -606,7 +608,6 @@ if (YUZU_USE_FASTER_LD AND CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
|
||||||
endif()
|
endif()
|
||||||
endif()
|
endif()
|
||||||
|
|
||||||
enable_testing()
|
|
||||||
add_subdirectory(externals)
|
add_subdirectory(externals)
|
||||||
add_subdirectory(src)
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
yuzu emulator early access
|
yuzu emulator early access
|
||||||
=============
|
=============
|
||||||
|
|
||||||
This is the source code for early-access 3323.
|
This is the source code for early-access 3324.
|
||||||
|
|
||||||
## Legal Notice
|
## Legal Notice
|
||||||
|
|
||||||
|
|
3
externals/CMakeLists.txt
vendored
3
externals/CMakeLists.txt
vendored
|
@ -5,6 +5,9 @@
|
||||||
# some of its variables, which is only possible in 3.13+
|
# some of its variables, which is only possible in 3.13+
|
||||||
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
set(CMAKE_POLICY_DEFAULT_CMP0077 NEW)
|
||||||
|
|
||||||
|
# Disable tests in all externals supporting the standard option name
|
||||||
|
set(BUILD_TESTING OFF)
|
||||||
|
|
||||||
# xbyak
|
# xbyak
|
||||||
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
|
if ((ARCHITECTURE_x86 OR ARCHITECTURE_x86_64) AND NOT TARGET xbyak::xbyak)
|
||||||
add_subdirectory(xbyak EXCLUDE_FROM_ALL)
|
add_subdirectory(xbyak EXCLUDE_FROM_ALL)
|
||||||
|
|
|
@ -74,7 +74,7 @@ Result KCodeMemory::Map(VAddr address, size_t size) {
|
||||||
R_UNLESS(!m_is_mapped, ResultInvalidState);
|
R_UNLESS(!m_is_mapped, ResultInvalidState);
|
||||||
|
|
||||||
// Map the memory.
|
// Map the memory.
|
||||||
R_TRY(kernel.CurrentProcess()->PageTable().MapPages(
|
R_TRY(kernel.CurrentProcess()->PageTable().MapPageGroup(
|
||||||
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
|
address, *m_page_group, KMemoryState::CodeOut, KMemoryPermission::UserReadWrite));
|
||||||
|
|
||||||
// Mark ourselves as mapped.
|
// Mark ourselves as mapped.
|
||||||
|
@ -91,8 +91,8 @@ Result KCodeMemory::Unmap(VAddr address, size_t size) {
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
// Unmap the memory.
|
// Unmap the memory.
|
||||||
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPages(address, *m_page_group,
|
R_TRY(kernel.CurrentProcess()->PageTable().UnmapPageGroup(address, *m_page_group,
|
||||||
KMemoryState::CodeOut));
|
KMemoryState::CodeOut));
|
||||||
|
|
||||||
// Mark ourselves as unmapped.
|
// Mark ourselves as unmapped.
|
||||||
m_is_mapped = false;
|
m_is_mapped = false;
|
||||||
|
@ -125,8 +125,8 @@ Result KCodeMemory::MapToOwner(VAddr address, size_t size, Svc::MemoryPermission
|
||||||
}
|
}
|
||||||
|
|
||||||
// Map the memory.
|
// Map the memory.
|
||||||
R_TRY(
|
R_TRY(m_owner->PageTable().MapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode,
|
||||||
m_owner->PageTable().MapPages(address, *m_page_group, KMemoryState::GeneratedCode, k_perm));
|
k_perm));
|
||||||
|
|
||||||
// Mark ourselves as mapped.
|
// Mark ourselves as mapped.
|
||||||
m_is_owner_mapped = true;
|
m_is_owner_mapped = true;
|
||||||
|
@ -142,7 +142,7 @@ Result KCodeMemory::UnmapFromOwner(VAddr address, size_t size) {
|
||||||
KScopedLightLock lk(m_lock);
|
KScopedLightLock lk(m_lock);
|
||||||
|
|
||||||
// Unmap the memory.
|
// Unmap the memory.
|
||||||
R_TRY(m_owner->PageTable().UnmapPages(address, *m_page_group, KMemoryState::GeneratedCode));
|
R_TRY(m_owner->PageTable().UnmapPageGroup(address, *m_page_group, KMemoryState::GeneratedCode));
|
||||||
|
|
||||||
// Mark ourselves as unmapped.
|
// Mark ourselves as unmapped.
|
||||||
m_is_owner_mapped = false;
|
m_is_owner_mapped = false;
|
||||||
|
|
|
@ -435,6 +435,9 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
|
||||||
KPageGroup pg{m_kernel, m_block_info_manager};
|
KPageGroup pg{m_kernel, m_block_info_manager};
|
||||||
AddRegionToPages(src_address, num_pages, pg);
|
AddRegionToPages(src_address, num_pages, pg);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
// Reprotect the source as kernel-read/not mapped.
|
// Reprotect the source as kernel-read/not mapped.
|
||||||
const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
|
const auto new_perm = static_cast<KMemoryPermission>(KMemoryPermission::KernelRead |
|
||||||
KMemoryPermission::NotMapped);
|
KMemoryPermission::NotMapped);
|
||||||
|
@ -447,7 +450,10 @@ Result KPageTable::MapCodeMemory(VAddr dst_address, VAddr src_address, size_t si
|
||||||
});
|
});
|
||||||
|
|
||||||
// Map the alias pages.
|
// Map the alias pages.
|
||||||
R_TRY(MapPages(dst_address, pg, new_perm));
|
const KPageProperties dst_properties = {new_perm, false, false,
|
||||||
|
DisableMergeAttribute::DisableHead};
|
||||||
|
R_TRY(
|
||||||
|
this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_properties, false));
|
||||||
|
|
||||||
// We successfully mapped the alias pages, so we don't need to unprotect the src pages on
|
// We successfully mapped the alias pages, so we don't need to unprotect the src pages on
|
||||||
// failure.
|
// failure.
|
||||||
|
@ -1881,7 +1887,8 @@ Result KPageTable::UnmapPhysicalMemory(VAddr address, size_t size) {
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size) {
|
Result KPageTable::MapMemory(KProcessAddress dst_address, KProcessAddress src_address,
|
||||||
|
size_t size) {
|
||||||
// Lock the table.
|
// Lock the table.
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
|
@ -1902,53 +1909,73 @@ Result KPageTable::MapMemory(VAddr dst_address, VAddr src_address, size_t size)
|
||||||
KMemoryAttribute::None));
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
// Create an update allocator for the source.
|
// Create an update allocator for the source.
|
||||||
Result src_allocator_result{ResultSuccess};
|
Result src_allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
|
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
|
||||||
m_memory_block_slab_manager,
|
m_memory_block_slab_manager,
|
||||||
num_src_allocator_blocks);
|
num_src_allocator_blocks);
|
||||||
R_TRY(src_allocator_result);
|
R_TRY(src_allocator_result);
|
||||||
|
|
||||||
// Create an update allocator for the destination.
|
// Create an update allocator for the destination.
|
||||||
Result dst_allocator_result{ResultSuccess};
|
Result dst_allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
|
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
|
||||||
m_memory_block_slab_manager,
|
m_memory_block_slab_manager,
|
||||||
num_dst_allocator_blocks);
|
num_dst_allocator_blocks);
|
||||||
R_TRY(dst_allocator_result);
|
R_TRY(dst_allocator_result);
|
||||||
|
|
||||||
// Map the memory.
|
// Map the memory.
|
||||||
KPageGroup page_linked_list{m_kernel, m_block_info_manager};
|
|
||||||
const size_t num_pages{size / PageSize};
|
|
||||||
const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
|
|
||||||
KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
|
|
||||||
const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
|
|
||||||
|
|
||||||
AddRegionToPages(src_address, num_pages, page_linked_list);
|
|
||||||
{
|
{
|
||||||
|
// Determine the number of pages being operated on.
|
||||||
|
const size_t num_pages = size / PageSize;
|
||||||
|
|
||||||
|
// Create page groups for the memory being unmapped.
|
||||||
|
KPageGroup pg{m_kernel, m_block_info_manager};
|
||||||
|
|
||||||
|
// Create the page group representing the source.
|
||||||
|
R_TRY(this->MakePageGroup(pg, src_address, num_pages));
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
// Reprotect the source as kernel-read/not mapped.
|
// Reprotect the source as kernel-read/not mapped.
|
||||||
auto block_guard = detail::ScopeExit([&] {
|
const KMemoryPermission new_src_perm = static_cast<KMemoryPermission>(
|
||||||
Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
|
KMemoryPermission::KernelRead | KMemoryPermission::NotMapped);
|
||||||
OperationType::ChangePermissions);
|
const KMemoryAttribute new_src_attr = KMemoryAttribute::Locked;
|
||||||
});
|
const KPageProperties src_properties = {new_src_perm, false, false,
|
||||||
R_TRY(Operate(src_address, num_pages, new_src_perm, OperationType::ChangePermissions));
|
DisableMergeAttribute::DisableHeadBodyTail};
|
||||||
R_TRY(MapPages(dst_address, page_linked_list, KMemoryPermission::UserReadWrite));
|
R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
|
||||||
|
OperationType::ChangePermissions));
|
||||||
|
|
||||||
block_guard.Cancel();
|
// Ensure that we unprotect the source pages on failure.
|
||||||
|
ON_RESULT_FAILURE {
|
||||||
|
const KPageProperties unprotect_properties = {
|
||||||
|
KMemoryPermission::UserReadWrite, false, false,
|
||||||
|
DisableMergeAttribute::EnableHeadBodyTail};
|
||||||
|
ASSERT(this->Operate(src_address, num_pages, unprotect_properties.perm,
|
||||||
|
OperationType::ChangePermissions) == ResultSuccess);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Map the alias pages.
|
||||||
|
const KPageProperties dst_map_properties = {KMemoryPermission::UserReadWrite, false, false,
|
||||||
|
DisableMergeAttribute::DisableHead};
|
||||||
|
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), dst_address, pg, dst_map_properties,
|
||||||
|
false));
|
||||||
|
|
||||||
|
// Apply the memory block updates.
|
||||||
|
m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages,
|
||||||
|
src_state, new_src_perm, new_src_attr,
|
||||||
|
KMemoryBlockDisableMergeAttribute::Locked,
|
||||||
|
KMemoryBlockDisableMergeAttribute::None);
|
||||||
|
m_memory_block_manager.Update(
|
||||||
|
std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::Stack,
|
||||||
|
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
|
||||||
|
KMemoryBlockDisableMergeAttribute::Normal, KMemoryBlockDisableMergeAttribute::None);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the memory block updates.
|
|
||||||
m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state,
|
|
||||||
new_src_perm, new_src_attr,
|
|
||||||
KMemoryBlockDisableMergeAttribute::Locked,
|
|
||||||
KMemoryBlockDisableMergeAttribute::None);
|
|
||||||
m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
|
|
||||||
KMemoryState::Stack, KMemoryPermission::UserReadWrite,
|
|
||||||
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
|
|
||||||
KMemoryBlockDisableMergeAttribute::None);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size) {
|
Result KPageTable::UnmapMemory(KProcessAddress dst_address, KProcessAddress src_address,
|
||||||
|
size_t size) {
|
||||||
// Lock the table.
|
// Lock the table.
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
|
@ -1970,108 +1997,208 @@ Result KPageTable::UnmapMemory(VAddr dst_address, VAddr src_address, size_t size
|
||||||
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
|
KMemoryPermission::None, KMemoryAttribute::All, KMemoryAttribute::None));
|
||||||
|
|
||||||
// Create an update allocator for the source.
|
// Create an update allocator for the source.
|
||||||
Result src_allocator_result{ResultSuccess};
|
Result src_allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
|
KMemoryBlockManagerUpdateAllocator src_allocator(std::addressof(src_allocator_result),
|
||||||
m_memory_block_slab_manager,
|
m_memory_block_slab_manager,
|
||||||
num_src_allocator_blocks);
|
num_src_allocator_blocks);
|
||||||
R_TRY(src_allocator_result);
|
R_TRY(src_allocator_result);
|
||||||
|
|
||||||
// Create an update allocator for the destination.
|
// Create an update allocator for the destination.
|
||||||
Result dst_allocator_result{ResultSuccess};
|
Result dst_allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
|
KMemoryBlockManagerUpdateAllocator dst_allocator(std::addressof(dst_allocator_result),
|
||||||
m_memory_block_slab_manager,
|
m_memory_block_slab_manager,
|
||||||
num_dst_allocator_blocks);
|
num_dst_allocator_blocks);
|
||||||
R_TRY(dst_allocator_result);
|
R_TRY(dst_allocator_result);
|
||||||
|
|
||||||
KPageGroup src_pages{m_kernel, m_block_info_manager};
|
// Unmap the memory.
|
||||||
KPageGroup dst_pages{m_kernel, m_block_info_manager};
|
|
||||||
const size_t num_pages{size / PageSize};
|
|
||||||
|
|
||||||
AddRegionToPages(src_address, num_pages, src_pages);
|
|
||||||
AddRegionToPages(dst_address, num_pages, dst_pages);
|
|
||||||
|
|
||||||
R_UNLESS(dst_pages.IsEquivalentTo(src_pages), ResultInvalidMemoryRegion);
|
|
||||||
|
|
||||||
{
|
{
|
||||||
auto block_guard = detail::ScopeExit([&] { MapPages(dst_address, dst_pages, dst_perm); });
|
// Determine the number of pages being operated on.
|
||||||
|
const size_t num_pages = size / PageSize;
|
||||||
|
|
||||||
R_TRY(Operate(dst_address, num_pages, KMemoryPermission::None, OperationType::Unmap));
|
// Create page groups for the memory being unmapped.
|
||||||
R_TRY(Operate(src_address, num_pages, KMemoryPermission::UserReadWrite,
|
KPageGroup pg{m_kernel, m_block_info_manager};
|
||||||
OperationType::ChangePermissions));
|
|
||||||
|
|
||||||
block_guard.Cancel();
|
// Create the page group representing the destination.
|
||||||
|
R_TRY(this->MakePageGroup(pg, dst_address, num_pages));
|
||||||
|
|
||||||
|
// Ensure the page group is the valid for the source.
|
||||||
|
R_UNLESS(this->IsValidPageGroup(pg, src_address, num_pages), ResultInvalidMemoryRegion);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
// Unmap the aliased copy of the pages.
|
||||||
|
const KPageProperties dst_unmap_properties = {KMemoryPermission::None, false, false,
|
||||||
|
DisableMergeAttribute::None};
|
||||||
|
R_TRY(
|
||||||
|
this->Operate(dst_address, num_pages, dst_unmap_properties.perm, OperationType::Unmap));
|
||||||
|
|
||||||
|
// Ensure that we re-map the aliased pages on failure.
|
||||||
|
ON_RESULT_FAILURE {
|
||||||
|
this->RemapPageGroup(updater.GetPageList(), dst_address, size, pg);
|
||||||
|
};
|
||||||
|
|
||||||
|
// Try to set the permissions for the source pages back to what they should be.
|
||||||
|
const KPageProperties src_properties = {KMemoryPermission::UserReadWrite, false, false,
|
||||||
|
DisableMergeAttribute::EnableAndMergeHeadBodyTail};
|
||||||
|
R_TRY(this->Operate(src_address, num_pages, src_properties.perm,
|
||||||
|
OperationType::ChangePermissions));
|
||||||
|
|
||||||
|
// Apply the memory block updates.
|
||||||
|
m_memory_block_manager.Update(
|
||||||
|
std::addressof(src_allocator), src_address, num_pages, src_state,
|
||||||
|
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
|
||||||
|
KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Locked);
|
||||||
|
m_memory_block_manager.Update(
|
||||||
|
std::addressof(dst_allocator), dst_address, num_pages, KMemoryState::None,
|
||||||
|
KMemoryPermission::None, KMemoryAttribute::None,
|
||||||
|
KMemoryBlockDisableMergeAttribute::None, KMemoryBlockDisableMergeAttribute::Normal);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply the memory block updates.
|
|
||||||
m_memory_block_manager.Update(std::addressof(src_allocator), src_address, num_pages, src_state,
|
|
||||||
KMemoryPermission::UserReadWrite, KMemoryAttribute::None,
|
|
||||||
KMemoryBlockDisableMergeAttribute::None,
|
|
||||||
KMemoryBlockDisableMergeAttribute::Locked);
|
|
||||||
m_memory_block_manager.Update(std::addressof(dst_allocator), dst_address, num_pages,
|
|
||||||
KMemoryState::None, KMemoryPermission::None,
|
|
||||||
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::None,
|
|
||||||
KMemoryBlockDisableMergeAttribute::Normal);
|
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapPages(VAddr addr, const KPageGroup& page_linked_list,
|
Result KPageTable::AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||||
KMemoryPermission perm) {
|
size_t num_pages, KMemoryPermission perm) {
|
||||||
ASSERT(this->IsLockedByCurrentThread());
|
ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
VAddr cur_addr{addr};
|
// Create a page group to hold the pages we allocate.
|
||||||
|
KPageGroup pg{m_kernel, m_block_info_manager};
|
||||||
|
|
||||||
for (const auto& node : page_linked_list) {
|
// Allocate the pages.
|
||||||
if (const auto result{
|
R_TRY(
|
||||||
Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
|
m_kernel.MemoryManager().AllocateAndOpen(std::addressof(pg), num_pages, m_allocate_option));
|
||||||
result.IsError()) {
|
|
||||||
const size_t num_pages{(addr - cur_addr) / PageSize};
|
|
||||||
|
|
||||||
ASSERT(Operate(addr, num_pages, KMemoryPermission::None, OperationType::Unmap)
|
// Ensure that the page group is closed when we're done working with it.
|
||||||
.IsSuccess());
|
SCOPE_EXIT({ pg.Close(); });
|
||||||
|
|
||||||
R_RETURN(result);
|
// Clear all pages.
|
||||||
}
|
for (const auto& it : pg) {
|
||||||
|
std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()), m_heap_fill_value,
|
||||||
cur_addr += node.GetNumPages() * PageSize;
|
it.GetSize());
|
||||||
}
|
}
|
||||||
|
|
||||||
R_SUCCEED();
|
|
||||||
}
|
|
||||||
|
|
||||||
Result KPageTable::MapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state,
|
|
||||||
KMemoryPermission perm) {
|
|
||||||
// Check that the map is in range.
|
|
||||||
const size_t num_pages{page_linked_list.GetNumPages()};
|
|
||||||
const size_t size{num_pages * PageSize};
|
|
||||||
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
|
|
||||||
|
|
||||||
// Lock the table.
|
|
||||||
KScopedLightLock lk(m_general_lock);
|
|
||||||
|
|
||||||
// Check the memory state.
|
|
||||||
R_TRY(this->CheckMemoryState(address, size, KMemoryState::All, KMemoryState::Free,
|
|
||||||
KMemoryPermission::None, KMemoryPermission::None,
|
|
||||||
KMemoryAttribute::None, KMemoryAttribute::None));
|
|
||||||
|
|
||||||
// Create an update allocator.
|
|
||||||
Result allocator_result{ResultSuccess};
|
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
|
||||||
m_memory_block_slab_manager);
|
|
||||||
|
|
||||||
// Map the pages.
|
// Map the pages.
|
||||||
R_TRY(MapPages(address, page_linked_list, perm));
|
R_RETURN(this->Operate(address, num_pages, pg, OperationType::MapGroup));
|
||||||
|
}
|
||||||
|
|
||||||
// Update the blocks.
|
Result KPageTable::MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
|
const KPageGroup& pg, const KPageProperties properties,
|
||||||
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
|
bool reuse_ll) {
|
||||||
KMemoryBlockDisableMergeAttribute::None);
|
ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
// Note the current address, so that we can iterate.
|
||||||
|
const KProcessAddress start_address = address;
|
||||||
|
KProcessAddress cur_address = address;
|
||||||
|
|
||||||
|
// Ensure that we clean up on failure.
|
||||||
|
ON_RESULT_FAILURE {
|
||||||
|
ASSERT(!reuse_ll);
|
||||||
|
if (cur_address != start_address) {
|
||||||
|
const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
|
||||||
|
DisableMergeAttribute::None};
|
||||||
|
ASSERT(this->Operate(start_address, (cur_address - start_address) / PageSize,
|
||||||
|
unmap_properties.perm, OperationType::Unmap) == ResultSuccess);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Iterate, mapping all pages in the group.
|
||||||
|
for (const auto& block : pg) {
|
||||||
|
// Map and advance.
|
||||||
|
const KPageProperties cur_properties =
|
||||||
|
(cur_address == start_address)
|
||||||
|
? properties
|
||||||
|
: KPageProperties{properties.perm, properties.io, properties.uncached,
|
||||||
|
DisableMergeAttribute::None};
|
||||||
|
this->Operate(cur_address, block.GetNumPages(), cur_properties.perm, OperationType::Map,
|
||||||
|
block.GetAddress());
|
||||||
|
cur_address += block.GetSize();
|
||||||
|
}
|
||||||
|
|
||||||
|
// We succeeded!
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
|
void KPageTable::RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
|
||||||
bool is_pa_valid, VAddr region_start, size_t region_num_pages,
|
const KPageGroup& pg) {
|
||||||
|
ASSERT(this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
// Note the current address, so that we can iterate.
|
||||||
|
const KProcessAddress start_address = address;
|
||||||
|
const KProcessAddress last_address = start_address + size - 1;
|
||||||
|
const KProcessAddress end_address = last_address + 1;
|
||||||
|
|
||||||
|
// Iterate over the memory.
|
||||||
|
auto pg_it = pg.begin();
|
||||||
|
ASSERT(pg_it != pg.end());
|
||||||
|
|
||||||
|
KPhysicalAddress pg_phys_addr = pg_it->GetAddress();
|
||||||
|
size_t pg_pages = pg_it->GetNumPages();
|
||||||
|
|
||||||
|
auto it = m_memory_block_manager.FindIterator(start_address);
|
||||||
|
while (true) {
|
||||||
|
// Check that the iterator is valid.
|
||||||
|
ASSERT(it != m_memory_block_manager.end());
|
||||||
|
|
||||||
|
// Get the memory info.
|
||||||
|
const KMemoryInfo info = it->GetMemoryInfo();
|
||||||
|
|
||||||
|
// Determine the range to map.
|
||||||
|
KProcessAddress map_address = std::max(info.GetAddress(), start_address);
|
||||||
|
const KProcessAddress map_end_address = std::min(info.GetEndAddress(), end_address);
|
||||||
|
ASSERT(map_end_address != map_address);
|
||||||
|
|
||||||
|
// Determine if we should disable head merge.
|
||||||
|
const bool disable_head_merge =
|
||||||
|
info.GetAddress() >= start_address &&
|
||||||
|
True(info.GetDisableMergeAttribute() & KMemoryBlockDisableMergeAttribute::Normal);
|
||||||
|
const KPageProperties map_properties = {
|
||||||
|
info.GetPermission(), false, false,
|
||||||
|
disable_head_merge ? DisableMergeAttribute::DisableHead : DisableMergeAttribute::None};
|
||||||
|
|
||||||
|
// While we have pages to map, map them.
|
||||||
|
size_t map_pages = (map_end_address - map_address) / PageSize;
|
||||||
|
while (map_pages > 0) {
|
||||||
|
// Check if we're at the end of the physical block.
|
||||||
|
if (pg_pages == 0) {
|
||||||
|
// Ensure there are more pages to map.
|
||||||
|
ASSERT(pg_it != pg.end());
|
||||||
|
|
||||||
|
// Advance our physical block.
|
||||||
|
++pg_it;
|
||||||
|
pg_phys_addr = pg_it->GetAddress();
|
||||||
|
pg_pages = pg_it->GetNumPages();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Map whatever we can.
|
||||||
|
const size_t cur_pages = std::min(pg_pages, map_pages);
|
||||||
|
ASSERT(this->Operate(map_address, map_pages, map_properties.perm, OperationType::Map,
|
||||||
|
pg_phys_addr) == ResultSuccess);
|
||||||
|
|
||||||
|
// Advance.
|
||||||
|
map_address += cur_pages * PageSize;
|
||||||
|
map_pages -= cur_pages;
|
||||||
|
|
||||||
|
pg_phys_addr += cur_pages * PageSize;
|
||||||
|
pg_pages -= cur_pages;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if we're done.
|
||||||
|
if (last_address <= info.GetLastAddress()) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advance.
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check that we re-mapped precisely the page group.
|
||||||
|
ASSERT((++pg_it) == pg.end());
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTable::MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
|
||||||
|
KPhysicalAddress phys_addr, bool is_pa_valid,
|
||||||
|
KProcessAddress region_start, size_t region_num_pages,
|
||||||
KMemoryState state, KMemoryPermission perm) {
|
KMemoryState state, KMemoryPermission perm) {
|
||||||
ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
|
ASSERT(Common::IsAligned(alignment, PageSize) && alignment >= PageSize);
|
||||||
|
|
||||||
|
@ -2084,26 +2211,30 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment,
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
// Find a random address to map at.
|
// Find a random address to map at.
|
||||||
VAddr addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment, 0,
|
KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, alignment,
|
||||||
this->GetNumGuardPages());
|
0, this->GetNumGuardPages());
|
||||||
R_UNLESS(addr != 0, ResultOutOfMemory);
|
R_UNLESS(addr != 0, ResultOutOfMemory);
|
||||||
ASSERT(Common::IsAligned(addr, alignment));
|
ASSERT(Common::IsAligned(addr, alignment));
|
||||||
ASSERT(this->CanContain(addr, num_pages * PageSize, state));
|
ASSERT(this->CanContain(addr, num_pages * PageSize, state));
|
||||||
ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
|
ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
|
||||||
KMemoryPermission::None, KMemoryPermission::None,
|
KMemoryPermission::None, KMemoryPermission::None,
|
||||||
KMemoryAttribute::None, KMemoryAttribute::None)
|
KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
|
||||||
.IsSuccess());
|
|
||||||
|
|
||||||
// Create an update allocator.
|
// Create an update allocator.
|
||||||
Result allocator_result{ResultSuccess};
|
Result allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
||||||
m_memory_block_slab_manager);
|
m_memory_block_slab_manager);
|
||||||
|
R_TRY(allocator_result);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
// Perform mapping operation.
|
// Perform mapping operation.
|
||||||
if (is_pa_valid) {
|
if (is_pa_valid) {
|
||||||
R_TRY(this->Operate(addr, num_pages, perm, OperationType::Map, phys_addr));
|
const KPageProperties properties = {perm, false, false, DisableMergeAttribute::DisableHead};
|
||||||
|
R_TRY(this->Operate(addr, num_pages, properties.perm, OperationType::Map, phys_addr));
|
||||||
} else {
|
} else {
|
||||||
UNIMPLEMENTED();
|
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), addr, num_pages, perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update the blocks.
|
// Update the blocks.
|
||||||
|
@ -2116,28 +2247,45 @@ Result KPageTable::MapPages(VAddr* out_addr, size_t num_pages, size_t alignment,
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::UnmapPages(VAddr addr, const KPageGroup& page_linked_list) {
|
Result KPageTable::MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
|
||||||
ASSERT(this->IsLockedByCurrentThread());
|
KMemoryPermission perm) {
|
||||||
|
// Check that the map is in range.
|
||||||
|
const size_t size = num_pages * PageSize;
|
||||||
|
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
VAddr cur_addr{addr};
|
// Lock the table.
|
||||||
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
for (const auto& node : page_linked_list) {
|
// Check the memory state.
|
||||||
if (const auto result{Operate(cur_addr, node.GetNumPages(), KMemoryPermission::None,
|
size_t num_allocator_blocks;
|
||||||
OperationType::Unmap)};
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
|
||||||
result.IsError()) {
|
KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
|
||||||
R_RETURN(result);
|
KMemoryPermission::None, KMemoryAttribute::None,
|
||||||
}
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
cur_addr += node.GetNumPages() * PageSize;
|
// Create an update allocator.
|
||||||
}
|
Result allocator_result;
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
||||||
|
m_memory_block_slab_manager, num_allocator_blocks);
|
||||||
|
R_TRY(allocator_result);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
// Map the pages.
|
||||||
|
R_TRY(this->AllocateAndMapPagesImpl(updater.GetPageList(), address, num_pages, perm));
|
||||||
|
|
||||||
|
// Update the blocks.
|
||||||
|
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, state, perm,
|
||||||
|
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
|
||||||
|
KMemoryBlockDisableMergeAttribute::None);
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemoryState state) {
|
Result KPageTable::UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state) {
|
||||||
// Check that the unmap is in range.
|
// Check that the unmap is in range.
|
||||||
const size_t num_pages{page_linked_list.GetNumPages()};
|
const size_t size = num_pages * PageSize;
|
||||||
const size_t size{num_pages * PageSize};
|
|
||||||
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
|
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
// Lock the table.
|
// Lock the table.
|
||||||
|
@ -2151,13 +2299,18 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo
|
||||||
KMemoryAttribute::None));
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
// Create an update allocator.
|
// Create an update allocator.
|
||||||
Result allocator_result{ResultSuccess};
|
Result allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
||||||
m_memory_block_slab_manager, num_allocator_blocks);
|
m_memory_block_slab_manager, num_allocator_blocks);
|
||||||
R_TRY(allocator_result);
|
R_TRY(allocator_result);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
// Perform the unmap.
|
// Perform the unmap.
|
||||||
R_TRY(UnmapPages(address, page_linked_list));
|
const KPageProperties unmap_properties = {KMemoryPermission::None, false, false,
|
||||||
|
DisableMergeAttribute::None};
|
||||||
|
R_TRY(this->Operate(address, num_pages, unmap_properties.perm, OperationType::Unmap));
|
||||||
|
|
||||||
// Update the blocks.
|
// Update the blocks.
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
|
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
|
||||||
|
@ -2168,29 +2321,130 @@ Result KPageTable::UnmapPages(VAddr address, KPageGroup& page_linked_list, KMemo
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KPageTable::UnmapPages(VAddr address, size_t num_pages, KMemoryState state) {
|
Result KPageTable::MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
|
||||||
// Check that the unmap is in range.
|
KProcessAddress region_start, size_t region_num_pages,
|
||||||
const size_t size = num_pages * PageSize;
|
KMemoryState state, KMemoryPermission perm) {
|
||||||
R_UNLESS(this->Contains(address, size), ResultInvalidCurrentMemory);
|
ASSERT(!this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
// Ensure this is a valid map request.
|
||||||
|
const size_t num_pages = pg.GetNumPages();
|
||||||
|
R_UNLESS(this->CanContain(region_start, region_num_pages * PageSize, state),
|
||||||
|
ResultInvalidCurrentMemory);
|
||||||
|
R_UNLESS(num_pages < region_num_pages, ResultOutOfMemory);
|
||||||
|
|
||||||
// Lock the table.
|
// Lock the table.
|
||||||
KScopedLightLock lk(m_general_lock);
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
// Check the memory state.
|
// Find a random address to map at.
|
||||||
size_t num_allocator_blocks{};
|
KProcessAddress addr = this->FindFreeArea(region_start, region_num_pages, num_pages, PageSize,
|
||||||
|
0, this->GetNumGuardPages());
|
||||||
|
R_UNLESS(addr != 0, ResultOutOfMemory);
|
||||||
|
ASSERT(this->CanContain(addr, num_pages * PageSize, state));
|
||||||
|
ASSERT(this->CheckMemoryState(addr, num_pages * PageSize, KMemoryState::All, KMemoryState::Free,
|
||||||
|
KMemoryPermission::None, KMemoryPermission::None,
|
||||||
|
KMemoryAttribute::None, KMemoryAttribute::None) == ResultSuccess);
|
||||||
|
|
||||||
|
// Create an update allocator.
|
||||||
|
Result allocator_result;
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
||||||
|
m_memory_block_slab_manager);
|
||||||
|
R_TRY(allocator_result);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
// Perform mapping operation.
|
||||||
|
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
|
||||||
|
DisableMergeAttribute::DisableHead};
|
||||||
|
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
||||||
|
|
||||||
|
// Update the blocks.
|
||||||
|
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
|
||||||
|
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
|
||||||
|
KMemoryBlockDisableMergeAttribute::None);
|
||||||
|
|
||||||
|
// We successfully mapped the pages.
|
||||||
|
*out_addr = addr;
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTable::MapPageGroup(KProcessAddress addr, const KPageGroup& pg, KMemoryState state,
|
||||||
|
KMemoryPermission perm) {
|
||||||
|
ASSERT(!this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
// Ensure this is a valid map request.
|
||||||
|
const size_t num_pages = pg.GetNumPages();
|
||||||
|
const size_t size = num_pages * PageSize;
|
||||||
|
R_UNLESS(this->CanContain(addr, size, state), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Lock the table.
|
||||||
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
|
// Check if state allows us to map.
|
||||||
|
size_t num_allocator_blocks;
|
||||||
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), addr, size,
|
||||||
|
KMemoryState::All, KMemoryState::Free, KMemoryPermission::None,
|
||||||
|
KMemoryPermission::None, KMemoryAttribute::None,
|
||||||
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
|
// Create an update allocator.
|
||||||
|
Result allocator_result;
|
||||||
|
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
||||||
|
m_memory_block_slab_manager, num_allocator_blocks);
|
||||||
|
R_TRY(allocator_result);
|
||||||
|
|
||||||
|
// We're going to perform an update, so create a helper.
|
||||||
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
// Perform mapping operation.
|
||||||
|
const KPageProperties properties = {perm, state == KMemoryState::Io, false,
|
||||||
|
DisableMergeAttribute::DisableHead};
|
||||||
|
R_TRY(this->MapPageGroupImpl(updater.GetPageList(), addr, pg, properties, false));
|
||||||
|
|
||||||
|
// Update the blocks.
|
||||||
|
m_memory_block_manager.Update(std::addressof(allocator), addr, num_pages, state, perm,
|
||||||
|
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
|
||||||
|
KMemoryBlockDisableMergeAttribute::None);
|
||||||
|
|
||||||
|
// We successfully mapped the pages.
|
||||||
|
R_SUCCEED();
|
||||||
|
}
|
||||||
|
|
||||||
|
Result KPageTable::UnmapPageGroup(KProcessAddress address, const KPageGroup& pg,
|
||||||
|
KMemoryState state) {
|
||||||
|
ASSERT(!this->IsLockedByCurrentThread());
|
||||||
|
|
||||||
|
// Ensure this is a valid unmap request.
|
||||||
|
const size_t num_pages = pg.GetNumPages();
|
||||||
|
const size_t size = num_pages * PageSize;
|
||||||
|
R_UNLESS(this->CanContain(address, size, state), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
|
// Lock the table.
|
||||||
|
KScopedLightLock lk(m_general_lock);
|
||||||
|
|
||||||
|
// Check if state allows us to unmap.
|
||||||
|
size_t num_allocator_blocks;
|
||||||
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
|
R_TRY(this->CheckMemoryState(std::addressof(num_allocator_blocks), address, size,
|
||||||
KMemoryState::All, state, KMemoryPermission::None,
|
KMemoryState::All, state, KMemoryPermission::None,
|
||||||
KMemoryPermission::None, KMemoryAttribute::All,
|
KMemoryPermission::None, KMemoryAttribute::All,
|
||||||
KMemoryAttribute::None));
|
KMemoryAttribute::None));
|
||||||
|
|
||||||
|
// Check that the page group is valid.
|
||||||
|
R_UNLESS(this->IsValidPageGroup(pg, address, num_pages), ResultInvalidCurrentMemory);
|
||||||
|
|
||||||
// Create an update allocator.
|
// Create an update allocator.
|
||||||
Result allocator_result{ResultSuccess};
|
Result allocator_result;
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
||||||
m_memory_block_slab_manager, num_allocator_blocks);
|
m_memory_block_slab_manager, num_allocator_blocks);
|
||||||
R_TRY(allocator_result);
|
R_TRY(allocator_result);
|
||||||
|
|
||||||
// Perform the unmap.
|
// We're going to perform an update, so create a helper.
|
||||||
R_TRY(Operate(address, num_pages, KMemoryPermission::None, OperationType::Unmap));
|
KScopedPageTableUpdater updater(this);
|
||||||
|
|
||||||
|
// Perform unmapping operation.
|
||||||
|
const KPageProperties properties = {KMemoryPermission::None, false, false,
|
||||||
|
DisableMergeAttribute::None};
|
||||||
|
R_TRY(this->Operate(address, num_pages, properties.perm, OperationType::Unmap));
|
||||||
|
|
||||||
// Update the blocks.
|
// Update the blocks.
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
|
m_memory_block_manager.Update(std::addressof(allocator), address, num_pages, KMemoryState::Free,
|
||||||
|
@ -2550,54 +2804,6 @@ Result KPageTable::SetHeapSize(VAddr* out, size_t size) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultVal<VAddr> KPageTable::AllocateAndMapMemory(size_t needed_num_pages, size_t align,
|
|
||||||
bool is_map_only, VAddr region_start,
|
|
||||||
size_t region_num_pages, KMemoryState state,
|
|
||||||
KMemoryPermission perm, PAddr map_addr) {
|
|
||||||
KScopedLightLock lk(m_general_lock);
|
|
||||||
|
|
||||||
R_UNLESS(CanContain(region_start, region_num_pages * PageSize, state),
|
|
||||||
ResultInvalidCurrentMemory);
|
|
||||||
R_UNLESS(region_num_pages > needed_num_pages, ResultOutOfMemory);
|
|
||||||
const VAddr addr{
|
|
||||||
AllocateVirtualMemory(region_start, region_num_pages, needed_num_pages, align)};
|
|
||||||
R_UNLESS(addr, ResultOutOfMemory);
|
|
||||||
|
|
||||||
// Create an update allocator.
|
|
||||||
Result allocator_result{ResultSuccess};
|
|
||||||
KMemoryBlockManagerUpdateAllocator allocator(std::addressof(allocator_result),
|
|
||||||
m_memory_block_slab_manager);
|
|
||||||
|
|
||||||
if (is_map_only) {
|
|
||||||
R_TRY(Operate(addr, needed_num_pages, perm, OperationType::Map, map_addr));
|
|
||||||
} else {
|
|
||||||
// Create a page group tohold the pages we allocate.
|
|
||||||
KPageGroup pg{m_kernel, m_block_info_manager};
|
|
||||||
|
|
||||||
R_TRY(m_system.Kernel().MemoryManager().AllocateAndOpen(
|
|
||||||
&pg, needed_num_pages,
|
|
||||||
KMemoryManager::EncodeOption(m_memory_pool, m_allocation_option)));
|
|
||||||
|
|
||||||
// Ensure that the page group is closed when we're done working with it.
|
|
||||||
SCOPE_EXIT({ pg.Close(); });
|
|
||||||
|
|
||||||
// Clear all pages.
|
|
||||||
for (const auto& it : pg) {
|
|
||||||
std::memset(m_system.DeviceMemory().GetPointer<void>(it.GetAddress()),
|
|
||||||
m_heap_fill_value, it.GetSize());
|
|
||||||
}
|
|
||||||
|
|
||||||
R_TRY(Operate(addr, needed_num_pages, pg, OperationType::MapGroup));
|
|
||||||
}
|
|
||||||
|
|
||||||
// Update the blocks.
|
|
||||||
m_memory_block_manager.Update(std::addressof(allocator), addr, needed_num_pages, state, perm,
|
|
||||||
KMemoryAttribute::None, KMemoryBlockDisableMergeAttribute::Normal,
|
|
||||||
KMemoryBlockDisableMergeAttribute::None);
|
|
||||||
|
|
||||||
return addr;
|
|
||||||
}
|
|
||||||
|
|
||||||
Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
|
Result KPageTable::LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
|
||||||
KMemoryPermission perm, bool is_aligned,
|
KMemoryPermission perm, bool is_aligned,
|
||||||
bool check_heap) {
|
bool check_heap) {
|
||||||
|
|
|
@ -24,12 +24,36 @@ class System;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
|
enum class DisableMergeAttribute : u8 {
|
||||||
|
None = (0U << 0),
|
||||||
|
DisableHead = (1U << 0),
|
||||||
|
DisableHeadAndBody = (1U << 1),
|
||||||
|
EnableHeadAndBody = (1U << 2),
|
||||||
|
DisableTail = (1U << 3),
|
||||||
|
EnableTail = (1U << 4),
|
||||||
|
EnableAndMergeHeadBodyTail = (1U << 5),
|
||||||
|
EnableHeadBodyTail = EnableHeadAndBody | EnableTail,
|
||||||
|
DisableHeadBodyTail = DisableHeadAndBody | DisableTail,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct KPageProperties {
|
||||||
|
KMemoryPermission perm;
|
||||||
|
bool io;
|
||||||
|
bool uncached;
|
||||||
|
DisableMergeAttribute disable_merge_attributes;
|
||||||
|
};
|
||||||
|
static_assert(std::is_trivial_v<KPageProperties>);
|
||||||
|
static_assert(sizeof(KPageProperties) == sizeof(u32));
|
||||||
|
|
||||||
class KBlockInfoManager;
|
class KBlockInfoManager;
|
||||||
class KMemoryBlockManager;
|
class KMemoryBlockManager;
|
||||||
class KResourceLimit;
|
class KResourceLimit;
|
||||||
class KSystemResource;
|
class KSystemResource;
|
||||||
|
|
||||||
class KPageTable final {
|
class KPageTable final {
|
||||||
|
protected:
|
||||||
|
struct PageLinkedList;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll };
|
enum class ICacheInvalidationStrategy : u32 { InvalidateRange, InvalidateAll };
|
||||||
|
|
||||||
|
@ -57,27 +81,12 @@ public:
|
||||||
Result UnmapPhysicalMemory(VAddr addr, size_t size);
|
Result UnmapPhysicalMemory(VAddr addr, size_t size);
|
||||||
Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
|
Result MapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
|
||||||
Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
|
Result UnmapMemory(VAddr dst_addr, VAddr src_addr, size_t size);
|
||||||
Result MapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state,
|
|
||||||
KMemoryPermission perm);
|
|
||||||
Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
|
|
||||||
KMemoryState state, KMemoryPermission perm) {
|
|
||||||
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
|
|
||||||
this->GetRegionAddress(state),
|
|
||||||
this->GetRegionSize(state) / PageSize, state, perm));
|
|
||||||
}
|
|
||||||
Result UnmapPages(VAddr addr, KPageGroup& page_linked_list, KMemoryState state);
|
|
||||||
Result UnmapPages(VAddr address, size_t num_pages, KMemoryState state);
|
|
||||||
Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm);
|
Result SetProcessMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission svc_perm);
|
||||||
KMemoryInfo QueryInfo(VAddr addr);
|
KMemoryInfo QueryInfo(VAddr addr);
|
||||||
Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm);
|
Result SetMemoryPermission(VAddr addr, size_t size, Svc::MemoryPermission perm);
|
||||||
Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr);
|
Result SetMemoryAttribute(VAddr addr, size_t size, u32 mask, u32 attr);
|
||||||
Result SetMaxHeapSize(size_t size);
|
Result SetMaxHeapSize(size_t size);
|
||||||
Result SetHeapSize(VAddr* out, size_t size);
|
Result SetHeapSize(VAddr* out, size_t size);
|
||||||
ResultVal<VAddr> AllocateAndMapMemory(size_t needed_num_pages, size_t align, bool is_map_only,
|
|
||||||
VAddr region_start, size_t region_num_pages,
|
|
||||||
KMemoryState state, KMemoryPermission perm,
|
|
||||||
PAddr map_addr = 0);
|
|
||||||
|
|
||||||
Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
|
Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
|
||||||
KMemoryPermission perm, bool is_aligned, bool check_heap);
|
KMemoryPermission perm, bool is_aligned, bool check_heap);
|
||||||
Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
|
Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
|
||||||
|
@ -113,6 +122,40 @@ public:
|
||||||
|
|
||||||
bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
|
bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
|
||||||
|
|
||||||
|
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
|
||||||
|
KPhysicalAddress phys_addr, KProcessAddress region_start,
|
||||||
|
size_t region_num_pages, KMemoryState state, KMemoryPermission perm) {
|
||||||
|
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true, region_start,
|
||||||
|
region_num_pages, state, perm));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
|
||||||
|
KPhysicalAddress phys_addr, KMemoryState state, KMemoryPermission perm) {
|
||||||
|
R_RETURN(this->MapPages(out_addr, num_pages, alignment, phys_addr, true,
|
||||||
|
this->GetRegionAddress(state),
|
||||||
|
this->GetRegionSize(state) / PageSize, state, perm));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MapPages(KProcessAddress* out_addr, size_t num_pages, KMemoryState state,
|
||||||
|
KMemoryPermission perm) {
|
||||||
|
R_RETURN(this->MapPages(out_addr, num_pages, PageSize, 0, false,
|
||||||
|
this->GetRegionAddress(state),
|
||||||
|
this->GetRegionSize(state) / PageSize, state, perm));
|
||||||
|
}
|
||||||
|
|
||||||
|
Result MapPages(KProcessAddress address, size_t num_pages, KMemoryState state,
|
||||||
|
KMemoryPermission perm);
|
||||||
|
Result UnmapPages(KProcessAddress address, size_t num_pages, KMemoryState state);
|
||||||
|
|
||||||
|
Result MapPageGroup(KProcessAddress* out_addr, const KPageGroup& pg,
|
||||||
|
KProcessAddress region_start, size_t region_num_pages, KMemoryState state,
|
||||||
|
KMemoryPermission perm);
|
||||||
|
Result MapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state,
|
||||||
|
KMemoryPermission perm);
|
||||||
|
Result UnmapPageGroup(KProcessAddress address, const KPageGroup& pg, KMemoryState state);
|
||||||
|
void RemapPageGroup(PageLinkedList* page_list, KProcessAddress address, size_t size,
|
||||||
|
const KPageGroup& pg);
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
struct PageLinkedList {
|
struct PageLinkedList {
|
||||||
private:
|
private:
|
||||||
|
@ -166,11 +209,9 @@ private:
|
||||||
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
|
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
|
||||||
KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared;
|
KMemoryAttribute::IpcLocked | KMemoryAttribute::DeviceShared;
|
||||||
|
|
||||||
Result MapPages(VAddr addr, const KPageGroup& page_linked_list, KMemoryPermission perm);
|
Result MapPages(KProcessAddress* out_addr, size_t num_pages, size_t alignment,
|
||||||
Result MapPages(VAddr* out_addr, size_t num_pages, size_t alignment, PAddr phys_addr,
|
KPhysicalAddress phys_addr, bool is_pa_valid, KProcessAddress region_start,
|
||||||
bool is_pa_valid, VAddr region_start, size_t region_num_pages,
|
size_t region_num_pages, KMemoryState state, KMemoryPermission perm);
|
||||||
KMemoryState state, KMemoryPermission perm);
|
|
||||||
Result UnmapPages(VAddr addr, const KPageGroup& page_linked_list);
|
|
||||||
bool IsRegionContiguous(VAddr addr, u64 size) const;
|
bool IsRegionContiguous(VAddr addr, u64 size) const;
|
||||||
void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list);
|
void AddRegionToPages(VAddr start, size_t num_pages, KPageGroup& page_linked_list);
|
||||||
KMemoryInfo QueryInfoImpl(VAddr addr);
|
KMemoryInfo QueryInfoImpl(VAddr addr);
|
||||||
|
@ -265,6 +306,11 @@ private:
|
||||||
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
|
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
|
||||||
size_t size, KMemoryPermission prot_perm);
|
size_t size, KMemoryPermission prot_perm);
|
||||||
|
|
||||||
|
Result AllocateAndMapPagesImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||||
|
size_t num_pages, KMemoryPermission perm);
|
||||||
|
Result MapPageGroupImpl(PageLinkedList* page_list, KProcessAddress address,
|
||||||
|
const KPageGroup& pg, const KPageProperties properties, bool reuse_ll);
|
||||||
|
|
||||||
mutable KLightLock m_general_lock;
|
mutable KLightLock m_general_lock;
|
||||||
mutable KLightLock m_map_physical_memory_lock;
|
mutable KLightLock m_map_physical_memory_lock;
|
||||||
|
|
||||||
|
|
|
@ -417,9 +417,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
|
||||||
}
|
}
|
||||||
|
|
||||||
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
|
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
|
||||||
AllocateMainThreadStack(stack_size);
|
ASSERT(AllocateMainThreadStack(stack_size) == ResultSuccess);
|
||||||
resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
|
resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
|
||||||
resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
|
|
||||||
|
|
||||||
const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
|
const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
|
||||||
ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
|
ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
|
||||||
|
@ -675,20 +674,31 @@ void KProcess::ChangeState(State new_state) {
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
|
Result KProcess::AllocateMainThreadStack(std::size_t stack_size) {
|
||||||
ASSERT(stack_size);
|
// Ensure that we haven't already allocated stack.
|
||||||
|
ASSERT(main_thread_stack_size == 0);
|
||||||
|
|
||||||
// The kernel always ensures that the given stack size is page aligned.
|
// Ensure that we're allocating a valid stack.
|
||||||
main_thread_stack_size = Common::AlignUp(stack_size, PageSize);
|
stack_size = Common::AlignUp(stack_size, PageSize);
|
||||||
|
// R_UNLESS(stack_size + image_size <= m_max_process_memory, ResultOutOfMemory);
|
||||||
|
R_UNLESS(stack_size + image_size >= image_size, ResultOutOfMemory);
|
||||||
|
|
||||||
const VAddr start{page_table.GetStackRegionStart()};
|
// Place a tentative reservation of memory for our new stack.
|
||||||
const std::size_t size{page_table.GetStackRegionEnd() - start};
|
KScopedResourceReservation mem_reservation(this, Svc::LimitableResource::PhysicalMemoryMax,
|
||||||
|
stack_size);
|
||||||
|
R_UNLESS(mem_reservation.Succeeded(), ResultLimitReached);
|
||||||
|
|
||||||
CASCADE_RESULT(main_thread_stack_top,
|
// Allocate and map our stack.
|
||||||
page_table.AllocateAndMapMemory(
|
if (stack_size) {
|
||||||
main_thread_stack_size / PageSize, PageSize, false, start, size / PageSize,
|
KProcessAddress stack_bottom;
|
||||||
KMemoryState::Stack, KMemoryPermission::UserReadWrite));
|
R_TRY(page_table.MapPages(std::addressof(stack_bottom), stack_size / PageSize,
|
||||||
|
KMemoryState::Stack, KMemoryPermission::UserReadWrite));
|
||||||
|
|
||||||
main_thread_stack_top += main_thread_stack_size;
|
main_thread_stack_top = stack_bottom + stack_size;
|
||||||
|
main_thread_stack_size = stack_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// We succeeded! Commit our memory reservation.
|
||||||
|
mem_reservation.Commit();
|
||||||
|
|
||||||
R_SUCCEED();
|
R_SUCCEED();
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,15 +94,15 @@ Result KSharedMemory::Map(KProcess& target_process, VAddr address, std::size_t m
|
||||||
R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
|
R_UNLESS(map_perm == test_perm, ResultInvalidNewMemoryPermission);
|
||||||
}
|
}
|
||||||
|
|
||||||
return target_process.PageTable().MapPages(address, *page_group, KMemoryState::Shared,
|
return target_process.PageTable().MapPageGroup(address, *page_group, KMemoryState::Shared,
|
||||||
ConvertToKMemoryPermission(map_perm));
|
ConvertToKMemoryPermission(map_perm));
|
||||||
}
|
}
|
||||||
|
|
||||||
Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
|
Result KSharedMemory::Unmap(KProcess& target_process, VAddr address, std::size_t unmap_size) {
|
||||||
// Validate the size.
|
// Validate the size.
|
||||||
R_UNLESS(size == unmap_size, ResultInvalidSize);
|
R_UNLESS(size == unmap_size, ResultInvalidSize);
|
||||||
|
|
||||||
return target_process.PageTable().UnmapPages(address, *page_group, KMemoryState::Shared);
|
return target_process.PageTable().UnmapPageGroup(address, *page_group, KMemoryState::Shared);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -1492,8 +1492,8 @@ static Result MapProcessMemory(Core::System& system, VAddr dst_address, Handle p
|
||||||
KMemoryAttribute::All, KMemoryAttribute::None));
|
KMemoryAttribute::All, KMemoryAttribute::None));
|
||||||
|
|
||||||
// Map the group.
|
// Map the group.
|
||||||
R_TRY(dst_pt.MapPages(dst_address, pg, KMemoryState::SharedCode,
|
R_TRY(dst_pt.MapPageGroup(dst_address, pg, KMemoryState::SharedCode,
|
||||||
KMemoryPermission::UserReadWrite));
|
KMemoryPermission::UserReadWrite));
|
||||||
|
|
||||||
return ResultSuccess;
|
return ResultSuccess;
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,6 @@ add_executable(tests
|
||||||
core/core_timing.cpp
|
core/core_timing.cpp
|
||||||
core/internal_network/network.cpp
|
core/internal_network/network.cpp
|
||||||
precompiled_headers.h
|
precompiled_headers.h
|
||||||
tests.cpp
|
|
||||||
video_core/buffer_base.cpp
|
video_core/buffer_base.cpp
|
||||||
input_common/calibration_configuration_job.cpp
|
input_common/calibration_configuration_job.cpp
|
||||||
)
|
)
|
||||||
|
@ -22,7 +21,7 @@ add_executable(tests
|
||||||
create_target_directory_groups(tests)
|
create_target_directory_groups(tests)
|
||||||
|
|
||||||
target_link_libraries(tests PRIVATE common core input_common)
|
target_link_libraries(tests PRIVATE common core input_common)
|
||||||
target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2 Threads::Threads)
|
target_link_libraries(tests PRIVATE ${PLATFORM_LIBRARIES} Catch2::Catch2WithMain Threads::Threads)
|
||||||
|
|
||||||
add_test(NAME tests COMMAND tests)
|
add_test(NAME tests COMMAND tests)
|
||||||
|
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <type_traits>
|
#include <type_traits>
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include "common/bit_field.h"
|
#include "common/bit_field.h"
|
||||||
|
|
||||||
TEST_CASE("BitField", "[common]") {
|
TEST_CASE("BitField", "[common]") {
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "common/cityhash.h"
|
#include "common/cityhash.h"
|
||||||
|
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/fiber.h"
|
#include "common/fiber.h"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "common/host_memory.h"
|
#include "common/host_memory.h"
|
||||||
#include "common/literals.h"
|
#include "common/literals.h"
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
// SPDX-FileCopyrightText: 2017 Citra Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include "common/logging/backend.h"
|
#include "common/logging/backend.h"
|
||||||
#include "common/param_package.h"
|
#include "common/param_package.h"
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "common/range_map.h"
|
#include "common/range_map.h"
|
||||||
|
|
||||||
|
|
|
@ -7,7 +7,7 @@
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include "common/ring_buffer.h"
|
#include "common/ring_buffer.h"
|
||||||
|
|
||||||
namespace Common {
|
namespace Common {
|
||||||
|
|
|
@ -5,7 +5,7 @@
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/scratch_buffer.h"
|
#include "common/scratch_buffer.h"
|
||||||
|
|
||||||
|
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "common/unique_function.h"
|
#include "common/unique_function.h"
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: 2016 Dolphin Emulator Project
|
// SPDX-FileCopyrightText: 2016 Dolphin Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2021 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "core/internal_network/network.h"
|
#include "core/internal_network/network.h"
|
||||||
#include "core/internal_network/sockets.h"
|
#include "core/internal_network/sockets.h"
|
||||||
|
|
|
@ -6,7 +6,7 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <boost/asio.hpp>
|
#include <boost/asio.hpp>
|
||||||
#include <boost/crc.hpp>
|
#include <boost/crc.hpp>
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "input_common/drivers/udp_client.h"
|
#include "input_common/drivers/udp_client.h"
|
||||||
#include "input_common/helpers/udp_protocol.h"
|
#include "input_common/helpers/udp_protocol.h"
|
||||||
|
|
|
@ -4,7 +4,7 @@
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
|
@ -40,7 +40,7 @@
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"name": "catch2",
|
"name": "catch2",
|
||||||
"version": "2.13.9"
|
"version": "3.0.1"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "fmt",
|
"name": "fmt",
|
||||||
|
|
Loading…
Reference in a new issue