Compare commits
2 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6323db9c42 | ||
|
|
88955ac4e8 |
@@ -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})
|
||||
|
||||
11
externals/CMakeLists.txt
vendored
11
externals/CMakeLists.txt
vendored
@@ -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)
|
||||
|
||||
2
externals/dynarmic
vendored
2
externals/dynarmic
vendored
Submodule externals/dynarmic updated: 424fdb5c50...2d4602a651
2
externals/xbyak
vendored
2
externals/xbyak
vendored
Submodule externals/xbyak updated: 348e3e548e...c306b8e578
@@ -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()
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
};
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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());
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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
@@ -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};
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) + \
|
||||
[&]()
|
||||
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 {};
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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>;
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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(), ¶ms, sizeof(params));
|
||||
return result;
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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_} {}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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]}};");
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -97,7 +97,6 @@ public:
|
||||
[[nodiscard]] U32 LocalInvocationIdZ();
|
||||
|
||||
[[nodiscard]] U32 InvocationId();
|
||||
[[nodiscard]] U32 InvocationInfo();
|
||||
[[nodiscard]] U32 SampleId();
|
||||
[[nodiscard]] U1 IsHelperInvocation();
|
||||
[[nodiscard]] F32 YDirection();
|
||||
|
||||
@@ -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, )
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)},
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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{};
|
||||
|
||||
@@ -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
Reference in New Issue
Block a user