Compare commits

..

2 Commits

Author SHA1 Message Date
Morph
6323db9c42 general: Fix various typos 2022-11-09 21:24:04 -05:00
Morph
88955ac4e8 ir/texture_pass: Use host_info instead of querying Settings::values
Adds a new entry support_snorm_render_buffer to determine whether the host device supports rendering to SNORM render buffers.
2022-11-04 03:41:36 -04:00
122 changed files with 1436 additions and 5649 deletions

View File

@@ -133,13 +133,13 @@ if (NOT ENABLE_GENERIC)
if (MSVC)
detect_architecture("_M_AMD64" x86_64)
detect_architecture("_M_IX86" x86)
detect_architecture("_M_ARM" arm)
detect_architecture("_M_ARM64" arm64)
detect_architecture("_M_ARM" ARM)
detect_architecture("_M_ARM64" ARM64)
else()
detect_architecture("__x86_64__" x86_64)
detect_architecture("__i386__" x86)
detect_architecture("__arm__" arm)
detect_architecture("__aarch64__" arm64)
detect_architecture("__arm__" ARM)
detect_architecture("__aarch64__" ARM64)
endif()
endif()
@@ -218,11 +218,11 @@ if(ENABLE_QT)
set(QT_VERSION 5.15)
# Check for system Qt on Linux, fallback to bundled Qt
if (UNIX AND NOT APPLE)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
if (NOT YUZU_USE_BUNDLED_QT)
find_package(Qt5 ${QT_VERSION} COMPONENTS Widgets DBus Multimedia)
endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" AND (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT))
if (NOT Qt5_FOUND OR YUZU_USE_BUNDLED_QT)
# Check for dependencies, then enable bundled Qt download
# Check that the system GLIBCXX version is compatible
@@ -323,7 +323,7 @@ if(ENABLE_QT)
set(YUZU_QT_NO_CMAKE_SYSTEM_PATH "NO_CMAKE_SYSTEM_PATH")
endif()
if (UNIX AND NOT APPLE AND YUZU_USE_BUNDLED_QT)
if ((${CMAKE_SYSTEM_NAME} STREQUAL "Linux") AND YUZU_USE_BUNDLED_QT)
find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia DBus ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH})
else()
find_package(Qt5 ${QT_VERSION} REQUIRED COMPONENTS Widgets Concurrent Multimedia ${QT_PREFIX_HINT} ${YUZU_QT_NO_CMAKE_SYSTEM_PATH})

View File

@@ -7,14 +7,15 @@ include(DownloadExternals)
# xbyak
if (ARCHITECTURE_x86 OR ARCHITECTURE_x86_64)
add_subdirectory(xbyak)
add_library(xbyak INTERFACE)
file(MAKE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
file(COPY ${CMAKE_CURRENT_SOURCE_DIR}/xbyak/xbyak DESTINATION ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
target_include_directories(xbyak SYSTEM INTERFACE ${CMAKE_CURRENT_BINARY_DIR}/xbyak/include)
target_compile_definitions(xbyak INTERFACE XBYAK_NO_OP_NAMES)
endif()
# Dynarmic
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
if (ARCHITECTURE_arm64)
set(DYNARMIC_FRONTENDS "A32")
endif()
if (ARCHITECTURE_x86_64)
set(DYNARMIC_NO_BUNDLED_FMT ON)
set(DYNARMIC_IGNORE_ASSERTS ON CACHE BOOL "" FORCE)
add_subdirectory(dynarmic)

View File

@@ -217,7 +217,7 @@ else()
endif()
target_link_libraries(audio_core PUBLIC common core)
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
if (ARCHITECTURE_x86_64)
target_link_libraries(audio_core PRIVATE dynarmic)
endif()

View File

@@ -31,10 +31,8 @@
#ifndef _MSC_VER
#if defined(ARCHITECTURE_x86_64)
#ifdef ARCHITECTURE_x86_64
#define Crash() __asm__ __volatile__("int $3")
#elif defined(ARCHITECTURE_arm64)
#define Crash() __asm__ __volatile__("brk #0")
#else
#define Crash() exit(1)
#endif

View File

@@ -359,12 +359,6 @@ public:
}
});
long page_size = sysconf(_SC_PAGESIZE);
if (page_size != 0x1000) {
LOG_CRITICAL(HW_Memory, "page size {:#x} is incompatible with 4K paging", page_size);
throw std::bad_alloc{};
}
// Backing memory initialization
#if defined(__FreeBSD__) && __FreeBSD__ < 13
// XXX Drop after FreeBSD 12.* reaches EOL on 2024-06-30

View File

@@ -151,7 +151,6 @@ void UpdateRescalingInfo() {
ASSERT(false);
info.up_scale = 1;
info.down_shift = 0;
break;
}
info.up_factor = static_cast<f32>(info.up_scale) / (1U << info.down_shift);
info.down_factor = static_cast<f32>(1U << info.down_shift) / info.up_scale;

View File

@@ -4,27 +4,14 @@
#include <array>
#include <cstring>
#include <fstream>
#include <iterator>
#include <optional>
#include <string_view>
#include <thread>
#include <vector>
#include "common/bit_util.h"
#include "common/common_types.h"
#include "common/logging/log.h"
#include "common/x64/cpu_detect.h"
#ifdef _WIN32
#include <windows.h>
#endif
#ifdef _MSC_VER
#include <intrin.h>
static inline u64 xgetbv(u32 index) {
return _xgetbv(index);
}
#else
#if defined(__DragonFly__) || defined(__FreeBSD__)
@@ -52,11 +39,12 @@ static inline void __cpuid(int info[4], u32 function_id) {
}
#define _XCR_XFEATURE_ENABLED_MASK 0
static inline u64 xgetbv(u32 index) {
static inline u64 _xgetbv(u32 index) {
u32 eax, edx;
__asm__ __volatile__("xgetbv" : "=a"(eax), "=d"(edx) : "c"(index));
return ((u64)edx << 32) | eax;
}
#endif // _MSC_VER
namespace Common {
@@ -119,7 +107,7 @@ static CPUCaps Detect() {
// - Is the XSAVE bit set in CPUID?
// - XGETBV result has the XCR bit set.
if (Common::Bit<28>(cpu_id[2]) && Common::Bit<27>(cpu_id[2])) {
if ((xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
if ((_xgetbv(_XCR_XFEATURE_ENABLED_MASK) & 0x6) == 0x6) {
caps.avx = true;
if (Common::Bit<12>(cpu_id[2]))
caps.fma = true;
@@ -204,45 +192,4 @@ const CPUCaps& GetCPUCaps() {
return caps;
}
std::optional<int> GetProcessorCount() {
#if defined(_WIN32)
// Get the buffer length.
DWORD length = 0;
GetLogicalProcessorInformation(nullptr, &length);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
LOG_ERROR(Frontend, "Failed to query core count.");
return std::nullopt;
}
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(
length / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION));
// Now query the core count.
if (!GetLogicalProcessorInformation(buffer.data(), &length)) {
LOG_ERROR(Frontend, "Failed to query core count.");
return std::nullopt;
}
return static_cast<int>(
std::count_if(buffer.cbegin(), buffer.cend(), [](const auto& proc_info) {
return proc_info.Relationship == RelationProcessorCore;
}));
#elif defined(__unix__)
const int thread_count = std::thread::hardware_concurrency();
std::ifstream smt("/sys/devices/system/cpu/smt/active");
char state = '0';
if (smt) {
smt.read(&state, sizeof(state));
}
switch (state) {
case '0':
return thread_count;
case '1':
return thread_count / 2;
default:
return std::nullopt;
}
#else
// Shame on you
return std::nullopt;
#endif
}
} // namespace Common

View File

@@ -4,7 +4,6 @@
#pragma once
#include <optional>
#include <string_view>
#include "common/common_types.h"
@@ -75,7 +74,4 @@ struct CPUCaps {
*/
const CPUCaps& GetCPUCaps();
/// Detects CPU core count
std::optional<int> GetProcessorCount();
} // namespace Common

View File

@@ -120,8 +120,6 @@ add_library(core STATIC
file_sys/vfs_vector.h
file_sys/xts_archive.cpp
file_sys/xts_archive.h
frontend/applets/cabinet.cpp
frontend/applets/cabinet.h
frontend/applets/controller.cpp
frontend/applets/controller.h
frontend/applets/error.cpp
@@ -192,13 +190,11 @@ add_library(core STATIC
hle/kernel/k_code_memory.h
hle/kernel/k_condition_variable.cpp
hle/kernel/k_condition_variable.h
hle/kernel/k_debug.h
hle/kernel/k_dynamic_page_manager.h
hle/kernel/k_dynamic_resource_manager.h
hle/kernel/k_dynamic_slab_heap.h
hle/kernel/k_event.cpp
hle/kernel/k_event.h
hle/kernel/k_event_info.h
hle/kernel/k_handle_table.cpp
hle/kernel/k_handle_table.h
hle/kernel/k_interrupt_manager.cpp
@@ -226,8 +222,6 @@ add_library(core STATIC
hle/kernel/k_page_group.h
hle/kernel/k_page_table.cpp
hle/kernel/k_page_table.h
hle/kernel/k_page_table_manager.h
hle/kernel/k_page_table_slab_heap.h
hle/kernel/k_port.cpp
hle/kernel/k_port.h
hle/kernel/k_priority_queue.h
@@ -260,8 +254,6 @@ add_library(core STATIC
hle/kernel/k_synchronization_object.cpp
hle/kernel/k_synchronization_object.h
hle/kernel/k_system_control.h
hle/kernel/k_system_resource.cpp
hle/kernel/k_system_resource.h
hle/kernel/k_thread.cpp
hle/kernel/k_thread.h
hle/kernel/k_thread_local_page.cpp
@@ -314,8 +306,6 @@ add_library(core STATIC
hle/service/am/applet_ae.h
hle/service/am/applet_oe.cpp
hle/service/am/applet_oe.h
hle/service/am/applets/applet_cabinet.cpp
hle/service/am/applets/applet_cabinet.h
hle/service/am/applets/applet_controller.cpp
hle/service/am/applets/applet_controller.h
hle/service/am/applets/applet_error.cpp
@@ -501,6 +491,10 @@ add_library(core STATIC
hle/service/hid/irsensor/processor_base.h
hle/service/hid/irsensor/tera_plugin_processor.cpp
hle/service/hid/irsensor/tera_plugin_processor.h
hle/service/jit/jit_context.cpp
hle/service/jit/jit_context.h
hle/service/jit/jit.cpp
hle/service/jit/jit.h
hle/service/lbl/lbl.cpp
hle/service/lbl/lbl.h
hle/service/ldn/lan_discovery.cpp
@@ -805,18 +799,14 @@ if (ENABLE_WEB_SERVICE)
target_link_libraries(core PRIVATE web_service)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
if (ARCHITECTURE_x86_64)
target_sources(core PRIVATE
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h
arm/dynarmic/arm_dynarmic_32.cpp
arm/dynarmic/arm_dynarmic_32.h
arm/dynarmic/arm_dynarmic_64.cpp
arm/dynarmic/arm_dynarmic_64.h
arm/dynarmic/arm_dynarmic_cp15.cpp
arm/dynarmic/arm_dynarmic_cp15.h
hle/service/jit/jit_context.cpp
hle/service/jit/jit_context.h
hle/service/jit/jit.cpp
hle/service/jit/jit.h
)
target_link_libraries(core PRIVATE dynarmic)
endif()

View File

@@ -301,11 +301,6 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
}
}
#ifdef ARCHITECTURE_arm64
// TODO: remove when fixed in dynarmic
config.optimizations &= ~Dynarmic::OptimizationFlag::BlockLinking;
#endif
return std::make_unique<Dynarmic::A32::Jit>(config);
}

View File

@@ -52,16 +52,12 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
case 4:
// CP15_DATA_SYNC_BARRIER
return Callback{
[](void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#if defined(_MSC_VER) && defined(ARCHITECTURE_x86_64)
[](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#ifdef _MSC_VER
_mm_mfence();
_mm_lfence();
#elif defined(ARCHITECTURE_x86_64)
asm volatile("mfence\n\tlfence\n\t" : : : "memory");
#elif defined(ARCHITECTURE_arm64)
asm volatile("dsb sy\n\t" : : : "memory");
#else
#error Unsupported architecture
asm volatile("mfence\n\tlfence\n\t" : : : "memory");
#endif
return 0;
},
@@ -70,15 +66,11 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
case 5:
// CP15_DATA_MEMORY_BARRIER
return Callback{
[](void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#if defined(_MSC_VER) && defined(ARCHITECTURE_x86_64)
[](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#ifdef _MSC_VER
_mm_mfence();
#elif defined(ARCHITECTURE_x86_64)
asm volatile("mfence\n\t" : : : "memory");
#elif defined(ARCHITECTURE_arm64)
asm volatile("dmb sy\n\t" : : : "memory");
#else
#error Unsupported architecture
asm volatile("mfence\n\t" : : : "memory");
#endif
return 0;
},
@@ -123,7 +115,7 @@ CallbackOrAccessOneWord DynarmicCP15::CompileGetOneWord(bool two, unsigned opc1,
CallbackOrAccessTwoWords DynarmicCP15::CompileGetTwoWords(bool two, unsigned opc, CoprocReg CRm) {
if (!two && opc == 0 && CRm == CoprocReg::C14) {
// CNTPCT
const auto callback = [](void* arg, u32, u32) -> u64 {
const auto callback = [](Dynarmic::A32::Jit*, void* arg, u32, u32) -> u64 {
const auto& parent_arg = *static_cast<ARM_Dynarmic_32*>(arg);
return parent_arg.system.CoreTiming().GetClockTicks();
};

View File

@@ -1,7 +1,7 @@
// SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
#ifdef ARCHITECTURE_x86_64
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#endif
#include "core/arm/exclusive_monitor.h"
@@ -13,7 +13,7 @@ ExclusiveMonitor::~ExclusiveMonitor() = default;
std::unique_ptr<Core::ExclusiveMonitor> MakeExclusiveMonitor(Memory::Memory& memory,
std::size_t num_cores) {
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
#ifdef ARCHITECTURE_x86_64
return std::make_unique<Core::DynarmicExclusiveMonitor>(memory, num_cores);
#else
// TODO(merry): Passthrough exclusive monitor

View File

@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/logging/log.h"
#include "core/frontend/applets/cabinet.h"
#include <thread>
namespace Core::Frontend {
CabinetApplet::~CabinetApplet() = default;
void DefaultCabinetApplet::ShowCabinetApplet(
const CabinetCallback& callback, const CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const {
LOG_WARNING(Service_AM, "(STUBBED) called");
callback(false, {});
}
} // namespace Core::Frontend

View File

@@ -1,37 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <functional>
#include "core/hle/service/nfp/nfp_types.h"
namespace Service::NFP {
class NfpDevice;
} // namespace Service::NFP
namespace Core::Frontend {
struct CabinetParameters {
Service::NFP::TagInfo tag_info;
Service::NFP::RegisterInfo register_info;
Service::NFP::CabinetMode mode;
};
using CabinetCallback = std::function<void(bool, const std::string&)>;
class CabinetApplet {
public:
virtual ~CabinetApplet();
virtual void ShowCabinetApplet(const CabinetCallback& callback,
const CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const = 0;
};
class DefaultCabinetApplet final : public CabinetApplet {
public:
void ShowCabinetApplet(const CabinetCallback& callback, const CabinetParameters& parameters,
std::shared_ptr<Service::NFP::NfpDevice> nfp_device) const override;
};
} // namespace Core::Frontend

View File

@@ -149,7 +149,7 @@ public:
context->AddDomainObject(std::move(iface));
} else {
kernel.CurrentProcess()->GetResourceLimit()->Reserve(
Kernel::LimitableResource::SessionCountMax, 1);
Kernel::LimitableResource::Sessions, 1);
auto* session = Kernel::KSession::Create(kernel);
session->Initialize(nullptr, iface->GetServiceName());

View File

@@ -8,10 +8,6 @@
namespace Kernel::Board::Nintendo::Nx {
class KSystemControl {
public:
// This can be overridden as needed.
static constexpr size_t SecureAppletMemorySize = 4 * 1024 * 1024; // 4_MB
public:
class Init {
public:

View File

@@ -27,12 +27,16 @@ namespace Kernel {
SessionRequestHandler::SessionRequestHandler(KernelCore& kernel_, const char* service_name_,
ServiceThreadType thread_type)
: kernel{kernel_}, service_thread{thread_type == ServiceThreadType::CreateNew
? kernel.CreateServiceThread(service_name_)
: kernel.GetDefaultServiceThread()} {}
: kernel{kernel_} {
if (thread_type == ServiceThreadType::CreateNew) {
service_thread = kernel.CreateServiceThread(service_name_);
} else {
service_thread = kernel.GetDefaultServiceThread();
}
}
SessionRequestHandler::~SessionRequestHandler() {
kernel.ReleaseServiceThread(service_thread);
kernel.ReleaseServiceThread(service_thread.lock());
}
void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
@@ -45,7 +49,7 @@ void SessionRequestHandler::AcceptSession(KServerPort* server_port) {
void SessionRequestHandler::RegisterSession(KServerSession* server_session,
std::shared_ptr<SessionRequestManager> manager) {
manager->SetSessionHandler(shared_from_this());
service_thread.RegisterServerSession(server_session, manager);
service_thread.lock()->RegisterServerSession(server_session, manager);
server_session->Close();
}

View File

@@ -82,13 +82,13 @@ public:
void RegisterSession(KServerSession* server_session,
std::shared_ptr<SessionRequestManager> manager);
ServiceThread& GetServiceThread() const {
std::weak_ptr<ServiceThread> GetServiceThread() const {
return service_thread;
}
protected:
KernelCore& kernel;
ServiceThread& service_thread;
std::weak_ptr<ServiceThread> service_thread;
};
using SessionRequestHandlerWeakPtr = std::weak_ptr<SessionRequestHandler>;
@@ -154,7 +154,7 @@ public:
session_handler = std::move(handler);
}
ServiceThread& GetServiceThread() const {
std::weak_ptr<ServiceThread> GetServiceThread() const {
return session_handler->GetServiceThread();
}

View File

@@ -10,9 +10,7 @@
#include "core/hardware_properties.h"
#include "core/hle/kernel/init/init_slab_setup.h"
#include "core/hle/kernel/k_code_memory.h"
#include "core/hle/kernel/k_debug.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_event_info.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_buffer.h"
@@ -24,7 +22,6 @@
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_shared_memory_info.h"
#include "core/hle/kernel/k_system_control.h"
#include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_local_page.h"
#include "core/hle/kernel/k_transfer_memory.h"
@@ -47,10 +44,7 @@ namespace Kernel::Init {
HANDLER(KThreadLocalPage, \
(SLAB_COUNT(KProcess) + (SLAB_COUNT(KProcess) + SLAB_COUNT(KThread)) / 8), \
##__VA_ARGS__) \
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__) \
HANDLER(KEventInfo, (SLAB_COUNT(KThread) + SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
HANDLER(KDebug, (SLAB_COUNT(KDebug)), ##__VA_ARGS__) \
HANDLER(KSecureSystemResource, (SLAB_COUNT(KProcess)), ##__VA_ARGS__)
HANDLER(KResourceLimit, (SLAB_COUNT(KResourceLimit)), ##__VA_ARGS__)
namespace {
@@ -79,20 +73,8 @@ constexpr size_t SlabCountKResourceLimit = 5;
constexpr size_t SlabCountKDebug = Core::Hardware::NUM_CPU_CORES;
constexpr size_t SlabCountKIoPool = 1;
constexpr size_t SlabCountKIoRegion = 6;
constexpr size_t SlabcountKSessionRequestMappings = 40;
constexpr size_t SlabCountExtraKThread = (1024 + 256 + 256) - SlabCountKThread;
namespace test {
static_assert(KernelPageBufferHeapSize ==
2 * PageSize + (SlabCountKProcess + SlabCountKThread +
(SlabCountKProcess + SlabCountKThread) / 8) *
PageSize);
static_assert(KernelPageBufferAdditionalSize ==
(SlabCountExtraKThread + (SlabCountExtraKThread / 8)) * PageSize);
} // namespace test
constexpr size_t SlabCountExtraKThread = 160;
/// Helper function to translate from the slab virtual address to the reserved location in physical
/// memory.
@@ -127,7 +109,7 @@ VAddr InitializeSlabHeap(Core::System& system, KMemoryLayout& memory_layout, VAd
}
size_t CalculateSlabHeapGapSize() {
constexpr size_t KernelSlabHeapGapSize = 2_MiB - 320_KiB;
constexpr size_t KernelSlabHeapGapSize = 2_MiB - 296_KiB;
static_assert(KernelSlabHeapGapSize <= KernelSlabHeapGapsSizeMax);
return KernelSlabHeapGapSize;
}
@@ -152,7 +134,6 @@ KSlabResourceCounts KSlabResourceCounts::CreateDefault() {
.num_KDebug = SlabCountKDebug,
.num_KIoPool = SlabCountKIoPool,
.num_KIoRegion = SlabCountKIoRegion,
.num_KSessionRequestMappings = SlabcountKSessionRequestMappings,
};
}
@@ -183,6 +164,29 @@ size_t CalculateTotalSlabHeapSize(const KernelCore& kernel) {
return size;
}
void InitializeKPageBufferSlabHeap(Core::System& system) {
auto& kernel = system.Kernel();
const auto& counts = kernel.SlabResourceCounts();
const size_t num_pages =
counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8;
const size_t slab_size = num_pages * PageSize;
// Reserve memory from the system resource limit.
ASSERT(kernel.GetSystemResourceLimit()->Reserve(LimitableResource::PhysicalMemory, slab_size));
// Allocate memory for the slab.
constexpr auto AllocateOption = KMemoryManager::EncodeOption(
KMemoryManager::Pool::System, KMemoryManager::Direction::FromFront);
const PAddr slab_address =
kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, AllocateOption);
ASSERT(slab_address != 0);
// Initialize the slabheap.
KPageBuffer::InitializeSlabHeap(kernel, system.DeviceMemory().GetPointer<void>(slab_address),
slab_size);
}
void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
auto& kernel = system.Kernel();
@@ -254,30 +258,3 @@ void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout) {
}
} // namespace Kernel::Init
namespace Kernel {
void KPageBufferSlabHeap::Initialize(Core::System& system) {
auto& kernel = system.Kernel();
const auto& counts = kernel.SlabResourceCounts();
const size_t num_pages =
counts.num_KProcess + counts.num_KThread + (counts.num_KProcess + counts.num_KThread) / 8;
const size_t slab_size = num_pages * PageSize;
// Reserve memory from the system resource limit.
ASSERT(
kernel.GetSystemResourceLimit()->Reserve(LimitableResource::PhysicalMemoryMax, slab_size));
// Allocate memory for the slab.
constexpr auto AllocateOption = KMemoryManager::EncodeOption(
KMemoryManager::Pool::System, KMemoryManager::Direction::FromFront);
const PAddr slab_address =
kernel.MemoryManager().AllocateAndOpenContinuous(num_pages, 1, AllocateOption);
ASSERT(slab_address != 0);
// Initialize the slabheap.
KPageBuffer::InitializeSlabHeap(kernel, system.DeviceMemory().GetPointer<void>(slab_address),
slab_size);
}
} // namespace Kernel

View File

@@ -33,11 +33,11 @@ struct KSlabResourceCounts {
size_t num_KDebug;
size_t num_KIoPool;
size_t num_KIoRegion;
size_t num_KSessionRequestMappings;
};
void InitializeSlabResourceCounts(KernelCore& kernel);
size_t CalculateTotalSlabHeapSize(const KernelCore& kernel);
void InitializeKPageBufferSlabHeap(Core::System& system);
void InitializeSlabHeaps(Core::System& system, KMemoryLayout& memory_layout);
} // namespace Kernel::Init

View File

@@ -16,7 +16,6 @@
#include "core/hle/kernel/k_session.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_synchronization_object.h"
#include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_transfer_memory.h"
@@ -120,6 +119,4 @@ static_assert(std::is_final_v<KTransferMemory> && std::is_base_of_v<KAutoObject,
// static_assert(std::is_final_v<KCodeMemory> &&
// std::is_base_of_v<KAutoObject, KCodeMemory>);
static_assert(std::is_base_of_v<KAutoObject, KSystemResource>);
} // namespace Kernel

View File

@@ -10,8 +10,6 @@ namespace Kernel {
class KAutoObject;
class KSystemResource;
class KClassTokenGenerator {
public:
using TokenBaseType = u16;
@@ -60,7 +58,7 @@ private:
if constexpr (std::is_same<T, KAutoObject>::value) {
static_assert(T::ObjectType == ObjectType::KAutoObject);
return 0;
} else if constexpr (!std::is_final<T>::value && !std::same_as<T, KSystemResource>) {
} else if constexpr (!std::is_final<T>::value) {
static_assert(ObjectType::BaseClassesStart <= T::ObjectType &&
T::ObjectType < ObjectType::BaseClassesEnd);
constexpr auto ClassIndex = static_cast<TokenBaseType>(T::ObjectType) -
@@ -110,8 +108,6 @@ public:
KSessionRequest,
KCodeMemory,
KSystemResource,
// NOTE: True order for these has not been determined yet.
KAlpha,
KBeta,

View File

@@ -61,7 +61,7 @@ bool KClientPort::IsSignaled() const {
Result KClientPort::CreateSession(KClientSession** out) {
// Reserve a new session from the resource limit.
KScopedResourceReservation session_reservation(kernel.CurrentProcess()->GetResourceLimit(),
LimitableResource::SessionCountMax);
LimitableResource::Sessions);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
// Update the session counts.

View File

@@ -1,20 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
class KDebug final : public KAutoObjectWithSlabHeapAndContainer<KDebug, KAutoObjectWithList> {
KERNEL_AUTOOBJECT_TRAITS(KDebug, KAutoObject);
public:
explicit KDebug(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
};
} // namespace Kernel

View File

@@ -3,8 +3,6 @@
#pragma once
#include <vector>
#include "common/alignment.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_page_bitmap.h"
@@ -35,36 +33,28 @@ public:
return reinterpret_cast<T*>(m_backing_memory.data() + (addr - m_address));
}
Result Initialize(VAddr memory, size_t size, size_t align) {
Result Initialize(VAddr addr, size_t sz) {
// We need to have positive size.
R_UNLESS(size > 0, ResultOutOfMemory);
m_backing_memory.resize(size);
R_UNLESS(sz > 0, ResultOutOfMemory);
m_backing_memory.resize(sz);
// Set addresses.
m_address = memory;
m_aligned_address = Common::AlignDown(memory, align);
// Calculate extents.
const size_t managed_size = m_address + size - m_aligned_address;
const size_t overhead_size = Common::AlignUp(
KPageBitmap::CalculateManagementOverheadSize(managed_size / sizeof(PageBuffer)),
sizeof(PageBuffer));
R_UNLESS(overhead_size < size, ResultOutOfMemory);
// Calculate management overhead.
const size_t management_size =
KPageBitmap::CalculateManagementOverheadSize(sz / sizeof(PageBuffer));
const size_t allocatable_size = sz - management_size;
// Set tracking fields.
m_size = Common::AlignDown(size - overhead_size, sizeof(PageBuffer));
m_count = m_size / sizeof(PageBuffer);
m_address = addr;
m_size = Common::AlignDown(allocatable_size, sizeof(PageBuffer));
m_count = allocatable_size / sizeof(PageBuffer);
R_UNLESS(m_count > 0, ResultOutOfMemory);
// Clear the management region.
u64* management_ptr = GetPointer<u64>(m_address + size - overhead_size);
std::memset(management_ptr, 0, overhead_size);
u64* management_ptr = GetPointer<u64>(m_address + allocatable_size);
std::memset(management_ptr, 0, management_size);
// Initialize the bitmap.
const size_t allocatable_region_size =
(m_address + size - overhead_size) - m_aligned_address;
ASSERT(allocatable_region_size >= sizeof(PageBuffer));
m_page_bitmap.Initialize(management_ptr, allocatable_region_size / sizeof(PageBuffer));
m_page_bitmap.Initialize(management_ptr, m_count);
// Free the pages to the bitmap.
for (size_t i = 0; i < m_count; i++) {
@@ -72,8 +62,7 @@ public:
std::memset(GetPointer<PageBuffer>(m_address) + i, 0, PageSize);
// Set the bit for the free page.
m_page_bitmap.SetBit((m_address + (i * sizeof(PageBuffer)) - m_aligned_address) /
sizeof(PageBuffer));
m_page_bitmap.SetBit(i);
}
R_SUCCEED();
@@ -112,28 +101,7 @@ public:
m_page_bitmap.ClearBit(offset);
m_peak = std::max(m_peak, (++m_used));
return GetPointer<PageBuffer>(m_aligned_address) + offset;
}
PageBuffer* Allocate(size_t count) {
// Take the lock.
// TODO(bunnei): We should disable interrupts here via KScopedInterruptDisable.
KScopedSpinLock lk(m_lock);
// Find a random free block.
s64 soffset = m_page_bitmap.FindFreeRange(count);
if (soffset < 0) [[likely]] {
return nullptr;
}
const size_t offset = static_cast<size_t>(soffset);
// Update our tracking.
m_page_bitmap.ClearRange(offset, count);
m_used += count;
m_peak = std::max(m_peak, m_used);
return GetPointer<PageBuffer>(m_aligned_address) + offset;
return GetPointer<PageBuffer>(m_address) + offset;
}
void Free(PageBuffer* pb) {
@@ -145,7 +113,7 @@ public:
KScopedSpinLock lk(m_lock);
// Set the bit for the free page.
size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_aligned_address) / sizeof(PageBuffer);
size_t offset = (reinterpret_cast<uintptr_t>(pb) - m_address) / sizeof(PageBuffer);
m_page_bitmap.SetBit(offset);
// Decrement our used count.
@@ -159,7 +127,6 @@ private:
size_t m_peak{};
size_t m_count{};
VAddr m_address{};
VAddr m_aligned_address{};
size_t m_size{};
// TODO(bunnei): Back by host memory until we emulate kernel virtual address space.

View File

@@ -6,7 +6,6 @@
#include "common/common_funcs.h"
#include "core/hle/kernel/k_dynamic_slab_heap.h"
#include "core/hle/kernel/k_memory_block.h"
#include "core/hle/kernel/k_page_group.h"
namespace Kernel {
@@ -52,10 +51,8 @@ private:
DynamicSlabType* m_slab_heap{};
};
class KBlockInfoManager : public KDynamicResourceManager<KBlockInfo> {};
class KMemoryBlockSlabManager : public KDynamicResourceManager<KMemoryBlock> {};
using KBlockInfoSlabHeap = typename KBlockInfoManager::DynamicSlabType;
using KMemoryBlockSlabHeap = typename KMemoryBlockSlabManager::DynamicSlabType;
} // namespace Kernel

View File

@@ -20,12 +20,8 @@ void KEvent::Initialize(KProcess* owner) {
m_readable_event.Initialize(this);
// Set our owner process.
// HACK: this should never be nullptr, but service threads don't have a
// proper parent process yet.
if (owner != nullptr) {
m_owner = owner;
m_owner->Open();
}
m_owner = owner;
m_owner->Open();
// Mark initialized.
m_initialized = true;
@@ -54,11 +50,8 @@ Result KEvent::Clear() {
void KEvent::PostDestroy(uintptr_t arg) {
// Release the event count resource the owner process holds.
KProcess* owner = reinterpret_cast<KProcess*>(arg);
if (owner != nullptr) {
owner->GetResourceLimit()->Release(LimitableResource::EventCountMax, 1);
owner->Close();
}
owner->GetResourceLimit()->Release(LimitableResource::Events, 1);
owner->Close();
}
} // namespace Kernel

View File

@@ -1,64 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <boost/intrusive/list.hpp>
#include "core/hle/kernel/slab_helpers.h"
#include "core/hle/kernel/svc_types.h"
namespace Kernel {
class KEventInfo : public KSlabAllocated<KEventInfo>, public boost::intrusive::list_base_hook<> {
public:
struct InfoCreateThread {
u32 thread_id{};
uintptr_t tls_address{};
};
struct InfoExitProcess {
Svc::ProcessExitReason reason{};
};
struct InfoExitThread {
Svc::ThreadExitReason reason{};
};
struct InfoException {
Svc::DebugException exception_type{};
s32 exception_data_count{};
uintptr_t exception_address{};
std::array<uintptr_t, 4> exception_data{};
};
struct InfoSystemCall {
s64 tick{};
s32 id{};
};
public:
KEventInfo() = default;
~KEventInfo() = default;
public:
Svc::DebugEvent event{};
u32 thread_id{};
u32 flags{};
bool is_attached{};
bool continue_flag{};
bool ignore_continue{};
bool close_once{};
union {
InfoCreateThread create_thread;
InfoExitProcess exit_process;
InfoExitThread exit_thread;
InfoException exception;
InfoSystemCall system_call;
} info{};
KThread* debug_thread{};
};
} // namespace Kernel

View File

@@ -5,11 +5,14 @@
namespace Kernel {
KHandleTable::KHandleTable(KernelCore& kernel_) : kernel{kernel_} {}
KHandleTable::~KHandleTable() = default;
Result KHandleTable::Finalize() {
// Get the table and clear our record of it.
u16 saved_table_size = 0;
{
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
std::swap(m_table_size, saved_table_size);
@@ -22,28 +25,28 @@ Result KHandleTable::Finalize() {
}
}
R_SUCCEED();
return ResultSuccess;
}
bool KHandleTable::Remove(Handle handle) {
// Don't allow removal of a pseudo-handle.
if (Svc::IsPseudoHandle(handle)) [[unlikely]] {
if (Svc::IsPseudoHandle(handle)) {
return false;
}
// Handles must not have reserved bits set.
const auto handle_pack = HandlePack(handle);
if (handle_pack.reserved != 0) [[unlikely]] {
if (handle_pack.reserved != 0) {
return false;
}
// Find the object and free the entry.
KAutoObject* obj = nullptr;
{
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
if (this->IsValidHandle(handle)) [[likely]] {
if (this->IsValidHandle(handle)) {
const auto index = handle_pack.index;
obj = m_objects[index];
@@ -54,13 +57,13 @@ bool KHandleTable::Remove(Handle handle) {
}
// Close the object.
m_kernel.UnregisterInUseObject(obj);
kernel.UnregisterInUseObject(obj);
obj->Close();
return true;
}
Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
// Never exceed our capacity.
@@ -79,22 +82,22 @@ Result KHandleTable::Add(Handle* out_handle, KAutoObject* obj) {
*out_handle = EncodeHandle(static_cast<u16>(index), linear_id);
}
R_SUCCEED();
return ResultSuccess;
}
Result KHandleTable::Reserve(Handle* out_handle) {
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
// Never exceed our capacity.
R_UNLESS(m_count < m_table_size, ResultOutOfHandles);
*out_handle = EncodeHandle(static_cast<u16>(this->AllocateEntry()), this->AllocateLinearId());
R_SUCCEED();
return ResultSuccess;
}
void KHandleTable::Unreserve(Handle handle) {
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
// Unpack the handle.
@@ -105,7 +108,7 @@ void KHandleTable::Unreserve(Handle handle) {
ASSERT(reserved == 0);
ASSERT(linear_id != 0);
if (index < m_table_size) [[likely]] {
if (index < m_table_size) {
// NOTE: This code does not check the linear id.
ASSERT(m_objects[index] == nullptr);
this->FreeEntry(index);
@@ -113,7 +116,7 @@ void KHandleTable::Unreserve(Handle handle) {
}
void KHandleTable::Register(Handle handle, KAutoObject* obj) {
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
// Unpack the handle.
@@ -124,7 +127,7 @@ void KHandleTable::Register(Handle handle, KAutoObject* obj) {
ASSERT(reserved == 0);
ASSERT(linear_id != 0);
if (index < m_table_size) [[likely]] {
if (index < m_table_size) {
// Set the entry.
ASSERT(m_objects[index] == nullptr);

View File

@@ -21,38 +21,33 @@ namespace Kernel {
class KernelCore;
class KHandleTable {
public:
YUZU_NON_COPYABLE(KHandleTable);
YUZU_NON_MOVEABLE(KHandleTable);
public:
static constexpr size_t MaxTableSize = 1024;
public:
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
explicit KHandleTable(KernelCore& kernel_);
~KHandleTable();
Result Initialize(s32 size) {
// Check that the table size is valid.
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
// Lock.
KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock);
// Initialize all fields.
m_max_count = 0;
m_table_size = static_cast<s16>((size <= 0) ? MaxTableSize : size);
m_table_size = static_cast<u16>((size <= 0) ? MaxTableSize : size);
m_next_linear_id = MinLinearId;
m_count = 0;
m_free_head_index = -1;
// Free all entries.
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
for (s16 i = 0; i < static_cast<s16>(m_table_size); ++i) {
m_objects[i] = nullptr;
m_entry_infos[i].next_free_index = static_cast<s16>(i - 1);
m_entry_infos[i].next_free_index = i - 1;
m_free_head_index = i;
}
R_SUCCEED();
return ResultSuccess;
}
size_t GetTableSize() const {
@@ -71,13 +66,13 @@ public:
template <typename T = KAutoObject>
KScopedAutoObject<T> GetObjectWithoutPseudoHandle(Handle handle) const {
// Lock and look up in table.
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
if constexpr (std::is_same_v<T, KAutoObject>) {
return this->GetObjectImpl(handle);
} else {
if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) [[likely]] {
if (auto* obj = this->GetObjectImpl(handle); obj != nullptr) {
return obj->DynamicCast<T*>();
} else {
return nullptr;
@@ -90,13 +85,13 @@ public:
// Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) {
auto* const cur_process = m_kernel.CurrentProcess();
auto* const cur_process = kernel.CurrentProcess();
ASSERT(cur_process != nullptr);
return cur_process;
}
} else if constexpr (std::derived_from<KThread, T>) {
if (handle == Svc::PseudoHandle::CurrentThread) {
auto* const cur_thread = GetCurrentThreadPointer(m_kernel);
auto* const cur_thread = GetCurrentThreadPointer(kernel);
ASSERT(cur_thread != nullptr);
return cur_thread;
}
@@ -105,37 +100,6 @@ public:
return this->template GetObjectWithoutPseudoHandle<T>(handle);
}
KScopedAutoObject<KAutoObject> GetObjectForIpcWithoutPseudoHandle(Handle handle) const {
// Lock and look up in table.
KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock);
return this->GetObjectImpl(handle);
}
KScopedAutoObject<KAutoObject> GetObjectForIpc(Handle handle, KThread* cur_thread) const {
// Handle pseudo-handles.
ASSERT(cur_thread != nullptr);
if (handle == Svc::PseudoHandle::CurrentProcess) {
auto* const cur_process =
static_cast<KAutoObject*>(static_cast<void*>(cur_thread->GetOwnerProcess()));
ASSERT(cur_process != nullptr);
return cur_process;
}
if (handle == Svc::PseudoHandle::CurrentThread) {
return static_cast<KAutoObject*>(cur_thread);
}
return GetObjectForIpcWithoutPseudoHandle(handle);
}
KScopedAutoObject<KAutoObject> GetObjectByIndex(Handle* out_handle, size_t index) const {
KScopedDisableDispatch dd{m_kernel};
KScopedSpinLock lk(m_lock);
return this->GetObjectByIndexImpl(out_handle, index);
}
Result Reserve(Handle* out_handle);
void Unreserve(Handle handle);
@@ -148,7 +112,7 @@ public:
size_t num_opened;
{
// Lock the table.
KScopedDisableDispatch dd{m_kernel};
KScopedDisableDispatch dd(kernel);
KScopedSpinLock lk(m_lock);
for (num_opened = 0; num_opened < num_handles; num_opened++) {
// Get the current handle.
@@ -156,13 +120,13 @@ public:
// Get the object for the current handle.
KAutoObject* cur_object = this->GetObjectImpl(cur_handle);
if (cur_object == nullptr) [[unlikely]] {
if (cur_object == nullptr) {
break;
}
// Cast the current object to the desired type.
T* cur_t = cur_object->DynamicCast<T*>();
if (cur_t == nullptr) [[unlikely]] {
if (cur_t == nullptr) {
break;
}
@@ -173,7 +137,7 @@ public:
}
// If we converted every object, succeed.
if (num_opened == num_handles) [[likely]] {
if (num_opened == num_handles) {
return true;
}
@@ -227,21 +191,21 @@ private:
ASSERT(reserved == 0);
// Validate our indexing information.
if (raw_value == 0) [[unlikely]] {
if (raw_value == 0) {
return false;
}
if (linear_id == 0) [[unlikely]] {
if (linear_id == 0) {
return false;
}
if (index >= m_table_size) [[unlikely]] {
if (index >= m_table_size) {
return false;
}
// Check that there's an object, and our serial id is correct.
if (m_objects[index] == nullptr) [[unlikely]] {
if (m_objects[index] == nullptr) {
return false;
}
if (m_entry_infos[index].GetLinearId() != linear_id) [[unlikely]] {
if (m_entry_infos[index].GetLinearId() != linear_id) {
return false;
}
@@ -251,11 +215,11 @@ private:
KAutoObject* GetObjectImpl(Handle handle) const {
// Handles must not have reserved bits set.
const auto handle_pack = HandlePack(handle);
if (handle_pack.reserved != 0) [[unlikely]] {
if (handle_pack.reserved != 0) {
return nullptr;
}
if (this->IsValidHandle(handle)) [[likely]] {
if (this->IsValidHandle(handle)) {
return m_objects[handle_pack.index];
} else {
return nullptr;
@@ -263,8 +227,9 @@ private:
}
KAutoObject* GetObjectByIndexImpl(Handle* out_handle, size_t index) const {
// Index must be in bounds.
if (index >= m_table_size) [[unlikely]] {
if (index >= m_table_size) {
return nullptr;
}
@@ -279,15 +244,18 @@ private:
private:
union HandlePack {
constexpr HandlePack() = default;
constexpr HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
HandlePack() = default;
HandlePack(Handle handle) : raw{static_cast<u32>(handle)} {}
u32 raw{};
u32 raw;
BitField<0, 15, u32> index;
BitField<15, 15, u32> linear_id;
BitField<30, 2, u32> reserved;
};
static constexpr u16 MinLinearId = 1;
static constexpr u16 MaxLinearId = 0x7FFF;
static constexpr Handle EncodeHandle(u16 index, u16 linear_id) {
HandlePack handle{};
handle.index.Assign(index);
@@ -296,10 +264,6 @@ private:
return handle.raw;
}
private:
static constexpr u16 MinLinearId = 1;
static constexpr u16 MaxLinearId = 0x7FFF;
union EntryInfo {
u16 linear_id;
s16 next_free_index;
@@ -307,21 +271,21 @@ private:
constexpr u16 GetLinearId() const {
return linear_id;
}
constexpr s32 GetNextFreeIndex() const {
constexpr s16 GetNextFreeIndex() const {
return next_free_index;
}
};
private:
KernelCore& m_kernel;
std::array<EntryInfo, MaxTableSize> m_entry_infos{};
std::array<KAutoObject*, MaxTableSize> m_objects{};
mutable KSpinLock m_lock;
s32 m_free_head_index{};
s32 m_free_head_index{-1};
u16 m_table_size{};
u16 m_max_count{};
u16 m_next_linear_id{};
u16 m_next_linear_id{MinLinearId};
u16 m_count{};
mutable KSpinLock m_lock;
KernelCore& kernel;
};
} // namespace Kernel

View File

@@ -35,32 +35,26 @@ enum class KMemoryState : u32 {
FlagCanMapProcess = (1 << 23),
FlagCanChangeAttribute = (1 << 24),
FlagCanCodeMemory = (1 << 25),
FlagLinearMapped = (1 << 26),
FlagsData = FlagCanReprotect | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
FlagMapped | FlagCanAlias | FlagCanTransfer | FlagCanQueryPhysical |
FlagCanDeviceMap | FlagCanAlignedDeviceMap | FlagCanIpcUserBuffer |
FlagReferenceCounted | FlagCanChangeAttribute | FlagLinearMapped,
FlagReferenceCounted | FlagCanChangeAttribute,
FlagsCode = FlagCanDebug | FlagCanUseIpc | FlagCanUseNonDeviceIpc | FlagCanUseNonSecureIpc |
FlagMapped | FlagCode | FlagCanQueryPhysical | FlagCanDeviceMap |
FlagCanAlignedDeviceMap | FlagReferenceCounted | FlagLinearMapped,
FlagCanAlignedDeviceMap | FlagReferenceCounted,
FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap |
FlagLinearMapped,
FlagsMisc = FlagMapped | FlagReferenceCounted | FlagCanQueryPhysical | FlagCanDeviceMap,
Free = static_cast<u32>(Svc::MemoryState::Free),
Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped | FlagCanDeviceMap |
FlagCanAlignedDeviceMap,
Io = static_cast<u32>(Svc::MemoryState::Io) | FlagMapped,
Static = static_cast<u32>(Svc::MemoryState::Static) | FlagMapped | FlagCanQueryPhysical,
Code = static_cast<u32>(Svc::MemoryState::Code) | FlagsCode | FlagCanMapProcess,
CodeData = static_cast<u32>(Svc::MemoryState::CodeData) | FlagsData | FlagCanMapProcess |
FlagCanCodeMemory,
Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted,
Normal = static_cast<u32>(Svc::MemoryState::Normal) | FlagsData | FlagCanCodeMemory,
Shared = static_cast<u32>(Svc::MemoryState::Shared) | FlagMapped | FlagReferenceCounted |
FlagLinearMapped,
// Alias was removed after 1.0.0.
AliasCode = static_cast<u32>(Svc::MemoryState::AliasCode) | FlagsCode | FlagCanMapProcess |
FlagCanCodeAlias,
@@ -73,18 +67,18 @@ enum class KMemoryState : u32 {
Stack = static_cast<u32>(Svc::MemoryState::Stack) | FlagsMisc | FlagCanAlignedDeviceMap |
FlagCanUseIpc | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
ThreadLocal = static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagLinearMapped,
ThreadLocal =
static_cast<u32>(Svc::MemoryState::ThreadLocal) | FlagMapped | FlagReferenceCounted,
Transfered = static_cast<u32>(Svc::MemoryState::Transfered) | FlagsMisc |
Transfered = static_cast<u32>(Svc::MemoryState::Transferred) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanChangeAttribute | FlagCanUseIpc |
FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransfered) | FlagsMisc |
SharedTransfered = static_cast<u32>(Svc::MemoryState::SharedTransferred) | FlagsMisc |
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
SharedCode = static_cast<u32>(Svc::MemoryState::SharedCode) | FlagMapped |
FlagReferenceCounted | FlagLinearMapped | FlagCanUseNonSecureIpc |
FlagCanUseNonDeviceIpc,
FlagReferenceCounted | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
Inaccessible = static_cast<u32>(Svc::MemoryState::Inaccessible),
@@ -97,69 +91,69 @@ enum class KMemoryState : u32 {
Kernel = static_cast<u32>(Svc::MemoryState::Kernel) | FlagMapped,
GeneratedCode = static_cast<u32>(Svc::MemoryState::GeneratedCode) | FlagMapped |
FlagReferenceCounted | FlagCanDebug | FlagLinearMapped,
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted |
FlagLinearMapped,
FlagReferenceCounted | FlagCanDebug,
CodeOut = static_cast<u32>(Svc::MemoryState::CodeOut) | FlagMapped | FlagReferenceCounted,
Coverage = static_cast<u32>(Svc::MemoryState::Coverage) | FlagMapped,
Insecure = static_cast<u32>(Svc::MemoryState::Insecure) | FlagMapped | FlagReferenceCounted |
FlagLinearMapped | FlagCanChangeAttribute | FlagCanDeviceMap |
FlagCanAlignedDeviceMap | FlagCanUseNonSecureIpc | FlagCanUseNonDeviceIpc,
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryState);
static_assert(static_cast<u32>(KMemoryState::Free) == 0x00000000);
static_assert(static_cast<u32>(KMemoryState::Io) == 0x00182001);
static_assert(static_cast<u32>(KMemoryState::Io) == 0x00002001);
static_assert(static_cast<u32>(KMemoryState::Static) == 0x00042002);
static_assert(static_cast<u32>(KMemoryState::Code) == 0x04DC7E03);
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x07FEBD04);
static_assert(static_cast<u32>(KMemoryState::Normal) == 0x077EBD05);
static_assert(static_cast<u32>(KMemoryState::Shared) == 0x04402006);
static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x04DD7E08);
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x07FFBD09);
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x045C3C0A);
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x045C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0400200C);
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x055C3C0D);
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x045C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0440380F);
static_assert(static_cast<u32>(KMemoryState::Code) == 0x00DC7E03);
static_assert(static_cast<u32>(KMemoryState::CodeData) == 0x03FEBD04);
static_assert(static_cast<u32>(KMemoryState::Normal) == 0x037EBD05);
static_assert(static_cast<u32>(KMemoryState::Shared) == 0x00402006);
static_assert(static_cast<u32>(KMemoryState::AliasCode) == 0x00DD7E08);
static_assert(static_cast<u32>(KMemoryState::AliasCodeData) == 0x03FFBD09);
static_assert(static_cast<u32>(KMemoryState::Ipc) == 0x005C3C0A);
static_assert(static_cast<u32>(KMemoryState::Stack) == 0x005C3C0B);
static_assert(static_cast<u32>(KMemoryState::ThreadLocal) == 0x0040200C);
static_assert(static_cast<u32>(KMemoryState::Transfered) == 0x015C3C0D);
static_assert(static_cast<u32>(KMemoryState::SharedTransfered) == 0x005C380E);
static_assert(static_cast<u32>(KMemoryState::SharedCode) == 0x0040380F);
static_assert(static_cast<u32>(KMemoryState::Inaccessible) == 0x00000010);
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x045C3811);
static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x044C2812);
static_assert(static_cast<u32>(KMemoryState::NonSecureIpc) == 0x005C3811);
static_assert(static_cast<u32>(KMemoryState::NonDeviceIpc) == 0x004C2812);
static_assert(static_cast<u32>(KMemoryState::Kernel) == 0x00002013);
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x04402214);
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x04402015);
static_assert(static_cast<u32>(KMemoryState::GeneratedCode) == 0x00402214);
static_assert(static_cast<u32>(KMemoryState::CodeOut) == 0x00402015);
static_assert(static_cast<u32>(KMemoryState::Coverage) == 0x00002016);
static_assert(static_cast<u32>(KMemoryState::Insecure) == 0x05583817);
enum class KMemoryPermission : u8 {
None = 0,
All = static_cast<u8>(~None),
Read = 1 << 0,
Write = 1 << 1,
Execute = 1 << 2,
ReadAndWrite = Read | Write,
ReadAndExecute = Read | Execute,
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
Svc::MemoryPermission::Execute),
KernelShift = 3,
KernelRead = static_cast<u8>(Svc::MemoryPermission::Read) << KernelShift,
KernelWrite = static_cast<u8>(Svc::MemoryPermission::Write) << KernelShift,
KernelExecute = static_cast<u8>(Svc::MemoryPermission::Execute) << KernelShift,
KernelRead = Read << KernelShift,
KernelWrite = Write << KernelShift,
KernelExecute = Execute << KernelShift,
NotMapped = (1 << (2 * KernelShift)),
KernelReadWrite = KernelRead | KernelWrite,
KernelReadExecute = KernelRead | KernelExecute,
UserRead = static_cast<u8>(Svc::MemoryPermission::Read) | KernelRead,
UserWrite = static_cast<u8>(Svc::MemoryPermission::Write) | KernelWrite,
UserExecute = static_cast<u8>(Svc::MemoryPermission::Execute),
UserRead = Read | KernelRead,
UserWrite = Write | KernelWrite,
UserExecute = Execute,
UserReadWrite = UserRead | UserWrite,
UserReadExecute = UserRead | UserExecute,
UserMask = static_cast<u8>(Svc::MemoryPermission::Read | Svc::MemoryPermission::Write |
Svc::MemoryPermission::Execute),
IpcLockChangeMask = NotMapped | UserReadWrite,
IpcLockChangeMask = NotMapped | UserReadWrite
};
DECLARE_ENUM_FLAG_OPERATORS(KMemoryPermission);
@@ -216,15 +210,13 @@ struct KMemoryInfo {
constexpr Svc::MemoryInfo GetSvcMemoryInfo() const {
return {
.base_address = m_address,
.addr = m_address,
.size = m_size,
.state = static_cast<Svc::MemoryState>(m_state & KMemoryState::Mask),
.attribute =
static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask),
.permission =
static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask),
.ipc_count = m_ipc_lock_count,
.device_count = m_device_use_count,
.attr = static_cast<Svc::MemoryAttribute>(m_attribute & KMemoryAttribute::UserMask),
.perm = static_cast<Svc::MemoryPermission>(m_permission & KMemoryPermission::UserMask),
.ipc_refcount = m_ipc_lock_count,
.device_refcount = m_device_use_count,
.padding = {},
};
}
@@ -476,7 +468,6 @@ public:
constexpr void UpdateDeviceDisableMergeStateForShareLeft(
[[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
// New permission/right aren't used.
if (left) {
m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::DeviceLeft);
@@ -487,7 +478,6 @@ public:
constexpr void UpdateDeviceDisableMergeStateForShareRight(
[[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
// New permission/left aren't used.
if (right) {
m_disable_merge_attribute = static_cast<KMemoryBlockDisableMergeAttribute>(
m_disable_merge_attribute | KMemoryBlockDisableMergeAttribute::DeviceRight);
@@ -504,8 +494,6 @@ public:
constexpr void ShareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
bool right) {
// New permission isn't used.
// We must either be shared or have a zero lock count.
ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared ||
m_device_use_count == 0);
@@ -521,7 +509,6 @@ public:
constexpr void UpdateDeviceDisableMergeStateForUnshareLeft(
[[maybe_unused]] KMemoryPermission new_perm, bool left, [[maybe_unused]] bool right) {
// New permission/right aren't used.
if (left) {
if (!m_device_disable_merge_left_count) {
@@ -541,8 +528,6 @@ public:
constexpr void UpdateDeviceDisableMergeStateForUnshareRight(
[[maybe_unused]] KMemoryPermission new_perm, [[maybe_unused]] bool left, bool right) {
// New permission/left aren't used.
if (right) {
const u16 old_device_disable_merge_right_count = m_device_disable_merge_right_count--;
ASSERT(old_device_disable_merge_right_count > 0);
@@ -561,8 +546,6 @@ public:
constexpr void UnshareToDevice([[maybe_unused]] KMemoryPermission new_perm, bool left,
bool right) {
// New permission isn't used.
// We must be shared.
ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
@@ -580,7 +563,6 @@ public:
constexpr void UnshareToDeviceRight([[maybe_unused]] KMemoryPermission new_perm, bool left,
bool right) {
// New permission isn't used.
// We must be shared.
ASSERT((m_attribute & KMemoryAttribute::DeviceShared) == KMemoryAttribute::DeviceShared);
@@ -631,8 +613,6 @@ public:
constexpr void UnlockForIpc([[maybe_unused]] KMemoryPermission new_perm, bool left,
[[maybe_unused]] bool right) {
// New permission isn't used.
// We must be locked.
ASSERT((m_attribute & KMemoryAttribute::IpcLocked) == KMemoryAttribute::IpcLocked);

View File

@@ -153,9 +153,13 @@ void KMemoryLayout::InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_
}
}
size_t KMemoryLayout::GetResourceRegionSizeForInit(bool use_extra_resource) {
return KernelResourceSize + KSystemControl::SecureAppletMemorySize +
(use_extra_resource ? KernelSlabHeapAdditionalSize + KernelPageBufferAdditionalSize : 0);
size_t KMemoryLayout::GetResourceRegionSizeForInit() {
// Calculate resource region size based on whether we allow extra threads.
const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
size_t resource_region_size =
KernelResourceSize + (use_extra_resources ? KernelSlabHeapAdditionalSize : 0);
return resource_region_size;
}
} // namespace Kernel

View File

@@ -60,12 +60,10 @@ constexpr std::size_t KernelSlabHeapGapsSizeMax = 2_MiB - 64_KiB;
constexpr std::size_t KernelSlabHeapSize = KernelSlabHeapDataSize + KernelSlabHeapGapsSizeMax;
// NOTE: This is calculated from KThread slab counts, assuming KThread size <= 0x860.
constexpr size_t KernelPageBufferHeapSize = 0x3E0000;
constexpr size_t KernelSlabHeapAdditionalSize = 0x148000;
constexpr size_t KernelPageBufferAdditionalSize = 0x33C000;
constexpr std::size_t KernelSlabHeapAdditionalSize = 0x68000;
constexpr std::size_t KernelResourceSize = KernelPageTableHeapSize + KernelInitialPageHeapSize +
KernelSlabHeapSize + KernelPageBufferHeapSize;
constexpr std::size_t KernelResourceSize =
KernelPageTableHeapSize + KernelInitialPageHeapSize + KernelSlabHeapSize;
constexpr bool IsKernelAddressKey(VAddr key) {
return KernelVirtualAddressSpaceBase <= key && key <= KernelVirtualAddressSpaceLast;
@@ -170,11 +168,6 @@ public:
KMemoryRegionType_VirtualDramKernelTraceBuffer));
}
const KMemoryRegion& GetSecureAppletMemoryRegion() {
return Dereference(GetVirtualMemoryRegionTree().FindByType(
KMemoryRegionType_VirtualDramKernelSecureAppletMemory));
}
const KMemoryRegion& GetVirtualLinearRegion(VAddr address) const {
return Dereference(FindVirtualLinear(address));
}
@@ -236,7 +229,7 @@ public:
void InitializeLinearMemoryRegionTrees(PAddr aligned_linear_phys_start,
VAddr linear_virtual_start);
static size_t GetResourceRegionSizeForInit(bool use_extra_resource);
static size_t GetResourceRegionSizeForInit();
auto GetKernelRegionExtents() const {
return GetVirtualMemoryRegionTree().GetDerivedRegionExtents(KMemoryRegionType_Kernel);
@@ -286,10 +279,6 @@ public:
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelSlab);
}
auto GetKernelSecureAppletMemoryRegionPhysicalExtents() {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelSecureAppletMemory);
}
auto GetKernelPageTableHeapRegionPhysicalExtents() const {
return GetPhysicalMemoryRegionTree().GetDerivedRegionExtents(
KMemoryRegionType_DramKernelPtHeap);

View File

@@ -29,44 +29,43 @@ constexpr KMemoryManager::Pool GetPoolFromMemoryRegionType(u32 type) {
} else if ((type | KMemoryRegionType_DramSystemNonSecurePool) == type) {
return KMemoryManager::Pool::SystemNonSecure;
} else {
UNREACHABLE_MSG("InvalidMemoryRegionType for conversion to Pool");
ASSERT_MSG(false, "InvalidMemoryRegionType for conversion to Pool");
return {};
}
}
} // namespace
KMemoryManager::KMemoryManager(Core::System& system)
: m_system{system}, m_memory_layout{system.Kernel().MemoryLayout()},
m_pool_locks{
KLightLock{system.Kernel()},
KLightLock{system.Kernel()},
KLightLock{system.Kernel()},
KLightLock{system.Kernel()},
} {}
KMemoryManager::KMemoryManager(Core::System& system_)
: system{system_}, pool_locks{
KLightLock{system_.Kernel()},
KLightLock{system_.Kernel()},
KLightLock{system_.Kernel()},
KLightLock{system_.Kernel()},
} {}
void KMemoryManager::Initialize(VAddr management_region, size_t management_region_size) {
// Clear the management region to zero.
const VAddr management_region_end = management_region + management_region_size;
// std::memset(GetVoidPointer(management_region), 0, management_region_size);
// Reset our manager count.
m_num_managers = 0;
num_managers = 0;
// Traverse the virtual memory layout tree, initializing each manager as appropriate.
while (m_num_managers != MaxManagerCount) {
while (num_managers != MaxManagerCount) {
// Locate the region that should initialize the current manager.
PAddr region_address = 0;
size_t region_size = 0;
Pool region_pool = Pool::Count;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
for (const auto& it : system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
// We only care about regions that we need to create managers for.
if (!it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
continue;
}
// We want to initialize the managers in order.
if (it.GetAttributes() != m_num_managers) {
if (it.GetAttributes() != num_managers) {
continue;
}
@@ -98,8 +97,8 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
}
// Initialize a new manager for the region.
Impl* manager = std::addressof(m_managers[m_num_managers++]);
ASSERT(m_num_managers <= m_managers.size());
Impl* manager = std::addressof(managers[num_managers++]);
ASSERT(num_managers <= managers.size());
const size_t cur_size = manager->Initialize(region_address, region_size, management_region,
management_region_end, region_pool);
@@ -108,13 +107,13 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
// Insert the manager into the pool list.
const auto region_pool_index = static_cast<u32>(region_pool);
if (m_pool_managers_tail[region_pool_index] == nullptr) {
m_pool_managers_head[region_pool_index] = manager;
if (pool_managers_tail[region_pool_index] == nullptr) {
pool_managers_head[region_pool_index] = manager;
} else {
m_pool_managers_tail[region_pool_index]->SetNext(manager);
manager->SetPrev(m_pool_managers_tail[region_pool_index]);
pool_managers_tail[region_pool_index]->SetNext(manager);
manager->SetPrev(pool_managers_tail[region_pool_index]);
}
m_pool_managers_tail[region_pool_index] = manager;
pool_managers_tail[region_pool_index] = manager;
}
// Free each region to its corresponding heap.
@@ -122,10 +121,11 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
const PAddr ini_start = GetInitialProcessBinaryPhysicalAddress();
const PAddr ini_end = ini_start + InitialProcessBinarySizeMax;
const PAddr ini_last = ini_end - 1;
for (const auto& it : m_system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
for (const auto& it : system.Kernel().MemoryLayout().GetPhysicalMemoryRegionTree()) {
if (it.IsDerivedFrom(KMemoryRegionType_DramUserPool)) {
// Get the manager for the region.
auto& manager = m_managers[it.GetAttributes()];
auto index = it.GetAttributes();
auto& manager = managers[index];
const PAddr cur_start = it.GetAddress();
const PAddr cur_last = it.GetLastAddress();
@@ -162,19 +162,11 @@ void KMemoryManager::Initialize(VAddr management_region, size_t management_regio
}
// Update the used size for all managers.
for (size_t i = 0; i < m_num_managers; ++i) {
m_managers[i].SetInitialUsedHeapSize(reserved_sizes[i]);
for (size_t i = 0; i < num_managers; ++i) {
managers[i].SetInitialUsedHeapSize(reserved_sizes[i]);
}
}
Result KMemoryManager::InitializeOptimizedMemory(u64 process_id, Pool pool) {
UNREACHABLE();
}
void KMemoryManager::FinalizeOptimizedMemory(u64 process_id, Pool pool) {
UNREACHABLE();
}
PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option) {
// Early return if we're allocating no pages.
if (num_pages == 0) {
@@ -183,7 +175,7 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
// Lock the pool that we're allocating from.
const auto [pool, dir] = DecodeOption(option);
KScopedLightLock lk(m_pool_locks[static_cast<std::size_t>(pool)]);
KScopedLightLock lk(pool_locks[static_cast<std::size_t>(pool)]);
// Choose a heap based on our page size request.
const s32 heap_index = KPageHeap::GetAlignedBlockIndex(num_pages, align_pages);
@@ -193,7 +185,7 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
PAddr allocated_block = 0;
for (chosen_manager = this->GetFirstManager(pool, dir); chosen_manager != nullptr;
chosen_manager = this->GetNextManager(chosen_manager, dir)) {
allocated_block = chosen_manager->AllocateAligned(heap_index, num_pages, align_pages);
allocated_block = chosen_manager->AllocateBlock(heap_index, true);
if (allocated_block != 0) {
break;
}
@@ -204,9 +196,10 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
return 0;
}
// Maintain the optimized memory bitmap, if we should.
if (m_has_optimized_process[static_cast<size_t>(pool)]) {
UNIMPLEMENTED();
// If we allocated more than we need, free some.
const size_t allocated_pages = KPageHeap::GetBlockNumPages(heap_index);
if (allocated_pages > num_pages) {
chosen_manager->Free(allocated_block + num_pages * PageSize, allocated_pages - num_pages);
}
// Open the first reference to the pages.
@@ -216,21 +209,20 @@ PAddr KMemoryManager::AllocateAndOpenContinuous(size_t num_pages, size_t align_p
}
Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool,
Direction dir, bool unoptimized, bool random) {
Direction dir, bool random) {
// Choose a heap based on our page size request.
const s32 heap_index = KPageHeap::GetBlockIndex(num_pages);
R_UNLESS(0 <= heap_index, ResultOutOfMemory);
// Ensure that we don't leave anything un-freed.
ON_RESULT_FAILURE {
auto group_guard = SCOPE_GUARD({
for (const auto& it : out->Nodes()) {
auto& manager = this->GetManager(it.GetAddress());
const size_t node_num_pages =
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), it.GetAddress());
const size_t num_pages_to_free =
std::min(it.GetNumPages(), (manager.GetEndAddress() - it.GetAddress()) / PageSize);
manager.Free(it.GetAddress(), node_num_pages);
manager.Free(it.GetAddress(), num_pages_to_free);
}
out->Finalize();
};
});
// Keep allocating until we've allocated all our pages.
for (s32 index = heap_index; index >= 0 && num_pages > 0; index--) {
@@ -244,17 +236,12 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
break;
}
// Ensure we don't leak the block if we fail.
ON_RESULT_FAILURE_2 {
cur_manager->Free(allocated_block, pages_per_alloc);
};
// Add the block to our group.
R_TRY(out->AddBlock(allocated_block, pages_per_alloc));
// Maintain the optimized memory bitmap, if we should.
if (unoptimized) {
UNIMPLEMENTED();
// Safely add it to our group.
{
auto block_guard =
SCOPE_GUARD({ cur_manager->Free(allocated_block, pages_per_alloc); });
R_TRY(out->AddBlock(allocated_block, pages_per_alloc));
block_guard.Cancel();
}
num_pages -= pages_per_alloc;
@@ -266,7 +253,8 @@ Result KMemoryManager::AllocatePageGroupImpl(KPageGroup* out, size_t num_pages,
R_UNLESS(num_pages == 0, ResultOutOfMemory);
// We succeeded!
R_SUCCEED();
group_guard.Cancel();
return ResultSuccess;
}
Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option) {
@@ -278,11 +266,10 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op
// Lock the pool that we're allocating from.
const auto [pool, dir] = DecodeOption(option);
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(pool)]);
KScopedLightLock lk(pool_locks[static_cast<size_t>(pool)]);
// Allocate the page group.
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir,
m_has_optimized_process[static_cast<size_t>(pool)], true));
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, false));
// Open the first reference to the pages.
for (const auto& block : out->Nodes()) {
@@ -290,7 +277,7 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
// Get the manager for the current address.
auto& manager = this->GetManager(cur_address);
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), cur_address);
// Process part or all of the block.
const size_t cur_pages =
@@ -303,11 +290,11 @@ Result KMemoryManager::AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 op
}
}
R_SUCCEED();
return ResultSuccess;
}
Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32 option,
u64 process_id, u8 fill_pattern) {
Result KMemoryManager::AllocateAndOpenForProcess(KPageGroup* out, size_t num_pages, u32 option,
u64 process_id, u8 fill_pattern) {
ASSERT(out != nullptr);
ASSERT(out->GetNumPages() == 0);
@@ -315,89 +302,83 @@ Result KMemoryManager::AllocateForProcess(KPageGroup* out, size_t num_pages, u32
const auto [pool, dir] = DecodeOption(option);
// Allocate the memory.
bool optimized;
{
// Lock the pool that we're allocating from.
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(pool)]);
// Check if we have an optimized process.
const bool has_optimized = m_has_optimized_process[static_cast<size_t>(pool)];
const bool is_optimized = m_optimized_process_ids[static_cast<size_t>(pool)] == process_id;
KScopedLightLock lk(pool_locks[static_cast<size_t>(pool)]);
// Allocate the page group.
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, has_optimized && !is_optimized,
false));
R_TRY(this->AllocatePageGroupImpl(out, num_pages, pool, dir, false));
// Set whether we should optimize.
optimized = has_optimized && is_optimized;
}
// Perform optimized memory tracking, if we should.
if (optimized) {
// Iterate over the allocated blocks.
// Open the first reference to the pages.
for (const auto& block : out->Nodes()) {
// Get the block extents.
const PAddr block_address = block.GetAddress();
const size_t block_pages = block.GetNumPages();
PAddr cur_address = block.GetAddress();
size_t remaining_pages = block.GetNumPages();
while (remaining_pages > 0) {
// Get the manager for the current address.
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), cur_address);
// If it has no pages, we don't need to do anything.
if (block_pages == 0) {
continue;
// Process part or all of the block.
const size_t cur_pages =
std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address));
manager.OpenFirst(cur_address, cur_pages);
// Advance.
cur_address += cur_pages * PageSize;
remaining_pages -= cur_pages;
}
// Fill all the pages that we need to fill.
bool any_new = false;
{
PAddr cur_address = block_address;
size_t remaining_pages = block_pages;
while (remaining_pages > 0) {
// Get the manager for the current address.
auto& manager = this->GetManager(cur_address);
// Process part or all of the block.
const size_t cur_pages =
std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address));
any_new =
manager.ProcessOptimizedAllocation(cur_address, cur_pages, fill_pattern);
// Advance.
cur_address += cur_pages * PageSize;
remaining_pages -= cur_pages;
}
}
// If there are new pages, update tracking for the allocation.
if (any_new) {
// Update tracking for the allocation.
PAddr cur_address = block_address;
size_t remaining_pages = block_pages;
while (remaining_pages > 0) {
// Get the manager for the current address.
auto& manager = this->GetManager(cur_address);
// Lock the pool for the manager.
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]);
// Track some or all of the current pages.
const size_t cur_pages =
std::min(remaining_pages, manager.GetPageOffsetToEnd(cur_address));
manager.TrackOptimizedAllocation(cur_address, cur_pages);
// Advance.
cur_address += cur_pages * PageSize;
remaining_pages -= cur_pages;
}
}
}
} else {
// Set all the allocated memory.
for (const auto& block : out->Nodes()) {
std::memset(m_system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern,
block.GetSize());
}
}
R_SUCCEED();
// Set all the allocated memory.
for (const auto& block : out->Nodes()) {
std::memset(system.DeviceMemory().GetPointer<void>(block.GetAddress()), fill_pattern,
block.GetSize());
}
return ResultSuccess;
}
void KMemoryManager::Open(PAddr address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.Open(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
void KMemoryManager::Close(PAddr address, size_t num_pages) {
// Repeatedly close references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(system.Kernel().MemoryLayout(), address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.Close(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
void KMemoryManager::Close(const KPageGroup& pg) {
for (const auto& node : pg.Nodes()) {
Close(node.GetAddress(), node.GetNumPages());
}
}
void KMemoryManager::Open(const KPageGroup& pg) {
for (const auto& node : pg.Nodes()) {
Open(node.GetAddress(), node.GetNumPages());
}
}
size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr management,
@@ -413,31 +394,18 @@ size_t KMemoryManager::Impl::Initialize(PAddr address, size_t size, VAddr manage
ASSERT(Common::IsAligned(total_management_size, PageSize));
// Setup region.
m_pool = p;
m_management_region = management;
m_page_reference_counts.resize(
pool = p;
management_region = management;
page_reference_counts.resize(
Kernel::Board::Nintendo::Nx::KSystemControl::Init::GetIntendedMemorySize() / PageSize);
ASSERT(Common::IsAligned(m_management_region, PageSize));
ASSERT(Common::IsAligned(management_region, PageSize));
// Initialize the manager's KPageHeap.
m_heap.Initialize(address, size, management + manager_size, page_heap_size);
heap.Initialize(address, size, management + manager_size, page_heap_size);
return total_management_size;
}
void KMemoryManager::Impl::TrackUnoptimizedAllocation(PAddr block, size_t num_pages) {
UNREACHABLE();
}
void KMemoryManager::Impl::TrackOptimizedAllocation(PAddr block, size_t num_pages) {
UNREACHABLE();
}
bool KMemoryManager::Impl::ProcessOptimizedAllocation(PAddr block, size_t num_pages,
u8 fill_pattern) {
UNREACHABLE();
}
size_t KMemoryManager::Impl::CalculateManagementOverheadSize(size_t region_size) {
const size_t ref_count_size = (region_size / PageSize) * sizeof(u16);
const size_t optimize_map_size =

View File

@@ -21,8 +21,11 @@ namespace Kernel {
class KPageGroup;
class KMemoryManager {
class KMemoryManager final {
public:
YUZU_NON_COPYABLE(KMemoryManager);
YUZU_NON_MOVEABLE(KMemoryManager);
enum class Pool : u32 {
Application = 0,
Applet = 1,
@@ -42,85 +45,16 @@ public:
enum class Direction : u32 {
FromFront = 0,
FromBack = 1,
Shift = 0,
Mask = (0xF << Shift),
};
static constexpr size_t MaxManagerCount = 10;
explicit KMemoryManager(Core::System& system);
explicit KMemoryManager(Core::System& system_);
void Initialize(VAddr management_region, size_t management_region_size);
Result InitializeOptimizedMemory(u64 process_id, Pool pool);
void FinalizeOptimizedMemory(u64 process_id, Pool pool);
PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option);
Result AllocateForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id,
u8 fill_pattern);
Pool GetPool(PAddr address) const {
return this->GetManager(address).GetPool();
}
void Open(PAddr address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.Open(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
void OpenFirst(PAddr address, size_t num_pages) {
// Repeatedly open references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.OpenFirst(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
void Close(PAddr address, size_t num_pages) {
// Repeatedly close references until we've done so for all pages.
while (num_pages) {
auto& manager = this->GetManager(address);
const size_t cur_pages = std::min(num_pages, manager.GetPageOffsetToEnd(address));
{
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(manager.GetPool())]);
manager.Close(address, cur_pages);
}
num_pages -= cur_pages;
address += cur_pages * PageSize;
}
}
size_t GetSize() {
size_t total = 0;
for (size_t i = 0; i < m_num_managers; i++) {
total += m_managers[i].GetSize();
}
return total;
}
size_t GetSize(Pool pool) {
constexpr size_t GetSize(Pool pool) const {
constexpr Direction GetSizeDirection = Direction::FromFront;
size_t total = 0;
for (auto* manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr;
@@ -130,36 +64,18 @@ public:
return total;
}
size_t GetFreeSize() {
size_t total = 0;
for (size_t i = 0; i < m_num_managers; i++) {
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(m_managers[i].GetPool())]);
total += m_managers[i].GetFreeSize();
}
return total;
}
PAddr AllocateAndOpenContinuous(size_t num_pages, size_t align_pages, u32 option);
Result AllocateAndOpen(KPageGroup* out, size_t num_pages, u32 option);
Result AllocateAndOpenForProcess(KPageGroup* out, size_t num_pages, u32 option, u64 process_id,
u8 fill_pattern);
size_t GetFreeSize(Pool pool) {
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(pool)]);
static constexpr size_t MaxManagerCount = 10;
constexpr Direction GetSizeDirection = Direction::FromFront;
size_t total = 0;
for (auto* manager = this->GetFirstManager(pool, GetSizeDirection); manager != nullptr;
manager = this->GetNextManager(manager, GetSizeDirection)) {
total += manager->GetFreeSize();
}
return total;
}
void Close(PAddr address, size_t num_pages);
void Close(const KPageGroup& pg);
void DumpFreeList(Pool pool) {
KScopedLightLock lk(m_pool_locks[static_cast<size_t>(pool)]);
constexpr Direction DumpDirection = Direction::FromFront;
for (auto* manager = this->GetFirstManager(pool, DumpDirection); manager != nullptr;
manager = this->GetNextManager(manager, DumpDirection)) {
manager->DumpFreeList();
}
}
void Open(PAddr address, size_t num_pages);
void Open(const KPageGroup& pg);
public:
static size_t CalculateManagementOverheadSize(size_t region_size) {
@@ -172,13 +88,14 @@ public:
}
static constexpr Pool GetPool(u32 option) {
return static_cast<Pool>((option & static_cast<u32>(Pool::Mask)) >>
return static_cast<Pool>((static_cast<u32>(option) & static_cast<u32>(Pool::Mask)) >>
static_cast<u32>(Pool::Shift));
}
static constexpr Direction GetDirection(u32 option) {
return static_cast<Direction>((option & static_cast<u32>(Direction::Mask)) >>
static_cast<u32>(Direction::Shift));
return static_cast<Direction>(
(static_cast<u32>(option) & static_cast<u32>(Direction::Mask)) >>
static_cast<u32>(Direction::Shift));
}
static constexpr std::tuple<Pool, Direction> DecodeOption(u32 option) {
@@ -186,88 +103,74 @@ public:
}
private:
class Impl {
class Impl final {
public:
static size_t CalculateManagementOverheadSize(size_t region_size);
YUZU_NON_COPYABLE(Impl);
YUZU_NON_MOVEABLE(Impl);
static constexpr size_t CalculateOptimizedProcessOverheadSize(size_t region_size) {
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
}
public:
Impl() = default;
~Impl() = default;
size_t Initialize(PAddr address, size_t size, VAddr management, VAddr management_end,
Pool p);
PAddr AllocateBlock(s32 index, bool random) {
return m_heap.AllocateBlock(index, random);
VAddr AllocateBlock(s32 index, bool random) {
return heap.AllocateBlock(index, random);
}
PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
return m_heap.AllocateAligned(index, num_pages, align_pages);
}
void Free(PAddr addr, size_t num_pages) {
m_heap.Free(addr, num_pages);
void Free(VAddr addr, size_t num_pages) {
heap.Free(addr, num_pages);
}
void SetInitialUsedHeapSize(size_t reserved_size) {
m_heap.SetInitialUsedSize(reserved_size);
heap.SetInitialUsedSize(reserved_size);
}
void InitializeOptimizedMemory() {
UNIMPLEMENTED();
}
void TrackUnoptimizedAllocation(PAddr block, size_t num_pages);
void TrackOptimizedAllocation(PAddr block, size_t num_pages);
bool ProcessOptimizedAllocation(PAddr block, size_t num_pages, u8 fill_pattern);
constexpr Pool GetPool() const {
return m_pool;
return pool;
}
constexpr size_t GetSize() const {
return m_heap.GetSize();
}
constexpr PAddr GetEndAddress() const {
return m_heap.GetEndAddress();
return heap.GetSize();
}
size_t GetFreeSize() const {
return m_heap.GetFreeSize();
constexpr VAddr GetAddress() const {
return heap.GetAddress();
}
void DumpFreeList() const {
UNIMPLEMENTED();
constexpr VAddr GetEndAddress() const {
return heap.GetEndAddress();
}
constexpr size_t GetPageOffset(PAddr address) const {
return m_heap.GetPageOffset(address);
return heap.GetPageOffset(address);
}
constexpr size_t GetPageOffsetToEnd(PAddr address) const {
return m_heap.GetPageOffsetToEnd(address);
return heap.GetPageOffsetToEnd(address);
}
constexpr void SetNext(Impl* n) {
m_next = n;
next = n;
}
constexpr void SetPrev(Impl* n) {
m_prev = n;
prev = n;
}
constexpr Impl* GetNext() const {
return m_next;
return next;
}
constexpr Impl* GetPrev() const {
return m_prev;
return prev;
}
void OpenFirst(PAddr address, size_t num_pages) {
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
const RefCount ref_count = (++m_page_reference_counts[index]);
const RefCount ref_count = (++page_reference_counts[index]);
ASSERT(ref_count == 1);
index++;
@@ -278,7 +181,7 @@ private:
size_t index = this->GetPageOffset(address);
const size_t end = index + num_pages;
while (index < end) {
const RefCount ref_count = (++m_page_reference_counts[index]);
const RefCount ref_count = (++page_reference_counts[index]);
ASSERT(ref_count > 1);
index++;
@@ -292,8 +195,8 @@ private:
size_t free_start = 0;
size_t free_count = 0;
while (index < end) {
ASSERT(m_page_reference_counts[index] > 0);
const RefCount ref_count = (--m_page_reference_counts[index]);
ASSERT(page_reference_counts[index] > 0);
const RefCount ref_count = (--page_reference_counts[index]);
// Keep track of how many zero refcounts we see in a row, to minimize calls to free.
if (ref_count == 0) {
@@ -305,7 +208,7 @@ private:
}
} else {
if (free_count > 0) {
this->Free(m_heap.GetAddress() + free_start * PageSize, free_count);
this->Free(heap.GetAddress() + free_start * PageSize, free_count);
free_count = 0;
}
}
@@ -314,36 +217,44 @@ private:
}
if (free_count > 0) {
this->Free(m_heap.GetAddress() + free_start * PageSize, free_count);
this->Free(heap.GetAddress() + free_start * PageSize, free_count);
}
}
static size_t CalculateManagementOverheadSize(size_t region_size);
static constexpr size_t CalculateOptimizedProcessOverheadSize(size_t region_size) {
return (Common::AlignUp((region_size / PageSize), Common::BitSize<u64>()) /
Common::BitSize<u64>()) *
sizeof(u64);
}
private:
using RefCount = u16;
KPageHeap m_heap;
std::vector<RefCount> m_page_reference_counts;
VAddr m_management_region{};
Pool m_pool{};
Impl* m_next{};
Impl* m_prev{};
KPageHeap heap;
std::vector<RefCount> page_reference_counts;
VAddr management_region{};
Pool pool{};
Impl* next{};
Impl* prev{};
};
private:
Impl& GetManager(PAddr address) {
return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
Impl& GetManager(const KMemoryLayout& memory_layout, PAddr address) {
return managers[memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
const Impl& GetManager(PAddr address) const {
return m_managers[m_memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
const Impl& GetManager(const KMemoryLayout& memory_layout, PAddr address) const {
return managers[memory_layout.GetPhysicalLinearRegion(address).GetAttributes()];
}
constexpr Impl* GetFirstManager(Pool pool, Direction dir) {
return dir == Direction::FromBack ? m_pool_managers_tail[static_cast<size_t>(pool)]
: m_pool_managers_head[static_cast<size_t>(pool)];
constexpr Impl* GetFirstManager(Pool pool, Direction dir) const {
return dir == Direction::FromBack ? pool_managers_tail[static_cast<size_t>(pool)]
: pool_managers_head[static_cast<size_t>(pool)];
}
constexpr Impl* GetNextManager(Impl* cur, Direction dir) {
constexpr Impl* GetNextManager(Impl* cur, Direction dir) const {
if (dir == Direction::FromBack) {
return cur->GetPrev();
} else {
@@ -352,21 +263,15 @@ private:
}
Result AllocatePageGroupImpl(KPageGroup* out, size_t num_pages, Pool pool, Direction dir,
bool unoptimized, bool random);
bool random);
private:
template <typename T>
using PoolArray = std::array<T, static_cast<size_t>(Pool::Count)>;
Core::System& m_system;
const KMemoryLayout& m_memory_layout;
PoolArray<KLightLock> m_pool_locks;
std::array<Impl*, MaxManagerCount> m_pool_managers_head{};
std::array<Impl*, MaxManagerCount> m_pool_managers_tail{};
std::array<Impl, MaxManagerCount> m_managers;
size_t m_num_managers{};
PoolArray<u64> m_optimized_process_ids{};
PoolArray<bool> m_has_optimized_process{};
Core::System& system;
std::array<KLightLock, static_cast<size_t>(Pool::Count)> pool_locks;
std::array<Impl*, MaxManagerCount> pool_managers_head{};
std::array<Impl*, MaxManagerCount> pool_managers_tail{};
std::array<Impl, MaxManagerCount> managers;
size_t num_managers{};
};
} // namespace Kernel

View File

@@ -142,38 +142,32 @@ private:
} // namespace impl
constexpr inline auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue();
constexpr inline auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2);
constexpr inline auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2);
constexpr auto KMemoryRegionType_None = impl::KMemoryRegionTypeValue();
constexpr auto KMemoryRegionType_Kernel = KMemoryRegionType_None.DeriveInitial(0, 2);
constexpr auto KMemoryRegionType_Dram = KMemoryRegionType_None.DeriveInitial(1, 2);
static_assert(KMemoryRegionType_Kernel.GetValue() == 0x1);
static_assert(KMemoryRegionType_Dram.GetValue() == 0x2);
// constexpr inline auto KMemoryRegionType_CoreLocalRegion =
// KMemoryRegionType_None.DeriveInitial(2).Finalize();
// static_assert(KMemoryRegionType_CoreLocalRegion.GetValue() == 0x4);
constexpr inline auto KMemoryRegionType_DramKernelBase =
constexpr auto KMemoryRegionType_DramKernelBase =
KMemoryRegionType_Dram.DeriveSparse(0, 3, 0)
.SetAttribute(KMemoryRegionAttr_NoUserMap)
.SetAttribute(KMemoryRegionAttr_CarveoutProtected);
constexpr inline auto KMemoryRegionType_DramReservedBase =
KMemoryRegionType_Dram.DeriveSparse(0, 3, 1);
constexpr inline auto KMemoryRegionType_DramHeapBase =
constexpr auto KMemoryRegionType_DramReservedBase = KMemoryRegionType_Dram.DeriveSparse(0, 3, 1);
constexpr auto KMemoryRegionType_DramHeapBase =
KMemoryRegionType_Dram.DeriveSparse(0, 3, 2).SetAttribute(KMemoryRegionAttr_LinearMapped);
static_assert(KMemoryRegionType_DramKernelBase.GetValue() ==
(0xE | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap));
static_assert(KMemoryRegionType_DramReservedBase.GetValue() == (0x16));
static_assert(KMemoryRegionType_DramHeapBase.GetValue() == (0x26 | KMemoryRegionAttr_LinearMapped));
constexpr inline auto KMemoryRegionType_DramKernelCode =
constexpr auto KMemoryRegionType_DramKernelCode =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 0);
constexpr inline auto KMemoryRegionType_DramKernelSlab =
constexpr auto KMemoryRegionType_DramKernelSlab =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 1);
constexpr inline auto KMemoryRegionType_DramKernelPtHeap =
constexpr auto KMemoryRegionType_DramKernelPtHeap =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 2).SetAttribute(
KMemoryRegionAttr_LinearMapped);
constexpr inline auto KMemoryRegionType_DramKernelInitPt =
constexpr auto KMemoryRegionType_DramKernelInitPt =
KMemoryRegionType_DramKernelBase.DeriveSparse(0, 4, 3).SetAttribute(
KMemoryRegionAttr_LinearMapped);
static_assert(KMemoryRegionType_DramKernelCode.GetValue() ==
@@ -187,40 +181,32 @@ static_assert(KMemoryRegionType_DramKernelInitPt.GetValue() ==
(0x44E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_LinearMapped));
constexpr inline auto KMemoryRegionType_DramKernelSecureAppletMemory =
KMemoryRegionType_DramKernelBase.DeriveSparse(1, 3, 0).SetAttribute(
KMemoryRegionAttr_LinearMapped);
static_assert(KMemoryRegionType_DramKernelSecureAppletMemory.GetValue() ==
(0x18E | KMemoryRegionAttr_CarveoutProtected | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_LinearMapped));
constexpr inline auto KMemoryRegionType_DramReservedEarly =
constexpr auto KMemoryRegionType_DramReservedEarly =
KMemoryRegionType_DramReservedBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_DramReservedEarly.GetValue() ==
(0x16 | KMemoryRegionAttr_NoUserMap));
constexpr inline auto KMemoryRegionType_KernelTraceBuffer =
constexpr auto KMemoryRegionType_KernelTraceBuffer =
KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 0)
.SetAttribute(KMemoryRegionAttr_LinearMapped)
.SetAttribute(KMemoryRegionAttr_UserReadOnly);
constexpr inline auto KMemoryRegionType_OnMemoryBootImage =
constexpr auto KMemoryRegionType_OnMemoryBootImage =
KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 1);
constexpr inline auto KMemoryRegionType_DTB =
KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2);
constexpr auto KMemoryRegionType_DTB = KMemoryRegionType_DramReservedBase.DeriveSparse(0, 3, 2);
static_assert(KMemoryRegionType_KernelTraceBuffer.GetValue() ==
(0xD6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_UserReadOnly));
static_assert(KMemoryRegionType_OnMemoryBootImage.GetValue() == 0x156);
static_assert(KMemoryRegionType_DTB.GetValue() == 0x256);
constexpr inline auto KMemoryRegionType_DramPoolPartition =
constexpr auto KMemoryRegionType_DramPoolPartition =
KMemoryRegionType_DramHeapBase.DeriveAttribute(KMemoryRegionAttr_NoUserMap);
static_assert(KMemoryRegionType_DramPoolPartition.GetValue() ==
(0x26 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
constexpr inline auto KMemoryRegionType_DramPoolManagement =
constexpr auto KMemoryRegionType_DramPoolManagement =
KMemoryRegionType_DramPoolPartition.DeriveTransition(0, 2).DeriveTransition().SetAttribute(
KMemoryRegionAttr_CarveoutProtected);
constexpr inline auto KMemoryRegionType_DramUserPool =
constexpr auto KMemoryRegionType_DramUserPool =
KMemoryRegionType_DramPoolPartition.DeriveTransition(1, 2).DeriveTransition();
static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
(0x166 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
@@ -228,13 +214,11 @@ static_assert(KMemoryRegionType_DramPoolManagement.GetValue() ==
static_assert(KMemoryRegionType_DramUserPool.GetValue() ==
(0x1A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
constexpr inline auto KMemoryRegionType_DramApplicationPool =
KMemoryRegionType_DramUserPool.Derive(4, 0);
constexpr inline auto KMemoryRegionType_DramAppletPool =
KMemoryRegionType_DramUserPool.Derive(4, 1);
constexpr inline auto KMemoryRegionType_DramSystemNonSecurePool =
constexpr auto KMemoryRegionType_DramApplicationPool = KMemoryRegionType_DramUserPool.Derive(4, 0);
constexpr auto KMemoryRegionType_DramAppletPool = KMemoryRegionType_DramUserPool.Derive(4, 1);
constexpr auto KMemoryRegionType_DramSystemNonSecurePool =
KMemoryRegionType_DramUserPool.Derive(4, 2);
constexpr inline auto KMemoryRegionType_DramSystemPool =
constexpr auto KMemoryRegionType_DramSystemPool =
KMemoryRegionType_DramUserPool.Derive(4, 3).SetAttribute(KMemoryRegionAttr_CarveoutProtected);
static_assert(KMemoryRegionType_DramApplicationPool.GetValue() ==
(0x7A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap));
@@ -246,55 +230,50 @@ static_assert(KMemoryRegionType_DramSystemPool.GetValue() ==
(0x13A6 | KMemoryRegionAttr_LinearMapped | KMemoryRegionAttr_NoUserMap |
KMemoryRegionAttr_CarveoutProtected));
constexpr inline auto KMemoryRegionType_VirtualDramHeapBase =
KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
constexpr inline auto KMemoryRegionType_VirtualDramKernelPtHeap =
constexpr auto KMemoryRegionType_VirtualDramHeapBase = KMemoryRegionType_Dram.DeriveSparse(1, 3, 0);
constexpr auto KMemoryRegionType_VirtualDramKernelPtHeap =
KMemoryRegionType_Dram.DeriveSparse(1, 3, 1);
constexpr inline auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
constexpr auto KMemoryRegionType_VirtualDramKernelTraceBuffer =
KMemoryRegionType_Dram.DeriveSparse(1, 3, 2);
static_assert(KMemoryRegionType_VirtualDramHeapBase.GetValue() == 0x1A);
static_assert(KMemoryRegionType_VirtualDramKernelPtHeap.GetValue() == 0x2A);
static_assert(KMemoryRegionType_VirtualDramKernelTraceBuffer.GetValue() == 0x4A);
// UNUSED: .DeriveSparse(2, 2, 0);
constexpr inline auto KMemoryRegionType_VirtualDramUnknownDebug =
constexpr auto KMemoryRegionType_VirtualDramUnknownDebug =
KMemoryRegionType_Dram.DeriveSparse(2, 2, 1);
static_assert(KMemoryRegionType_VirtualDramUnknownDebug.GetValue() == (0x52));
constexpr inline auto KMemoryRegionType_VirtualDramKernelSecureAppletMemory =
KMemoryRegionType_Dram.DeriveSparse(3, 1, 0);
static_assert(KMemoryRegionType_VirtualDramKernelSecureAppletMemory.GetValue() == (0x62));
constexpr inline auto KMemoryRegionType_VirtualDramKernelInitPt =
constexpr auto KMemoryRegionType_VirtualDramKernelInitPt =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 0);
constexpr inline auto KMemoryRegionType_VirtualDramPoolManagement =
constexpr auto KMemoryRegionType_VirtualDramPoolManagement =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 1);
constexpr inline auto KMemoryRegionType_VirtualDramUserPool =
constexpr auto KMemoryRegionType_VirtualDramUserPool =
KMemoryRegionType_VirtualDramHeapBase.Derive(3, 2);
static_assert(KMemoryRegionType_VirtualDramKernelInitPt.GetValue() == 0x19A);
static_assert(KMemoryRegionType_VirtualDramPoolManagement.GetValue() == 0x29A);
static_assert(KMemoryRegionType_VirtualDramUserPool.GetValue() == 0x31A);
// NOTE: For unknown reason, the pools are derived out-of-order here.
// It's worth eventually trying to understand why Nintendo made this choice.
// NOTE: For unknown reason, the pools are derived out-of-order here. It's worth eventually trying
// to understand why Nintendo made this choice.
// UNUSED: .Derive(6, 0);
// UNUSED: .Derive(6, 1);
constexpr inline auto KMemoryRegionType_VirtualDramAppletPool =
constexpr auto KMemoryRegionType_VirtualDramAppletPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 2);
constexpr inline auto KMemoryRegionType_VirtualDramApplicationPool =
constexpr auto KMemoryRegionType_VirtualDramApplicationPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 3);
constexpr inline auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
constexpr auto KMemoryRegionType_VirtualDramSystemNonSecurePool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 4);
constexpr inline auto KMemoryRegionType_VirtualDramSystemPool =
constexpr auto KMemoryRegionType_VirtualDramSystemPool =
KMemoryRegionType_VirtualDramUserPool.Derive(6, 5);
static_assert(KMemoryRegionType_VirtualDramAppletPool.GetValue() == 0x1B1A);
static_assert(KMemoryRegionType_VirtualDramApplicationPool.GetValue() == 0x271A);
static_assert(KMemoryRegionType_VirtualDramSystemNonSecurePool.GetValue() == 0x2B1A);
static_assert(KMemoryRegionType_VirtualDramSystemPool.GetValue() == 0x331A);
constexpr inline auto KMemoryRegionType_ArchDeviceBase =
constexpr auto KMemoryRegionType_ArchDeviceBase =
KMemoryRegionType_Kernel.DeriveTransition(0, 1).SetSparseOnly();
constexpr inline auto KMemoryRegionType_BoardDeviceBase =
constexpr auto KMemoryRegionType_BoardDeviceBase =
KMemoryRegionType_Kernel.DeriveTransition(0, 2).SetDenseOnly();
static_assert(KMemoryRegionType_ArchDeviceBase.GetValue() == 0x5);
static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5);
@@ -305,7 +284,7 @@ static_assert(KMemoryRegionType_BoardDeviceBase.GetValue() == 0x5);
#error "Unimplemented"
#else
// Default to no architecture devices.
constexpr inline auto NumArchitectureDeviceRegions = 0;
constexpr auto NumArchitectureDeviceRegions = 0;
#endif
static_assert(NumArchitectureDeviceRegions >= 0);
@@ -313,35 +292,34 @@ static_assert(NumArchitectureDeviceRegions >= 0);
#include "core/hle/kernel/board/nintendo/nx/k_memory_region_device_types.inc"
#else
// Default to no board devices.
constexpr inline auto NumBoardDeviceRegions = 0;
constexpr auto NumBoardDeviceRegions = 0;
#endif
static_assert(NumBoardDeviceRegions >= 0);
constexpr inline auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0);
constexpr inline auto KMemoryRegionType_KernelStack =
KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1);
constexpr inline auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2);
constexpr inline auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3);
constexpr auto KMemoryRegionType_KernelCode = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 0);
constexpr auto KMemoryRegionType_KernelStack = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 1);
constexpr auto KMemoryRegionType_KernelMisc = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 2);
constexpr auto KMemoryRegionType_KernelSlab = KMemoryRegionType_Kernel.DeriveSparse(1, 4, 3);
static_assert(KMemoryRegionType_KernelCode.GetValue() == 0x19);
static_assert(KMemoryRegionType_KernelStack.GetValue() == 0x29);
static_assert(KMemoryRegionType_KernelMisc.GetValue() == 0x49);
static_assert(KMemoryRegionType_KernelSlab.GetValue() == 0x89);
constexpr inline auto KMemoryRegionType_KernelMiscDerivedBase =
constexpr auto KMemoryRegionType_KernelMiscDerivedBase =
KMemoryRegionType_KernelMisc.DeriveTransition();
static_assert(KMemoryRegionType_KernelMiscDerivedBase.GetValue() == 0x149);
// UNUSED: .Derive(7, 0);
constexpr inline auto KMemoryRegionType_KernelMiscMainStack =
constexpr auto KMemoryRegionType_KernelMiscMainStack =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 1);
constexpr inline auto KMemoryRegionType_KernelMiscMappedDevice =
constexpr auto KMemoryRegionType_KernelMiscMappedDevice =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 2);
constexpr inline auto KMemoryRegionType_KernelMiscExceptionStack =
constexpr auto KMemoryRegionType_KernelMiscExceptionStack =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 3);
constexpr inline auto KMemoryRegionType_KernelMiscUnknownDebug =
constexpr auto KMemoryRegionType_KernelMiscUnknownDebug =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 4);
// UNUSED: .Derive(7, 5);
constexpr inline auto KMemoryRegionType_KernelMiscIdleStack =
constexpr auto KMemoryRegionType_KernelMiscIdleStack =
KMemoryRegionType_KernelMiscDerivedBase.Derive(7, 6);
static_assert(KMemoryRegionType_KernelMiscMainStack.GetValue() == 0xB49);
static_assert(KMemoryRegionType_KernelMiscMappedDevice.GetValue() == 0xD49);
@@ -349,8 +327,7 @@ static_assert(KMemoryRegionType_KernelMiscExceptionStack.GetValue() == 0x1349);
static_assert(KMemoryRegionType_KernelMiscUnknownDebug.GetValue() == 0x1549);
static_assert(KMemoryRegionType_KernelMiscIdleStack.GetValue() == 0x2349);
constexpr inline auto KMemoryRegionType_KernelTemp =
KMemoryRegionType_Kernel.Advance(2).Derive(2, 0);
constexpr auto KMemoryRegionType_KernelTemp = KMemoryRegionType_Kernel.Advance(2).Derive(2, 0);
static_assert(KMemoryRegionType_KernelTemp.GetValue() == 0x31);
constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
@@ -358,8 +335,6 @@ constexpr KMemoryRegionType GetTypeForVirtualLinearMapping(u32 type_id) {
return KMemoryRegionType_VirtualDramKernelTraceBuffer;
} else if (KMemoryRegionType_DramKernelPtHeap.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelPtHeap;
} else if (KMemoryRegionType_DramKernelSecureAppletMemory.IsAncestorOf(type_id)) {
return KMemoryRegionType_VirtualDramKernelSecureAppletMemory;
} else if ((type_id | KMemoryRegionAttr_ShouldKernelMap) == type_id) {
return KMemoryRegionType_VirtualDramUnknownDebug;
} else {

View File

@@ -16,126 +16,107 @@
namespace Kernel {
class KPageBitmap {
public:
private:
class RandomBitGenerator {
public:
RandomBitGenerator() {
m_rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
private:
Common::TinyMT rng{};
u32 entropy{};
u32 bits_available{};
private:
void RefreshEntropy() {
entropy = rng.GenerateRandomU32();
bits_available = static_cast<u32>(Common::BitSize<decltype(entropy)>());
}
u64 SelectRandomBit(u64 bitmap) {
bool GenerateRandomBit() {
if (bits_available == 0) {
this->RefreshEntropy();
}
const bool rnd_bit = (entropy & 1) != 0;
entropy >>= 1;
--bits_available;
return rnd_bit;
}
public:
RandomBitGenerator() {
rng.Initialize(static_cast<u32>(KSystemControl::GenerateRandomU64()));
}
std::size_t SelectRandomBit(u64 bitmap) {
u64 selected = 0;
for (size_t cur_num_bits = Common::BitSize<decltype(bitmap)>() / 2; cur_num_bits != 0;
cur_num_bits /= 2) {
const u64 high = (bitmap >> cur_num_bits);
const u64 low = (bitmap & (~(UINT64_C(0xFFFFFFFFFFFFFFFF) << cur_num_bits)));
u64 cur_num_bits = Common::BitSize<decltype(bitmap)>() / 2;
u64 cur_mask = (1ULL << cur_num_bits) - 1;
// Choose high if we have high and (don't have low or select high randomly).
if (high && (low == 0 || this->GenerateRandomBit())) {
bitmap = high;
selected += cur_num_bits;
while (cur_num_bits) {
const u64 low = (bitmap >> 0) & cur_mask;
const u64 high = (bitmap >> cur_num_bits) & cur_mask;
bool choose_low;
if (high == 0) {
// If only low val is set, choose low.
choose_low = true;
} else if (low == 0) {
// If only high val is set, choose high.
choose_low = false;
} else {
// If both are set, choose random.
choose_low = this->GenerateRandomBit();
}
// If we chose low, proceed with low.
if (choose_low) {
bitmap = low;
selected += 0;
} else {
bitmap = high;
selected += cur_num_bits;
}
// Proceed.
cur_num_bits /= 2;
cur_mask >>= cur_num_bits;
}
return selected;
}
u64 GenerateRandom(u64 max) {
// Determine the number of bits we need.
const u64 bits_needed = 1 + (Common::BitSize<decltype(max)>() - std::countl_zero(max));
// Generate a random value of the desired bitwidth.
const u64 rnd = this->GenerateRandomBits(static_cast<u32>(bits_needed));
// Adjust the value to be in range.
return rnd - ((rnd / max) * max);
}
private:
void RefreshEntropy() {
m_entropy = m_rng.GenerateRandomU32();
m_bits_available = static_cast<u32>(Common::BitSize<decltype(m_entropy)>());
}
bool GenerateRandomBit() {
if (m_bits_available == 0) {
this->RefreshEntropy();
}
const bool rnd_bit = (m_entropy & 1) != 0;
m_entropy >>= 1;
--m_bits_available;
return rnd_bit;
}
u64 GenerateRandomBits(u32 num_bits) {
u64 result = 0;
// Iteratively add random bits to our result.
while (num_bits > 0) {
// Ensure we have random bits to take from.
if (m_bits_available == 0) {
this->RefreshEntropy();
}
// Determine how many bits to take this round.
const auto cur_bits = std::min(num_bits, m_bits_available);
// Generate mask for our current bits.
const u64 mask = (static_cast<u64>(1) << cur_bits) - 1;
// Add bits to output from our entropy.
result <<= cur_bits;
result |= (m_entropy & mask);
// Remove bits from our entropy.
m_entropy >>= cur_bits;
m_bits_available -= cur_bits;
// Advance.
num_bits -= cur_bits;
}
return result;
}
private:
Common::TinyMT m_rng;
u32 m_entropy{};
u32 m_bits_available{};
};
public:
static constexpr size_t MaxDepth = 4;
static constexpr std::size_t MaxDepth = 4;
private:
std::array<u64*, MaxDepth> bit_storages{};
RandomBitGenerator rng{};
std::size_t num_bits{};
std::size_t used_depths{};
public:
KPageBitmap() = default;
constexpr size_t GetNumBits() const {
return m_num_bits;
constexpr std::size_t GetNumBits() const {
return num_bits;
}
constexpr s32 GetHighestDepthIndex() const {
return static_cast<s32>(m_used_depths) - 1;
return static_cast<s32>(used_depths) - 1;
}
u64* Initialize(u64* storage, size_t size) {
u64* Initialize(u64* storage, std::size_t size) {
// Initially, everything is un-set.
m_num_bits = 0;
num_bits = 0;
// Calculate the needed bitmap depth.
m_used_depths = static_cast<size_t>(GetRequiredDepth(size));
ASSERT(m_used_depths <= MaxDepth);
used_depths = static_cast<std::size_t>(GetRequiredDepth(size));
ASSERT(used_depths <= MaxDepth);
// Set the bitmap pointers.
for (s32 depth = this->GetHighestDepthIndex(); depth >= 0; depth--) {
m_bit_storages[depth] = storage;
bit_storages[depth] = storage;
size = Common::AlignUp(size, Common::BitSize<u64>()) / Common::BitSize<u64>();
storage += size;
m_end_storages[depth] = storage;
}
return storage;
@@ -147,19 +128,19 @@ public:
if (random) {
do {
const u64 v = m_bit_storages[depth][offset];
const u64 v = bit_storages[depth][offset];
if (v == 0) {
// If depth is bigger than zero, then a previous level indicated a block was
// free.
ASSERT(depth == 0);
return -1;
}
offset = offset * Common::BitSize<u64>() + m_rng.SelectRandomBit(v);
offset = offset * Common::BitSize<u64>() + rng.SelectRandomBit(v);
++depth;
} while (depth < static_cast<s32>(m_used_depths));
} while (depth < static_cast<s32>(used_depths));
} else {
do {
const u64 v = m_bit_storages[depth][offset];
const u64 v = bit_storages[depth][offset];
if (v == 0) {
// If depth is bigger than zero, then a previous level indicated a block was
// free.
@@ -168,69 +149,28 @@ public:
}
offset = offset * Common::BitSize<u64>() + std::countr_zero(v);
++depth;
} while (depth < static_cast<s32>(m_used_depths));
} while (depth < static_cast<s32>(used_depths));
}
return static_cast<s64>(offset);
}
s64 FindFreeRange(size_t count) {
// Check that it is possible to find a range.
const u64* const storage_start = m_bit_storages[m_used_depths - 1];
const u64* const storage_end = m_end_storages[m_used_depths - 1];
// If we don't have a storage to iterate (or want more blocks than fit in a single storage),
// we can't find a free range.
if (!(storage_start < storage_end && count <= Common::BitSize<u64>())) {
return -1;
}
// Walk the storages to select a random free range.
const size_t options_per_storage = std::max<size_t>(Common::BitSize<u64>() / count, 1);
const size_t num_entries = std::max<size_t>(storage_end - storage_start, 1);
const u64 free_mask = (static_cast<u64>(1) << count) - 1;
size_t num_valid_options = 0;
s64 chosen_offset = -1;
for (size_t storage_index = 0; storage_index < num_entries; ++storage_index) {
u64 storage = storage_start[storage_index];
for (size_t option = 0; option < options_per_storage; ++option) {
if ((storage & free_mask) == free_mask) {
// We've found a new valid option.
++num_valid_options;
// Select the Kth valid option with probability 1/K. This leads to an overall
// uniform distribution.
if (num_valid_options == 1 || m_rng.GenerateRandom(num_valid_options) == 0) {
// This is our first option, so select it.
chosen_offset = storage_index * Common::BitSize<u64>() + option * count;
}
}
storage >>= count;
}
}
// Return the random offset we chose.*/
return chosen_offset;
}
void SetBit(size_t offset) {
void SetBit(std::size_t offset) {
this->SetBit(this->GetHighestDepthIndex(), offset);
m_num_bits++;
num_bits++;
}
void ClearBit(size_t offset) {
void ClearBit(std::size_t offset) {
this->ClearBit(this->GetHighestDepthIndex(), offset);
m_num_bits--;
num_bits--;
}
bool ClearRange(size_t offset, size_t count) {
bool ClearRange(std::size_t offset, std::size_t count) {
s32 depth = this->GetHighestDepthIndex();
u64* bits = m_bit_storages[depth];
size_t bit_ind = offset / Common::BitSize<u64>();
if (count < Common::BitSize<u64>()) [[likely]] {
const size_t shift = offset % Common::BitSize<u64>();
u64* bits = bit_storages[depth];
std::size_t bit_ind = offset / Common::BitSize<u64>();
if (count < Common::BitSize<u64>()) {
const std::size_t shift = offset % Common::BitSize<u64>();
ASSERT(shift + count <= Common::BitSize<u64>());
// Check that all the bits are set.
const u64 mask = ((u64(1) << count) - 1) << shift;
@@ -249,8 +189,8 @@ public:
ASSERT(offset % Common::BitSize<u64>() == 0);
ASSERT(count % Common::BitSize<u64>() == 0);
// Check that all the bits are set.
size_t remaining = count;
size_t i = 0;
std::size_t remaining = count;
std::size_t i = 0;
do {
if (bits[bit_ind + i++] != ~u64(0)) {
return false;
@@ -269,18 +209,18 @@ public:
} while (remaining > 0);
}
m_num_bits -= count;
num_bits -= count;
return true;
}
private:
void SetBit(s32 depth, size_t offset) {
void SetBit(s32 depth, std::size_t offset) {
while (depth >= 0) {
size_t ind = offset / Common::BitSize<u64>();
size_t which = offset % Common::BitSize<u64>();
std::size_t ind = offset / Common::BitSize<u64>();
std::size_t which = offset % Common::BitSize<u64>();
const u64 mask = u64(1) << which;
u64* bit = std::addressof(m_bit_storages[depth][ind]);
u64* bit = std::addressof(bit_storages[depth][ind]);
u64 v = *bit;
ASSERT((v & mask) == 0);
*bit = v | mask;
@@ -292,13 +232,13 @@ private:
}
}
void ClearBit(s32 depth, size_t offset) {
void ClearBit(s32 depth, std::size_t offset) {
while (depth >= 0) {
size_t ind = offset / Common::BitSize<u64>();
size_t which = offset % Common::BitSize<u64>();
std::size_t ind = offset / Common::BitSize<u64>();
std::size_t which = offset % Common::BitSize<u64>();
const u64 mask = u64(1) << which;
u64* bit = std::addressof(m_bit_storages[depth][ind]);
u64* bit = std::addressof(bit_storages[depth][ind]);
u64 v = *bit;
ASSERT((v & mask) != 0);
v &= ~mask;
@@ -312,7 +252,7 @@ private:
}
private:
static constexpr s32 GetRequiredDepth(size_t region_size) {
static constexpr s32 GetRequiredDepth(std::size_t region_size) {
s32 depth = 0;
while (true) {
region_size /= Common::BitSize<u64>();
@@ -324,8 +264,8 @@ private:
}
public:
static constexpr size_t CalculateManagementOverheadSize(size_t region_size) {
size_t overhead_bits = 0;
static constexpr std::size_t CalculateManagementOverheadSize(std::size_t region_size) {
std::size_t overhead_bits = 0;
for (s32 depth = GetRequiredDepth(region_size) - 1; depth >= 0; depth--) {
region_size =
Common::AlignUp(region_size, Common::BitSize<u64>()) / Common::BitSize<u64>();
@@ -333,13 +273,6 @@ public:
}
return overhead_bits * sizeof(u64);
}
private:
std::array<u64*, MaxDepth> m_bit_storages{};
std::array<u64*, MaxDepth> m_end_storages{};
RandomBitGenerator m_rng;
size_t m_num_bits{};
size_t m_used_depths{};
};
} // namespace Kernel

View File

@@ -11,16 +11,6 @@
namespace Kernel {
class KernelCore;
class KPageBufferSlabHeap : protected impl::KSlabHeapImpl {
public:
static constexpr size_t BufferSize = PageSize;
public:
void Initialize(Core::System& system);
};
class KPageBuffer final : public KSlabAllocated<KPageBuffer> {
public:
explicit KPageBuffer(KernelCore&) {}
@@ -31,6 +21,8 @@ public:
private:
[[maybe_unused]] alignas(PageSize) std::array<u8, PageSize> m_buffer{};
};
static_assert(sizeof(KPageBuffer) == KPageBufferSlabHeap::BufferSize);
static_assert(sizeof(KPageBuffer) == PageSize);
static_assert(alignof(KPageBuffer) == PageSize);
} // namespace Kernel

View File

@@ -5,7 +5,6 @@
#include <list>
#include "common/alignment.h"
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/kernel/memory_types.h"
@@ -13,89 +12,6 @@
namespace Kernel {
class KPageGroup;
class KBlockInfo {
private:
friend class KPageGroup;
public:
constexpr KBlockInfo() = default;
constexpr void Initialize(PAddr addr, size_t np) {
ASSERT(Common::IsAligned(addr, PageSize));
ASSERT(static_cast<u32>(np) == np);
m_page_index = static_cast<u32>(addr) / PageSize;
m_num_pages = static_cast<u32>(np);
}
constexpr PAddr GetAddress() const {
return m_page_index * PageSize;
}
constexpr size_t GetNumPages() const {
return m_num_pages;
}
constexpr size_t GetSize() const {
return this->GetNumPages() * PageSize;
}
constexpr PAddr GetEndAddress() const {
return (m_page_index + m_num_pages) * PageSize;
}
constexpr PAddr GetLastAddress() const {
return this->GetEndAddress() - 1;
}
constexpr KBlockInfo* GetNext() const {
return m_next;
}
constexpr bool IsEquivalentTo(const KBlockInfo& rhs) const {
return m_page_index == rhs.m_page_index && m_num_pages == rhs.m_num_pages;
}
constexpr bool operator==(const KBlockInfo& rhs) const {
return this->IsEquivalentTo(rhs);
}
constexpr bool operator!=(const KBlockInfo& rhs) const {
return !(*this == rhs);
}
constexpr bool IsStrictlyBefore(PAddr addr) const {
const PAddr end = this->GetEndAddress();
if (m_page_index != 0 && end == 0) {
return false;
}
return end < addr;
}
constexpr bool operator<(PAddr addr) const {
return this->IsStrictlyBefore(addr);
}
constexpr bool TryConcatenate(PAddr addr, size_t np) {
if (addr != 0 && addr == this->GetEndAddress()) {
m_num_pages += static_cast<u32>(np);
return true;
}
return false;
}
private:
constexpr void SetNext(KBlockInfo* next) {
m_next = next;
}
private:
KBlockInfo* m_next{};
u32 m_page_index{};
u32 m_num_pages{};
};
static_assert(sizeof(KBlockInfo) <= 0x10);
class KPageGroup final {
public:
class Node final {
@@ -176,8 +92,6 @@ public:
return nodes.empty();
}
void Finalize() {}
private:
std::list<Node> nodes;
};

View File

@@ -44,11 +44,11 @@ size_t KPageHeap::GetNumFreePages() const {
return num_free;
}
PAddr KPageHeap::AllocateByLinearSearch(s32 index) {
PAddr KPageHeap::AllocateBlock(s32 index, bool random) {
const size_t needed_size = m_blocks[index].GetSize();
for (s32 i = index; i < static_cast<s32>(m_num_blocks); i++) {
if (const PAddr addr = m_blocks[i].PopBlock(false); addr != 0) {
if (const PAddr addr = m_blocks[i].PopBlock(random); addr != 0) {
if (const size_t allocated_size = m_blocks[i].GetSize(); allocated_size > needed_size) {
this->Free(addr + needed_size, (allocated_size - needed_size) / PageSize);
}
@@ -59,88 +59,6 @@ PAddr KPageHeap::AllocateByLinearSearch(s32 index) {
return 0;
}
PAddr KPageHeap::AllocateByRandom(s32 index, size_t num_pages, size_t align_pages) {
// Get the size and required alignment.
const size_t needed_size = num_pages * PageSize;
const size_t align_size = align_pages * PageSize;
// Determine meta-alignment of our desired alignment size.
const size_t align_shift = std::countr_zero(align_size);
// Decide on a block to allocate from.
constexpr size_t MinimumPossibleAlignmentsForRandomAllocation = 4;
{
// By default, we'll want to look at all blocks larger than our current one.
s32 max_blocks = static_cast<s32>(m_num_blocks);
// Determine the maximum block we should try to allocate from.
size_t possible_alignments = 0;
for (s32 i = index; i < max_blocks; ++i) {
// Add the possible alignments from blocks at the current size.
possible_alignments += (1 + ((m_blocks[i].GetSize() - needed_size) >> align_shift)) *
m_blocks[i].GetNumFreeBlocks();
// If there are enough possible alignments, we don't need to look at larger blocks.
if (possible_alignments >= MinimumPossibleAlignmentsForRandomAllocation) {
max_blocks = i + 1;
break;
}
}
// If we have any possible alignments which require a larger block, we need to pick one.
if (possible_alignments > 0 && index + 1 < max_blocks) {
// Select a random alignment from the possibilities.
const size_t rnd = m_rng.GenerateRandom(possible_alignments);
// Determine which block corresponds to the random alignment we chose.
possible_alignments = 0;
for (s32 i = index; i < max_blocks; ++i) {
// Add the possible alignments from blocks at the current size.
possible_alignments +=
(1 + ((m_blocks[i].GetSize() - needed_size) >> align_shift)) *
m_blocks[i].GetNumFreeBlocks();
// If the current block gets us to our random choice, use the current block.
if (rnd < possible_alignments) {
index = i;
break;
}
}
}
}
// Pop a block from the index we selected.
if (PAddr addr = m_blocks[index].PopBlock(true); addr != 0) {
// Determine how much size we have left over.
if (const size_t leftover_size = m_blocks[index].GetSize() - needed_size;
leftover_size > 0) {
// Determine how many valid alignments we can have.
const size_t possible_alignments = 1 + (leftover_size >> align_shift);
// Select a random valid alignment.
const size_t random_offset = m_rng.GenerateRandom(possible_alignments) << align_shift;
// Free memory before the random offset.
if (random_offset != 0) {
this->Free(addr, random_offset / PageSize);
}
// Advance our block by the random offset.
addr += random_offset;
// Free memory after our allocated block.
if (random_offset != leftover_size) {
this->Free(addr + needed_size, (leftover_size - random_offset) / PageSize);
}
}
// Return the block we allocated.
return addr;
}
return 0;
}
void KPageHeap::FreeBlock(PAddr block, s32 index) {
do {
block = m_blocks[index++].PushBlock(block);

View File

@@ -14,9 +14,13 @@
namespace Kernel {
class KPageHeap {
class KPageHeap final {
public:
YUZU_NON_COPYABLE(KPageHeap);
YUZU_NON_MOVEABLE(KPageHeap);
KPageHeap() = default;
~KPageHeap() = default;
constexpr PAddr GetAddress() const {
return m_heap_address;
@@ -53,20 +57,7 @@ public:
m_initial_used_size = m_heap_size - free_size - reserved_size;
}
PAddr AllocateBlock(s32 index, bool random) {
if (random) {
const size_t block_pages = m_blocks[index].GetNumPages();
return this->AllocateByRandom(index, block_pages, block_pages);
} else {
return this->AllocateByLinearSearch(index);
}
}
PAddr AllocateAligned(s32 index, size_t num_pages, size_t align_pages) {
// TODO: linear search support?
return this->AllocateByRandom(index, num_pages, align_pages);
}
PAddr AllocateBlock(s32 index, bool random);
void Free(PAddr addr, size_t num_pages);
static size_t CalculateManagementOverheadSize(size_t region_size) {
@@ -77,7 +68,7 @@ public:
static constexpr s32 GetAlignedBlockIndex(size_t num_pages, size_t align_pages) {
const size_t target_pages = std::max(num_pages, align_pages);
for (size_t i = 0; i < NumMemoryBlockPageShifts; i++) {
if (target_pages <= (static_cast<size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
if (target_pages <= (size_t(1) << MemoryBlockPageShifts[i]) / PageSize) {
return static_cast<s32>(i);
}
}
@@ -86,7 +77,7 @@ public:
static constexpr s32 GetBlockIndex(size_t num_pages) {
for (s32 i = static_cast<s32>(NumMemoryBlockPageShifts) - 1; i >= 0; i--) {
if (num_pages >= (static_cast<size_t>(1) << MemoryBlockPageShifts[i]) / PageSize) {
if (num_pages >= (size_t(1) << MemoryBlockPageShifts[i]) / PageSize) {
return i;
}
}
@@ -94,7 +85,7 @@ public:
}
static constexpr size_t GetBlockSize(size_t index) {
return static_cast<size_t>(1) << MemoryBlockPageShifts[index];
return size_t(1) << MemoryBlockPageShifts[index];
}
static constexpr size_t GetBlockNumPages(size_t index) {
@@ -102,9 +93,13 @@ public:
}
private:
class Block {
class Block final {
public:
YUZU_NON_COPYABLE(Block);
YUZU_NON_MOVEABLE(Block);
Block() = default;
~Block() = default;
constexpr size_t GetShift() const {
return m_block_shift;
@@ -206,9 +201,6 @@ private:
};
private:
PAddr AllocateByLinearSearch(s32 index);
PAddr AllocateByRandom(s32 index, size_t num_pages, size_t align_pages);
static size_t CalculateManagementOverheadSize(size_t region_size, const size_t* block_shifts,
size_t num_block_shifts);
@@ -217,8 +209,7 @@ private:
size_t m_heap_size{};
size_t m_initial_used_size{};
size_t m_num_blocks{};
std::array<Block, NumMemoryBlockPageShifts> m_blocks;
KPageBitmap::RandomBitGenerator m_rng;
std::array<Block, NumMemoryBlockPageShifts> m_blocks{};
std::vector<u64> m_management_data;
};

File diff suppressed because it is too large Load Diff

View File

@@ -16,7 +16,6 @@
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/result.h"
#include "core/memory.h"
namespace Core {
class System;
@@ -24,10 +23,7 @@ class System;
namespace Kernel {
class KBlockInfoManager;
class KMemoryBlockManager;
class KResourceLimit;
class KSystemResource;
class KPageTable final {
public:
@@ -40,9 +36,9 @@ public:
~KPageTable();
Result InitializeForProcess(FileSys::ProgramAddressSpaceType as_type, bool enable_aslr,
bool enable_das_merge, bool from_back, KMemoryManager::Pool pool,
VAddr code_addr, size_t code_size, KSystemResource* system_resource,
KResourceLimit* resource_limit);
VAddr code_addr, size_t code_size,
KMemoryBlockSlabManager* mem_block_slab_manager,
KMemoryManager::Pool pool);
void Finalize();
@@ -78,20 +74,12 @@ public:
KMemoryState state, KMemoryPermission perm,
PAddr map_addr = 0);
Result LockForMapDeviceAddressSpace(bool* out_is_io, VAddr address, size_t size,
KMemoryPermission perm, bool is_aligned, bool check_heap);
Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size, bool check_heap);
Result LockForMapDeviceAddressSpace(VAddr address, size_t size, KMemoryPermission perm,
bool is_aligned);
Result LockForUnmapDeviceAddressSpace(VAddr address, size_t size);
Result UnlockForDeviceAddressSpace(VAddr addr, size_t size);
Result LockForIpcUserBuffer(PAddr* out, VAddr address, size_t size);
Result UnlockForIpcUserBuffer(VAddr address, size_t size);
Result SetupForIpc(VAddr* out_dst_addr, size_t size, VAddr src_addr, KPageTable& src_page_table,
KMemoryPermission test_perm, KMemoryState dst_state, bool send);
Result CleanupForIpcServer(VAddr address, size_t size, KMemoryState dst_state);
Result CleanupForIpcClient(VAddr address, size_t size, KMemoryState dst_state);
Result LockForCodeMemory(KPageGroup* out, VAddr addr, size_t size);
Result UnlockForCodeMemory(VAddr addr, size_t size, const KPageGroup& pg);
Result MakeAndOpenPageGroup(KPageGroup* out, VAddr address, size_t num_pages,
@@ -109,54 +97,13 @@ public:
bool CanContain(VAddr addr, size_t size, KMemoryState state) const;
protected:
struct PageLinkedList {
private:
struct Node {
Node* m_next;
std::array<u8, PageSize - sizeof(Node*)> m_buffer;
};
public:
constexpr PageLinkedList() = default;
void Push(Node* n) {
ASSERT(Common::IsAligned(reinterpret_cast<uintptr_t>(n), PageSize));
n->m_next = m_root;
m_root = n;
}
void Push(Core::Memory::Memory& memory, VAddr addr) {
this->Push(memory.GetPointer<Node>(addr));
}
Node* Peek() const {
return m_root;
}
Node* Pop() {
Node* const r = m_root;
m_root = r->m_next;
r->m_next = nullptr;
return r;
}
private:
Node* m_root{};
};
static_assert(std::is_trivially_destructible<PageLinkedList>::value);
private:
enum class OperationType : u32 {
Map = 0,
MapFirst = 1,
MapGroup = 2,
Unmap = 3,
ChangePermissions = 4,
ChangePermissionsAndRefresh = 5,
Separate = 6,
Map,
MapGroup,
Unmap,
ChangePermissions,
ChangePermissionsAndRefresh,
};
static constexpr KMemoryAttribute DefaultMemoryIgnoreAttr =
@@ -176,7 +123,6 @@ private:
OperationType operation);
Result Operate(VAddr addr, size_t num_pages, KMemoryPermission perm, OperationType operation,
PAddr map_addr = 0);
void FinalizeUpdate(PageLinkedList* page_list);
VAddr GetRegionAddress(KMemoryState state) const;
size_t GetRegionSize(KMemoryState state) const;
@@ -253,18 +199,6 @@ private:
return *out != 0;
}
Result SetupForIpcClient(PageLinkedList* page_list, size_t* out_blocks_needed, VAddr address,
size_t size, KMemoryPermission test_perm, KMemoryState dst_state);
Result SetupForIpcServer(VAddr* out_addr, size_t size, VAddr src_addr,
KMemoryPermission test_perm, KMemoryState dst_state,
KPageTable& src_page_table, bool send);
void CleanupForIpcClientOnServerSetupFailure(PageLinkedList* page_list, VAddr address,
size_t size, KMemoryPermission prot_perm);
// HACK: These will be removed once we automatically manage page reference counts.
void HACK_OpenPages(PAddr phys_addr, size_t num_pages);
void HACK_ClosePages(VAddr virt_addr, size_t num_pages);
mutable KLightLock m_general_lock;
mutable KLightLock m_map_physical_memory_lock;
@@ -382,31 +316,6 @@ public:
addr + size - 1 <= m_address_space_end - 1;
}
public:
static VAddr GetLinearMappedVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
return layout.GetLinearVirtualAddress(addr);
}
static PAddr GetLinearMappedPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
return layout.GetLinearPhysicalAddress(addr);
}
static VAddr GetHeapVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
return GetLinearMappedVirtualAddress(layout, addr);
}
static PAddr GetHeapPhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
return GetLinearMappedPhysicalAddress(layout, addr);
}
static VAddr GetPageTableVirtualAddress(const KMemoryLayout& layout, PAddr addr) {
return GetLinearMappedVirtualAddress(layout, addr);
}
static PAddr GetPageTablePhysicalAddress(const KMemoryLayout& layout, VAddr addr) {
return GetLinearMappedPhysicalAddress(layout, addr);
}
private:
constexpr bool IsKernel() const {
return m_is_kernel;
@@ -421,24 +330,6 @@ private:
(addr + num_pages * PageSize - 1 <= m_address_space_end - 1);
}
private:
class KScopedPageTableUpdater {
private:
KPageTable* m_pt{};
PageLinkedList m_ll;
public:
explicit KScopedPageTableUpdater(KPageTable* pt) : m_pt(pt) {}
explicit KScopedPageTableUpdater(KPageTable& pt) : KScopedPageTableUpdater(&pt) {}
~KScopedPageTableUpdater() {
m_pt->FinalizeUpdate(this->GetPageList());
}
PageLinkedList* GetPageList() {
return &m_ll;
}
};
private:
VAddr m_address_space_start{};
VAddr m_address_space_end{};
@@ -456,27 +347,20 @@ private:
VAddr m_alias_code_region_start{};
VAddr m_alias_code_region_end{};
size_t m_max_heap_size{};
size_t m_mapped_physical_memory_size{};
size_t m_mapped_unsafe_physical_memory{};
size_t m_mapped_insecure_memory{};
size_t m_mapped_ipc_server_memory{};
size_t m_max_heap_size{};
size_t m_max_physical_memory_size{};
size_t m_address_space_width{};
KMemoryBlockManager m_memory_block_manager;
u32 m_allocate_option{};
bool m_is_kernel{};
bool m_enable_aslr{};
bool m_enable_device_address_space_merge{};
KMemoryBlockSlabManager* m_memory_block_slab_manager{};
KBlockInfoManager* m_block_info_manager{};
KResourceLimit* m_resource_limit{};
u32 m_heap_fill_value{};
u32 m_ipc_fill_value{};
u32 m_stack_fill_value{};
const KMemoryRegion* m_cached_physical_heap_region{};
KMemoryManager::Pool m_memory_pool{KMemoryManager::Pool::Application};

View File

@@ -1,55 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_page_table_slab_heap.h"
namespace Kernel {
class KPageTableManager : public KDynamicResourceManager<impl::PageTablePage, true> {
public:
using RefCount = KPageTableSlabHeap::RefCount;
static constexpr size_t PageTableSize = KPageTableSlabHeap::PageTableSize;
public:
KPageTableManager() = default;
void Initialize(KDynamicPageManager* page_allocator, KPageTableSlabHeap* pt_heap) {
m_pt_heap = pt_heap;
static_assert(std::derived_from<KPageTableSlabHeap, DynamicSlabType>);
BaseHeap::Initialize(page_allocator, pt_heap);
}
VAddr Allocate() {
return VAddr(BaseHeap::Allocate());
}
RefCount GetRefCount(VAddr addr) const {
return m_pt_heap->GetRefCount(addr);
}
void Open(VAddr addr, int count) {
return m_pt_heap->Open(addr, count);
}
bool Close(VAddr addr, int count) {
return m_pt_heap->Close(addr, count);
}
bool IsInPageTableHeap(VAddr addr) const {
return m_pt_heap->IsInRange(addr);
}
private:
using BaseHeap = KDynamicResourceManager<impl::PageTablePage, true>;
KPageTableSlabHeap* m_pt_heap{};
};
} // namespace Kernel

View File

@@ -1,93 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include <vector>
#include "common/common_types.h"
#include "core/hle/kernel/k_dynamic_slab_heap.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
namespace impl {
class PageTablePage {
public:
// Do not initialize anything.
PageTablePage() = default;
private:
std::array<u8, PageSize> m_buffer{};
};
static_assert(sizeof(PageTablePage) == PageSize);
} // namespace impl
class KPageTableSlabHeap : public KDynamicSlabHeap<impl::PageTablePage, true> {
public:
using RefCount = u16;
static constexpr size_t PageTableSize = sizeof(impl::PageTablePage);
static_assert(PageTableSize == PageSize);
public:
KPageTableSlabHeap() = default;
static constexpr size_t CalculateReferenceCountSize(size_t size) {
return (size / PageSize) * sizeof(RefCount);
}
void Initialize(KDynamicPageManager* page_allocator, size_t object_count, RefCount* rc) {
BaseHeap::Initialize(page_allocator, object_count);
this->Initialize(rc);
}
RefCount GetRefCount(VAddr addr) {
ASSERT(this->IsInRange(addr));
return *this->GetRefCountPointer(addr);
}
void Open(VAddr addr, int count) {
ASSERT(this->IsInRange(addr));
*this->GetRefCountPointer(addr) += static_cast<RefCount>(count);
ASSERT(this->GetRefCount(addr) > 0);
}
bool Close(VAddr addr, int count) {
ASSERT(this->IsInRange(addr));
ASSERT(this->GetRefCount(addr) >= count);
*this->GetRefCountPointer(addr) -= static_cast<RefCount>(count);
return this->GetRefCount(addr) == 0;
}
bool IsInPageTableHeap(VAddr addr) const {
return this->IsInRange(addr);
}
private:
void Initialize([[maybe_unused]] RefCount* rc) {
// TODO(bunnei): Use rc once we support kernel virtual memory allocations.
const auto count = this->GetSize() / PageSize;
m_ref_counts.resize(count);
for (size_t i = 0; i < count; i++) {
m_ref_counts[i] = 0;
}
}
RefCount* GetRefCountPointer(VAddr addr) {
return m_ref_counts.data() + ((addr - this->GetAddress()) / PageSize);
}
private:
using BaseHeap = KDynamicSlabHeap<impl::PageTablePage, true>;
std::vector<RefCount> m_ref_counts;
};
} // namespace Kernel

View File

@@ -38,7 +38,7 @@ namespace {
*/
void SetupMainThread(Core::System& system, KProcess& owner_process, u32 priority, VAddr stack_top) {
const VAddr entry_point = owner_process.PageTable().GetCodeRegionStart();
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::ThreadCountMax, 1));
ASSERT(owner_process.GetResourceLimit()->Reserve(LimitableResource::Threads, 1));
KThread* thread = KThread::Create(system.Kernel());
SCOPE_EXIT({ thread->Close(); });
@@ -124,7 +124,7 @@ void KProcess::DecrementRunningThreadCount() {
}
u64 KProcess::GetTotalPhysicalMemoryAvailable() {
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemoryMax) +
const u64 capacity{resource_limit->GetFreeValue(LimitableResource::PhysicalMemory) +
page_table.GetNormalMemorySize() + GetSystemResourceSize() + image_size +
main_thread_stack_size};
if (const auto pool_size = kernel.MemoryManager().GetSize(KMemoryManager::Pool::Application);
@@ -349,8 +349,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
// We currently do not support process-specific system resource
UNIMPLEMENTED_IF(system_resource_size != 0);
KScopedResourceReservation memory_reservation(
resource_limit, LimitableResource::PhysicalMemoryMax, code_size + system_resource_size);
KScopedResourceReservation memory_reservation(resource_limit, LimitableResource::PhysicalMemory,
code_size + system_resource_size);
if (!memory_reservation.Succeeded()) {
LOG_ERROR(Kernel, "Could not reserve process memory requirements of size {:X} bytes",
code_size + system_resource_size);
@@ -358,8 +358,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
}
// Initialize proces address space
if (const Result result{page_table.InitializeForProcess(
metadata.GetAddressSpaceType(), false, false, false, KMemoryManager::Pool::Application,
0x8000000, code_size, &kernel.GetSystemSystemResource(), resource_limit)};
metadata.GetAddressSpaceType(), false, 0x8000000, code_size,
&kernel.GetApplicationMemoryBlockManager(), KMemoryManager::Pool::Application)};
result.IsError()) {
R_RETURN(result);
}
@@ -406,8 +406,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
void KProcess::Run(s32 main_thread_priority, u64 stack_size) {
AllocateMainThreadStack(stack_size);
resource_limit->Reserve(LimitableResource::ThreadCountMax, 1);
resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, main_thread_stack_size);
resource_limit->Reserve(LimitableResource::Threads, 1);
resource_limit->Reserve(LimitableResource::PhysicalMemory, main_thread_stack_size);
const std::size_t heap_capacity{memory_usage_capacity - (main_thread_stack_size + image_size)};
ASSERT(!page_table.SetMaxHeapSize(heap_capacity).IsError());
@@ -442,7 +442,7 @@ void KProcess::PrepareForTermination() {
plr_address = 0;
if (resource_limit) {
resource_limit->Release(LimitableResource::PhysicalMemoryMax,
resource_limit->Release(LimitableResource::PhysicalMemory,
main_thread_stack_size + image_size);
}

View File

@@ -159,13 +159,12 @@ KResourceLimit* CreateResourceLimitForProcess(Core::System& system, s64 physical
// TODO(bunnei): These values are the system defaults, the limits for service processes are
// lower. These should use the correct limit values.
ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, physical_memory_size)
ASSERT(resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, physical_memory_size)
.IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::EventCountMax, 900).IsSuccess());
ASSERT(
resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 1133).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200).IsSuccess());
ASSERT(resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
return resource_limit;
}

View File

@@ -16,8 +16,15 @@ class CoreTiming;
namespace Kernel {
class KernelCore;
enum class LimitableResource : u32 {
PhysicalMemory = 0,
Threads = 1,
Events = 2,
TransferMemory = 3,
Sessions = 4,
using LimitableResource = Svc::LimitableResource;
Count,
};
constexpr bool IsValidResourceType(LimitableResource type) {
return type < LimitableResource::Count;

View File

@@ -384,8 +384,7 @@ void KScheduler::SwitchThread(KThread* next_thread) {
void KScheduler::ScheduleImpl() {
// First, clear the needs scheduling bool.
m_state.needs_scheduling.store(false, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
m_state.needs_scheduling.store(false, std::memory_order_seq_cst);
// Load the appropriate thread pointers for scheduling.
KThread* const cur_thread{GetCurrentThreadPointer(kernel)};
@@ -401,8 +400,7 @@ void KScheduler::ScheduleImpl() {
// If there aren't, we want to check if the highest priority thread is the same as the current
// thread.
if (highest_priority_thread == cur_thread) {
// If they're the same, then we can just issue a memory barrier and return.
std::atomic_thread_fence(std::memory_order_seq_cst);
// If they're the same, then we can just return.
return;
}
@@ -478,8 +476,7 @@ void KScheduler::ScheduleImplFiber() {
// We failed to successfully do the context switch, and need to retry.
// Clear needs_scheduling.
m_state.needs_scheduling.store(false, std::memory_order_relaxed);
std::atomic_thread_fence(std::memory_order_seq_cst);
m_state.needs_scheduling.store(false, std::memory_order_seq_cst);
// Refresh the highest priority thread.
highest_priority_thread = m_state.highest_priority_thread;

View File

@@ -60,9 +60,6 @@ public:
// Release an instance of the lock.
if ((--lock_count) == 0) {
// Perform a memory barrier here.
std::atomic_thread_fence(std::memory_order_seq_cst);
// We're no longer going to hold the lock. Take note of what cores need scheduling.
const u64 cores_needing_scheduling =
SchedulerType::UpdateHighestPriorityThreads(kernel);

View File

@@ -76,7 +76,7 @@ void KSession::OnClientClosed() {
void KSession::PostDestroy(uintptr_t arg) {
// Release the session count resource the owner process holds.
KProcess* owner = reinterpret_cast<KProcess*>(arg);
owner->GetResourceLimit()->Release(LimitableResource::SessionCountMax, 1);
owner->GetResourceLimit()->Release(LimitableResource::Sessions, 1);
owner->Close();
}

View File

@@ -14,7 +14,7 @@ namespace Kernel {
KSharedMemory::KSharedMemory(KernelCore& kernel_) : KAutoObjectWithSlabHeapAndContainer{kernel_} {}
KSharedMemory::~KSharedMemory() {
kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemoryMax, size);
kernel.GetSystemResourceLimit()->Release(LimitableResource::PhysicalMemory, size);
}
Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* owner_process_,
@@ -35,7 +35,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
KResourceLimit* reslimit = kernel.GetSystemResourceLimit();
// Reserve memory for ourselves.
KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemoryMax,
KScopedResourceReservation memory_reservation(reslimit, LimitableResource::PhysicalMemory,
size_);
R_UNLESS(memory_reservation.Succeeded(), ResultLimitReached);
@@ -57,7 +57,7 @@ Result KSharedMemory::Initialize(Core::DeviceMemory& device_memory_, KProcess* o
void KSharedMemory::Finalize() {
// Release the memory reservation.
resource_limit->Release(LimitableResource::PhysicalMemoryMax, size);
resource_limit->Release(LimitableResource::PhysicalMemory, size);
resource_limit->Close();
// Perform inherited finalization.

View File

@@ -1,26 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/hle/kernel/k_system_resource.h"
namespace Kernel {
Result KSecureSystemResource::Initialize([[maybe_unused]] size_t size,
[[maybe_unused]] KResourceLimit* resource_limit,
[[maybe_unused]] KMemoryManager::Pool pool) {
// Unimplemented
UNREACHABLE();
}
void KSecureSystemResource::Finalize() {
// Unimplemented
UNREACHABLE();
}
size_t KSecureSystemResource::CalculateRequiredSecureMemorySize(
[[maybe_unused]] size_t size, [[maybe_unused]] KMemoryManager::Pool pool) {
// Unimplemented
UNREACHABLE();
}
} // namespace Kernel

View File

@@ -1,137 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include "common/assert.h"
#include "common/common_types.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_dynamic_resource_manager.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_table_manager.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/slab_helpers.h"
namespace Kernel {
// NOTE: Nintendo's implementation does not have the "is_secure_resource" field, and instead uses
// virtual IsSecureResource().
class KSystemResource : public KAutoObject {
KERNEL_AUTOOBJECT_TRAITS(KSystemResource, KAutoObject);
public:
explicit KSystemResource(KernelCore& kernel_) : KAutoObject(kernel_) {}
protected:
void SetSecureResource() {
m_is_secure_resource = true;
}
public:
virtual void Destroy() override {
UNREACHABLE_MSG("KSystemResource::Destroy() was called");
}
bool IsSecureResource() const {
return m_is_secure_resource;
}
void SetManagers(KMemoryBlockSlabManager& mb, KBlockInfoManager& bi, KPageTableManager& pt) {
ASSERT(m_p_memory_block_slab_manager == nullptr);
ASSERT(m_p_block_info_manager == nullptr);
ASSERT(m_p_page_table_manager == nullptr);
m_p_memory_block_slab_manager = std::addressof(mb);
m_p_block_info_manager = std::addressof(bi);
m_p_page_table_manager = std::addressof(pt);
}
const KMemoryBlockSlabManager& GetMemoryBlockSlabManager() const {
return *m_p_memory_block_slab_manager;
}
const KBlockInfoManager& GetBlockInfoManager() const {
return *m_p_block_info_manager;
}
const KPageTableManager& GetPageTableManager() const {
return *m_p_page_table_manager;
}
KMemoryBlockSlabManager& GetMemoryBlockSlabManager() {
return *m_p_memory_block_slab_manager;
}
KBlockInfoManager& GetBlockInfoManager() {
return *m_p_block_info_manager;
}
KPageTableManager& GetPageTableManager() {
return *m_p_page_table_manager;
}
KMemoryBlockSlabManager* GetMemoryBlockSlabManagerPointer() {
return m_p_memory_block_slab_manager;
}
KBlockInfoManager* GetBlockInfoManagerPointer() {
return m_p_block_info_manager;
}
KPageTableManager* GetPageTableManagerPointer() {
return m_p_page_table_manager;
}
private:
KMemoryBlockSlabManager* m_p_memory_block_slab_manager{};
KBlockInfoManager* m_p_block_info_manager{};
KPageTableManager* m_p_page_table_manager{};
bool m_is_secure_resource{false};
};
class KSecureSystemResource final
: public KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource> {
public:
explicit KSecureSystemResource(KernelCore& kernel_)
: KAutoObjectWithSlabHeap<KSecureSystemResource, KSystemResource>(kernel_) {
// Mark ourselves as being a secure resource.
this->SetSecureResource();
}
Result Initialize(size_t size, KResourceLimit* resource_limit, KMemoryManager::Pool pool);
void Finalize();
bool IsInitialized() const {
return m_is_initialized;
}
static void PostDestroy([[maybe_unused]] uintptr_t arg) {}
size_t CalculateRequiredSecureMemorySize() const {
return CalculateRequiredSecureMemorySize(m_resource_size, m_resource_pool);
}
size_t GetSize() const {
return m_resource_size;
}
size_t GetUsedSize() const {
return m_dynamic_page_manager.GetUsed() * PageSize;
}
const KDynamicPageManager& GetDynamicPageManager() const {
return m_dynamic_page_manager;
}
public:
static size_t CalculateRequiredSecureMemorySize(size_t size, KMemoryManager::Pool pool);
private:
bool m_is_initialized{};
KMemoryManager::Pool m_resource_pool{};
KDynamicPageManager m_dynamic_page_manager;
KMemoryBlockSlabManager m_memory_block_slab_manager;
KBlockInfoManager m_block_info_manager;
KPageTableManager m_page_table_manager;
KMemoryBlockSlabHeap m_memory_block_heap;
KBlockInfoSlabHeap m_block_info_heap;
KPageTableSlabHeap m_page_table_heap;
KResourceLimit* m_resource_limit{};
VAddr m_resource_address{};
size_t m_resource_size{};
};
} // namespace Kernel

View File

@@ -263,9 +263,9 @@ Result KThread::InitializeThread(KThread* thread, KThreadFunction func, uintptr_
R_SUCCEED();
}
Result KThread::InitializeDummyThread(KThread* thread, KProcess* owner) {
Result KThread::InitializeDummyThread(KThread* thread) {
// Initialize the thread.
R_TRY(thread->Initialize({}, {}, {}, DummyThreadPriority, 3, owner, ThreadType::Dummy));
R_TRY(thread->Initialize({}, {}, {}, DummyThreadPriority, 3, {}, ThreadType::Dummy));
// Initialize emulation parameters.
thread->stack_parameters.disable_count = 0;
@@ -303,7 +303,7 @@ void KThread::PostDestroy(uintptr_t arg) {
const bool resource_limit_release_hint = (arg & 1);
const s64 hint_value = (resource_limit_release_hint ? 0 : 1);
if (owner != nullptr) {
owner->GetResourceLimit()->Release(LimitableResource::ThreadCountMax, 1, hint_value);
owner->GetResourceLimit()->Release(LimitableResource::Threads, 1, hint_value);
owner->Close();
}
}
@@ -1054,7 +1054,7 @@ void KThread::Exit() {
// Release the thread resource hint, running thread count from parent.
if (parent != nullptr) {
parent->GetResourceLimit()->Release(Kernel::LimitableResource::ThreadCountMax, 0, 1);
parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1);
resource_limit_release_hint = true;
parent->DecrementRunningThreadCount();
}

View File

@@ -415,7 +415,7 @@ public:
static void PostDestroy(uintptr_t arg);
[[nodiscard]] static Result InitializeDummyThread(KThread* thread, KProcess* owner);
[[nodiscard]] static Result InitializeDummyThread(KThread* thread);
[[nodiscard]] static Result InitializeMainThread(Core::System& system, KThread* thread,
s32 virt_core);

View File

@@ -37,7 +37,7 @@ void KTransferMemory::Finalize() {
void KTransferMemory::PostDestroy(uintptr_t arg) {
KProcess* owner = reinterpret_cast<KProcess*>(arg);
owner->GetResourceLimit()->Release(LimitableResource::TransferMemoryCountMax, 1);
owner->GetResourceLimit()->Release(LimitableResource::TransferMemory, 1);
owner->Close();
}

View File

@@ -28,12 +28,10 @@
#include "core/hle/kernel/k_handle_table.h"
#include "core/hle/kernel/k_memory_layout.h"
#include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_page_buffer.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_resource_limit.h"
#include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_shared_memory.h"
#include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_worker_task_manager.h"
#include "core/hle/kernel/kernel.h"
@@ -49,11 +47,6 @@ MICROPROFILE_DEFINE(Kernel_SVC, "Kernel", "SVC", MP_RGB(70, 200, 70));
namespace Kernel {
struct KernelCore::Impl {
static constexpr size_t ApplicationMemoryBlockSlabHeapSize = 20000;
static constexpr size_t SystemMemoryBlockSlabHeapSize = 10000;
static constexpr size_t BlockInfoSlabHeapSize = 4000;
static constexpr size_t ReservedDynamicPageCount = 64;
explicit Impl(Core::System& system_, KernelCore& kernel_)
: time_manager{system_}, service_threads_manager{1, "ServiceThreadsManager"},
service_thread_barrier{2}, system{system_} {}
@@ -78,6 +71,7 @@ struct KernelCore::Impl {
// Initialize kernel memory and resources.
InitializeSystemResourceLimit(kernel, system.CoreTiming());
InitializeMemoryLayout();
Init::InitializeKPageBufferSlabHeap(system);
InitializeShutdownThreads();
InitializePhysicalCores();
InitializePreemption(kernel);
@@ -87,13 +81,12 @@ struct KernelCore::Impl {
const auto& pt_heap_region = memory_layout->GetPageTableHeapRegion();
ASSERT(pt_heap_region.GetEndAddress() != 0);
InitializeResourceManagers(kernel, pt_heap_region.GetAddress(),
pt_heap_region.GetSize());
InitializeResourceManagers(pt_heap_region.GetAddress(), pt_heap_region.GetSize());
}
RegisterHostThread(nullptr);
RegisterHostThread();
default_service_thread = &CreateServiceThread(kernel, "DefaultServiceThread");
default_service_thread = CreateServiceThread(kernel, "DefaultServiceThread");
}
void InitializeCores() {
@@ -229,22 +222,18 @@ struct KernelCore::Impl {
const auto kernel_size{sizes.second};
// If setting the default system values fails, then something seriously wrong has occurred.
ASSERT(
system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemoryMax, total_size)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::ThreadCountMax, 800)
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::PhysicalMemory, total_size)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::EventCountMax, 900)
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Threads, 800).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Events, 900).IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemory, 200)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::TransferMemoryCountMax, 200)
.IsSuccess());
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::SessionCountMax, 1133)
.IsSuccess());
system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax, kernel_size);
ASSERT(system_resource_limit->SetLimitValue(LimitableResource::Sessions, 1133).IsSuccess());
system_resource_limit->Reserve(LimitableResource::PhysicalMemory, kernel_size);
// Reserve secure applet memory, introduced in firmware 5.0.0
constexpr u64 secure_applet_memory_size{4_MiB};
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemoryMax,
ASSERT(system_resource_limit->Reserve(LimitableResource::PhysicalMemory,
secure_applet_memory_size));
}
@@ -264,82 +253,16 @@ struct KernelCore::Impl {
system.CoreTiming().ScheduleLoopingEvent(time_interval, time_interval, preemption_event);
}
void InitializeResourceManagers(KernelCore& kernel, VAddr address, size_t size) {
// Ensure that the buffer is suitable for our use.
ASSERT(Common::IsAligned(address, PageSize));
ASSERT(Common::IsAligned(size, PageSize));
// Ensure that we have space for our reference counts.
const size_t rc_size =
Common::AlignUp(KPageTableSlabHeap::CalculateReferenceCountSize(size), PageSize);
ASSERT(rc_size < size);
size -= rc_size;
// Initialize the resource managers' shared page manager.
resource_manager_page_manager = std::make_unique<KDynamicPageManager>();
resource_manager_page_manager->Initialize(
address, size, std::max<size_t>(PageSize, KPageBufferSlabHeap::BufferSize));
// Initialize the KPageBuffer slab heap.
page_buffer_slab_heap.Initialize(system);
// Initialize the fixed-size slabheaps.
app_memory_block_heap = std::make_unique<KMemoryBlockSlabHeap>();
sys_memory_block_heap = std::make_unique<KMemoryBlockSlabHeap>();
block_info_heap = std::make_unique<KBlockInfoSlabHeap>();
app_memory_block_heap->Initialize(resource_manager_page_manager.get(),
ApplicationMemoryBlockSlabHeapSize);
sys_memory_block_heap->Initialize(resource_manager_page_manager.get(),
SystemMemoryBlockSlabHeapSize);
block_info_heap->Initialize(resource_manager_page_manager.get(), BlockInfoSlabHeapSize);
// Reserve all but a fixed number of remaining pages for the page table heap.
const size_t num_pt_pages = resource_manager_page_manager->GetCount() -
resource_manager_page_manager->GetUsed() -
ReservedDynamicPageCount;
page_table_heap = std::make_unique<KPageTableSlabHeap>();
// TODO(bunnei): Pass in address once we support kernel virtual memory allocations.
page_table_heap->Initialize(
resource_manager_page_manager.get(), num_pt_pages,
/*GetPointer<KPageTableManager::RefCount>(address + size)*/ nullptr);
// Setup the slab managers.
KDynamicPageManager* const app_dynamic_page_manager = nullptr;
KDynamicPageManager* const sys_dynamic_page_manager =
/*KTargetSystem::IsDynamicResourceLimitsEnabled()*/ true
? resource_manager_page_manager.get()
: nullptr;
void InitializeResourceManagers(VAddr address, size_t size) {
dynamic_page_manager = std::make_unique<KDynamicPageManager>();
memory_block_heap = std::make_unique<KMemoryBlockSlabHeap>();
app_memory_block_manager = std::make_unique<KMemoryBlockSlabManager>();
sys_memory_block_manager = std::make_unique<KMemoryBlockSlabManager>();
app_block_info_manager = std::make_unique<KBlockInfoManager>();
sys_block_info_manager = std::make_unique<KBlockInfoManager>();
app_page_table_manager = std::make_unique<KPageTableManager>();
sys_page_table_manager = std::make_unique<KPageTableManager>();
app_memory_block_manager->Initialize(app_dynamic_page_manager, app_memory_block_heap.get());
sys_memory_block_manager->Initialize(sys_dynamic_page_manager, sys_memory_block_heap.get());
app_block_info_manager->Initialize(app_dynamic_page_manager, block_info_heap.get());
sys_block_info_manager->Initialize(sys_dynamic_page_manager, block_info_heap.get());
app_page_table_manager->Initialize(app_dynamic_page_manager, page_table_heap.get());
sys_page_table_manager->Initialize(sys_dynamic_page_manager, page_table_heap.get());
// Check that we have the correct number of dynamic pages available.
ASSERT(resource_manager_page_manager->GetCount() -
resource_manager_page_manager->GetUsed() ==
ReservedDynamicPageCount);
// Create the system page table managers.
app_system_resource = std::make_unique<KSystemResource>(kernel);
sys_system_resource = std::make_unique<KSystemResource>(kernel);
// Set the managers for the system resources.
app_system_resource->SetManagers(*app_memory_block_manager, *app_block_info_manager,
*app_page_table_manager);
sys_system_resource->SetManagers(*sys_memory_block_manager, *sys_block_info_manager,
*sys_page_table_manager);
dynamic_page_manager->Initialize(address, size);
static constexpr size_t ApplicationMemoryBlockSlabHeapSize = 20000;
memory_block_heap->Initialize(dynamic_page_manager.get(),
ApplicationMemoryBlockSlabHeapSize);
app_memory_block_manager->Initialize(nullptr, memory_block_heap.get());
}
void InitializeShutdownThreads() {
@@ -377,18 +300,15 @@ struct KernelCore::Impl {
}
// Gets the dummy KThread for the caller, allocating a new one if this is the first time
KThread* GetHostDummyThread(KThread* existing_thread) {
KThread* GetHostDummyThread() {
auto initialize = [this](KThread* thread) {
ASSERT(KThread::InitializeDummyThread(thread, nullptr).IsSuccess());
ASSERT(KThread::InitializeDummyThread(thread).IsSuccess());
thread->SetName(fmt::format("DummyThread:{}", GetHostThreadId()));
return thread;
};
thread_local KThread raw_thread{system.Kernel()};
thread_local KThread* thread = nullptr;
if (thread == nullptr) {
thread = (existing_thread == nullptr) ? initialize(&raw_thread) : existing_thread;
}
thread_local auto raw_thread = KThread(system.Kernel());
thread_local auto thread = initialize(&raw_thread);
return thread;
}
@@ -403,9 +323,9 @@ struct KernelCore::Impl {
}
/// Registers a new host thread by allocating a host thread ID for it
void RegisterHostThread(KThread* existing_thread) {
void RegisterHostThread() {
[[maybe_unused]] const auto this_id = GetHostThreadId();
[[maybe_unused]] const auto dummy_thread = GetHostDummyThread(existing_thread);
[[maybe_unused]] const auto dummy_thread = GetHostDummyThread();
}
[[nodiscard]] u32 GetCurrentHostThreadID() {
@@ -436,7 +356,7 @@ struct KernelCore::Impl {
KThread* GetCurrentEmuThread() {
const auto thread_id = GetCurrentHostThreadID();
if (thread_id >= Core::Hardware::NUM_CPU_CORES) {
return GetHostDummyThread(nullptr);
return GetHostDummyThread();
}
return current_thread;
@@ -526,9 +446,6 @@ struct KernelCore::Impl {
ASSERT(memory_layout->GetVirtualMemoryRegionTree().Insert(
misc_region_start, misc_region_size, KMemoryRegionType_KernelMisc));
// Determine if we'll use extra thread resources.
const bool use_extra_resources = KSystemControl::Init::ShouldIncreaseThreadResourceLimit();
// Setup the stack region.
constexpr size_t StackRegionSize = 14_MiB;
constexpr size_t StackRegionAlign = KernelAslrAlignment;
@@ -539,8 +456,7 @@ struct KernelCore::Impl {
stack_region_start, StackRegionSize, KMemoryRegionType_KernelStack));
// Determine the size of the resource region.
const size_t resource_region_size =
memory_layout->GetResourceRegionSizeForInit(use_extra_resources);
const size_t resource_region_size = memory_layout->GetResourceRegionSizeForInit();
// Determine the size of the slab region.
const size_t slab_region_size =
@@ -786,31 +702,33 @@ struct KernelCore::Impl {
search->second(system.ServiceManager(), server_port);
}
Kernel::ServiceThread& CreateServiceThread(KernelCore& kernel, const std::string& name) {
auto* ptr = new ServiceThread(kernel, name);
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(KernelCore& kernel,
const std::string& name) {
auto service_thread = std::make_shared<Kernel::ServiceThread>(kernel, name);
service_threads_manager.QueueWork(
[this, ptr]() { service_threads.emplace(ptr, std::unique_ptr<ServiceThread>(ptr)); });
[this, service_thread]() { service_threads.emplace(service_thread); });
return *ptr;
return service_thread;
}
void ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
auto* ptr = &service_thread;
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
if (auto strong_ptr = service_thread.lock()) {
if (strong_ptr == default_service_thread.lock()) {
// Nothing to do here, the service is using default_service_thread, which will be
// released on shutdown.
return;
}
if (ptr == default_service_thread) {
// Nothing to do here, the service is using default_service_thread, which will be
// released on shutdown.
return;
service_threads_manager.QueueWork(
[this, strong_ptr{std::move(strong_ptr)}]() { service_threads.erase(strong_ptr); });
}
service_threads_manager.QueueWork([this, ptr]() { service_threads.erase(ptr); });
}
void ClearServiceThreads() {
service_threads_manager.QueueWork([this] {
service_threads.clear();
default_service_thread = nullptr;
default_service_thread.reset();
service_thread_barrier.Sync();
});
service_thread_barrier.Sync();
@@ -833,8 +751,6 @@ struct KernelCore::Impl {
Init::KSlabResourceCounts slab_resource_counts{};
KResourceLimit* system_resource_limit{};
KPageBufferSlabHeap page_buffer_slab_heap;
std::shared_ptr<Core::Timing::EventType> preemption_event;
// This is the kernel's handle table or supervisor handle table which
@@ -860,20 +776,10 @@ struct KernelCore::Impl {
// Kernel memory management
std::unique_ptr<KMemoryManager> memory_manager;
// Resource managers
std::unique_ptr<KDynamicPageManager> resource_manager_page_manager;
std::unique_ptr<KPageTableSlabHeap> page_table_heap;
std::unique_ptr<KMemoryBlockSlabHeap> app_memory_block_heap;
std::unique_ptr<KMemoryBlockSlabHeap> sys_memory_block_heap;
std::unique_ptr<KBlockInfoSlabHeap> block_info_heap;
std::unique_ptr<KPageTableManager> app_page_table_manager;
std::unique_ptr<KPageTableManager> sys_page_table_manager;
// Dynamic slab managers
std::unique_ptr<KDynamicPageManager> dynamic_page_manager;
std::unique_ptr<KMemoryBlockSlabHeap> memory_block_heap;
std::unique_ptr<KMemoryBlockSlabManager> app_memory_block_manager;
std::unique_ptr<KMemoryBlockSlabManager> sys_memory_block_manager;
std::unique_ptr<KBlockInfoManager> app_block_info_manager;
std::unique_ptr<KBlockInfoManager> sys_block_info_manager;
std::unique_ptr<KSystemResource> app_system_resource;
std::unique_ptr<KSystemResource> sys_system_resource;
// Shared memory for services
Kernel::KSharedMemory* hid_shared_mem{};
@@ -886,8 +792,8 @@ struct KernelCore::Impl {
std::unique_ptr<KMemoryLayout> memory_layout;
// Threads used for services
std::unordered_map<ServiceThread*, std::unique_ptr<ServiceThread>> service_threads;
ServiceThread* default_service_thread{};
std::unordered_set<std::shared_ptr<ServiceThread>> service_threads;
std::weak_ptr<ServiceThread> default_service_thread;
Common::ThreadWorker service_threads_manager;
Common::Barrier service_thread_barrier;
@@ -1127,12 +1033,8 @@ void KernelCore::RegisterCoreThread(std::size_t core_id) {
impl->RegisterCoreThread(core_id);
}
void KernelCore::RegisterHostThread(KThread* existing_thread) {
impl->RegisterHostThread(existing_thread);
if (existing_thread != nullptr) {
ASSERT(GetCurrentEmuThread() == existing_thread);
}
void KernelCore::RegisterHostThread() {
impl->RegisterHostThread();
}
u32 KernelCore::GetCurrentHostThreadID() const {
@@ -1155,12 +1057,12 @@ const KMemoryManager& KernelCore::MemoryManager() const {
return *impl->memory_manager;
}
KSystemResource& KernelCore::GetSystemSystemResource() {
return *impl->sys_system_resource;
KMemoryBlockSlabManager& KernelCore::GetApplicationMemoryBlockManager() {
return *impl->app_memory_block_manager;
}
const KSystemResource& KernelCore::GetSystemSystemResource() const {
return *impl->sys_system_resource;
const KMemoryBlockSlabManager& KernelCore::GetApplicationMemoryBlockManager() const {
return *impl->app_memory_block_manager;
}
Kernel::KSharedMemory& KernelCore::GetHidSharedMem() {
@@ -1207,28 +1109,16 @@ void KernelCore::Suspend(bool suspended) {
const bool should_suspend{exception_exited || suspended};
const auto activity = should_suspend ? ProcessActivity::Paused : ProcessActivity::Runnable;
std::vector<KScopedAutoObject<KThread>> process_threads;
{
KScopedSchedulerLock sl{*this};
if (auto* process = CurrentProcess(); process != nullptr) {
process->SetActivity(activity);
if (!should_suspend) {
// Runnable now; no need to wait.
return;
}
for (auto* process : GetProcessList()) {
process->SetActivity(activity);
if (should_suspend) {
// Wait for execution to stop
for (auto* thread : process->GetThreadList()) {
process_threads.emplace_back(thread);
thread->WaitUntilSuspended();
}
}
}
// Wait for execution to stop.
for (auto& thread : process_threads) {
thread->WaitUntilSuspended();
}
}
void KernelCore::ShutdownCores() {
@@ -1260,15 +1150,15 @@ void KernelCore::ExitSVCProfile() {
MicroProfileLeave(MICROPROFILE_TOKEN(Kernel_SVC), impl->svc_ticks[CurrentPhysicalCoreIndex()]);
}
Kernel::ServiceThread& KernelCore::CreateServiceThread(const std::string& name) {
std::weak_ptr<Kernel::ServiceThread> KernelCore::CreateServiceThread(const std::string& name) {
return impl->CreateServiceThread(*this, name);
}
Kernel::ServiceThread& KernelCore::GetDefaultServiceThread() const {
return *impl->default_service_thread;
std::weak_ptr<Kernel::ServiceThread> KernelCore::GetDefaultServiceThread() const {
return impl->default_service_thread;
}
void KernelCore::ReleaseServiceThread(Kernel::ServiceThread& service_thread) {
void KernelCore::ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread) {
impl->ReleaseServiceThread(service_thread);
}

View File

@@ -34,16 +34,13 @@ class KClientPort;
class GlobalSchedulerContext;
class KAutoObjectWithListContainer;
class KClientSession;
class KDebug;
class KDynamicPageManager;
class KEvent;
class KEventInfo;
class KHandleTable;
class KLinkedListNode;
class KMemoryBlockSlabManager;
class KMemoryLayout;
class KMemoryManager;
class KPageBuffer;
class KPageBufferSlabHeap;
class KPort;
class KProcess;
class KResourceLimit;
@@ -54,7 +51,6 @@ class KSession;
class KSessionRequest;
class KSharedMemory;
class KSharedMemoryInfo;
class KSecureSystemResource;
class KThread;
class KThreadLocalPage;
class KTransferMemory;
@@ -240,7 +236,7 @@ public:
void RegisterCoreThread(std::size_t core_id);
/// Register the current thread as a non CPU core thread.
void RegisterHostThread(KThread* existing_thread = nullptr);
void RegisterHostThread();
/// Gets the virtual memory manager for the kernel.
KMemoryManager& MemoryManager();
@@ -248,11 +244,11 @@ public:
/// Gets the virtual memory manager for the kernel.
const KMemoryManager& MemoryManager() const;
/// Gets the system resource manager.
KSystemResource& GetSystemSystemResource();
/// Gets the application memory block manager for the kernel.
KMemoryBlockSlabManager& GetApplicationMemoryBlockManager();
/// Gets the system resource manager.
const KSystemResource& GetSystemSystemResource() const;
/// Gets the application memory block manager for the kernel.
const KMemoryBlockSlabManager& GetApplicationMemoryBlockManager() const;
/// Gets the shared memory object for HID services.
Kernel::KSharedMemory& GetHidSharedMem();
@@ -309,24 +305,24 @@ public:
* See GetDefaultServiceThread.
* @param name String name for the ServerSession creating this thread, used for debug
* purposes.
* @returns A reference to the newly created service thread.
* @returns The a weak pointer newly created service thread.
*/
Kernel::ServiceThread& CreateServiceThread(const std::string& name);
std::weak_ptr<Kernel::ServiceThread> CreateServiceThread(const std::string& name);
/**
* Gets the default host service thread, which executes HLE service requests. Unless service
* requests need to block on the host, the default service thread should be used in favor of
* creating a new service thread.
* @returns A reference to the default service thread.
* @returns The a weak pointer for the default service thread.
*/
Kernel::ServiceThread& GetDefaultServiceThread() const;
std::weak_ptr<Kernel::ServiceThread> GetDefaultServiceThread() const;
/**
* Releases a HLE service thread, instructing KernelCore to free it. This should be called when
* the ServerSession associated with the thread is destroyed.
* @param service_thread Service thread to release.
*/
void ReleaseServiceThread(Kernel::ServiceThread& service_thread);
void ReleaseServiceThread(std::weak_ptr<Kernel::ServiceThread> service_thread);
/// Workaround for single-core mode when preempting threads while idle.
bool IsPhantomModeForSingleCore() const;
@@ -368,12 +364,6 @@ public:
return slab_heap_container->thread_local_page;
} else if constexpr (std::is_same_v<T, KSessionRequest>) {
return slab_heap_container->session_request;
} else if constexpr (std::is_same_v<T, KSecureSystemResource>) {
return slab_heap_container->secure_system_resource;
} else if constexpr (std::is_same_v<T, KEventInfo>) {
return slab_heap_container->event_info;
} else if constexpr (std::is_same_v<T, KDebug>) {
return slab_heap_container->debug;
}
}
@@ -437,9 +427,6 @@ private:
KSlabHeap<KPageBuffer> page_buffer;
KSlabHeap<KThreadLocalPage> thread_local_page;
KSlabHeap<KSessionRequest> session_request;
KSlabHeap<KSecureSystemResource> secure_system_resource;
KSlabHeap<KEventInfo> event_info;
KSlabHeap<KDebug> debug;
};
std::unique_ptr<SlabHeapContainer> slab_heap_container;

View File

@@ -12,7 +12,7 @@ namespace Kernel {
PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_)
: core_index{core_index_}, system{system_}, scheduler{scheduler_} {
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
#ifdef ARCHITECTURE_x86_64
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
auto& kernel = system.Kernel();
@@ -26,7 +26,7 @@ PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KSche
PhysicalCore::~PhysicalCore() = default;
void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
#if defined(ARCHITECTURE_x86_64) || defined(ARCHITECTURE_arm64)
#ifdef ARCHITECTURE_x86_64
auto& kernel = system.Kernel();
if (!is_64_bit) {
// We already initialized a 64-bit core, replace with a 32-bit one.

View File

@@ -36,11 +36,11 @@ public:
private:
KernelCore& kernel;
std::jthread m_host_thread;
std::jthread m_thread;
std::mutex m_session_mutex;
std::map<KServerSession*, std::shared_ptr<SessionRequestManager>> m_sessions;
KEvent* m_wakeup_event;
KThread* m_thread;
KProcess* m_process;
std::atomic<bool> m_shutdown_requested;
const std::string m_service_name;
};
@@ -132,7 +132,7 @@ void ServiceThread::Impl::SessionClosed(KServerSession* server_session,
void ServiceThread::Impl::LoopProcess() {
Common::SetCurrentThreadName(m_service_name.c_str());
kernel.RegisterHostThread(m_thread);
kernel.RegisterHostThread();
while (!m_shutdown_requested.load()) {
WaitAndProcessImpl();
@@ -160,7 +160,7 @@ ServiceThread::Impl::~Impl() {
// Shut down the processing thread.
m_shutdown_requested.store(true);
m_wakeup_event->Signal();
m_host_thread.join();
m_thread.join();
// Lock mutex.
m_session_mutex.lock();
@@ -177,22 +177,33 @@ ServiceThread::Impl::~Impl() {
m_wakeup_event->GetReadableEvent().Close();
m_wakeup_event->Close();
// Close thread.
m_thread->Close();
// Close process.
m_process->Close();
}
ServiceThread::Impl::Impl(KernelCore& kernel_, const std::string& service_name)
: kernel{kernel_}, m_service_name{service_name} {
// Initialize process.
m_process = KProcess::Create(kernel);
KProcess::Initialize(m_process, kernel.System(), service_name,
KProcess::ProcessType::KernelInternal, kernel.GetSystemResourceLimit());
// Reserve a new event from the process resource limit
KScopedResourceReservation event_reservation(m_process, LimitableResource::Events);
ASSERT(event_reservation.Succeeded());
// Initialize event.
m_wakeup_event = KEvent::Create(kernel);
m_wakeup_event->Initialize(nullptr);
m_wakeup_event->Initialize(m_process);
// Initialize thread.
m_thread = KThread::Create(kernel);
ASSERT(KThread::InitializeDummyThread(m_thread, nullptr).IsSuccess());
// Commit the event reservation.
event_reservation.Commit();
// Register the event.
KEvent::Register(kernel, m_wakeup_event);
// Start thread.
m_host_thread = std::jthread([this] { LoopProcess(); });
m_thread = std::jthread([this] { LoopProcess(); });
}
ServiceThread::ServiceThread(KernelCore& kernel, const std::string& name)

View File

@@ -52,84 +52,6 @@ public:
}
};
template <typename Derived, typename Base>
class KAutoObjectWithSlabHeap : public Base {
static_assert(std::is_base_of<KAutoObject, Base>::value);
private:
static Derived* Allocate(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().Allocate(kernel);
}
static void Free(KernelCore& kernel, Derived* obj) {
kernel.SlabHeap<Derived>().Free(obj);
}
public:
explicit KAutoObjectWithSlabHeap(KernelCore& kernel_) : Base(kernel_), kernel(kernel_) {}
virtual ~KAutoObjectWithSlabHeap() = default;
virtual void Destroy() override {
const bool is_initialized = this->IsInitialized();
uintptr_t arg = 0;
if (is_initialized) {
arg = this->GetPostDestroyArgument();
this->Finalize();
}
Free(kernel, static_cast<Derived*>(this));
if (is_initialized) {
Derived::PostDestroy(arg);
}
}
virtual bool IsInitialized() const {
return true;
}
virtual uintptr_t GetPostDestroyArgument() const {
return 0;
}
size_t GetSlabIndex() const {
return SlabHeap<Derived>(kernel).GetObjectIndex(static_cast<const Derived*>(this));
}
public:
static void InitializeSlabHeap(KernelCore& kernel, void* memory, size_t memory_size) {
kernel.SlabHeap<Derived>().Initialize(memory, memory_size);
}
static Derived* Create(KernelCore& kernel) {
Derived* obj = Allocate(kernel);
if (obj != nullptr) {
KAutoObject::Create(obj);
}
return obj;
}
static size_t GetObjectSize(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().GetObjectSize();
}
static size_t GetSlabHeapSize(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().GetSlabHeapSize();
}
static size_t GetPeakIndex(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().GetPeakIndex();
}
static uintptr_t GetSlabHeapAddress(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().GetSlabHeapAddress();
}
static size_t GetNumRemaining(KernelCore& kernel) {
return kernel.SlabHeap<Derived>().GetNumRemaining();
}
protected:
KernelCore& kernel;
};
template <typename Derived, typename Base>
class KAutoObjectWithSlabHeapAndContainer : public Base {
static_assert(std::is_base_of<KAutoObjectWithList, Base>::value);

View File

@@ -267,7 +267,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
// Reserve a new session from the process resource limit.
// FIXME: LimitableResource_SessionCountMax
KScopedResourceReservation session_reservation(&process, LimitableResource::SessionCountMax);
KScopedResourceReservation session_reservation(&process, LimitableResource::Sessions);
if (session_reservation.Succeeded()) {
session = T::Create(system.Kernel());
} else {
@@ -298,7 +298,7 @@ Result CreateSession(Core::System& system, Handle* out_server, Handle* out_clien
// We successfully allocated a session, so add the object we allocated to the resource
// limit.
// system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::SessionCountMax, 1);
// system.Kernel().GetSystemResourceLimit().Reserve(LimitableResource::Sessions, 1);
}
// Check that we successfully created a session.
@@ -656,12 +656,27 @@ static Result ArbitrateUnlock32(Core::System& system, u32 address) {
return ArbitrateUnlock(system, address);
}
enum class BreakType : u32 {
Panic = 0,
AssertionFailed = 1,
PreNROLoad = 3,
PostNROLoad = 4,
PreNROUnload = 5,
PostNROUnload = 6,
CppException = 7,
};
struct BreakReason {
union {
u32 raw;
BitField<0, 30, BreakType> break_type;
BitField<31, 1, u32> signal_debugger;
};
};
/// Break program execution
static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
BreakReason break_reason =
static_cast<BreakReason>(reason & ~static_cast<u32>(BreakReason::NotificationOnlyFlag));
bool notification_only = (reason & static_cast<u32>(BreakReason::NotificationOnlyFlag)) != 0;
BreakReason break_reason{reason};
bool has_dumped_buffer{};
std::vector<u8> debug_buffer;
@@ -690,56 +705,57 @@ static void Break(Core::System& system, u32 reason, u64 info1, u64 info2) {
}
has_dumped_buffer = true;
};
switch (break_reason) {
case BreakReason::Panic:
LOG_CRITICAL(Debug_Emulated, "Userspace PANIC! info1=0x{:016X}, info2=0x{:016X}", info1,
info2);
handle_debug_buffer(info1, info2);
break;
case BreakReason::Assert:
LOG_CRITICAL(Debug_Emulated, "Userspace Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
switch (break_reason.break_type) {
case BreakType::Panic:
LOG_CRITICAL(Debug_Emulated, "Signalling debugger, PANIC! info1=0x{:016X}, info2=0x{:016X}",
info1, info2);
handle_debug_buffer(info1, info2);
break;
case BreakReason::User:
LOG_WARNING(Debug_Emulated, "Userspace Break! 0x{:016X} with size 0x{:016X}", info1, info2);
case BreakType::AssertionFailed:
LOG_CRITICAL(Debug_Emulated,
"Signalling debugger, Assertion failed! info1=0x{:016X}, info2=0x{:016X}",
info1, info2);
handle_debug_buffer(info1, info2);
break;
case BreakReason::PreLoadDll:
LOG_INFO(Debug_Emulated,
"Userspace Attempting to load an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
case BreakType::PreNROLoad:
LOG_WARNING(
Debug_Emulated,
"Signalling debugger, Attempting to load an NRO at 0x{:016X} with size 0x{:016X}",
info1, info2);
break;
case BreakReason::PostLoadDll:
LOG_INFO(Debug_Emulated, "Userspace Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
case BreakType::PostNROLoad:
LOG_WARNING(Debug_Emulated,
"Signalling debugger, Loaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
break;
case BreakReason::PreUnloadDll:
LOG_INFO(Debug_Emulated,
"Userspace Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
case BreakType::PreNROUnload:
LOG_WARNING(
Debug_Emulated,
"Signalling debugger, Attempting to unload an NRO at 0x{:016X} with size 0x{:016X}",
info1, info2);
break;
case BreakReason::PostUnloadDll:
LOG_INFO(Debug_Emulated, "Userspace Unloaded an NRO at 0x{:016X} with size 0x{:016X}",
info1, info2);
case BreakType::PostNROUnload:
LOG_WARNING(Debug_Emulated,
"Signalling debugger, Unloaded an NRO at 0x{:016X} with size 0x{:016X}", info1,
info2);
break;
case BreakReason::CppException:
case BreakType::CppException:
LOG_CRITICAL(Debug_Emulated, "Signalling debugger. Uncaught C++ exception encountered.");
break;
default:
LOG_WARNING(
Debug_Emulated,
"Signalling debugger, Unknown break reason {:#X}, info1=0x{:016X}, info2=0x{:016X}",
reason, info1, info2);
"Signalling debugger, Unknown break reason {}, info1=0x{:016X}, info2=0x{:016X}",
static_cast<u32>(break_reason.break_type.Value()), info1, info2);
handle_debug_buffer(info1, info2);
break;
}
system.GetReporter().SaveSvcBreakReport(reason, notification_only, info1, info2,
has_dumped_buffer ? std::make_optional(debug_buffer)
: std::nullopt);
system.GetReporter().SaveSvcBreakReport(
static_cast<u32>(break_reason.break_type.Value()), break_reason.signal_debugger.As<bool>(),
info1, info2, has_dumped_buffer ? std::make_optional(debug_buffer) : std::nullopt);
if (!notification_only) {
if (!break_reason.signal_debugger) {
LOG_CRITICAL(
Debug_Emulated,
"Emulated program broke execution! reason=0x{:016X}, info1=0x{:016X}, info2=0x{:016X}",
@@ -1700,13 +1716,13 @@ static Result QueryProcessMemory(Core::System& system, VAddr memory_info_address
auto& memory{system.Memory()};
const auto memory_info{process->PageTable().QueryInfo(address).GetSvcMemoryInfo()};
memory.Write64(memory_info_address + 0x00, memory_info.base_address);
memory.Write64(memory_info_address + 0x00, memory_info.addr);
memory.Write64(memory_info_address + 0x08, memory_info.size);
memory.Write32(memory_info_address + 0x10, static_cast<u32>(memory_info.state) & 0xff);
memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attribute));
memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.permission));
memory.Write32(memory_info_address + 0x1c, memory_info.ipc_count);
memory.Write32(memory_info_address + 0x20, memory_info.device_count);
memory.Write32(memory_info_address + 0x14, static_cast<u32>(memory_info.attr));
memory.Write32(memory_info_address + 0x18, static_cast<u32>(memory_info.perm));
memory.Write32(memory_info_address + 0x1c, memory_info.ipc_refcount);
memory.Write32(memory_info_address + 0x20, memory_info.device_refcount);
memory.Write32(memory_info_address + 0x24, 0);
// Page info appears to be currently unused by the kernel and is always set to zero.
@@ -1927,7 +1943,7 @@ static Result CreateThread(Core::System& system, Handle* out_handle, VAddr entry
// Reserve a new thread from the process resource limit (waiting up to 100ms).
KScopedResourceReservation thread_reservation(
kernel.CurrentProcess(), LimitableResource::ThreadCountMax, 1,
kernel.CurrentProcess(), LimitableResource::Threads, 1,
system.CoreTiming().GetGlobalTimeNs().count() + 100000000);
if (!thread_reservation.Succeeded()) {
LOG_ERROR(Kernel_SVC, "Could not reserve a new thread");
@@ -2231,7 +2247,7 @@ static u64 GetSystemTick(Core::System& system) {
auto& core_timing = system.CoreTiming();
// Returns the value of cntpct_el0 (https://switchbrew.org/wiki/SVC#svcGetSystemTick)
const u64 result{core_timing.GetClockTicks()};
const u64 result{system.CoreTiming().GetClockTicks()};
if (!system.Kernel().IsMulticore()) {
core_timing.AddTicks(400U);
@@ -2328,7 +2344,7 @@ static Result CreateTransferMemory(Core::System& system, Handle* out, VAddr addr
// Reserve a new transfer memory from the process resource limit.
KScopedResourceReservation trmem_reservation(kernel.CurrentProcess(),
LimitableResource::TransferMemoryCountMax);
LimitableResource::TransferMemory);
R_UNLESS(trmem_reservation.Succeeded(), ResultLimitReached);
// Create the transfer memory.
@@ -2480,7 +2496,7 @@ static Result CreateEvent(Core::System& system, Handle* out_write, Handle* out_r
// Reserve a new event from the process resource limit
KScopedResourceReservation event_reservation(kernel.CurrentProcess(),
LimitableResource::EventCountMax);
LimitableResource::Events);
R_UNLESS(event_reservation.Succeeded(), ResultLimitReached);
// Create a new event.
@@ -2523,6 +2539,11 @@ static Result CreateEvent32(Core::System& system, Handle* out_write, Handle* out
static Result GetProcessInfo(Core::System& system, u64* out, Handle process_handle, u32 type) {
LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, type=0x{:X}", process_handle, type);
// This function currently only allows retrieving a process' status.
enum class InfoType {
Status,
};
const auto& handle_table = system.Kernel().CurrentProcess()->GetHandleTable();
KScopedAutoObject process = handle_table.GetObject<KProcess>(process_handle);
if (process.IsNull()) {
@@ -2531,9 +2552,9 @@ static Result GetProcessInfo(Core::System& system, u64* out, Handle process_hand
return ResultInvalidHandle;
}
const auto info_type = static_cast<ProcessInfoType>(type);
if (info_type != ProcessInfoType::ProcessState) {
LOG_ERROR(Kernel_SVC, "Expected info_type to be ProcessState but got {} instead", type);
const auto info_type = static_cast<InfoType>(type);
if (info_type != InfoType::Status) {
LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type);
return ResultInvalidEnumValue;
}

View File

@@ -37,7 +37,6 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
} // namespace Kernel

View File

@@ -8,8 +8,6 @@
namespace Kernel::Svc {
using Handle = u32;
enum class MemoryState : u32 {
Free = 0x00,
Io = 0x01,
@@ -24,8 +22,8 @@ enum class MemoryState : u32 {
Ipc = 0x0A,
Stack = 0x0B,
ThreadLocal = 0x0C,
Transfered = 0x0D,
SharedTransfered = 0x0E,
Transferred = 0x0D,
SharedTransferred = 0x0E,
SharedCode = 0x0F,
Inaccessible = 0x10,
NonSecureIpc = 0x11,
@@ -34,7 +32,6 @@ enum class MemoryState : u32 {
GeneratedCode = 0x14,
CodeOut = 0x15,
Coverage = 0x16,
Insecure = 0x17,
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryState);
@@ -57,6 +54,17 @@ enum class MemoryPermission : u32 {
};
DECLARE_ENUM_FLAG_OPERATORS(MemoryPermission);
struct MemoryInfo {
u64 addr{};
u64 size{};
MemoryState state{};
MemoryAttribute attr{};
MemoryPermission perm{};
u32 ipc_refcount{};
u32 device_refcount{};
u32 padding{};
};
enum class SignalType : u32 {
Signal = 0,
SignalAndIncrementIfEqual = 1,
@@ -75,13 +83,6 @@ enum class YieldType : s64 {
ToAnyThread = -2,
};
enum class ThreadExitReason : u32 {
ExitThread = 0,
TerminateThread = 1,
ExitProcess = 2,
TerminateProcess = 3,
};
enum class ThreadActivity : u32 {
Runnable = 0,
Paused = 1,
@@ -107,489 +108,6 @@ enum class ProcessState : u32 {
DebugBreak = 7,
};
enum class ProcessExitReason : u32 {
ExitProcess = 0,
TerminateProcess = 1,
Exception = 2,
};
constexpr inline size_t ThreadLocalRegionSize = 0x200;
struct PageInfo {
u32 flags;
};
// Info Types.
enum class InfoType : u32 {
CoreMask = 0,
PriorityMask = 1,
AliasRegionAddress = 2,
AliasRegionSize = 3,
HeapRegionAddress = 4,
HeapRegionSize = 5,
TotalMemorySize = 6,
UsedMemorySize = 7,
DebuggerAttached = 8,
ResourceLimit = 9,
IdleTickCount = 10,
RandomEntropy = 11,
AslrRegionAddress = 12,
AslrRegionSize = 13,
StackRegionAddress = 14,
StackRegionSize = 15,
SystemResourceSizeTotal = 16,
SystemResourceSizeUsed = 17,
ProgramId = 18,
InitialProcessIdRange = 19,
UserExceptionContextAddress = 20,
TotalNonSystemMemorySize = 21,
UsedNonSystemMemorySize = 22,
IsApplication = 23,
FreeThreadCount = 24,
ThreadTickCount = 25,
IsSvcPermitted = 26,
MesosphereMeta = 65000,
MesosphereCurrentProcess = 65001,
};
enum class BreakReason : u32 {
Panic = 0,
Assert = 1,
User = 2,
PreLoadDll = 3,
PostLoadDll = 4,
PreUnloadDll = 5,
PostUnloadDll = 6,
CppException = 7,
NotificationOnlyFlag = 0x80000000,
};
enum class DebugEvent : u32 {
CreateProcess = 0,
CreateThread = 1,
ExitProcess = 2,
ExitThread = 3,
Exception = 4,
};
enum class DebugThreadParam : u32 {
Priority = 0,
State = 1,
IdealCore = 2,
CurrentCore = 3,
AffinityMask = 4,
};
enum class DebugException : u32 {
UndefinedInstruction = 0,
InstructionAbort = 1,
DataAbort = 2,
AlignmentFault = 3,
DebuggerAttached = 4,
BreakPoint = 5,
UserBreak = 6,
DebuggerBreak = 7,
UndefinedSystemCall = 8,
MemorySystemError = 9,
};
enum class DebugEventFlag : u32 {
Stopped = (1u << 0),
};
enum class BreakPointType : u32 {
HardwareInstruction = 0,
HardwareData = 1,
};
enum class HardwareBreakPointRegisterName : u32 {
I0 = 0,
I1 = 1,
I2 = 2,
I3 = 3,
I4 = 4,
I5 = 5,
I6 = 6,
I7 = 7,
I8 = 8,
I9 = 9,
I10 = 10,
I11 = 11,
I12 = 12,
I13 = 13,
I14 = 14,
I15 = 15,
D0 = 16,
D1 = 17,
D2 = 18,
D3 = 19,
D4 = 20,
D5 = 21,
D6 = 22,
D7 = 23,
D8 = 24,
D9 = 25,
D10 = 26,
D11 = 27,
D12 = 28,
D13 = 29,
D14 = 30,
D15 = 31,
};
namespace lp64 {
struct LastThreadContext {
u64 fp;
u64 sp;
u64 lr;
u64 pc;
};
struct PhysicalMemoryInfo {
PAddr physical_address;
u64 virtual_address;
u64 size;
};
struct DebugInfoCreateProcess {
u64 program_id;
u64 process_id;
std::array<char, 0xC> name;
u32 flags;
u64 user_exception_context_address; // 5.0.0+
};
struct DebugInfoCreateThread {
u64 thread_id;
u64 tls_address;
// Removed in 11.0.0 u64 entrypoint;
};
struct DebugInfoExitProcess {
ProcessExitReason reason;
};
struct DebugInfoExitThread {
ThreadExitReason reason;
};
struct DebugInfoUndefinedInstructionException {
u32 insn;
};
struct DebugInfoDataAbortException {
u64 address;
};
struct DebugInfoAlignmentFaultException {
u64 address;
};
struct DebugInfoBreakPointException {
BreakPointType type;
u64 address;
};
struct DebugInfoUserBreakException {
BreakReason break_reason;
u64 address;
u64 size;
};
struct DebugInfoDebuggerBreakException {
std::array<u64, 4> active_thread_ids;
};
struct DebugInfoUndefinedSystemCallException {
u32 id;
};
union DebugInfoSpecificException {
DebugInfoUndefinedInstructionException undefined_instruction;
DebugInfoDataAbortException data_abort;
DebugInfoAlignmentFaultException alignment_fault;
DebugInfoBreakPointException break_point;
DebugInfoUserBreakException user_break;
DebugInfoDebuggerBreakException debugger_break;
DebugInfoUndefinedSystemCallException undefined_system_call;
u64 raw;
};
struct DebugInfoException {
DebugException type;
u64 address;
DebugInfoSpecificException specific;
};
union DebugInfo {
DebugInfoCreateProcess create_process;
DebugInfoCreateThread create_thread;
DebugInfoExitProcess exit_process;
DebugInfoExitThread exit_thread;
DebugInfoException exception;
};
struct DebugEventInfo {
DebugEvent type;
u32 flags;
u64 thread_id;
DebugInfo info;
};
static_assert(sizeof(DebugEventInfo) >= 0x40);
struct SecureMonitorArguments {
std::array<u64, 8> r;
};
static_assert(sizeof(SecureMonitorArguments) == 0x40);
} // namespace lp64
namespace ilp32 {
struct LastThreadContext {
u32 fp;
u32 sp;
u32 lr;
u32 pc;
};
struct PhysicalMemoryInfo {
PAddr physical_address;
u32 virtual_address;
u32 size;
};
struct DebugInfoCreateProcess {
u64 program_id;
u64 process_id;
std::array<char, 0xC> name;
u32 flags;
u32 user_exception_context_address; // 5.0.0+
};
struct DebugInfoCreateThread {
u64 thread_id;
u32 tls_address;
// Removed in 11.0.0 u32 entrypoint;
};
struct DebugInfoExitProcess {
ProcessExitReason reason;
};
struct DebugInfoExitThread {
ThreadExitReason reason;
};
struct DebugInfoUndefinedInstructionException {
u32 insn;
};
struct DebugInfoDataAbortException {
u32 address;
};
struct DebugInfoAlignmentFaultException {
u32 address;
};
struct DebugInfoBreakPointException {
BreakPointType type;
u32 address;
};
struct DebugInfoUserBreakException {
BreakReason break_reason;
u32 address;
u32 size;
};
struct DebugInfoDebuggerBreakException {
std::array<u64, 4> active_thread_ids;
};
struct DebugInfoUndefinedSystemCallException {
u32 id;
};
union DebugInfoSpecificException {
DebugInfoUndefinedInstructionException undefined_instruction;
DebugInfoDataAbortException data_abort;
DebugInfoAlignmentFaultException alignment_fault;
DebugInfoBreakPointException break_point;
DebugInfoUserBreakException user_break;
DebugInfoDebuggerBreakException debugger_break;
DebugInfoUndefinedSystemCallException undefined_system_call;
u64 raw;
};
struct DebugInfoException {
DebugException type;
u32 address;
DebugInfoSpecificException specific;
};
union DebugInfo {
DebugInfoCreateProcess create_process;
DebugInfoCreateThread create_thread;
DebugInfoExitProcess exit_process;
DebugInfoExitThread exit_thread;
DebugInfoException exception;
};
struct DebugEventInfo {
DebugEvent type;
u32 flags;
u64 thread_id;
DebugInfo info;
};
struct SecureMonitorArguments {
std::array<u32, 8> r;
};
static_assert(sizeof(SecureMonitorArguments) == 0x20);
} // namespace ilp32
struct ThreadContext {
std::array<u64, 29> r;
u64 fp;
u64 lr;
u64 sp;
u64 pc;
u32 pstate;
u32 padding;
std::array<u128, 32> v;
u32 fpcr;
u32 fpsr;
u64 tpidr;
};
static_assert(sizeof(ThreadContext) == 0x320);
struct MemoryInfo {
u64 base_address;
u64 size;
MemoryState state;
MemoryAttribute attribute;
MemoryPermission permission;
u32 ipc_count;
u32 device_count;
u32 padding;
};
enum class LimitableResource : u32 {
PhysicalMemoryMax = 0,
ThreadCountMax = 1,
EventCountMax = 2,
TransferMemoryCountMax = 3,
SessionCountMax = 4,
Count,
};
enum class IoPoolType : u32 {
// Not supported.
Count = 0,
};
enum class MemoryMapping : u32 {
IoRegister = 0,
Uncached = 1,
Memory = 2,
};
enum class KernelDebugType : u32 {
Thread = 0,
ThreadCallStack = 1,
KernelObject = 2,
Handle_ = 3,
Memory = 4,
PageTable = 5,
CpuUtilization = 6,
Process = 7,
SuspendProcess = 8,
ResumeProcess = 9,
Port = 10,
};
enum class KernelTraceState : u32 {
Disabled = 0,
Enabled = 1,
};
enum class CodeMemoryOperation : u32 {
Map = 0,
MapToOwner = 1,
Unmap = 2,
UnmapFromOwner = 3,
};
enum class InterruptType : u32 {
Edge = 0,
Level = 1,
};
enum class DeviceName {
Afi = 0,
Avpc = 1,
Dc = 2,
Dcb = 3,
Hc = 4,
Hda = 5,
Isp2 = 6,
MsencNvenc = 7,
Nv = 8,
Nv2 = 9,
Ppcs = 10,
Sata = 11,
Vi = 12,
Vic = 13,
XusbHost = 14,
XusbDev = 15,
Tsec = 16,
Ppcs1 = 17,
Dc1 = 18,
Sdmmc1a = 19,
Sdmmc2a = 20,
Sdmmc3a = 21,
Sdmmc4a = 22,
Isp2b = 23,
Gpu = 24,
Gpub = 25,
Ppcs2 = 26,
Nvdec = 27,
Ape = 28,
Se = 29,
Nvjpg = 30,
Hc1 = 31,
Se1 = 32,
Axiap = 33,
Etr = 34,
Tsecb = 35,
Tsec1 = 36,
Tsecb1 = 37,
Nvdec1 = 38,
Count,
};
enum class SystemInfoType : u32 {
TotalPhysicalMemorySize = 0,
UsedPhysicalMemorySize = 1,
InitialProcessIdRange = 2,
};
enum class ProcessInfoType : u32 {
ProcessState = 0,
};
struct CreateProcessParameter {
std::array<char, 12> name;
u32 version;
u64 program_id;
u64 code_address;
s32 code_num_pages;
u32 flags;
Handle reslimit;
s32 system_resource_num_pages;
};
static_assert(sizeof(CreateProcessParameter) == 0x30);
} // namespace Kernel::Svc

View File

@@ -423,17 +423,16 @@ constexpr void UpdateCurrentResultReference<const Result>(Result result_referenc
} // namespace ResultImpl
#define DECLARE_CURRENT_RESULT_REFERENCE_AND_STORAGE(COUNTER_VALUE) \
[[maybe_unused]] constexpr bool CONCAT2(HasPrevRef_, COUNTER_VALUE) = \
[[maybe_unused]] constexpr bool HasPrevRef_##COUNTER_VALUE = \
std::same_as<decltype(__TmpCurrentResultReference), Result&>; \
[[maybe_unused]] Result CONCAT2(PrevRef_, COUNTER_VALUE) = __TmpCurrentResultReference; \
[[maybe_unused]] Result CONCAT2(__tmp_result_, COUNTER_VALUE) = ResultSuccess; \
Result& __TmpCurrentResultReference = CONCAT2(HasPrevRef_, COUNTER_VALUE) \
? CONCAT2(PrevRef_, COUNTER_VALUE) \
: CONCAT2(__tmp_result_, COUNTER_VALUE)
[[maybe_unused]] auto& PrevRef_##COUNTER_VALUE = __TmpCurrentResultReference; \
[[maybe_unused]] Result __tmp_result_##COUNTER_VALUE = ResultSuccess; \
Result& __TmpCurrentResultReference = \
HasPrevRef_##COUNTER_VALUE ? PrevRef_##COUNTER_VALUE : __tmp_result_##COUNTER_VALUE
#define ON_RESULT_RETURN_IMPL(...) \
static_assert(std::same_as<decltype(__TmpCurrentResultReference), Result&>); \
auto CONCAT2(RESULT_GUARD_STATE_, __COUNTER__) = \
auto RESULT_GUARD_STATE_##__COUNTER__ = \
ResultImpl::ResultReferenceForScopedResultGuard<__VA_ARGS__>( \
__TmpCurrentResultReference) + \
[&]()

View File

@@ -1,177 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h"
#include "common/logging/log.h"
#include "core/core.h"
#include "core/frontend/applets/cabinet.h"
#include "core/hid/hid_core.h"
#include "core/hle/kernel/k_event.h"
#include "core/hle/kernel/k_readable_event.h"
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/mii/mii_manager.h"
#include "core/hle/service/nfp/nfp_device.h"
namespace Service::AM::Applets {
Cabinet::Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::CabinetApplet& frontend_)
: Applet{system_, applet_mode_}, frontend{frontend_}, system{system_}, service_context{
system_,
"CabinetApplet"} {
availability_change_event =
service_context.CreateEvent("CabinetApplet:AvailabilityChangeEvent");
}
Cabinet::~Cabinet() = default;
void Cabinet::Initialize() {
Applet::Initialize();
LOG_INFO(Service_HID, "Initializing Cabinet Applet.");
LOG_DEBUG(Service_HID,
"Initializing Applet with common_args: arg_version={}, lib_version={}, "
"play_startup_sound={}, size={}, system_tick={}, theme_color={}",
common_args.arguments_version, common_args.library_version,
common_args.play_startup_sound, common_args.size, common_args.system_tick,
common_args.theme_color);
const auto storage = broker.PopNormalDataToApplet();
ASSERT(storage != nullptr);
const auto applet_input_data = storage->GetData();
ASSERT(applet_input_data.size() >= sizeof(StartParamForAmiiboSettings));
std::memcpy(&applet_input_common, applet_input_data.data(),
sizeof(StartParamForAmiiboSettings));
}
bool Cabinet::TransactionComplete() const {
return is_complete;
}
Result Cabinet::GetStatus() const {
return ResultSuccess;
}
void Cabinet::ExecuteInteractive() {
ASSERT_MSG(false, "Attempted to call interactive execution on non-interactive applet.");
}
void Cabinet::Execute() {
if (is_complete) {
return;
}
const auto callback = [this](bool apply_changes, const std::string& amiibo_name) {
DisplayCompleted(apply_changes, amiibo_name);
};
// TODO: listen on all controllers
if (nfp_device == nullptr) {
nfp_device = std::make_shared<Service::NFP::NfpDevice>(
system.HIDCore().GetFirstNpadId(), system, service_context, availability_change_event);
nfp_device->Initialize();
nfp_device->StartDetection(Service::NFP::TagProtocol::All);
}
const Core::Frontend::CabinetParameters parameters{
.tag_info = applet_input_common.tag_info,
.register_info = applet_input_common.register_info,
.mode = applet_input_common.applet_mode,
};
switch (applet_input_common.applet_mode) {
case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings:
case Service::NFP::CabinetMode::StartGameDataEraser:
case Service::NFP::CabinetMode::StartRestorer:
case Service::NFP::CabinetMode::StartFormatter:
frontend.ShowCabinetApplet(callback, parameters, nfp_device);
break;
default:
UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
DisplayCompleted(false, {});
break;
}
}
void Cabinet::DisplayCompleted(bool apply_changes, std::string_view amiibo_name) {
Service::Mii::MiiManager manager;
ReturnValueForAmiiboSettings applet_output{};
if (!apply_changes) {
Cancel();
}
if (nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagFound &&
nfp_device->GetCurrentState() != Service::NFP::DeviceState::TagMounted) {
Cancel();
}
if (nfp_device->GetCurrentState() == Service::NFP::DeviceState::TagFound) {
nfp_device->Mount(Service::NFP::MountTarget::All);
}
switch (applet_input_common.applet_mode) {
case Service::NFP::CabinetMode::StartNicknameAndOwnerSettings: {
Service::NFP::AmiiboName name{};
std::memcpy(name.data(), amiibo_name.data(), std::min(amiibo_name.size(), name.size() - 1));
nfp_device->SetNicknameAndOwner(name);
break;
}
case Service::NFP::CabinetMode::StartGameDataEraser:
nfp_device->DeleteApplicationArea();
break;
case Service::NFP::CabinetMode::StartRestorer:
nfp_device->RestoreAmiibo();
break;
case Service::NFP::CabinetMode::StartFormatter:
nfp_device->DeleteAllData();
break;
default:
UNIMPLEMENTED_MSG("Unknown CabinetMode={}", applet_input_common.applet_mode);
break;
}
applet_output.device_handle = applet_input_common.device_handle;
applet_output.result = CabinetResult::Cancel;
const auto reg_result = nfp_device->GetRegisterInfo(applet_output.register_info);
const auto tag_result = nfp_device->GetTagInfo(applet_output.tag_info);
nfp_device->Finalize();
if (reg_result.IsSuccess()) {
applet_output.result |= CabinetResult::RegisterInfo;
}
if (tag_result.IsSuccess()) {
applet_output.result |= CabinetResult::TagInfo;
}
std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
is_complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
}
void Cabinet::Cancel() {
ReturnValueForAmiiboSettings applet_output{};
applet_output.device_handle = applet_input_common.device_handle;
applet_output.result = CabinetResult::Cancel;
nfp_device->Finalize();
std::vector<u8> out_data(sizeof(ReturnValueForAmiiboSettings));
std::memcpy(out_data.data(), &applet_output, sizeof(ReturnValueForAmiiboSettings));
is_complete = true;
broker.PushNormalDataFromApplet(std::make_shared<IStorage>(system, std::move(out_data)));
broker.SignalStateChanged();
}
} // namespace Service::AM::Applets

View File

@@ -1,104 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2022 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <array>
#include "core/hle/result.h"
#include "core/hle/service/am/applets/applets.h"
#include "core/hle/service/kernel_helpers.h"
#include "core/hle/service/nfp/nfp_types.h"
namespace Kernel {
class KEvent;
class KReadableEvent;
} // namespace Kernel
namespace Core {
class System;
} // namespace Core
namespace Service::NFP {
class NfpDevice;
}
namespace Service::AM::Applets {
enum class CabinetAppletVersion : u32 {
Version1 = 0x1,
};
enum class CabinetResult : u8 {
Cancel = 0,
TagInfo = 1 << 1,
RegisterInfo = 1 << 2,
All = TagInfo | RegisterInfo,
};
DECLARE_ENUM_FLAG_OPERATORS(CabinetResult)
// This is nn::nfp::AmiiboSettingsStartParam
struct AmiiboSettingsStartParam {
u64 device_handle;
std::array<u8, 0x20> param_1;
u8 param_2;
};
static_assert(sizeof(AmiiboSettingsStartParam) == 0x30,
"AmiiboSettingsStartParam is an invalid size");
#pragma pack(push, 1)
// This is nn::nfp::StartParamForAmiiboSettings
struct StartParamForAmiiboSettings {
u8 param_1;
Service::NFP::CabinetMode applet_mode;
u8 flags;
u8 amiibo_settings_1;
u64 device_handle;
Service::NFP::TagInfo tag_info;
Service::NFP::RegisterInfo register_info;
std::array<u8, 0x20> amiibo_settings_3;
INSERT_PADDING_BYTES(0x24);
};
static_assert(sizeof(StartParamForAmiiboSettings) == 0x1A8,
"StartParamForAmiiboSettings is an invalid size");
// This is nn::nfp::ReturnValueForAmiiboSettings
struct ReturnValueForAmiiboSettings {
CabinetResult result;
INSERT_PADDING_BYTES(0x3);
u64 device_handle;
Service::NFP::TagInfo tag_info;
Service::NFP::RegisterInfo register_info;
INSERT_PADDING_BYTES(0x24);
};
static_assert(sizeof(ReturnValueForAmiiboSettings) == 0x188,
"ReturnValueForAmiiboSettings is an invalid size");
#pragma pack(pop)
class Cabinet final : public Applet {
public:
explicit Cabinet(Core::System& system_, LibraryAppletMode applet_mode_,
const Core::Frontend::CabinetApplet& frontend_);
~Cabinet() override;
void Initialize() override;
bool TransactionComplete() const override;
Result GetStatus() const override;
void ExecuteInteractive() override;
void Execute() override;
void DisplayCompleted(bool apply_changes, std::string_view amiibo_name);
void Cancel();
private:
const Core::Frontend::CabinetApplet& frontend;
Core::System& system;
bool is_complete{false};
std::shared_ptr<Service::NFP::NfpDevice> nfp_device;
Kernel::KEvent* availability_change_event;
KernelHelpers::ServiceContext service_context;
StartParamForAmiiboSettings applet_input_common{};
};
} // namespace Service::AM::Applets

View File

@@ -5,7 +5,6 @@
#include "common/assert.h"
#include "core/core.h"
#include "core/frontend/applets/cabinet.h"
#include "core/frontend/applets/controller.h"
#include "core/frontend/applets/error.h"
#include "core/frontend/applets/general_frontend.h"
@@ -17,7 +16,6 @@
#include "core/hle/service/am/am.h"
#include "core/hle/service/am/applet_ae.h"
#include "core/hle/service/am/applet_oe.h"
#include "core/hle/service/am/applets/applet_cabinet.h"
#include "core/hle/service/am/applets/applet_controller.h"
#include "core/hle/service/am/applets/applet_error.h"
#include "core/hle/service/am/applets/applet_general_backend.h"
@@ -173,15 +171,13 @@ void Applet::Initialize() {
AppletFrontendSet::AppletFrontendSet() = default;
AppletFrontendSet::AppletFrontendSet(CabinetApplet cabinet_applet,
ControllerApplet controller_applet, ErrorApplet error_applet,
AppletFrontendSet::AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet,
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_)
: cabinet{std::move(cabinet_applet)}, controller{std::move(controller_applet)},
error{std::move(error_applet)}, mii_edit{std::move(mii_edit_)},
parental_controls{std::move(parental_controls_applet)},
: controller{std::move(controller_applet)}, error{std::move(error_applet)},
mii_edit{std::move(mii_edit_)}, parental_controls{std::move(parental_controls_applet)},
photo_viewer{std::move(photo_viewer_)}, profile_select{std::move(profile_select_)},
software_keyboard{std::move(software_keyboard_)}, web_browser{std::move(web_browser_)} {}
@@ -200,10 +196,6 @@ const AppletFrontendSet& AppletManager::GetAppletFrontendSet() const {
}
void AppletManager::SetAppletFrontendSet(AppletFrontendSet set) {
if (set.cabinet != nullptr) {
frontend.cabinet = std::move(set.cabinet);
}
if (set.controller != nullptr) {
frontend.controller = std::move(set.controller);
}
@@ -243,10 +235,6 @@ void AppletManager::SetDefaultAppletFrontendSet() {
}
void AppletManager::SetDefaultAppletsIfMissing() {
if (frontend.cabinet == nullptr) {
frontend.cabinet = std::make_unique<Core::Frontend::DefaultCabinetApplet>();
}
if (frontend.controller == nullptr) {
frontend.controller =
std::make_unique<Core::Frontend::DefaultControllerApplet>(system.HIDCore());
@@ -291,8 +279,6 @@ std::shared_ptr<Applet> AppletManager::GetApplet(AppletId id, LibraryAppletMode
switch (id) {
case AppletId::Auth:
return std::make_shared<Auth>(system, mode, *frontend.parental_controls);
case AppletId::Cabinet:
return std::make_shared<Cabinet>(system, mode, *frontend.cabinet);
case AppletId::Controller:
return std::make_shared<Controller>(system, mode, *frontend.controller);
case AppletId::Error:

View File

@@ -16,7 +16,6 @@ class System;
}
namespace Core::Frontend {
class CabinetApplet;
class ControllerApplet;
class ECommerceApplet;
class ErrorApplet;
@@ -177,7 +176,6 @@ protected:
};
struct AppletFrontendSet {
using CabinetApplet = std::unique_ptr<Core::Frontend::CabinetApplet>;
using ControllerApplet = std::unique_ptr<Core::Frontend::ControllerApplet>;
using ErrorApplet = std::unique_ptr<Core::Frontend::ErrorApplet>;
using MiiEdit = std::unique_ptr<Core::Frontend::MiiEditApplet>;
@@ -188,11 +186,10 @@ struct AppletFrontendSet {
using WebBrowser = std::unique_ptr<Core::Frontend::WebBrowserApplet>;
AppletFrontendSet();
AppletFrontendSet(CabinetApplet cabinet_applet, ControllerApplet controller_applet,
ErrorApplet error_applet, MiiEdit mii_edit_,
ParentalControlsApplet parental_controls_applet, PhotoViewer photo_viewer_,
ProfileSelect profile_select_, SoftwareKeyboard software_keyboard_,
WebBrowser web_browser_);
AppletFrontendSet(ControllerApplet controller_applet, ErrorApplet error_applet,
MiiEdit mii_edit_, ParentalControlsApplet parental_controls_applet,
PhotoViewer photo_viewer_, ProfileSelect profile_select_,
SoftwareKeyboard software_keyboard_, WebBrowser web_browser_);
~AppletFrontendSet();
AppletFrontendSet(const AppletFrontendSet&) = delete;
@@ -201,7 +198,6 @@ struct AppletFrontendSet {
AppletFrontendSet(AppletFrontendSet&&) noexcept;
AppletFrontendSet& operator=(AppletFrontendSet&&) noexcept;
CabinetApplet cabinet;
ControllerApplet controller;
ErrorApplet error;
MiiEdit mii_edit;

View File

@@ -31,7 +31,7 @@ ServiceContext::~ServiceContext() {
Kernel::KEvent* ServiceContext::CreateEvent(std::string&& name) {
// Reserve a new event from the process resource limit
Kernel::KScopedResourceReservation event_reservation(process,
Kernel::LimitableResource::EventCountMax);
Kernel::LimitableResource::Events);
if (!event_reservation.Succeeded()) {
LOG_CRITICAL(Service, "Resource limit reached!");
return {};

View File

@@ -77,9 +77,6 @@ void NfpDevice::NpadUpdate(Core::HID::ControllerTriggerType type) {
LoadAmiibo(nfc_status.data);
break;
case Common::Input::NfcState::AmiiboRemoved:
if (device_state == DeviceState::Initialized || device_state == DeviceState::TagRemoved) {
break;
}
if (device_state != DeviceState::SearchingForTag) {
CloseAmiibo();
}
@@ -100,8 +97,6 @@ bool NfpDevice::LoadAmiibo(std::span<const u8> data) {
return false;
}
// TODO: Filter by allowed_protocols here
memcpy(&encrypted_tag_data, data.data(), sizeof(EncryptedNTAG215File));
device_state = DeviceState::TagFound;
@@ -148,7 +143,7 @@ void NfpDevice::Finalize() {
device_state = DeviceState::Unavailable;
}
Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
Result NfpDevice::StartDetection(s32 protocol_) {
if (device_state != DeviceState::Initialized && device_state != DeviceState::TagRemoved) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
return WrongDeviceState;
@@ -160,7 +155,7 @@ Result NfpDevice::StartDetection(TagProtocol allowed_protocol) {
}
device_state = DeviceState::SearchingForTag;
allowed_protocols = allowed_protocol;
protocol = protocol_;
return ResultSuccess;
}
@@ -474,32 +469,6 @@ Result NfpDevice::OpenApplicationArea(u32 access_id) {
return ResultSuccess;
}
Result NfpDevice::GetApplicationAreaId(u32& application_area_id) const {
application_area_id = {};
if (device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);
if (device_state == DeviceState::TagRemoved) {
return TagRemoved;
}
return WrongDeviceState;
}
if (mount_target == MountTarget::None || mount_target == MountTarget::Rom) {
LOG_ERROR(Service_NFP, "Amiibo is read only", device_state);
return WrongDeviceState;
}
if (tag_data.settings.settings.appdata_initialized.Value() == 0) {
LOG_WARNING(Service_NFP, "Application area is not initialized");
return ApplicationAreaIsNotInitialized;
}
application_area_id = tag_data.application_area_id;
return ResultSuccess;
}
Result NfpDevice::GetApplicationArea(std::vector<u8>& data) const {
if (device_state != DeviceState::TagMounted) {
LOG_ERROR(Service_NFP, "Wrong device state {}", device_state);

View File

@@ -4,7 +4,6 @@
#pragma once
#include <array>
#include <span>
#include <vector>
#include "common/common_funcs.h"
@@ -38,7 +37,7 @@ public:
void Initialize();
void Finalize();
Result StartDetection(TagProtocol allowed_protocol);
Result StartDetection(s32 protocol_);
Result StopDetection();
Result Mount(MountTarget mount_target);
Result Unmount();
@@ -54,7 +53,6 @@ public:
Result DeleteAllData();
Result OpenApplicationArea(u32 access_id);
Result GetApplicationAreaId(u32& application_area_id) const;
Result GetApplicationArea(std::vector<u8>& data) const;
Result SetApplicationArea(std::span<const u8> data);
Result CreateApplicationArea(u32 access_id, std::span<const u8> data);
@@ -90,7 +88,7 @@ private:
bool is_data_moddified{};
bool is_app_area_open{};
TagProtocol allowed_protocols{};
s32 protocol{};
s64 current_posix_time{};
MountTarget mount_target{MountTarget::None};
DeviceState device_state{DeviceState::Unavailable};

View File

@@ -88,22 +88,11 @@ enum class PackedTagType : u8 {
Type5, // ISO15693 RW/RO 540 bytes 106kbit/s
};
// Verify this enum. It might be completely wrong default protocol is 0x48
enum class TagProtocol : u32 {
None,
TypeA = 1U << 0, // ISO14443A
TypeB = 1U << 1, // ISO14443B
TypeF = 1U << 2, // Sony Felica
Unknown1 = 1U << 3,
Unknown2 = 1U << 5,
All = 0xFFFFFFFFU,
};
enum class CabinetMode : u8 {
StartNicknameAndOwnerSettings,
StartGameDataEraser,
StartRestorer,
StartFormatter,
TypeA, // ISO14443A
TypeB, // ISO14443B
TypeF, // Sony Felica
};
using UniqueSerialNumber = std::array<u8, 7>;

View File

@@ -130,7 +130,7 @@ void IUser::ListDevices(Kernel::HLERequestContext& ctx) {
void IUser::StartDetection(Kernel::HLERequestContext& ctx) {
IPC::RequestParser rp{ctx};
const auto device_handle{rp.Pop<u64>()};
const auto nfp_protocol{rp.PopEnum<TagProtocol>()};
const auto nfp_protocol{rp.Pop<s32>()};
LOG_INFO(Service_NFP, "called, device_handle={}, nfp_protocol={}", device_handle, nfp_protocol);
if (state == State::NonInitialized) {

View File

@@ -126,12 +126,10 @@ NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output)
LOG_CRITICAL(Service_NVDRV, "Object failed to allocate, handle={:08X}", params.handle);
return result;
}
bool is_out_io{};
ASSERT(system.CurrentProcess()
->PageTable()
.LockForMapDeviceAddressSpace(&is_out_io, handle_description->address,
handle_description->size,
Kernel::KMemoryPermission::None, true, false)
.LockForMapDeviceAddressSpace(handle_description->address, handle_description->size,
Kernel::KMemoryPermission::None, true)
.IsSuccess());
std::memcpy(output.data(), &params, sizeof(params));
return result;

View File

@@ -34,8 +34,8 @@ void Controller::CloneCurrentObject(Kernel::HLERequestContext& ctx) {
// once this is a proper process
// Reserve a new session from the process resource limit.
Kernel::KScopedResourceReservation session_reservation(
&process, Kernel::LimitableResource::SessionCountMax);
Kernel::KScopedResourceReservation session_reservation(&process,
Kernel::LimitableResource::Sessions);
ASSERT(session_reservation.Succeeded());
// Create the session.

View File

@@ -11,10 +11,6 @@
#include "core/internal_network/network_interface.h"
#include "core/internal_network/socket_proxy.h"
#if YUZU_UNIX
#include <sys/socket.h>
#endif
namespace Network {
ProxySocket::ProxySocket(RoomNetwork& room_network_) noexcept : room_network{room_network_} {}

View File

@@ -60,8 +60,6 @@ Common::Input::NfcState VirtualAmiibo::WriteNfcData(
return Common::Input::NfcState::WriteFailed;
}
amiibo_data = data;
return Common::Input::NfcState::Success;
}
@@ -93,15 +91,6 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) {
return Info::Success;
}
VirtualAmiibo::Info VirtualAmiibo::ReloadAmiibo() {
if (state == State::AmiiboIsOpen) {
SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, amiibo_data});
return Info::Success;
}
return LoadAmiibo(file_path);
}
VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
state = polling_mode == Common::Input::PollingMode::NFC ? State::WaitingForAmiibo
: State::Initialized;
@@ -109,8 +98,4 @@ VirtualAmiibo::Info VirtualAmiibo::CloseAmiibo() {
return Info::Success;
}
std::string VirtualAmiibo::GetLastFilePath() const {
return file_path;
}
} // namespace InputCommon

View File

@@ -47,11 +47,8 @@ public:
State GetCurrentState() const;
Info LoadAmiibo(const std::string& amiibo_file);
Info ReloadAmiibo();
Info CloseAmiibo();
std::string GetLastFilePath() const;
private:
static constexpr std::size_t amiibo_size = 0x21C;
static constexpr std::size_t amiibo_size_without_password = amiibo_size - 0x8;

View File

@@ -133,7 +133,7 @@ public:
return Common::Input::CameraError::NotSupported;
}
// Returns success if nfc is supported
// Request nfc data from a controller
virtual Common::Input::NfcState SupportsNfc(
[[maybe_unused]] const PadIdentifier& identifier) const {
return Common::Input::NfcState::NotSupported;

View File

@@ -379,18 +379,6 @@ void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
ctx.Add("MOV.S {}.x,primitive_invocation.x;", inst);
}
void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst) {
switch (ctx.stage) {
case Stage::TessellationControl:
case Stage::TessellationEval:
ctx.Add("SHL.U {}.x,primitive.vertexcount,16;", inst);
break;
default:
LOG_WARNING(Shader, "(STUBBED) called");
ctx.Add("MOV.S {}.x,0x00ff0000;", inst);
}
}
void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
ctx.Add("MOV.S {}.x,fragment.sampleid.x;", inst);
}

View File

@@ -69,7 +69,6 @@ void EmitSetOFlag(EmitContext& ctx);
void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst);
void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst);
void EmitInvocationId(EmitContext& ctx, IR::Inst& inst);
void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst);
void EmitSampleId(EmitContext& ctx, IR::Inst& inst);
void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst);
void EmitYDirection(EmitContext& ctx, IR::Inst& inst);

View File

@@ -95,10 +95,6 @@ EmitContext::EmitContext(IR::Program& program, Bindings& bindings, const Profile
if (info.uses_invocation_id) {
Add("ATTRIB primitive_invocation=primitive.invocation;");
}
if (info.uses_invocation_info &&
(stage == Stage::TessellationControl || stage == Stage::TessellationEval)) {
Add("ATTRIB primitive_vertexcount = primitive.vertexcount;");
}
if (info.stores_tess_level_outer) {
Add("OUTPUT result_patch_tessouter[]={{result.patch.tessouter[0..3]}};");
}

View File

@@ -399,18 +399,6 @@ void EmitInvocationId(EmitContext& ctx, IR::Inst& inst) {
ctx.AddU32("{}=uint(gl_InvocationID);", inst);
}
void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst) {
switch (ctx.stage) {
case Stage::TessellationControl:
case Stage::TessellationEval:
ctx.AddU32("{}=uint(gl_PatchVerticesIn)<<16;", inst);
break;
default:
LOG_WARNING(Shader, "(STUBBED) called");
ctx.AddU32("{}=uint(0x00ff0000);", inst);
}
}
void EmitSampleId(EmitContext& ctx, IR::Inst& inst) {
ctx.AddU32("{}=uint(gl_SampleID);", inst);
}

View File

@@ -83,7 +83,6 @@ void EmitSetOFlag(EmitContext& ctx);
void EmitWorkgroupId(EmitContext& ctx, IR::Inst& inst);
void EmitLocalInvocationId(EmitContext& ctx, IR::Inst& inst);
void EmitInvocationId(EmitContext& ctx, IR::Inst& inst);
void EmitInvocationInfo(EmitContext& ctx, IR::Inst& inst);
void EmitSampleId(EmitContext& ctx, IR::Inst& inst);
void EmitIsHelperInvocation(EmitContext& ctx, IR::Inst& inst);
void EmitYDirection(EmitContext& ctx, IR::Inst& inst);

View File

@@ -512,18 +512,6 @@ Id EmitInvocationId(EmitContext& ctx) {
return ctx.OpLoad(ctx.U32[1], ctx.invocation_id);
}
Id EmitInvocationInfo(EmitContext& ctx) {
switch (ctx.stage) {
case Stage::TessellationControl:
case Stage::TessellationEval:
return ctx.OpShiftLeftLogical(ctx.U32[1], ctx.OpLoad(ctx.U32[1], ctx.patch_vertices_in),
ctx.Const(16u));
default:
LOG_WARNING(Shader, "(STUBBED) called");
return ctx.Const(0x00ff0000u);
}
}
Id EmitSampleId(EmitContext& ctx) {
return ctx.OpLoad(ctx.U32[1], ctx.sample_id);
}

View File

@@ -72,7 +72,6 @@ void EmitSetOFlag(EmitContext& ctx);
Id EmitWorkgroupId(EmitContext& ctx);
Id EmitLocalInvocationId(EmitContext& ctx);
Id EmitInvocationId(EmitContext& ctx);
Id EmitInvocationInfo(EmitContext& ctx);
Id EmitSampleId(EmitContext& ctx);
Id EmitIsHelperInvocation(EmitContext& ctx);
Id EmitYDirection(EmitContext& ctx);

View File

@@ -1325,10 +1325,6 @@ void EmitContext::DefineInputs(const IR::Program& program) {
if (info.uses_invocation_id) {
invocation_id = DefineInput(*this, U32[1], false, spv::BuiltIn::InvocationId);
}
if (info.uses_invocation_info &&
(stage == Shader::Stage::TessellationControl || stage == Shader::Stage::TessellationEval)) {
patch_vertices_in = DefineInput(*this, U32[1], false, spv::BuiltIn::PatchVertices);
}
if (info.uses_sample_id) {
sample_id = DefineInput(*this, U32[1], false, spv::BuiltIn::SampleId);
}

View File

@@ -204,7 +204,6 @@ public:
Id workgroup_id{};
Id local_invocation_id{};
Id invocation_id{};
Id patch_vertices_in{};
Id sample_id{};
Id is_helper_invocation{};
Id subgroup_local_invocation_id{};

View File

@@ -362,10 +362,6 @@ U32 IREmitter::InvocationId() {
return Inst<U32>(Opcode::InvocationId);
}
U32 IREmitter::InvocationInfo() {
return Inst<U32>(Opcode::InvocationInfo);
}
U32 IREmitter::SampleId() {
return Inst<U32>(Opcode::SampleId);
}

View File

@@ -97,7 +97,6 @@ public:
[[nodiscard]] U32 LocalInvocationIdZ();
[[nodiscard]] U32 InvocationId();
[[nodiscard]] U32 InvocationInfo();
[[nodiscard]] U32 SampleId();
[[nodiscard]] U1 IsHelperInvocation();
[[nodiscard]] F32 YDirection();

View File

@@ -59,7 +59,6 @@ OPCODE(SetOFlag, Void, U1,
OPCODE(WorkgroupId, U32x3, )
OPCODE(LocalInvocationId, U32x3, )
OPCODE(InvocationId, U32, )
OPCODE(InvocationInfo, U32, )
OPCODE(SampleId, U32, )
OPCODE(IsHelperInvocation, U1, )
OPCODE(YDirection, F32, )

View File

@@ -14,6 +14,8 @@ enum class Patch : u64 {
TessellationLodBottom,
TessellationLodInteriorU,
TessellationLodInteriorV,
ComponentPadding0,
ComponentPadding1,
Component0,
Component1,
Component2,
@@ -135,7 +137,7 @@ enum class Patch : u64 {
Component118,
Component119,
};
static_assert(static_cast<u64>(Patch::Component119) == 125);
static_assert(static_cast<u64>(Patch::Component119) == 127);
[[nodiscard]] bool IsGeneric(Patch patch) noexcept;

View File

@@ -117,7 +117,8 @@ enum class SpecialRegister : u64 {
case SpecialRegister::SR_THREAD_KILL:
return IR::U32{ir.Select(ir.IsHelperInvocation(), ir.Imm32(-1), ir.Imm32(0))};
case SpecialRegister::SR_INVOCATION_INFO:
return ir.InvocationInfo();
LOG_WARNING(Shader, "(STUBBED) SR_INVOCATION_INFO");
return ir.Imm32(0x00ff'0000);
case SpecialRegister::SR_TID: {
const IR::Value tid{ir.LocalInvocationId()};
return ir.BitFieldInsert(ir.BitFieldInsert(IR::U32{ir.CompositeExtract(tid, 0)},

View File

@@ -468,9 +468,6 @@ void VisitUsages(Info& info, IR::Inst& inst) {
case IR::Opcode::InvocationId:
info.uses_invocation_id = true;
break;
case IR::Opcode::InvocationInfo:
info.uses_invocation_info = true;
break;
case IR::Opcode::SampleId:
info.uses_sample_id = true;
break;

View File

@@ -127,7 +127,6 @@ struct Info {
bool uses_workgroup_id{};
bool uses_local_invocation_id{};
bool uses_invocation_id{};
bool uses_invocation_info{};
bool uses_sample_id{};
bool uses_is_helper_invocation{};
bool uses_subgroup_invocation_id{};

View File

@@ -73,6 +73,8 @@ add_library(video_core STATIC
macro/macro_hle.h
macro/macro_interpreter.cpp
macro/macro_interpreter.h
macro/macro_jit_x64.cpp
macro/macro_jit_x64.h
fence_manager.h
gpu.cpp
gpu.h
@@ -243,7 +245,7 @@ add_library(video_core STATIC
create_target_directory_groups(video_core)
target_link_libraries(video_core PUBLIC common core)
target_link_libraries(video_core PUBLIC glad shader_recompiler)
target_link_libraries(video_core PUBLIC glad shader_recompiler xbyak)
if (YUZU_USE_BUNDLED_FFMPEG AND NOT WIN32)
add_dependencies(video_core ffmpeg-build)
@@ -280,19 +282,8 @@ else()
-Wno-sign-conversion
)
# xbyak
set_source_files_properties(macro/macro_jit_x64.cpp PROPERTIES COMPILE_OPTIONS "-Wno-conversion;-Wno-shadow")
endif()
if (ARCHITECTURE_x86_64)
target_sources(video_core PRIVATE
macro/macro_jit_x64.cpp
macro/macro_jit_x64.h
)
target_link_libraries(video_core PUBLIC xbyak)
endif()
if (ARCHITECTURE_x86_64 OR ARCHITECTURE_arm64)
target_link_libraries(video_core PRIVATE dynarmic)
endif()

Some files were not shown because too many files have changed in this diff Show More