Merge pull request #4908 from hamish-milne/feature/savestates-2
Save states
This commit is contained in:
commit
c605bb42db
354 changed files with 6100 additions and 604 deletions
|
@ -164,6 +164,7 @@ add_library(core STATIC
|
|||
hle/kernel/server_session.cpp
|
||||
hle/kernel/server_session.h
|
||||
hle/kernel/session.h
|
||||
hle/kernel/session.cpp
|
||||
hle/kernel/shared_memory.cpp
|
||||
hle/kernel/shared_memory.h
|
||||
hle/kernel/shared_page.cpp
|
||||
|
@ -450,6 +451,8 @@ add_library(core STATIC
|
|||
rpc/server.h
|
||||
rpc/udp_server.cpp
|
||||
rpc/udp_server.h
|
||||
savestate.cpp
|
||||
savestate.h
|
||||
settings.cpp
|
||||
settings.h
|
||||
telemetry_session.cpp
|
||||
|
@ -469,7 +472,7 @@ endif()
|
|||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core network video_core)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE cryptopp fmt open_source_archives Boost::serialization)
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
get_directory_property(OPENSSL_LIBS
|
||||
|
|
|
@ -6,10 +6,14 @@
|
|||
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/arm/skyeye_common/arm_regformat.h"
|
||||
#include "core/arm/skyeye_common/vfp/asm_vfp.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
namespace Memory {
|
||||
struct PageTable;
|
||||
|
@ -23,6 +27,48 @@ public:
|
|||
virtual ~ARM_Interface() {}
|
||||
|
||||
class ThreadContext {
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <class Archive>
|
||||
void save(Archive& ar, const unsigned int file_version) const {
|
||||
for (std::size_t i = 0; i < 16; i++) {
|
||||
const auto r = GetCpuRegister(i);
|
||||
ar << r;
|
||||
}
|
||||
std::size_t fpu_reg_count = file_version == 0 ? 16 : 64;
|
||||
for (std::size_t i = 0; i < fpu_reg_count; i++) {
|
||||
const auto r = GetFpuRegister(i);
|
||||
ar << r;
|
||||
}
|
||||
const auto r1 = GetCpsr();
|
||||
ar << r1;
|
||||
const auto r2 = GetFpscr();
|
||||
ar << r2;
|
||||
const auto r3 = GetFpexc();
|
||||
ar << r3;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load(Archive& ar, const unsigned int file_version) {
|
||||
u32 r;
|
||||
for (std::size_t i = 0; i < 16; i++) {
|
||||
ar >> r;
|
||||
SetCpuRegister(i, r);
|
||||
}
|
||||
std::size_t fpu_reg_count = file_version == 0 ? 16 : 64;
|
||||
for (std::size_t i = 0; i < fpu_reg_count; i++) {
|
||||
ar >> r;
|
||||
SetFpuRegister(i, r);
|
||||
}
|
||||
ar >> r;
|
||||
SetCpsr(r);
|
||||
ar >> r;
|
||||
SetFpscr(r);
|
||||
ar >> r;
|
||||
SetFpexc(r);
|
||||
}
|
||||
|
||||
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
||||
public:
|
||||
virtual ~ThreadContext() = default;
|
||||
|
||||
|
@ -77,7 +123,7 @@ public:
|
|||
virtual void InvalidateCacheRange(u32 start_address, std::size_t length) = 0;
|
||||
|
||||
/// Notify CPU emulation that page tables have changed
|
||||
virtual void PageTableChanged(Memory::PageTable* new_page_table) = 0;
|
||||
virtual void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) = 0;
|
||||
|
||||
/**
|
||||
* Set the Program Counter to an address
|
||||
|
@ -150,7 +196,7 @@ public:
|
|||
* @param reg The CP15 register to retrieve the value from.
|
||||
* @return the value stored in the given CP15 register.
|
||||
*/
|
||||
virtual u32 GetCP15Register(CP15Register reg) = 0;
|
||||
virtual u32 GetCP15Register(CP15Register reg) const = 0;
|
||||
|
||||
/**
|
||||
* Stores the given value into the indicated CP15 register.
|
||||
|
@ -180,6 +226,8 @@ public:
|
|||
/// Prepare core for thread reschedule (if needed to correctly handle state)
|
||||
virtual void PrepareReschedule() = 0;
|
||||
|
||||
virtual void PurgeState() = 0;
|
||||
|
||||
std::shared_ptr<Core::Timing::Timer> GetTimer() {
|
||||
return timer;
|
||||
}
|
||||
|
@ -189,8 +237,101 @@ public:
|
|||
}
|
||||
|
||||
protected:
|
||||
// This us used for serialization. Returning nullptr is valid if page tables are not used.
|
||||
virtual std::shared_ptr<Memory::PageTable> GetPageTable() const = 0;
|
||||
|
||||
std::shared_ptr<Core::Timing::Timer> timer;
|
||||
|
||||
private:
|
||||
u32 id;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
|
||||
template <class Archive>
|
||||
void save(Archive& ar, const unsigned int file_version) const {
|
||||
ar << timer;
|
||||
ar << id;
|
||||
const auto page_table = GetPageTable();
|
||||
ar << page_table;
|
||||
for (int i = 0; i < 15; i++) {
|
||||
const auto r = GetReg(i);
|
||||
ar << r;
|
||||
}
|
||||
const auto pc = GetPC();
|
||||
ar << pc;
|
||||
const auto cpsr = GetCPSR();
|
||||
ar << cpsr;
|
||||
int vfp_reg_count = file_version == 0 ? 32 : 64;
|
||||
for (int i = 0; i < vfp_reg_count; i++) {
|
||||
const auto r = GetVFPReg(i);
|
||||
ar << r;
|
||||
}
|
||||
for (std::size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
|
||||
const auto reg = static_cast<VFPSystemRegister>(i);
|
||||
u32 r = 0;
|
||||
switch (reg) {
|
||||
case VFP_FPSCR:
|
||||
case VFP_FPEXC:
|
||||
r = GetVFPSystemReg(reg);
|
||||
}
|
||||
ar << r;
|
||||
}
|
||||
for (std::size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
|
||||
const auto reg = static_cast<CP15Register>(i);
|
||||
u32 r = 0;
|
||||
switch (reg) {
|
||||
case CP15_THREAD_UPRW:
|
||||
case CP15_THREAD_URO:
|
||||
r = GetCP15Register(reg);
|
||||
}
|
||||
ar << r;
|
||||
}
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load(Archive& ar, const unsigned int file_version) {
|
||||
PurgeState();
|
||||
ar >> timer;
|
||||
ar >> id;
|
||||
std::shared_ptr<Memory::PageTable> page_table{};
|
||||
ar >> page_table;
|
||||
SetPageTable(page_table);
|
||||
u32 r;
|
||||
for (int i = 0; i < 15; i++) {
|
||||
ar >> r;
|
||||
SetReg(i, r);
|
||||
}
|
||||
ar >> r;
|
||||
SetPC(r);
|
||||
ar >> r;
|
||||
SetCPSR(r);
|
||||
int vfp_reg_count = file_version == 0 ? 32 : 64;
|
||||
for (int i = 0; i < vfp_reg_count; i++) {
|
||||
ar >> r;
|
||||
SetVFPReg(i, r);
|
||||
}
|
||||
for (std::size_t i = 0; i < VFPSystemRegister::VFP_SYSTEM_REGISTER_COUNT; i++) {
|
||||
ar >> r;
|
||||
const auto reg = static_cast<VFPSystemRegister>(i);
|
||||
switch (reg) {
|
||||
case VFP_FPSCR:
|
||||
case VFP_FPEXC:
|
||||
SetVFPSystemReg(reg, r);
|
||||
}
|
||||
}
|
||||
for (std::size_t i = 0; i < CP15Register::CP15_REGISTER_COUNT; i++) {
|
||||
ar >> r;
|
||||
const auto reg = static_cast<CP15Register>(i);
|
||||
switch (reg) {
|
||||
case CP15_THREAD_UPRW:
|
||||
case CP15_THREAD_URO:
|
||||
SetCP15Register(reg, r);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
||||
};
|
||||
|
||||
BOOST_CLASS_VERSION(ARM_Interface, 1)
|
||||
BOOST_CLASS_VERSION(ARM_Interface::ThreadContext, 1)
|
||||
|
|
|
@ -153,7 +153,7 @@ ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, u
|
|||
std::shared_ptr<Core::Timing::Timer> timer)
|
||||
: ARM_Interface(id, timer), system(*system), memory(memory),
|
||||
cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
||||
PageTableChanged(memory.GetCurrentPageTable());
|
||||
SetPageTable(memory.GetCurrentPageTable());
|
||||
}
|
||||
|
||||
ARM_Dynarmic::~ARM_Dynarmic() = default;
|
||||
|
@ -229,7 +229,7 @@ void ARM_Dynarmic::SetCPSR(u32 cpsr) {
|
|||
jit->SetCpsr(cpsr);
|
||||
}
|
||||
|
||||
u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) {
|
||||
u32 ARM_Dynarmic::GetCP15Register(CP15Register reg) const {
|
||||
switch (reg) {
|
||||
case CP15_THREAD_UPRW:
|
||||
return cp15_state.cp15_thread_uprw;
|
||||
|
@ -287,17 +287,27 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
|||
jit->InvalidateCacheRange(start_address, length);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PageTableChanged(Memory::PageTable* new_page_table) {
|
||||
current_page_table = new_page_table;
|
||||
std::shared_ptr<Memory::PageTable> ARM_Dynarmic::GetPageTable() const {
|
||||
return current_page_table;
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) {
|
||||
current_page_table = page_table;
|
||||
Dynarmic::A32::Context ctx{};
|
||||
if (jit) {
|
||||
jit->SaveContext(ctx);
|
||||
}
|
||||
|
||||
auto iter = jits.find(current_page_table);
|
||||
if (iter != jits.end()) {
|
||||
jit = iter->second.get();
|
||||
jit->LoadContext(ctx);
|
||||
return;
|
||||
}
|
||||
|
||||
auto new_jit = MakeJit();
|
||||
jit = new_jit.get();
|
||||
jit->LoadContext(ctx);
|
||||
jits.emplace(current_page_table, std::move(new_jit));
|
||||
}
|
||||
|
||||
|
@ -311,8 +321,12 @@ void ARM_Dynarmic::ServeBreak() {
|
|||
std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() {
|
||||
Dynarmic::A32::UserConfig config;
|
||||
config.callbacks = cb.get();
|
||||
config.page_table = ¤t_page_table->pointers;
|
||||
config.page_table = ¤t_page_table->GetPointerArray();
|
||||
config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state);
|
||||
config.define_unpredictable_behaviour = true;
|
||||
return std::make_unique<Dynarmic::A32::Jit>(config);
|
||||
}
|
||||
|
||||
void ARM_Dynarmic::PurgeState() {
|
||||
ClearInstructionCache();
|
||||
}
|
||||
|
|
|
@ -41,7 +41,7 @@ public:
|
|||
void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
|
||||
u32 GetCPSR() const override;
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
u32 GetCP15Register(CP15Register reg) override;
|
||||
u32 GetCP15Register(CP15Register reg) const override;
|
||||
void SetCP15Register(CP15Register reg, u32 value) override;
|
||||
|
||||
std::unique_ptr<ThreadContext> NewContext() const override;
|
||||
|
@ -52,7 +52,11 @@ public:
|
|||
|
||||
void ClearInstructionCache() override;
|
||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||
void PageTableChanged(Memory::PageTable* new_page_table) override;
|
||||
void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
|
||||
void PurgeState() override;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Memory::PageTable> GetPageTable() const override;
|
||||
|
||||
private:
|
||||
void ServeBreak();
|
||||
|
@ -67,6 +71,6 @@ private:
|
|||
CP15State cp15_state;
|
||||
|
||||
Dynarmic::A32::Jit* jit = nullptr;
|
||||
Memory::PageTable* current_page_table = nullptr;
|
||||
std::map<Memory::PageTable*, std::unique_ptr<Dynarmic::A32::Jit>> jits;
|
||||
std::shared_ptr<Memory::PageTable> current_page_table = nullptr;
|
||||
std::map<std::shared_ptr<Memory::PageTable>, std::unique_ptr<Dynarmic::A32::Jit>> jits;
|
||||
};
|
||||
|
|
|
@ -95,10 +95,16 @@ void ARM_DynCom::InvalidateCacheRange(u32, std::size_t) {
|
|||
ClearInstructionCache();
|
||||
}
|
||||
|
||||
void ARM_DynCom::PageTableChanged(Memory::PageTable*) {
|
||||
void ARM_DynCom::SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) {
|
||||
ClearInstructionCache();
|
||||
}
|
||||
|
||||
std::shared_ptr<Memory::PageTable> ARM_DynCom::GetPageTable() const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void ARM_DynCom::PurgeState() {}
|
||||
|
||||
void ARM_DynCom::SetPC(u32 pc) {
|
||||
state->Reg[15] = pc;
|
||||
}
|
||||
|
@ -139,7 +145,7 @@ void ARM_DynCom::SetCPSR(u32 cpsr) {
|
|||
state->Cpsr = cpsr;
|
||||
}
|
||||
|
||||
u32 ARM_DynCom::GetCP15Register(CP15Register reg) {
|
||||
u32 ARM_DynCom::GetCP15Register(CP15Register reg) const {
|
||||
return state->CP15[reg];
|
||||
}
|
||||
|
||||
|
|
|
@ -30,7 +30,6 @@ public:
|
|||
|
||||
void ClearInstructionCache() override;
|
||||
void InvalidateCacheRange(u32 start_address, std::size_t length) override;
|
||||
void PageTableChanged(Memory::PageTable* new_page_table) override;
|
||||
|
||||
void SetPC(u32 pc) override;
|
||||
u32 GetPC() const override;
|
||||
|
@ -42,14 +41,19 @@ public:
|
|||
void SetVFPSystemReg(VFPSystemRegister reg, u32 value) override;
|
||||
u32 GetCPSR() const override;
|
||||
void SetCPSR(u32 cpsr) override;
|
||||
u32 GetCP15Register(CP15Register reg) override;
|
||||
u32 GetCP15Register(CP15Register reg) const override;
|
||||
void SetCP15Register(CP15Register reg, u32 value) override;
|
||||
|
||||
std::unique_ptr<ThreadContext> NewContext() const override;
|
||||
void SaveContext(const std::unique_ptr<ThreadContext>& arg) override;
|
||||
void LoadContext(const std::unique_ptr<ThreadContext>& arg) override;
|
||||
|
||||
void SetPageTable(const std::shared_ptr<Memory::PageTable>& page_table) override;
|
||||
void PrepareReschedule() override;
|
||||
void PurgeState() override;
|
||||
|
||||
protected:
|
||||
std::shared_ptr<Memory::PageTable> GetPageTable() const override;
|
||||
|
||||
private:
|
||||
void ExecuteInstructions(u64 num_instructions);
|
||||
|
|
|
@ -18,6 +18,10 @@ constexpr u64 run_interval_ticks = BASE_CLOCK_RATE_ARM11 / 60;
|
|||
|
||||
CheatEngine::CheatEngine(Core::System& system_) : system(system_) {
|
||||
LoadCheatFile();
|
||||
Connect();
|
||||
}
|
||||
|
||||
void CheatEngine::Connect() {
|
||||
event = system.CoreTiming().RegisterEvent(
|
||||
"CheatCore::run_event",
|
||||
[this](u64 thread_id, s64 cycle_late) { RunCallback(thread_id, cycle_late); });
|
||||
|
|
|
@ -26,6 +26,7 @@ class CheatEngine {
|
|||
public:
|
||||
explicit CheatEngine(Core::System& system);
|
||||
~CheatEngine();
|
||||
void Connect();
|
||||
std::vector<std::shared_ptr<CheatBase>> GetCheats() const;
|
||||
void AddCheat(const std::shared_ptr<CheatBase>& cheat);
|
||||
void RemoveCheat(int index);
|
||||
|
|
|
@ -2,8 +2,11 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fstream>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <utility>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include "audio_core/dsp_interface.h"
|
||||
#include "audio_core/hle/hle.h"
|
||||
#include "audio_core/lle/lle.h"
|
||||
|
@ -23,25 +26,48 @@
|
|||
#endif
|
||||
#include "core/custom_tex_cache.h"
|
||||
#include "core/gdbstub/gdbstub.h"
|
||||
#include "core/global.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/service/fs/archive.h"
|
||||
#include "core/hle/service/gsp/gsp.h"
|
||||
#include "core/hle/service/pm/pm_app.h"
|
||||
#include "core/hle/service/service.h"
|
||||
#include "core/hle/service/sm/sm.h"
|
||||
#include "core/hw/gpu.h"
|
||||
#include "core/hw/hw.h"
|
||||
#include "core/hw/lcd.h"
|
||||
#include "core/loader/loader.h"
|
||||
#include "core/movie.h"
|
||||
#include "core/rpc/rpc_server.h"
|
||||
#include "core/settings.h"
|
||||
#include "network/network.h"
|
||||
#include "video_core/renderer_base.h"
|
||||
#include "video_core/video_core.h"
|
||||
|
||||
namespace Core {
|
||||
|
||||
/*static*/ System System::s_instance;
|
||||
|
||||
template <>
|
||||
Core::System& Global() {
|
||||
return System::GetInstance();
|
||||
}
|
||||
|
||||
template <>
|
||||
Kernel::KernelSystem& Global() {
|
||||
return System::GetInstance().Kernel();
|
||||
}
|
||||
|
||||
template <>
|
||||
Core::Timing& Global() {
|
||||
return System::GetInstance().CoreTiming();
|
||||
}
|
||||
|
||||
System::~System() = default;
|
||||
|
||||
System::ResultStatus System::RunLoop(bool tight_loop) {
|
||||
status = ResultStatus::Success;
|
||||
if (std::any_of(cpu_cores.begin(), cpu_cores.end(),
|
||||
|
@ -67,6 +93,52 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
|
|||
}
|
||||
}
|
||||
|
||||
Signal signal{Signal::None};
|
||||
u32 param{};
|
||||
{
|
||||
std::lock_guard lock{signal_mutex};
|
||||
if (current_signal != Signal::None) {
|
||||
signal = current_signal;
|
||||
param = signal_param;
|
||||
current_signal = Signal::None;
|
||||
}
|
||||
}
|
||||
switch (signal) {
|
||||
case Signal::Reset:
|
||||
Reset();
|
||||
return ResultStatus::Success;
|
||||
case Signal::Shutdown:
|
||||
return ResultStatus::ShutdownRequested;
|
||||
case Signal::Load: {
|
||||
LOG_INFO(Core, "Begin load");
|
||||
try {
|
||||
System::LoadState(param);
|
||||
LOG_INFO(Core, "Load completed");
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(Core, "Error loading: {}", e.what());
|
||||
status_details = e.what();
|
||||
return ResultStatus::ErrorSavestate;
|
||||
}
|
||||
frame_limiter.WaitOnce();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
case Signal::Save: {
|
||||
LOG_INFO(Core, "Begin save");
|
||||
try {
|
||||
System::SaveState(param);
|
||||
LOG_INFO(Core, "Save completed");
|
||||
} catch (const std::exception& e) {
|
||||
LOG_ERROR(Core, "Error saving: {}", e.what());
|
||||
status_details = e.what();
|
||||
return ResultStatus::ErrorSavestate;
|
||||
}
|
||||
frame_limiter.WaitOnce();
|
||||
return ResultStatus::Success;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// All cores should have executed the same amount of ticks. If this is not the case an event was
|
||||
// scheduled with a cycles_into_future smaller then the current downcount.
|
||||
// So we have to get those cores to the same global time first
|
||||
|
@ -141,20 +213,26 @@ System::ResultStatus System::RunLoop(bool tight_loop) {
|
|||
HW::Update();
|
||||
Reschedule();
|
||||
|
||||
if (reset_requested.exchange(false)) {
|
||||
Reset();
|
||||
} else if (shutdown_requested.exchange(false)) {
|
||||
return ResultStatus::ShutdownRequested;
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
bool System::SendSignal(System::Signal signal, u32 param) {
|
||||
std::lock_guard lock{signal_mutex};
|
||||
if (current_signal != signal && current_signal != Signal::None) {
|
||||
LOG_ERROR(Core, "Unable to {} as {} is ongoing", signal, current_signal);
|
||||
return false;
|
||||
}
|
||||
current_signal = signal;
|
||||
signal_param = param;
|
||||
return true;
|
||||
}
|
||||
|
||||
System::ResultStatus System::SingleStep() {
|
||||
return RunLoop(false);
|
||||
}
|
||||
|
||||
System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) {
|
||||
FileUtil::SetCurrentRomPath(filepath);
|
||||
app_loader = Loader::GetLoader(filepath);
|
||||
if (!app_loader) {
|
||||
LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath);
|
||||
|
@ -180,7 +258,11 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||
ASSERT(system_mode.first);
|
||||
auto n3ds_mode = app_loader->LoadKernelN3dsMode();
|
||||
ASSERT(n3ds_mode.first);
|
||||
ResultStatus init_result{Init(emu_window, *system_mode.first, *n3ds_mode.first)};
|
||||
u32 num_cores = 2;
|
||||
if (Settings::values.is_new_3ds) {
|
||||
num_cores = 4;
|
||||
}
|
||||
ResultStatus init_result{Init(emu_window, *system_mode.first, *n3ds_mode.first, num_cores)};
|
||||
if (init_result != ResultStatus::Success) {
|
||||
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
|
||||
static_cast<u32>(init_result));
|
||||
|
@ -206,7 +288,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
|||
}
|
||||
}
|
||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
||||
u64 title_id{0};
|
||||
title_id = 0;
|
||||
if (app_loader->ReadProgramId(title_id) != Loader::ResultStatus::Success) {
|
||||
LOG_ERROR(Core, "Failed to find title id for ROM (Error {})",
|
||||
static_cast<u32>(load_result));
|
||||
|
@ -237,7 +319,8 @@ void System::PrepareReschedule() {
|
|||
}
|
||||
|
||||
PerfStats::Results System::GetAndResetPerfStats() {
|
||||
return perf_stats->GetAndResetStats(timing->GetGlobalTimeUs());
|
||||
return (perf_stats && timing) ? perf_stats->GetAndResetStats(timing->GetGlobalTimeUs())
|
||||
: PerfStats::Results{};
|
||||
}
|
||||
|
||||
void System::Reschedule() {
|
||||
|
@ -252,14 +335,10 @@ void System::Reschedule() {
|
|||
}
|
||||
}
|
||||
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode) {
|
||||
System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode,
|
||||
u32 num_cores) {
|
||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||
|
||||
std::size_t num_cores = 2;
|
||||
if (Settings::values.is_new_3ds) {
|
||||
num_cores = 4;
|
||||
}
|
||||
|
||||
memory = std::make_unique<Memory::MemorySystem>();
|
||||
|
||||
timing = std::make_unique<Timing>(num_cores, Settings::values.cpu_clock_percentage);
|
||||
|
@ -269,19 +348,19 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
|||
|
||||
if (Settings::values.use_cpu_jit) {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
for (std::size_t i = 0; i < num_cores; ++i) {
|
||||
for (u32 i = 0; i < num_cores; ++i) {
|
||||
cpu_cores.push_back(
|
||||
std::make_shared<ARM_Dynarmic>(this, *memory, i, timing->GetTimer(i)));
|
||||
}
|
||||
#else
|
||||
for (std::size_t i = 0; i < num_cores; ++i) {
|
||||
for (u32 i = 0; i < num_cores; ++i) {
|
||||
cpu_cores.push_back(
|
||||
std::make_shared<ARM_DynCom>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
|
||||
}
|
||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||
#endif
|
||||
} else {
|
||||
for (std::size_t i = 0; i < num_cores; ++i) {
|
||||
for (u32 i = 0; i < num_cores; ++i) {
|
||||
cpu_cores.push_back(
|
||||
std::make_shared<ARM_DynCom>(this, *memory, USER32MODE, i, timing->GetTimer(i)));
|
||||
}
|
||||
|
@ -307,7 +386,7 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, u32 system_mo
|
|||
|
||||
rpc_server = std::make_unique<RPC::RPCServer>();
|
||||
|
||||
service_manager = std::make_shared<Service::SM::ServiceManager>(*this);
|
||||
service_manager = std::make_unique<Service::SM::ServiceManager>(*this);
|
||||
archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
|
||||
|
||||
HW::Init(*memory);
|
||||
|
@ -419,7 +498,7 @@ void System::RegisterImageInterface(std::shared_ptr<Frontend::ImageInterface> im
|
|||
registered_image_interface = std::move(image_interface);
|
||||
}
|
||||
|
||||
void System::Shutdown() {
|
||||
void System::Shutdown(bool is_deserializing) {
|
||||
// Log last frame performance stats
|
||||
const auto perf_results = GetAndResetPerfStats();
|
||||
telemetry_session->AddField(Telemetry::FieldType::Performance, "Shutdown_EmulationSpeed",
|
||||
|
@ -432,20 +511,22 @@ void System::Shutdown() {
|
|||
perf_stats->GetMeanFrametime());
|
||||
|
||||
// Shutdown emulation session
|
||||
GDBStub::Shutdown();
|
||||
VideoCore::Shutdown();
|
||||
HW::Shutdown();
|
||||
if (!is_deserializing) {
|
||||
GDBStub::Shutdown();
|
||||
perf_stats.reset();
|
||||
cheat_engine.reset();
|
||||
app_loader.reset();
|
||||
}
|
||||
telemetry_session.reset();
|
||||
perf_stats.reset();
|
||||
rpc_server.reset();
|
||||
cheat_engine.reset();
|
||||
archive_manager.reset();
|
||||
service_manager.reset();
|
||||
dsp_core.reset();
|
||||
cpu_cores.clear();
|
||||
kernel.reset();
|
||||
timing.reset();
|
||||
app_loader.reset();
|
||||
|
||||
if (video_dumper->IsDumping()) {
|
||||
video_dumper->StopDumping();
|
||||
|
@ -469,4 +550,63 @@ void System::Reset() {
|
|||
Load(*m_emu_window, m_filepath);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void System::serialize(Archive& ar, const unsigned int file_version) {
|
||||
|
||||
u32 num_cores;
|
||||
if (Archive::is_saving::value) {
|
||||
num_cores = this->GetNumCores();
|
||||
}
|
||||
ar& num_cores;
|
||||
|
||||
if (Archive::is_loading::value) {
|
||||
// When loading, we want to make sure any lingering state gets cleared out before we begin.
|
||||
// Shutdown, but persist a few things between loads...
|
||||
Shutdown(true);
|
||||
|
||||
// Re-initialize everything like it was before
|
||||
auto system_mode = this->app_loader->LoadKernelSystemMode();
|
||||
auto n3ds_mode = this->app_loader->LoadKernelN3dsMode();
|
||||
Init(*m_emu_window, *system_mode.first, *n3ds_mode.first, num_cores);
|
||||
}
|
||||
|
||||
// flush on save, don't flush on load
|
||||
bool should_flush = !Archive::is_loading::value;
|
||||
Memory::RasterizerClearAll(should_flush);
|
||||
ar&* timing.get();
|
||||
for (u32 i = 0; i < num_cores; i++) {
|
||||
ar&* cpu_cores[i].get();
|
||||
}
|
||||
ar&* service_manager.get();
|
||||
ar&* archive_manager.get();
|
||||
ar& GPU::g_regs;
|
||||
ar& LCD::g_regs;
|
||||
|
||||
// NOTE: DSP doesn't like being destroyed and recreated. So instead we do an inline
|
||||
// serialization; this means that the DSP Settings need to match for loading to work.
|
||||
auto dsp_hle = dynamic_cast<AudioCore::DspHle*>(dsp_core.get());
|
||||
if (dsp_hle) {
|
||||
ar&* dsp_hle;
|
||||
} else {
|
||||
throw std::runtime_error("LLE audio not supported for save states");
|
||||
}
|
||||
|
||||
ar&* memory.get();
|
||||
ar&* kernel.get();
|
||||
VideoCore::serialize(ar, file_version);
|
||||
if (file_version >= 1) {
|
||||
ar& Movie::GetInstance();
|
||||
}
|
||||
|
||||
// This needs to be set from somewhere - might as well be here!
|
||||
if (Archive::is_loading::value) {
|
||||
Service::GSP::SetGlobalModule(*this);
|
||||
memory->SetDSP(*dsp_core);
|
||||
cheat_engine->Connect();
|
||||
VideoCore::g_renderer->Sync();
|
||||
}
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(System)
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -5,7 +5,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <string>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/custom_tex_cache.h"
|
||||
#include "core/frontend/applets/mii_selector.h"
|
||||
|
@ -87,10 +89,13 @@ public:
|
|||
/// generic drivers installed
|
||||
ErrorVideoCore_ErrorBelowGL33, ///< Error in the video core due to the user not having
|
||||
/// OpenGL 3.3 or higher
|
||||
ErrorSavestate, ///< Error saving or loading
|
||||
ShutdownRequested, ///< Emulated program requested a system shutdown
|
||||
ErrorUnknown ///< Any other error
|
||||
};
|
||||
|
||||
~System();
|
||||
|
||||
/**
|
||||
* Run the core CPU loop
|
||||
* This function runs the core for the specified number of CPU instructions before trying to
|
||||
|
@ -110,19 +115,23 @@ public:
|
|||
ResultStatus SingleStep();
|
||||
|
||||
/// Shutdown the emulated system.
|
||||
void Shutdown();
|
||||
void Shutdown(bool is_deserializing = false);
|
||||
|
||||
/// Shutdown and then load again
|
||||
void Reset();
|
||||
|
||||
enum class Signal : u32 { None, Shutdown, Reset, Save, Load };
|
||||
|
||||
bool SendSignal(Signal signal, u32 param = 0);
|
||||
|
||||
/// Request reset of the system
|
||||
void RequestReset() {
|
||||
reset_requested = true;
|
||||
SendSignal(Signal::Reset);
|
||||
}
|
||||
|
||||
/// Request shutdown of the system
|
||||
void RequestShutdown() {
|
||||
shutdown_requested = true;
|
||||
SendSignal(Signal::Shutdown);
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -179,7 +188,7 @@ public:
|
|||
};
|
||||
|
||||
u32 GetNumCores() const {
|
||||
return cpu_cores.size();
|
||||
return static_cast<u32>(cpu_cores.size());
|
||||
}
|
||||
|
||||
void InvalidateCacheRange(u32 start_address, std::size_t length) {
|
||||
|
@ -295,6 +304,10 @@ public:
|
|||
return registered_image_interface;
|
||||
}
|
||||
|
||||
void SaveState(u32 slot) const;
|
||||
|
||||
void LoadState(u32 slot);
|
||||
|
||||
private:
|
||||
/**
|
||||
* Initialize the emulated system.
|
||||
|
@ -303,7 +316,8 @@ private:
|
|||
* @param system_mode The system mode.
|
||||
* @return ResultStatus code, indicating if the operation succeeded.
|
||||
*/
|
||||
ResultStatus Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode);
|
||||
ResultStatus Init(Frontend::EmuWindow& emu_window, u32 system_mode, u8 n3ds_mode,
|
||||
u32 num_cores);
|
||||
|
||||
/// Reschedule the core emulation
|
||||
void Reschedule();
|
||||
|
@ -325,7 +339,7 @@ private:
|
|||
std::unique_ptr<Core::TelemetrySession> telemetry_session;
|
||||
|
||||
/// Service manager
|
||||
std::shared_ptr<Service::SM::ServiceManager> service_manager;
|
||||
std::unique_ptr<Service::SM::ServiceManager> service_manager;
|
||||
|
||||
/// Frontend applets
|
||||
std::shared_ptr<Frontend::MiiSelector> registered_mii_selector;
|
||||
|
@ -362,9 +376,15 @@ private:
|
|||
/// Saved variables for reset
|
||||
Frontend::EmuWindow* m_emu_window;
|
||||
std::string m_filepath;
|
||||
u64 title_id;
|
||||
|
||||
std::atomic<bool> reset_requested;
|
||||
std::atomic<bool> shutdown_requested;
|
||||
std::mutex signal_mutex;
|
||||
Signal current_signal;
|
||||
u32 signal_param;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <typename Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
inline ARM_Interface& GetRunningCore() {
|
||||
|
@ -384,3 +404,5 @@ inline AudioCore::DspInterface& DSP() {
|
|||
}
|
||||
|
||||
} // namespace Core
|
||||
|
||||
BOOST_CLASS_VERSION(Core::System, 1)
|
||||
|
|
|
@ -23,8 +23,9 @@ bool Timing::Event::operator<(const Timing::Event& right) const {
|
|||
Timing::Timing(std::size_t num_cores, u32 cpu_clock_percentage) {
|
||||
timers.resize(num_cores);
|
||||
for (std::size_t i = 0; i < num_cores; ++i) {
|
||||
timers[i] = std::make_shared<Timer>(100.0 / cpu_clock_percentage);
|
||||
timers[i] = std::make_shared<Timer>();
|
||||
}
|
||||
UpdateClockSpeed(cpu_clock_percentage);
|
||||
current_timer = timers[0];
|
||||
}
|
||||
|
||||
|
@ -37,14 +38,12 @@ void Timing::UpdateClockSpeed(u32 cpu_clock_percentage) {
|
|||
TimingEventType* Timing::RegisterEvent(const std::string& name, TimedCallback callback) {
|
||||
// check for existing type with same name.
|
||||
// we want event type names to remain unique so that we can use them for serialization.
|
||||
ASSERT_MSG(event_types.find(name) == event_types.end(),
|
||||
"CoreTiming Event \"{}\" is already registered. Events should only be registered "
|
||||
"during Init to avoid breaking save states.",
|
||||
name);
|
||||
|
||||
auto info = event_types.emplace(name, TimingEventType{callback, nullptr});
|
||||
auto info = event_types.emplace(name, TimingEventType{});
|
||||
TimingEventType* event_type = &info.first->second;
|
||||
event_type->name = &info.first->first;
|
||||
if (callback != nullptr) {
|
||||
event_type->callback = callback;
|
||||
}
|
||||
return event_type;
|
||||
}
|
||||
|
||||
|
@ -123,7 +122,7 @@ std::shared_ptr<Timing::Timer> Timing::GetTimer(std::size_t cpu_id) {
|
|||
return timers[cpu_id];
|
||||
}
|
||||
|
||||
Timing::Timer::Timer(double cpu_clock_scale_) : cpu_clock_scale(cpu_clock_scale_) {}
|
||||
Timing::Timer::Timer() = default;
|
||||
|
||||
Timing::Timer::~Timer() {
|
||||
MoveEvents();
|
||||
|
@ -184,7 +183,11 @@ void Timing::Timer::Advance(s64 max_slice_length) {
|
|||
Event evt = std::move(event_queue.front());
|
||||
std::pop_heap(event_queue.begin(), event_queue.end(), std::greater<>());
|
||||
event_queue.pop_back();
|
||||
evt.type->callback(evt.userdata, executed_ticks - evt.time);
|
||||
if (evt.type->callback != nullptr) {
|
||||
evt.type->callback(evt.userdata, executed_ticks - evt.time);
|
||||
} else {
|
||||
LOG_ERROR(Core, "Event '{}' has no callback", *evt.type->name);
|
||||
}
|
||||
}
|
||||
|
||||
is_timer_sane = false;
|
||||
|
|
|
@ -23,9 +23,12 @@
|
|||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/threadsafe_queue.h"
|
||||
#include "core/global.h"
|
||||
|
||||
// The timing we get from the assembly is 268,111,855.956 Hz
|
||||
// It is possible that this number isn't just an integer because the compiler could have
|
||||
|
@ -133,6 +136,7 @@ struct TimingEventType {
|
|||
};
|
||||
|
||||
class Timing {
|
||||
|
||||
public:
|
||||
struct Event {
|
||||
s64 time;
|
||||
|
@ -142,13 +146,36 @@ public:
|
|||
|
||||
bool operator>(const Event& right) const;
|
||||
bool operator<(const Event& right) const;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void save(Archive& ar, const unsigned int) const {
|
||||
ar& time;
|
||||
ar& fifo_order;
|
||||
ar& userdata;
|
||||
std::string name = *(type->name);
|
||||
ar << name;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void load(Archive& ar, const unsigned int) {
|
||||
ar& time;
|
||||
ar& fifo_order;
|
||||
ar& userdata;
|
||||
std::string name;
|
||||
ar >> name;
|
||||
type = Global<Timing>().RegisterEvent(name, nullptr);
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
|
||||
BOOST_SERIALIZATION_SPLIT_MEMBER()
|
||||
};
|
||||
|
||||
static constexpr int MAX_SLICE_LENGTH = 20000;
|
||||
|
||||
class Timer {
|
||||
public:
|
||||
Timer(double cpu_clock_scale);
|
||||
Timer();
|
||||
~Timer();
|
||||
|
||||
s64 GetMaxSliceLength() const;
|
||||
|
@ -195,6 +222,19 @@ public:
|
|||
// Stores a scaling for the internal clockspeed. Changing this number results in
|
||||
// under/overclocking the guest cpu
|
||||
double cpu_clock_scale = 1.0;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
MoveEvents();
|
||||
// NOTE: ts_queue should be empty now
|
||||
ar& event_queue;
|
||||
ar& event_fifo_id;
|
||||
ar& slice_length;
|
||||
ar& downcount;
|
||||
ar& executed_ticks;
|
||||
ar& idled_cycles;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
explicit Timing(std::size_t num_cores, u32 cpu_clock_percentage);
|
||||
|
@ -246,6 +286,15 @@ private:
|
|||
// Stores a scaling for the internal clockspeed. Changing this number results in
|
||||
// under/overclocking the guest cpu
|
||||
double cpu_clock_scale = 1.0;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
// event_types set during initialization of other things
|
||||
ar& global_timer;
|
||||
ar& timers;
|
||||
ar& current_timer;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace Core
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <string>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
|
@ -64,6 +66,32 @@ private:
|
|||
std::vector<u8> binary;
|
||||
std::string string;
|
||||
std::u16string u16str;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& type;
|
||||
switch (type) {
|
||||
case LowPathType::Binary:
|
||||
ar& binary;
|
||||
break;
|
||||
case LowPathType::Char:
|
||||
ar& string;
|
||||
break;
|
||||
case LowPathType::Wchar: {
|
||||
std::vector<char16_t> data;
|
||||
if (Archive::is_saving::value) {
|
||||
std::copy(u16str.begin(), u16str.end(), std::back_inserter(data));
|
||||
}
|
||||
ar& data;
|
||||
if (Archive::is_loading::value) {
|
||||
u16str = std::u16string(data.data(), data.size());
|
||||
}
|
||||
} break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// Parameters of the archive, as specified in the Create or Format call.
|
||||
|
@ -169,6 +197,13 @@ public:
|
|||
|
||||
protected:
|
||||
std::unique_ptr<DelayGenerator> delay_generator;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& delay_generator;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class ArchiveFactory : NonCopyable {
|
||||
|
@ -205,6 +240,10 @@ public:
|
|||
* @return Format information about the archive or error code
|
||||
*/
|
||||
virtual ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const = 0;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -19,6 +20,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_ExtSaveData)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
/**
|
||||
|
@ -77,6 +80,8 @@ public:
|
|||
static constexpr u64 IPCDelayNanoseconds(3085068);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -162,6 +167,14 @@ public:
|
|||
}
|
||||
return SaveDataArchive::CreateFile(path, size);
|
||||
}
|
||||
|
||||
private:
|
||||
ExtSaveDataArchive() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<SaveDataArchive>(*this);
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
struct ExtSaveDataArchivePath {
|
||||
|
@ -297,3 +310,6 @@ void ArchiveFactory_ExtSaveData::WriteIcon(const Path& path, const u8* icon_data
|
|||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ExtSaveDataDelayGenerator)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ExtSaveDataArchive)
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -54,6 +56,15 @@ private:
|
|||
|
||||
/// Returns a path with the correct SaveIdHigh value for Shared extdata paths.
|
||||
Path GetCorrectedPath(const Path& path);
|
||||
|
||||
ArchiveFactory_ExtSaveData() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& shared;
|
||||
ar& mount_point;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -93,4 +104,9 @@ std::string GetExtDataContainerPath(const std::string& mount_point, bool shared)
|
|||
*/
|
||||
Path ConstructExtDataBinaryPath(u32 media_type, u32 high, u32 low);
|
||||
|
||||
class ExtSaveDataDelayGenerator;
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_ExtSaveData)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ExtSaveDataDelayGenerator)
|
||||
|
|
|
@ -8,6 +8,7 @@
|
|||
#include <utility>
|
||||
#include <vector>
|
||||
#include "bad_word_list.app.romfs.h"
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -28,6 +29,10 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::NCCHArchive)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::NCCHFile)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_NCCH)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
struct NCCHArchivePath {
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include <array>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/file_sys/file_backend.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -63,6 +66,17 @@ public:
|
|||
protected:
|
||||
u64 title_id;
|
||||
Service::FS::MediaType media_type;
|
||||
|
||||
private:
|
||||
NCCHArchive() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveBackend>(*this);
|
||||
ar& title_id;
|
||||
ar& media_type;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
// File backend for NCCH files
|
||||
|
@ -82,6 +96,15 @@ public:
|
|||
|
||||
private:
|
||||
std::vector<u8> file_buffer;
|
||||
|
||||
NCCHFile() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<FileBackend>(*this);
|
||||
ar& file_buffer;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// File system interface to the NCCH archive
|
||||
|
@ -97,6 +120,17 @@ public:
|
|||
ResultCode Format(const Path& path, const FileSys::ArchiveFormatInfo& format_info,
|
||||
u64 program_id) override;
|
||||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::NCCHArchive)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::NCCHFile)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_NCCH)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <tuple>
|
||||
#include <utility>
|
||||
#include "common/archives.h"
|
||||
#include "core/file_sys/archive_other_savedata.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
|
@ -12,6 +13,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_OtherSaveDataPermitted)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_OtherSaveDataGeneral)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
// TODO(wwylele): The storage info in exheader should be checked before accessing these archives
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -27,8 +30,15 @@ public:
|
|||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||
|
||||
private:
|
||||
std::string mount_point;
|
||||
std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
|
||||
|
||||
ArchiveFactory_OtherSaveDataPermitted() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& sd_savedata_source;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// File system interface to the OtherSaveDataGeneral archive
|
||||
|
@ -47,8 +57,18 @@ public:
|
|||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||
|
||||
private:
|
||||
std::string mount_point;
|
||||
std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
|
||||
|
||||
ArchiveFactory_OtherSaveDataGeneral() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& sd_savedata_source;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_OtherSaveDataPermitted)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_OtherSaveDataGeneral)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <utility>
|
||||
#include "common/archives.h"
|
||||
#include "core/core.h"
|
||||
#include "core/file_sys/archive_savedata.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
|
@ -10,6 +11,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SaveData)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
ArchiveFactory_SaveData::ArchiveFactory_SaveData(
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
@ -27,8 +29,17 @@ public:
|
|||
ResultVal<ArchiveFormatInfo> GetFormatInfo(const Path& path, u64 program_id) const override;
|
||||
|
||||
private:
|
||||
std::string mount_point;
|
||||
std::shared_ptr<ArchiveSource_SDSaveData> sd_savedata_source;
|
||||
|
||||
ArchiveFactory_SaveData() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& sd_savedata_source;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SaveData)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include "common/archives.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/archive_sdmc.h"
|
||||
|
@ -15,6 +16,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SDMCArchive)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SDMC)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class SDMCDelayGenerator : public DelayGenerator {
|
||||
|
@ -37,6 +41,8 @@ public:
|
|||
static constexpr u64 IPCDelayNanoseconds(269082);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> SDMCArchive::OpenFile(const Path& path,
|
||||
|
@ -405,3 +411,5 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMC::GetFormatInfo(const Path& path
|
|||
return ResultCode(-1);
|
||||
}
|
||||
} // namespace FileSys
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SDMCDelayGenerator)
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
|
@ -42,6 +45,14 @@ public:
|
|||
protected:
|
||||
ResultVal<std::unique_ptr<FileBackend>> OpenFileBase(const Path& path, const Mode& mode) const;
|
||||
std::string mount_point;
|
||||
|
||||
SDMCArchive() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveBackend>(*this);
|
||||
ar& mount_point;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// File system interface to the SDMC archive
|
||||
|
@ -66,6 +77,20 @@ public:
|
|||
|
||||
private:
|
||||
std::string sdmc_directory;
|
||||
|
||||
ArchiveFactory_SDMC() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& sdmc_directory;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class SDMCDelayGenerator;
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SDMCArchive)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SDMC)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SDMCDelayGenerator)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
#include "common/archives.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/archive_sdmcwriteonly.h"
|
||||
#include "core/file_sys/directory_backend.h"
|
||||
|
@ -13,6 +14,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SDMCWriteOnlyArchive)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SDMCWriteOnly)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class SDMCWriteOnlyDelayGenerator : public DelayGenerator {
|
||||
|
@ -35,6 +39,8 @@ public:
|
|||
static constexpr u64 IPCDelayNanoseconds(269082);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> SDMCWriteOnlyArchive::OpenFile(const Path& path,
|
||||
|
@ -96,3 +102,5 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SDMCWriteOnly::GetFormatInfo(const P
|
|||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SDMCWriteOnlyDelayGenerator)
|
||||
|
|
|
@ -31,6 +31,14 @@ public:
|
|||
const Mode& mode) const override;
|
||||
|
||||
ResultVal<std::unique_ptr<DirectoryBackend>> OpenDirectory(const Path& path) const override;
|
||||
|
||||
private:
|
||||
SDMCWriteOnlyArchive() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<SDMCArchive>(*this);
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// File system interface to the SDMC write-only archive
|
||||
|
@ -55,6 +63,20 @@ public:
|
|||
|
||||
private:
|
||||
std::string sdmc_directory;
|
||||
|
||||
ArchiveFactory_SDMCWriteOnly() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& sdmc_directory;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class SDMCWriteOnlyDelayGenerator;
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SDMCWriteOnlyArchive)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SDMCWriteOnly)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SDMCWriteOnlyDelayGenerator)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <array>
|
||||
#include <cinttypes>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/swap.h"
|
||||
|
@ -16,6 +17,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SelfNCCH)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
enum class SelfNCCHFilePathType : u32 {
|
||||
|
@ -74,6 +77,15 @@ public:
|
|||
|
||||
private:
|
||||
std::shared_ptr<std::vector<u8>> data;
|
||||
|
||||
ExeFSSectionFile() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<FileBackend>(*this);
|
||||
ar& data;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
// SelfNCCHArchive represents the running application itself. From this archive the application can
|
||||
|
@ -231,6 +243,15 @@ private:
|
|||
}
|
||||
|
||||
NCCHData ncch_data;
|
||||
|
||||
SelfNCCHArchive() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveBackend>(*this);
|
||||
ar& ncch_data;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
void ArchiveFactory_SelfNCCH::Register(Loader::AppLoader& app_loader) {
|
||||
|
@ -297,3 +318,6 @@ ResultVal<ArchiveFormatInfo> ArchiveFactory_SelfNCCH::GetFormatInfo(const Path&,
|
|||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ExeFSSectionFile)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SelfNCCHArchive)
|
||||
|
|
|
@ -8,6 +8,10 @@
|
|||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -24,6 +28,17 @@ struct NCCHData {
|
|||
std::shared_ptr<std::vector<u8>> banner;
|
||||
std::shared_ptr<RomFSReader> romfs_file;
|
||||
std::shared_ptr<RomFSReader> update_romfs_file;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& icon;
|
||||
ar& logo;
|
||||
ar& banner;
|
||||
ar& romfs_file;
|
||||
ar& update_romfs_file;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// File system interface to the SelfNCCH archive
|
||||
|
@ -45,6 +60,20 @@ public:
|
|||
private:
|
||||
/// Mapping of ProgramId -> NCCHData
|
||||
std::unordered_map<u64, NCCHData> ncch_data;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& ncch_data;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class ExeFSSectionFile;
|
||||
class SelfNCCHArchive;
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SelfNCCH)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ExeFSSectionFile)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SelfNCCHArchive)
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <fmt/format.h>
|
||||
#include "common/archives.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/archive_source_sd_savedata.h"
|
||||
|
@ -13,6 +14,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveSource_SDSaveData)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
namespace {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
|
@ -27,6 +29,15 @@ public:
|
|||
|
||||
private:
|
||||
std::string mount_point;
|
||||
|
||||
ArchiveSource_SDSaveData() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& mount_point;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveSource_SDSaveData)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <memory>
|
||||
#include <vector>
|
||||
#include <fmt/format.h>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/archive_systemsavedata.h"
|
||||
|
@ -17,6 +18,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ArchiveFactory_SystemSaveData)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
std::string GetSystemSaveDataPath(const std::string& mount_point, const Path& path) {
|
||||
|
|
|
@ -6,6 +6,8 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -31,6 +33,14 @@ public:
|
|||
|
||||
private:
|
||||
std::string base_path;
|
||||
|
||||
ArchiveFactory_SystemSaveData() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveFactory>(*this);
|
||||
ar& base_path;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -60,3 +70,5 @@ std::string GetSystemSaveDataContainerPath(const std::string& mount_point);
|
|||
Path ConstructSystemSaveDataBinaryPath(u32 high, u32 low);
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ArchiveFactory_SystemSaveData)
|
||||
|
|
|
@ -3,8 +3,11 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/archives.h"
|
||||
#include "core/file_sys/delay_generator.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::DefaultDelayGenerator)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
DelayGenerator::~DelayGenerator() = default;
|
||||
|
|
|
@ -5,8 +5,18 @@
|
|||
#pragma once
|
||||
|
||||
#include <cstddef>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/common_types.h"
|
||||
|
||||
#define SERIALIZE_DELAY_GENERATOR \
|
||||
private: \
|
||||
template <class Archive> \
|
||||
void serialize(Archive& ar, const unsigned int) { \
|
||||
ar& boost::serialization::base_object<DelayGenerator>(*this); \
|
||||
} \
|
||||
friend class boost::serialization::access;
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
class DelayGenerator {
|
||||
|
@ -16,12 +26,20 @@ public:
|
|||
virtual u64 GetOpenDelayNs() = 0;
|
||||
|
||||
// TODO (B3N30): Add getter for all other file/directory io operations
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class DefaultDelayGenerator : public DelayGenerator {
|
||||
public:
|
||||
u64 GetReadDelayNs(std::size_t length) override;
|
||||
u64 GetOpenDelayNs() override;
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::DefaultDelayGenerator);
|
||||
|
|
|
@ -53,6 +53,11 @@ public:
|
|||
* @return true if the directory closed correctly
|
||||
*/
|
||||
virtual bool Close() const = 0;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstdio>
|
||||
#include <memory>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -14,6 +15,9 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::DiskFile)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::DiskDirectory)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
ResultVal<std::size_t> DiskFile::Read(const u64 offset, const std::size_t length,
|
||||
|
|
|
@ -8,6 +8,9 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/unique_ptr.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
|
@ -43,6 +46,17 @@ public:
|
|||
protected:
|
||||
Mode mode;
|
||||
std::unique_ptr<FileUtil::IOFile> file;
|
||||
|
||||
private:
|
||||
DiskFile() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<FileBackend>(*this);
|
||||
ar& mode.hex;
|
||||
ar& file;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class DiskDirectory : public DirectoryBackend {
|
||||
|
@ -65,6 +79,27 @@ protected:
|
|||
// We need to remember the last entry we returned, so a subsequent call to Read will continue
|
||||
// from the next one. This iterator will always point to the next unread entry.
|
||||
std::vector<FileUtil::FSTEntry>::iterator children_iterator;
|
||||
|
||||
private:
|
||||
DiskDirectory() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<DirectoryBackend>(*this);
|
||||
ar& directory;
|
||||
u64 child_index;
|
||||
if (Archive::is_saving::value) {
|
||||
child_index = children_iterator - directory.children.begin();
|
||||
}
|
||||
ar& child_index;
|
||||
if (Archive::is_loading::value) {
|
||||
children_iterator = directory.children.begin() + child_index;
|
||||
}
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::DiskFile)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::DiskDirectory)
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <boost/serialization/unique_ptr.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "delay_generator.h"
|
||||
|
@ -90,6 +91,12 @@ public:
|
|||
|
||||
protected:
|
||||
std::unique_ptr<DelayGenerator> delay_generator;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& delay_generator;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <utility>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/file_sys/ivfc_archive.h"
|
||||
|
@ -12,6 +13,12 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// FileSys namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::IVFCFile)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::IVFCFileInMemory)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::IVFCDelayGenerator)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::RomFSDelayGenerator)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::ExeFSDelayGenerator)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
IVFCArchive::IVFCArchive(std::shared_ptr<RomFSReader> file,
|
||||
|
|
|
@ -8,6 +8,8 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/archive_backend.h"
|
||||
|
@ -38,6 +40,8 @@ class IVFCDelayGenerator : public DelayGenerator {
|
|||
static constexpr u64 IPCDelayNanoseconds(9438006);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
class RomFSDelayGenerator : public DelayGenerator {
|
||||
|
@ -60,6 +64,8 @@ public:
|
|||
static constexpr u64 IPCDelayNanoseconds(9438006);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
class ExeFSDelayGenerator : public DelayGenerator {
|
||||
|
@ -82,6 +88,8 @@ public:
|
|||
static constexpr u64 IPCDelayNanoseconds(9438006);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -128,6 +136,15 @@ public:
|
|||
|
||||
private:
|
||||
std::shared_ptr<RomFSReader> romfs_file;
|
||||
|
||||
IVFCFile() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<FileBackend>(*this);
|
||||
ar& romfs_file;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class IVFCDirectory : public DirectoryBackend {
|
||||
|
@ -159,6 +176,23 @@ private:
|
|||
std::vector<u8> romfs_file;
|
||||
u64 data_offset;
|
||||
u64 data_size;
|
||||
|
||||
IVFCFileInMemory() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<FileBackend>(*this);
|
||||
ar& romfs_file;
|
||||
ar& data_offset;
|
||||
ar& data_size;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFile)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::IVFCFileInMemory)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::IVFCDelayGenerator)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::RomFSDelayGenerator)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ExeFSDelayGenerator)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "common/alignment.h"
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_paths.h"
|
||||
#include "common/file_util.h"
|
||||
|
@ -13,6 +14,8 @@
|
|||
#include "core/file_sys/layered_fs.h"
|
||||
#include "core/file_sys/patch.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::LayeredFS)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
struct FileRelocationInfo {
|
||||
|
@ -51,11 +54,16 @@ struct FileMetadata {
|
|||
};
|
||||
static_assert(sizeof(FileMetadata) == 0x20, "Size of FileMetadata is not correct");
|
||||
|
||||
LayeredFS::LayeredFS(std::shared_ptr<RomFSReader> romfs_, std::string patch_path_,
|
||||
std::string patch_ext_path_, bool load_relocations)
|
||||
: romfs(std::move(romfs_)), patch_path(std::move(patch_path_)),
|
||||
patch_ext_path(std::move(patch_ext_path_)) {
|
||||
LayeredFS::LayeredFS() = default;
|
||||
|
||||
LayeredFS::LayeredFS(std::shared_ptr<RomFSReader> romfs_, std::string patch_path_,
|
||||
std::string patch_ext_path_, bool load_relocations_)
|
||||
: romfs(std::move(romfs_)), patch_path(std::move(patch_path_)),
|
||||
patch_ext_path(std::move(patch_ext_path_)), load_relocations(load_relocations_) {
|
||||
Load();
|
||||
}
|
||||
|
||||
void LayeredFS::Load() {
|
||||
romfs->ReadFile(0, sizeof(header), reinterpret_cast<u8*>(&header));
|
||||
|
||||
ASSERT_MSG(header.header_length == sizeof(header), "Header size is incorrect");
|
||||
|
@ -273,7 +281,7 @@ std::size_t GetNameSize(const std::string& name) {
|
|||
}
|
||||
|
||||
void LayeredFS::PrepareBuildDirectory(Directory& current) {
|
||||
directory_metadata_offset_map.emplace(¤t, current_directory_offset);
|
||||
directory_metadata_offset_map.emplace(¤t, static_cast<u32>(current_directory_offset));
|
||||
directory_list.emplace_back(¤t);
|
||||
current_directory_offset += sizeof(DirectoryMetadata) + GetNameSize(current.name);
|
||||
}
|
||||
|
@ -282,7 +290,7 @@ void LayeredFS::PrepareBuildFile(File& current) {
|
|||
if (current.relocation.type == 3) { // Deleted files are not counted
|
||||
return;
|
||||
}
|
||||
file_metadata_offset_map.emplace(¤t, current_file_offset);
|
||||
file_metadata_offset_map.emplace(¤t, static_cast<u32>(current_file_offset));
|
||||
file_list.emplace_back(¤t);
|
||||
current_file_offset += sizeof(FileMetadata) + GetNameSize(current.name);
|
||||
}
|
||||
|
@ -361,7 +369,7 @@ void LayeredFS::BuildDirectories() {
|
|||
|
||||
// Write metadata and name
|
||||
std::u16string u16name = Common::UTF8ToUTF16(directory->name);
|
||||
metadata.name_length = u16name.size() * 2;
|
||||
metadata.name_length = static_cast<u32_le>(u16name.size() * 2);
|
||||
|
||||
std::memcpy(directory_metadata_table.data() + written, &metadata, sizeof(metadata));
|
||||
written += sizeof(metadata);
|
||||
|
@ -410,7 +418,7 @@ void LayeredFS::BuildFiles() {
|
|||
|
||||
// Write metadata and name
|
||||
std::u16string u16name = Common::UTF8ToUTF16(file->name);
|
||||
metadata.name_length = u16name.size() * 2;
|
||||
metadata.name_length = static_cast<u32_le>(u16name.size() * 2);
|
||||
|
||||
std::memcpy(file_metadata_table.data() + written, &metadata, sizeof(metadata));
|
||||
written += sizeof(metadata);
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/file_sys/romfs_reader.h"
|
||||
|
@ -92,9 +96,12 @@ private:
|
|||
|
||||
void RebuildMetadata();
|
||||
|
||||
void Load();
|
||||
|
||||
std::shared_ptr<RomFSReader> romfs;
|
||||
std::string patch_path;
|
||||
std::string patch_ext_path;
|
||||
bool load_relocations;
|
||||
|
||||
RomFSHeader header;
|
||||
Directory root;
|
||||
|
@ -118,6 +125,24 @@ private:
|
|||
u64 current_file_offset{}; // current file metadata offset
|
||||
std::vector<u8> file_metadata_table; // rebuilt file metadata table
|
||||
u64 current_data_offset{}; // current assigned data offset
|
||||
|
||||
LayeredFS();
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<RomFSReader>(*this);
|
||||
ar& romfs;
|
||||
ar& patch_path;
|
||||
ar& patch_ext_path;
|
||||
ar& load_relocations;
|
||||
if (Archive::is_loading::value) {
|
||||
Load();
|
||||
}
|
||||
// NOTE: Everything else is essentially cached, updated when we call Load
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::LayeredFS)
|
||||
|
|
|
@ -1,15 +1,18 @@
|
|||
#include <algorithm>
|
||||
#include <cryptopp/aes.h>
|
||||
#include <cryptopp/modes.h>
|
||||
#include "common/archives.h"
|
||||
#include "core/file_sys/romfs_reader.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::DirectRomFSReader)
|
||||
|
||||
namespace FileSys {
|
||||
|
||||
std::size_t DirectRomFSReader::ReadFile(std::size_t offset, std::size_t length, u8* buffer) {
|
||||
if (length == 0)
|
||||
return 0; // Crypto++ does not like zero size buffer
|
||||
file.Seek(file_offset + offset, SEEK_SET);
|
||||
std::size_t read_length = std::min(length, data_size - offset);
|
||||
std::size_t read_length = std::min(length, static_cast<std::size_t>(data_size) - offset);
|
||||
read_length = file.ReadBytes(buffer, read_length);
|
||||
if (is_encrypted) {
|
||||
CryptoPP::CTR_Mode<CryptoPP::AES>::Decryption d(key.data(), key.size(), ctr.data());
|
||||
|
|
|
@ -1,6 +1,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/file_util.h"
|
||||
|
||||
|
@ -15,6 +18,11 @@ public:
|
|||
|
||||
virtual std::size_t GetSize() const = 0;
|
||||
virtual std::size_t ReadFile(std::size_t offset, std::size_t length, u8* buffer) = 0;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -45,9 +53,26 @@ private:
|
|||
FileUtil::IOFile file;
|
||||
std::array<u8, 16> key;
|
||||
std::array<u8, 16> ctr;
|
||||
std::size_t file_offset;
|
||||
std::size_t crypto_offset;
|
||||
std::size_t data_size;
|
||||
u64 file_offset;
|
||||
u64 crypto_offset;
|
||||
u64 data_size;
|
||||
|
||||
DirectRomFSReader() = default;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<RomFSReader>(*this);
|
||||
ar& is_encrypted;
|
||||
ar& file;
|
||||
ar& key;
|
||||
ar& ctr;
|
||||
ar& file_offset;
|
||||
ar& crypto_offset;
|
||||
ar& data_size;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::DirectRomFSReader)
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/archives.h"
|
||||
#include "common/file_util.h"
|
||||
#include "core/file_sys/disk_archive.h"
|
||||
#include "core/file_sys/errors.h"
|
||||
|
@ -33,6 +34,8 @@ public:
|
|||
static constexpr u64 IPCDelayNanoseconds(269082);
|
||||
return IPCDelayNanoseconds;
|
||||
}
|
||||
|
||||
SERIALIZE_DELAY_GENERATOR
|
||||
};
|
||||
|
||||
ResultVal<std::unique_ptr<FileBackend>> SaveDataArchive::OpenFile(const Path& path,
|
||||
|
@ -353,3 +356,6 @@ u64 SaveDataArchive::GetFreeBytes() const {
|
|||
}
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SaveDataArchive)
|
||||
SERIALIZE_EXPORT_IMPL(FileSys::SaveDataDelayGenerator)
|
||||
|
|
|
@ -38,6 +38,22 @@ public:
|
|||
|
||||
protected:
|
||||
std::string mount_point;
|
||||
SaveDataArchive() = default;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<ArchiveBackend>(*this);
|
||||
ar& mount_point;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class SaveDataDelayGenerator;
|
||||
class ExtSaveDataArchive;
|
||||
|
||||
} // namespace FileSys
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataArchive)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::SaveDataDelayGenerator)
|
||||
BOOST_CLASS_EXPORT_KEY(FileSys::ExtSaveDataArchive)
|
||||
|
|
21
src/core/global.h
Normal file
21
src/core/global.h
Normal file
|
@ -0,0 +1,21 @@
|
|||
// Copyright 2020 Citra Emulator Project
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
namespace Core {
|
||||
|
||||
template <class T>
|
||||
T& Global();
|
||||
|
||||
// Declare explicit specialisation to prevent automatic instantiation
|
||||
class System;
|
||||
template <>
|
||||
System& Global();
|
||||
|
||||
class Timing;
|
||||
template <>
|
||||
Timing& Global();
|
||||
|
||||
} // namespace Core
|
|
@ -3,8 +3,10 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/global.h"
|
||||
#include "core/hle/kernel/address_arbiter.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
@ -14,6 +16,8 @@
|
|||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
// Kernel namespace
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::AddressArbiter)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void AddressArbiter::WaitThread(std::shared_ptr<Thread> thread, VAddr wait_address) {
|
||||
|
@ -76,16 +80,18 @@ std::shared_ptr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string n
|
|||
return address_arbiter;
|
||||
}
|
||||
|
||||
void AddressArbiter::WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(reason == ThreadWakeupReason::Timeout);
|
||||
// Remove the newly-awakened thread from the Arbiter's waiting list.
|
||||
waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread),
|
||||
waiting_threads.end());
|
||||
};
|
||||
|
||||
ResultCode AddressArbiter::ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type,
|
||||
VAddr address, s32 value, u64 nanoseconds) {
|
||||
|
||||
auto timeout_callback = [this](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(reason == ThreadWakeupReason::Timeout);
|
||||
// Remove the newly-awakened thread from the Arbiter's waiting list.
|
||||
waiting_threads.erase(std::remove(waiting_threads.begin(), waiting_threads.end(), thread),
|
||||
waiting_threads.end());
|
||||
};
|
||||
auto timeout_callback = std::dynamic_pointer_cast<WakeupCallback>(shared_from_this());
|
||||
|
||||
switch (type) {
|
||||
|
||||
|
|
|
@ -6,8 +6,15 @@
|
|||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include <boost/serialization/version.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
// Address arbiters are an underlying kernel synchronization object that can be created/used via
|
||||
|
@ -30,7 +37,7 @@ enum class ArbitrationType : u32 {
|
|||
DecrementAndWaitIfLessThanWithTimeout,
|
||||
};
|
||||
|
||||
class AddressArbiter final : public Object {
|
||||
class AddressArbiter final : public Object, public WakeupCallback {
|
||||
public:
|
||||
explicit AddressArbiter(KernelSystem& kernel);
|
||||
~AddressArbiter() override;
|
||||
|
@ -52,6 +59,9 @@ public:
|
|||
ResultCode ArbitrateAddress(std::shared_ptr<Thread> thread, ArbitrationType type, VAddr address,
|
||||
s32 value, u64 nanoseconds);
|
||||
|
||||
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object);
|
||||
|
||||
private:
|
||||
KernelSystem& kernel;
|
||||
|
||||
|
@ -67,6 +77,21 @@ private:
|
|||
|
||||
/// Threads waiting for the address arbiter to be signaled.
|
||||
std::vector<std::shared_ptr<Thread>> waiting_threads;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
if (file_version > 0) {
|
||||
ar& boost::serialization::base_object<WakeupCallback>(*this);
|
||||
}
|
||||
ar& name;
|
||||
ar& waiting_threads;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::AddressArbiter)
|
||||
BOOST_CLASS_VERSION(Kernel::AddressArbiter, 1)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::AddressArbiter)
|
||||
|
|
|
@ -2,7 +2,9 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/global.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
|
@ -11,6 +13,8 @@
|
|||
#include "core/hle/kernel/server_port.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::ClientPort)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ClientPort::ClientPort(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
|
||||
|
|
|
@ -6,6 +6,9 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_port.h"
|
||||
|
@ -59,6 +62,20 @@ private:
|
|||
std::string name; ///< Name of client port (optional)
|
||||
|
||||
friend class KernelSystem;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
ar& server_port;
|
||||
ar& max_sessions;
|
||||
ar& active_sessions;
|
||||
ar& name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::ClientPort)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::ClientPort)
|
||||
|
|
|
@ -2,8 +2,8 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
|
@ -11,6 +11,8 @@
|
|||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::ClientSession)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ClientSession::ClientSession(KernelSystem& kernel) : Object(kernel) {}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -46,6 +50,18 @@ public:
|
|||
|
||||
/// The parent session, which links to the server endpoint.
|
||||
std::shared_ptr<Session> parent;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
ar& name;
|
||||
ar& parent;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::ClientSession)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::ClientSession)
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "common/archives.h"
|
||||
#include "core/hle/kernel/config_mem.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(ConfigMem::Handler)
|
||||
|
||||
namespace ConfigMem {
|
||||
|
||||
Handler::Handler() {
|
||||
|
|
|
@ -9,8 +9,11 @@
|
|||
// bootrom. Because we're not emulating this, and essentially just "stubbing" the functionality, I'm
|
||||
// putting this as a subset of HLE for now.
|
||||
|
||||
#include <boost/serialization/binary_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/memory_ref.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
|
@ -49,13 +52,34 @@ struct ConfigMemDef {
|
|||
static_assert(sizeof(ConfigMemDef) == Memory::CONFIG_MEMORY_SIZE,
|
||||
"Config Memory structure size is wrong");
|
||||
|
||||
class Handler {
|
||||
class Handler : public BackingMem {
|
||||
public:
|
||||
Handler();
|
||||
ConfigMemDef& GetConfigMem();
|
||||
|
||||
u8* GetPtr() override {
|
||||
return reinterpret_cast<u8*>(&config_mem);
|
||||
}
|
||||
|
||||
const u8* GetPtr() const override {
|
||||
return reinterpret_cast<const u8*>(&config_mem);
|
||||
}
|
||||
|
||||
std::size_t GetSize() const override {
|
||||
return sizeof(config_mem);
|
||||
}
|
||||
|
||||
private:
|
||||
ConfigMemDef config_mem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<BackingMem>(*this);
|
||||
ar& boost::serialization::make_binary_object(&config_mem, sizeof(config_mem));
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace ConfigMem
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(ConfigMem::Handler)
|
||||
|
|
|
@ -5,11 +5,14 @@
|
|||
#include <algorithm>
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/event.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::Event)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Event::Event(KernelSystem& kernel) : WaitObject(kernel) {}
|
||||
|
|
|
@ -4,6 +4,9 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
|
@ -49,6 +52,18 @@ private:
|
|||
std::string name; ///< Name of event (optional)
|
||||
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar& reset_type;
|
||||
ar& signaled;
|
||||
ar& name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::Event)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::Event)
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <memory>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -116,6 +118,15 @@ private:
|
|||
u16 next_free_slot;
|
||||
|
||||
KernelSystem& kernel;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& objects;
|
||||
ar& generations;
|
||||
ar& next_generation;
|
||||
ar& next_free_slot;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -16,6 +16,47 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
class HLERequestContext::ThreadCallback : public Kernel::WakeupCallback {
|
||||
|
||||
public:
|
||||
ThreadCallback(std::shared_ptr<HLERequestContext> context_,
|
||||
std::shared_ptr<HLERequestContext::WakeupCallback> callback_)
|
||||
: context(std::move(context_)), callback(std::move(callback_)) {}
|
||||
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(thread->status == ThreadStatus::WaitHleEvent);
|
||||
if (callback) {
|
||||
callback->WakeUp(thread, *context, reason);
|
||||
}
|
||||
|
||||
auto& process = thread->owner_process;
|
||||
// We must copy the entire command buffer *plus* the entire static buffers area, since
|
||||
// the translation might need to read from it in order to retrieve the StaticBuffer
|
||||
// target addresses.
|
||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
||||
Memory::MemorySystem& memory = context->kernel.memory;
|
||||
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||
cmd_buff.size() * sizeof(u32));
|
||||
context->WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
||||
// Copy the translated command buffer back into the thread's command buffer area.
|
||||
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||
cmd_buff.size() * sizeof(u32));
|
||||
}
|
||||
|
||||
private:
|
||||
ThreadCallback() = default;
|
||||
std::shared_ptr<HLERequestContext::WakeupCallback> callback{};
|
||||
std::shared_ptr<HLERequestContext> context{};
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
|
||||
ar& callback;
|
||||
ar& context;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
SessionRequestHandler::SessionInfo::SessionInfo(std::shared_ptr<ServerSession> session,
|
||||
std::unique_ptr<SessionDataBase> data)
|
||||
: session(std::move(session)), data(std::move(data)) {}
|
||||
|
@ -33,34 +74,16 @@ void SessionRequestHandler::ClientDisconnected(std::shared_ptr<ServerSession> se
|
|||
connected_sessions.end());
|
||||
}
|
||||
|
||||
std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& reason,
|
||||
std::chrono::nanoseconds timeout,
|
||||
WakeupCallback&& callback) {
|
||||
std::shared_ptr<Event> HLERequestContext::SleepClientThread(
|
||||
const std::string& reason, std::chrono::nanoseconds timeout,
|
||||
std::shared_ptr<WakeupCallback> callback) {
|
||||
// Put the client thread to sleep until the wait event is signaled or the timeout expires.
|
||||
thread->wakeup_callback = [context = *this,
|
||||
callback](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) mutable {
|
||||
ASSERT(thread->status == ThreadStatus::WaitHleEvent);
|
||||
callback(thread, context, reason);
|
||||
|
||||
auto& process = thread->owner_process;
|
||||
// We must copy the entire command buffer *plus* the entire static buffers area, since
|
||||
// the translation might need to read from it in order to retrieve the StaticBuffer
|
||||
// target addresses.
|
||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
||||
Memory::MemorySystem& memory = context.kernel.memory;
|
||||
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||
cmd_buff.size() * sizeof(u32));
|
||||
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
||||
// Copy the translated command buffer back into the thread's command buffer area.
|
||||
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||
cmd_buff.size() * sizeof(u32));
|
||||
};
|
||||
thread->wakeup_callback = std::make_shared<ThreadCallback>(shared_from_this(), callback);
|
||||
|
||||
auto event = kernel.CreateEvent(Kernel::ResetType::OneShot, "HLE Pause Event: " + reason);
|
||||
thread->status = ThreadStatus::WaitHleEvent;
|
||||
thread->wait_objects = {event};
|
||||
event->AddWaitingThread(SharedFrom(thread));
|
||||
event->AddWaitingThread(thread);
|
||||
|
||||
if (timeout.count() > 0)
|
||||
thread->WakeAfterDelay(timeout.count());
|
||||
|
@ -68,8 +91,10 @@ std::shared_ptr<Event> HLERequestContext::SleepClientThread(const std::string& r
|
|||
return event;
|
||||
}
|
||||
|
||||
HLERequestContext::HLERequestContext() : kernel(Core::Global<KernelSystem>()) {}
|
||||
|
||||
HLERequestContext::HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
|
||||
Thread* thread)
|
||||
std::shared_ptr<Thread> thread)
|
||||
: kernel(kernel), session(std::move(session)), thread(thread) {
|
||||
cmd_buf[0] = 0;
|
||||
}
|
||||
|
@ -98,8 +123,9 @@ void HLERequestContext::AddStaticBuffer(u8 buffer_id, std::vector<u8> data) {
|
|||
static_buffers[buffer_id] = std::move(data);
|
||||
}
|
||||
|
||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
|
||||
Process& src_process) {
|
||||
ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(
|
||||
const u32_le* src_cmdbuf, std::shared_ptr<Process> src_process_) {
|
||||
auto& src_process = *src_process_;
|
||||
IPC::Header header{src_cmdbuf[0]};
|
||||
|
||||
std::size_t untranslated_size = 1u + header.normal_params_size;
|
||||
|
@ -158,7 +184,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
|||
}
|
||||
case IPC::DescriptorType::MappedBuffer: {
|
||||
u32 next_id = static_cast<u32>(request_mapped_buffers.size());
|
||||
request_mapped_buffers.emplace_back(kernel.memory, src_process, descriptor,
|
||||
request_mapped_buffers.emplace_back(kernel.memory, src_process_, descriptor,
|
||||
src_cmdbuf[i], next_id);
|
||||
cmd_buf[i++] = next_id;
|
||||
break;
|
||||
|
@ -170,7 +196,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
|||
|
||||
if (should_record) {
|
||||
std::vector<u32> translated_cmdbuf{cmd_buf.begin(), cmd_buf.begin() + command_size};
|
||||
kernel.GetIPCRecorder().SetRequestInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
|
||||
kernel.GetIPCRecorder().SetRequestInfo(thread, std::move(untranslated_cmdbuf),
|
||||
std::move(translated_cmdbuf));
|
||||
}
|
||||
|
||||
|
@ -248,7 +274,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
|
|||
|
||||
if (should_record) {
|
||||
std::vector<u32> translated_cmdbuf{dst_cmdbuf, dst_cmdbuf + command_size};
|
||||
kernel.GetIPCRecorder().SetReplyInfo(SharedFrom(thread), std::move(untranslated_cmdbuf),
|
||||
kernel.GetIPCRecorder().SetReplyInfo(thread, std::move(untranslated_cmdbuf),
|
||||
std::move(translated_cmdbuf));
|
||||
}
|
||||
|
||||
|
@ -262,13 +288,15 @@ MappedBuffer& HLERequestContext::GetMappedBuffer(u32 id_from_cmdbuf) {
|
|||
|
||||
void HLERequestContext::ReportUnimplemented() const {
|
||||
if (kernel.GetIPCRecorder().IsEnabled()) {
|
||||
kernel.GetIPCRecorder().SetHLEUnimplemented(SharedFrom(thread));
|
||||
kernel.GetIPCRecorder().SetHLEUnimplemented(thread);
|
||||
}
|
||||
}
|
||||
|
||||
MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
|
||||
VAddr address, u32 id)
|
||||
: memory(&memory), id(id), address(address), process(&process) {
|
||||
MappedBuffer::MappedBuffer() : memory(&Core::Global<Core::System>().Memory()) {}
|
||||
|
||||
MappedBuffer::MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process,
|
||||
u32 descriptor, VAddr address, u32 id)
|
||||
: memory(&memory), id(id), address(address), process(std::move(process)) {
|
||||
IPC::MappedBufferDescInfo desc{descriptor};
|
||||
size = desc.size;
|
||||
perms = desc.perms;
|
||||
|
@ -287,3 +315,5 @@ void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t
|
|||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::HLERequestContext::ThreadCallback)
|
||||
|
|
|
@ -11,7 +11,12 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/container/small_vector.hpp>
|
||||
#include <boost/serialization/assume_abstract.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/unique_ptr.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/serialization/boost_small_vector.hpp"
|
||||
#include "common/swap.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
@ -68,6 +73,11 @@ public:
|
|||
/// in each service must inherit from this.
|
||||
struct SessionDataBase {
|
||||
virtual ~SessionDataBase() = default;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
protected:
|
||||
|
@ -90,15 +100,33 @@ protected:
|
|||
|
||||
std::shared_ptr<ServerSession> session;
|
||||
std::unique_ptr<SessionDataBase> data;
|
||||
|
||||
private:
|
||||
SessionInfo() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& session;
|
||||
ar& data;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
/// List of sessions that are connected to this handler. A ServerSession whose server endpoint
|
||||
/// is an HLE implementation is kept alive by this list for the duration of the connection.
|
||||
std::vector<SessionInfo> connected_sessions;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& connected_sessions;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
// NOTE: The below classes are ephemeral and don't need serialization
|
||||
|
||||
class MappedBuffer {
|
||||
public:
|
||||
MappedBuffer(Memory::MemorySystem& memory, const Process& process, u32 descriptor,
|
||||
MappedBuffer(Memory::MemorySystem& memory, std::shared_ptr<Process> process, u32 descriptor,
|
||||
VAddr address, u32 id);
|
||||
|
||||
// interface for service
|
||||
|
@ -122,9 +150,21 @@ private:
|
|||
Memory::MemorySystem* memory;
|
||||
u32 id;
|
||||
VAddr address;
|
||||
const Process* process;
|
||||
std::size_t size;
|
||||
std::shared_ptr<Process> process;
|
||||
u32 size;
|
||||
IPC::MappedBufferPermissions perms;
|
||||
|
||||
MappedBuffer();
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& id;
|
||||
ar& address;
|
||||
ar& process;
|
||||
ar& size;
|
||||
ar& perms;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -156,9 +196,10 @@ private:
|
|||
* id of the memory interface and let kernel convert it back to client vaddr. No real unmapping is
|
||||
* needed in this case, though.
|
||||
*/
|
||||
class HLERequestContext {
|
||||
class HLERequestContext : public std::enable_shared_from_this<HLERequestContext> {
|
||||
public:
|
||||
HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session, Thread* thread);
|
||||
HLERequestContext(KernelSystem& kernel, std::shared_ptr<ServerSession> session,
|
||||
std::shared_ptr<Thread> thread);
|
||||
~HLERequestContext();
|
||||
|
||||
/// Returns a pointer to the IPC command buffer for this request.
|
||||
|
@ -174,8 +215,17 @@ public:
|
|||
return session;
|
||||
}
|
||||
|
||||
using WakeupCallback = std::function<void(
|
||||
std::shared_ptr<Thread> thread, HLERequestContext& context, ThreadWakeupReason reason)>;
|
||||
class WakeupCallback {
|
||||
public:
|
||||
virtual ~WakeupCallback() = default;
|
||||
virtual void WakeUp(std::shared_ptr<Thread> thread, HLERequestContext& context,
|
||||
ThreadWakeupReason reason) = 0;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/**
|
||||
* Puts the specified guest thread to sleep until the returned event is signaled or until the
|
||||
|
@ -190,7 +240,7 @@ public:
|
|||
*/
|
||||
std::shared_ptr<Event> SleepClientThread(const std::string& reason,
|
||||
std::chrono::nanoseconds timeout,
|
||||
WakeupCallback&& callback);
|
||||
std::shared_ptr<WakeupCallback> callback);
|
||||
|
||||
/**
|
||||
* Resolves a object id from the request command buffer into a pointer to an object. See the
|
||||
|
@ -230,24 +280,42 @@ public:
|
|||
MappedBuffer& GetMappedBuffer(u32 id_from_cmdbuf);
|
||||
|
||||
/// Populates this context with data from the requesting process/thread.
|
||||
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf, Process& src_process);
|
||||
ResultCode PopulateFromIncomingCommandBuffer(const u32_le* src_cmdbuf,
|
||||
std::shared_ptr<Process> src_process);
|
||||
/// Writes data from this context back to the requesting process/thread.
|
||||
ResultCode WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf, Process& dst_process) const;
|
||||
|
||||
/// Reports an unimplemented function.
|
||||
void ReportUnimplemented() const;
|
||||
|
||||
class ThreadCallback;
|
||||
friend class ThreadCallback;
|
||||
|
||||
private:
|
||||
KernelSystem& kernel;
|
||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||
std::shared_ptr<ServerSession> session;
|
||||
Thread* thread;
|
||||
std::shared_ptr<Thread> thread;
|
||||
// TODO(yuriks): Check common usage of this and optimize size accordingly
|
||||
boost::container::small_vector<std::shared_ptr<Object>, 8> request_handles;
|
||||
// The static buffers will be created when the IPC request is translated.
|
||||
std::array<std::vector<u8>, IPC::MAX_STATIC_BUFFERS> static_buffers;
|
||||
// The mapped buffers will be created when the IPC request is translated
|
||||
boost::container::small_vector<MappedBuffer, 8> request_mapped_buffers;
|
||||
|
||||
HLERequestContext();
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& cmd_buf;
|
||||
ar& session;
|
||||
ar& thread;
|
||||
ar& request_handles;
|
||||
ar& static_buffers;
|
||||
ar& request_mapped_buffers;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::HLERequestContext::ThreadCallback)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include "common/alignment.h"
|
||||
#include "common/memory_ref.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
|
@ -71,7 +72,7 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
|||
if (handle == CurrentThread) {
|
||||
object = src_thread;
|
||||
} else if (handle == CurrentProcess) {
|
||||
object = SharedFrom(src_process);
|
||||
object = src_process;
|
||||
} else if (handle != 0) {
|
||||
object = src_process->handle_table.GetGeneric(handle);
|
||||
if (descriptor == IPC::DescriptorType::MoveHandle) {
|
||||
|
@ -193,28 +194,29 @@ ResultCode TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySy
|
|||
// TODO(Subv): Perform permission checks.
|
||||
|
||||
// Reserve a page of memory before the mapped buffer
|
||||
auto reserve_buffer = std::make_unique<u8[]>(Memory::PAGE_SIZE);
|
||||
std::shared_ptr<BackingMem> reserve_buffer =
|
||||
std::make_shared<BufferMem>(Memory::PAGE_SIZE);
|
||||
dst_process->vm_manager.MapBackingMemoryToBase(
|
||||
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.get(),
|
||||
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
|
||||
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
|
||||
|
||||
auto buffer = std::make_unique<u8[]>(num_pages * Memory::PAGE_SIZE);
|
||||
memory.ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
|
||||
std::shared_ptr<BackingMem> buffer =
|
||||
std::make_shared<BufferMem>(num_pages * Memory::PAGE_SIZE);
|
||||
memory.ReadBlock(*src_process, source_address, buffer->GetPtr() + page_offset, size);
|
||||
|
||||
// Map the page(s) into the target process' address space.
|
||||
target_address =
|
||||
dst_process->vm_manager
|
||||
.MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE,
|
||||
buffer.get(), num_pages * Memory::PAGE_SIZE,
|
||||
Kernel::MemoryState::Shared)
|
||||
buffer, buffer->GetSize(), Kernel::MemoryState::Shared)
|
||||
.Unwrap();
|
||||
|
||||
cmd_buf[i++] = target_address + page_offset;
|
||||
|
||||
// Reserve a page of memory after the mapped buffer
|
||||
dst_process->vm_manager.MapBackingMemoryToBase(
|
||||
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer.get(),
|
||||
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
|
||||
Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, reserve_buffer,
|
||||
reserve_buffer->GetSize(), Kernel::MemoryState::Reserved);
|
||||
|
||||
mapped_buffer_context.push_back({permissions, size, source_address,
|
||||
target_address + page_offset, std::move(buffer),
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/ipc.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
@ -24,8 +25,20 @@ struct MappedBufferContext {
|
|||
VAddr source_address;
|
||||
VAddr target_address;
|
||||
|
||||
std::unique_ptr<u8[]> buffer;
|
||||
std::unique_ptr<u8[]> reserve_buffer;
|
||||
std::shared_ptr<BackingMem> buffer;
|
||||
std::shared_ptr<BackingMem> reserve_buffer;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& permissions;
|
||||
ar& size;
|
||||
ar& source_address;
|
||||
ar& target_address;
|
||||
ar& buffer;
|
||||
ar& reserve_buffer;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// Performs IPC command buffer translation from one process to another.
|
||||
|
|
|
@ -52,7 +52,7 @@ void Recorder::RegisterRequest(const std::shared_ptr<Kernel::ClientSession>& cli
|
|||
|
||||
RequestRecord record = {/* id */ ++record_count,
|
||||
/* status */ RequestStatus::Sent,
|
||||
/* client_process */ GetObjectInfo(client_thread->owner_process),
|
||||
/* client_process */ GetObjectInfo(client_thread->owner_process.get()),
|
||||
/* client_thread */ GetObjectInfo(client_thread.get()),
|
||||
/* client_session */ GetObjectInfo(client_session.get()),
|
||||
/* client_port */ GetObjectInfo(client_session->parent->port.get()),
|
||||
|
@ -82,7 +82,7 @@ void Recorder::SetRequestInfo(const std::shared_ptr<Kernel::Thread>& client_thre
|
|||
record.translated_request_cmdbuf = std::move(translated_cmdbuf);
|
||||
|
||||
if (server_thread) {
|
||||
record.server_process = GetObjectInfo(server_thread->owner_process);
|
||||
record.server_process = GetObjectInfo(server_thread->owner_process.get());
|
||||
record.server_thread = GetObjectInfo(server_thread.get());
|
||||
} else {
|
||||
record.is_hle = true;
|
||||
|
|
|
@ -2,6 +2,11 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "common/serialization/atomic.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/config_mem.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
|
@ -22,6 +27,8 @@ KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
|
|||
u32 num_cores, u8 n3ds_mode)
|
||||
: memory(memory), timing(timing),
|
||||
prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
|
||||
std::generate(memory_regions.begin(), memory_regions.end(),
|
||||
[] { return std::make_shared<MemoryRegionInfo>(); });
|
||||
MemoryInit(system_mode, n3ds_mode);
|
||||
|
||||
resource_limits = std::make_unique<ResourceLimitList>(*this);
|
||||
|
@ -58,24 +65,23 @@ std::shared_ptr<Process> KernelSystem::GetCurrentProcess() const {
|
|||
|
||||
void KernelSystem::SetCurrentProcess(std::shared_ptr<Process> process) {
|
||||
current_process = process;
|
||||
SetCurrentMemoryPageTable(&process->vm_manager.page_table);
|
||||
SetCurrentMemoryPageTable(process->vm_manager.page_table);
|
||||
}
|
||||
|
||||
void KernelSystem::SetCurrentProcessForCPU(std::shared_ptr<Process> process, u32 core_id) {
|
||||
if (current_cpu->GetID() == core_id) {
|
||||
current_process = process;
|
||||
SetCurrentMemoryPageTable(&process->vm_manager.page_table);
|
||||
SetCurrentMemoryPageTable(process->vm_manager.page_table);
|
||||
} else {
|
||||
stored_processes[core_id] = process;
|
||||
thread_managers[core_id]->cpu->PageTableChanged(&process->vm_manager.page_table);
|
||||
thread_managers[core_id]->cpu->SetPageTable(process->vm_manager.page_table);
|
||||
}
|
||||
}
|
||||
|
||||
void KernelSystem::SetCurrentMemoryPageTable(Memory::PageTable* page_table) {
|
||||
void KernelSystem::SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table) {
|
||||
memory.SetCurrentPageTable(page_table);
|
||||
if (current_cpu != nullptr) {
|
||||
// Notify the CPU the page table in memory has changed
|
||||
current_cpu->PageTableChanged(page_table);
|
||||
current_cpu->SetPageTable(page_table);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -150,4 +156,29 @@ void KernelSystem::ResetThreadIDs() {
|
|||
next_thread_id = 0;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void KernelSystem::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& memory_regions;
|
||||
ar& named_ports;
|
||||
// current_cpu set externally
|
||||
// NB: subsystem references and prepare_reschedule_callback are constant
|
||||
ar&* resource_limits.get();
|
||||
ar& next_object_id;
|
||||
ar&* timer_manager.get();
|
||||
ar& next_process_id;
|
||||
ar& process_list;
|
||||
ar& current_process;
|
||||
// NB: core count checked in 'core'
|
||||
for (auto& thread_manager : thread_managers) {
|
||||
ar&* thread_manager.get();
|
||||
}
|
||||
ar& config_mem_handler;
|
||||
ar& shared_page_handler;
|
||||
ar& stored_processes;
|
||||
ar& next_thread_id;
|
||||
// Deliberately don't include debugger info to allow debugging through loads
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(KernelSystem)
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -132,7 +132,8 @@ public:
|
|||
*/
|
||||
ResultVal<std::shared_ptr<Thread>> CreateThread(std::string name, VAddr entry_point,
|
||||
u32 priority, u32 arg, s32 processor_id,
|
||||
VAddr stack_top, Process& owner_process);
|
||||
VAddr stack_top,
|
||||
std::shared_ptr<Process> owner_process);
|
||||
|
||||
/**
|
||||
* Creates a semaphore.
|
||||
|
@ -213,7 +214,7 @@ public:
|
|||
void SetCurrentProcess(std::shared_ptr<Process> process);
|
||||
void SetCurrentProcessForCPU(std::shared_ptr<Process> process, u32 core_id);
|
||||
|
||||
void SetCurrentMemoryPageTable(Memory::PageTable* page_table);
|
||||
void SetCurrentMemoryPageTable(std::shared_ptr<Memory::PageTable> page_table);
|
||||
|
||||
void SetCPUs(std::vector<std::shared_ptr<ARM_Interface>> cpu);
|
||||
|
||||
|
@ -236,11 +237,11 @@ public:
|
|||
IPCDebugger::Recorder& GetIPCRecorder();
|
||||
const IPCDebugger::Recorder& GetIPCRecorder() const;
|
||||
|
||||
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
|
||||
std::shared_ptr<MemoryRegionInfo> GetMemoryRegion(MemoryRegion region);
|
||||
|
||||
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
|
||||
|
||||
std::array<MemoryRegionInfo, 3> memory_regions;
|
||||
std::array<std::shared_ptr<MemoryRegionInfo>, 3> memory_regions{};
|
||||
|
||||
/// Adds a port to the named port table
|
||||
void AddNamedPort(std::string name, std::shared_ptr<ClientPort> port);
|
||||
|
@ -291,12 +292,16 @@ private:
|
|||
|
||||
std::vector<std::unique_ptr<ThreadManager>> thread_managers;
|
||||
|
||||
std::unique_ptr<ConfigMem::Handler> config_mem_handler;
|
||||
std::unique_ptr<SharedPage::Handler> shared_page_handler;
|
||||
std::shared_ptr<ConfigMem::Handler> config_mem_handler;
|
||||
std::shared_ptr<SharedPage::Handler> shared_page_handler;
|
||||
|
||||
std::unique_ptr<IPCDebugger::Recorder> ipc_recorder;
|
||||
|
||||
u32 next_thread_id;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -71,32 +71,32 @@ void KernelSystem::MemoryInit(u32 mem_type, u8 n3ds_mode) {
|
|||
// the sizes specified in the memory_region_sizes table.
|
||||
VAddr base = 0;
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
memory_regions[i].Reset(base, memory_region_sizes[mem_type][i]);
|
||||
memory_regions[i]->Reset(base, memory_region_sizes[mem_type][i]);
|
||||
|
||||
base += memory_regions[i].size;
|
||||
base += memory_regions[i]->size;
|
||||
}
|
||||
|
||||
// We must've allocated the entire FCRAM by the end
|
||||
ASSERT(base == (is_new_3ds ? Memory::FCRAM_N3DS_SIZE : Memory::FCRAM_SIZE));
|
||||
|
||||
config_mem_handler = std::make_unique<ConfigMem::Handler>();
|
||||
config_mem_handler = std::make_shared<ConfigMem::Handler>();
|
||||
auto& config_mem = config_mem_handler->GetConfigMem();
|
||||
config_mem.app_mem_type = reported_mem_type;
|
||||
config_mem.app_mem_alloc = memory_region_sizes[reported_mem_type][0];
|
||||
config_mem.sys_mem_alloc = memory_regions[1].size;
|
||||
config_mem.base_mem_alloc = memory_regions[2].size;
|
||||
config_mem.sys_mem_alloc = memory_regions[1]->size;
|
||||
config_mem.base_mem_alloc = memory_regions[2]->size;
|
||||
|
||||
shared_page_handler = std::make_unique<SharedPage::Handler>(timing);
|
||||
shared_page_handler = std::make_shared<SharedPage::Handler>(timing);
|
||||
}
|
||||
|
||||
MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
|
||||
std::shared_ptr<MemoryRegionInfo> KernelSystem::GetMemoryRegion(MemoryRegion region) {
|
||||
switch (region) {
|
||||
case MemoryRegion::APPLICATION:
|
||||
return &memory_regions[0];
|
||||
return memory_regions[0];
|
||||
case MemoryRegion::SYSTEM:
|
||||
return &memory_regions[1];
|
||||
return memory_regions[1];
|
||||
case MemoryRegion::BASE:
|
||||
return &memory_regions[2];
|
||||
return memory_regions[2];
|
||||
default:
|
||||
UNREACHABLE();
|
||||
}
|
||||
|
@ -147,7 +147,7 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM
|
|||
return;
|
||||
}
|
||||
|
||||
u8* target_pointer = memory.GetPhysicalPointer(area->paddr_base + offset_into_region);
|
||||
auto target_pointer = memory.GetPhysicalRef(area->paddr_base + offset_into_region);
|
||||
|
||||
// TODO(yuriks): This flag seems to have some other effect, but it's unknown what
|
||||
MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO;
|
||||
|
@ -160,20 +160,16 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM
|
|||
}
|
||||
|
||||
void KernelSystem::MapSharedPages(VMManager& address_space) {
|
||||
auto cfg_mem_vma =
|
||||
address_space
|
||||
.MapBackingMemory(Memory::CONFIG_MEMORY_VADDR,
|
||||
reinterpret_cast<u8*>(&config_mem_handler->GetConfigMem()),
|
||||
Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared)
|
||||
.Unwrap();
|
||||
auto cfg_mem_vma = address_space
|
||||
.MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, {config_mem_handler},
|
||||
Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared)
|
||||
.Unwrap();
|
||||
address_space.Reprotect(cfg_mem_vma, VMAPermission::Read);
|
||||
|
||||
auto shared_page_vma =
|
||||
address_space
|
||||
.MapBackingMemory(Memory::SHARED_PAGE_VADDR,
|
||||
reinterpret_cast<u8*>(&shared_page_handler->GetSharedPage()),
|
||||
Memory::SHARED_PAGE_SIZE, MemoryState::Shared)
|
||||
.Unwrap();
|
||||
auto shared_page_vma = address_space
|
||||
.MapBackingMemory(Memory::SHARED_PAGE_VADDR, {shared_page_handler},
|
||||
Memory::SHARED_PAGE_SIZE, MemoryState::Shared)
|
||||
.Unwrap();
|
||||
address_space.Reprotect(shared_page_vma, VMAPermission::Read);
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,9 @@
|
|||
|
||||
#include <optional>
|
||||
#include <boost/icl/interval_set.hpp>
|
||||
#include <boost/serialization/set.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/serialization/boost_interval_set.hpp"
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
|
@ -60,6 +62,16 @@ struct MemoryRegionInfo {
|
|||
* @param size the size of the region to free.
|
||||
*/
|
||||
void Free(u32 offset, u32 size);
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& base;
|
||||
ar& size;
|
||||
ar& used;
|
||||
ar& free_blocks;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -4,14 +4,18 @@
|
|||
|
||||
#include <map>
|
||||
#include <vector>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/core.h"
|
||||
#include "core/global.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/mutex.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::Mutex)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
void ReleaseThreadMutexes(Thread* thread) {
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
|
@ -58,6 +62,16 @@ public:
|
|||
|
||||
private:
|
||||
KernelSystem& kernel;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar& lock_count;
|
||||
ar& priority;
|
||||
ar& name;
|
||||
ar& holding_thread;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -67,3 +81,6 @@ private:
|
|||
void ReleaseThreadMutexes(Thread* thread);
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::Mutex)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::Mutex)
|
||||
|
|
|
@ -7,7 +7,12 @@
|
|||
#include <atomic>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include <boost/serialization/assume_abstract.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/serialization/atomic.h"
|
||||
#include "core/global.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -64,6 +69,12 @@ public:
|
|||
|
||||
private:
|
||||
std::atomic<u32> object_id;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& object_id;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -87,3 +98,13 @@ inline std::shared_ptr<T> DynamicObjectCast(std::shared_ptr<Object> object) {
|
|||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_SERIALIZATION_ASSUME_ABSTRACT(Kernel::Object)
|
||||
|
||||
#define CONSTRUCT_KERNEL_OBJECT(T) \
|
||||
namespace boost::serialization { \
|
||||
template <class Archive> \
|
||||
void load_construct_data(Archive& ar, T* t, const unsigned int file_version) { \
|
||||
::new (t) T(Core::Global<Kernel::KernelSystem>()); \
|
||||
} \
|
||||
}
|
||||
|
|
|
@ -4,9 +4,14 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/bitset.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/serialization/boost_vector.hpp"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
|
@ -15,8 +20,34 @@
|
|||
#include "core/hle/kernel/vm_manager.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::Process)
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::CodeSet)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
template <class Archive>
|
||||
void Process::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
ar& handle_table;
|
||||
ar& codeset; // TODO: Replace with apploader reference
|
||||
ar& resource_limit;
|
||||
ar& svc_access_mask;
|
||||
ar& handle_table_size;
|
||||
ar&(boost::container::vector<AddressMapping, boost::container::dtl::static_storage_allocator<
|
||||
AddressMapping, 8, 0, true>>&)address_mappings;
|
||||
ar& flags.raw;
|
||||
ar& kernel_version;
|
||||
ar& ideal_processor;
|
||||
ar& status;
|
||||
ar& process_id;
|
||||
ar& vm_manager;
|
||||
ar& memory_used;
|
||||
ar& memory_region;
|
||||
ar& tls_slots;
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(Process)
|
||||
|
||||
std::shared_ptr<CodeSet> KernelSystem::CreateCodeSet(std::string name, u64 program_id) {
|
||||
auto codeset{std::make_shared<CodeSet>(*this)};
|
||||
|
||||
|
@ -191,7 +222,7 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
|||
std::fill(kernel.memory.GetFCRAMPointer(interval.lower()),
|
||||
kernel.memory.GetFCRAMPointer(interval.upper()), 0);
|
||||
auto vma = vm_manager.MapBackingMemory(interval_target,
|
||||
kernel.memory.GetFCRAMPointer(interval.lower()),
|
||||
kernel.memory.GetFCRAMRef(interval.lower()),
|
||||
interval_size, memory_state);
|
||||
ASSERT(vma.Succeeded());
|
||||
vm_manager.Reprotect(vma.Unwrap(), perms);
|
||||
|
@ -219,7 +250,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
|
|||
// Free heaps block by block
|
||||
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
|
||||
for (const auto [backing_memory, block_size] : backing_blocks) {
|
||||
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory), block_size);
|
||||
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()), block_size);
|
||||
}
|
||||
|
||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||
|
@ -263,9 +294,9 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
|||
}
|
||||
}
|
||||
|
||||
u8* backing_memory = kernel.memory.GetFCRAMPointer(physical_offset);
|
||||
auto backing_memory = kernel.memory.GetFCRAMRef(physical_offset);
|
||||
|
||||
std::fill(backing_memory, backing_memory + size, 0);
|
||||
std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + size, 0);
|
||||
auto vma = vm_manager.MapBackingMemory(target, backing_memory, size, MemoryState::Continuous);
|
||||
ASSERT(vma.Succeeded());
|
||||
vm_manager.Reprotect(vma.Unwrap(), perms);
|
||||
|
@ -403,8 +434,7 @@ ResultCode Process::Unmap(VAddr target, VAddr source, u32 size, VMAPermission pe
|
|||
|
||||
Kernel::Process::Process(KernelSystem& kernel)
|
||||
: Object(kernel), handle_table(kernel), vm_manager(kernel.memory), kernel(kernel) {
|
||||
|
||||
kernel.memory.RegisterPageTable(&vm_manager.page_table);
|
||||
kernel.memory.RegisterPageTable(vm_manager.page_table);
|
||||
}
|
||||
Kernel::Process::~Process() {
|
||||
// Release all objects this process owns first so that their potential destructor can do clean
|
||||
|
@ -413,7 +443,7 @@ Kernel::Process::~Process() {
|
|||
// memory etc.) even if they are still referenced by other processes.
|
||||
handle_table.Clear();
|
||||
|
||||
kernel.memory.UnregisterPageTable(&vm_manager.page_table);
|
||||
kernel.memory.UnregisterPageTable(vm_manager.page_table);
|
||||
}
|
||||
|
||||
std::shared_ptr<Process> KernelSystem::GetProcessById(u32 process_id) const {
|
||||
|
|
|
@ -11,6 +11,10 @@
|
|||
#include <string>
|
||||
#include <vector>
|
||||
#include <boost/container/static_vector.hpp>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/handle_table.h"
|
||||
|
@ -25,6 +29,16 @@ struct AddressMapping {
|
|||
u32 size;
|
||||
bool read_only;
|
||||
bool unk_flag;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& address;
|
||||
ar& size;
|
||||
ar& read_only;
|
||||
ar& unk_flag;
|
||||
}
|
||||
};
|
||||
|
||||
union ProcessFlags {
|
||||
|
@ -59,6 +73,15 @@ public:
|
|||
std::size_t offset = 0;
|
||||
VAddr addr = 0;
|
||||
u32 size = 0;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& offset;
|
||||
ar& addr;
|
||||
ar& size;
|
||||
}
|
||||
};
|
||||
|
||||
std::string GetTypeName() const override {
|
||||
|
@ -106,6 +129,18 @@ public:
|
|||
std::string name;
|
||||
/// Title ID corresponding to the process
|
||||
u64 program_id;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
ar& memory;
|
||||
ar& segments;
|
||||
ar& entrypoint;
|
||||
ar& name;
|
||||
ar& program_id;
|
||||
}
|
||||
};
|
||||
|
||||
class Process final : public Object {
|
||||
|
@ -167,7 +202,7 @@ public:
|
|||
|
||||
u32 memory_used = 0;
|
||||
|
||||
MemoryRegionInfo* memory_region = nullptr;
|
||||
std::shared_ptr<MemoryRegionInfo> memory_region = nullptr;
|
||||
|
||||
/// The Thread Local Storage area is allocated as processes create threads,
|
||||
/// each TLS area is 0x200 bytes, so one page (0x1000) is split up in 8 parts, and each part
|
||||
|
@ -195,5 +230,14 @@ public:
|
|||
|
||||
private:
|
||||
KernelSystem& kernel;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::CodeSet)
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::Process)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::CodeSet)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::Process)
|
||||
|
|
|
@ -3,10 +3,13 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/resource_limit.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::ResourceLimit)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ResourceLimit::ResourceLimit(KernelSystem& kernel) : Object(kernel) {}
|
||||
|
|
|
@ -6,6 +6,10 @@
|
|||
|
||||
#include <array>
|
||||
#include <memory>
|
||||
#include <boost/serialization/array.hpp>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
|
@ -110,6 +114,35 @@ public:
|
|||
|
||||
/// Current CPU time that the processes in this category are utilizing
|
||||
s32 current_cpu_time = 0;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
// NB most of these aren't used at all currently, but we're adding them here for forwards
|
||||
// compatibility
|
||||
ar& name;
|
||||
ar& max_priority;
|
||||
ar& max_commit;
|
||||
ar& max_threads;
|
||||
ar& max_events;
|
||||
ar& max_mutexes;
|
||||
ar& max_semaphores;
|
||||
ar& max_timers;
|
||||
ar& max_shared_mems;
|
||||
ar& max_address_arbiters;
|
||||
ar& max_cpu_time;
|
||||
ar& current_commit;
|
||||
ar& current_threads;
|
||||
ar& current_events;
|
||||
ar& current_mutexes;
|
||||
ar& current_semaphores;
|
||||
ar& current_timers;
|
||||
ar& current_shared_mems;
|
||||
ar& current_address_arbiters;
|
||||
ar& current_cpu_time;
|
||||
}
|
||||
};
|
||||
|
||||
class ResourceLimitList {
|
||||
|
@ -126,6 +159,15 @@ public:
|
|||
|
||||
private:
|
||||
std::array<std::shared_ptr<ResourceLimit>, 4> resource_limits;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& resource_limits;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::ResourceLimit)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::ResourceLimit)
|
||||
|
|
|
@ -2,12 +2,15 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/kernel.h"
|
||||
#include "core/hle/kernel/semaphore.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::Semaphore)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Semaphore::Semaphore(KernelSystem& kernel) : WaitObject(kernel) {}
|
||||
|
|
|
@ -5,6 +5,9 @@
|
|||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <queue>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
@ -43,6 +46,19 @@ public:
|
|||
* @return The number of free slots the semaphore had before this call
|
||||
*/
|
||||
ResultVal<s32> Release(s32 release_count);
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar& max_count;
|
||||
ar& available_count;
|
||||
ar& name;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::Semaphore)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::Semaphore)
|
||||
|
|
|
@ -3,14 +3,22 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <tuple>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_port.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::ServerPort)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
ServerPort::ServerPort(KernelSystem& kernel) : WaitObject(kernel) {}
|
||||
|
@ -48,4 +56,13 @@ KernelSystem::PortPair KernelSystem::CreatePortPair(u32 max_sessions, std::strin
|
|||
return std::make_pair(std::move(server_port), std::move(client_port));
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void ServerPort::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar& name;
|
||||
ar& pending_sessions;
|
||||
ar& hle_handler;
|
||||
}
|
||||
SERIALIZE_IMPL(ServerPort)
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -7,8 +7,10 @@
|
|||
#include <memory>
|
||||
#include <string>
|
||||
#include <tuple>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/hle/result.h"
|
||||
|
||||
|
@ -60,6 +62,14 @@ public:
|
|||
|
||||
bool ShouldWait(const Thread* thread) const override;
|
||||
void Acquire(Thread* thread) override;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::ServerPort)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::ServerPort)
|
||||
|
|
|
@ -3,7 +3,10 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <tuple>
|
||||
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/hle_ipc.h"
|
||||
|
@ -11,8 +14,22 @@
|
|||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::ServerSession)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
template <class Archive>
|
||||
void ServerSession::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar& name;
|
||||
ar& parent;
|
||||
ar& hle_handler;
|
||||
ar& pending_requesting_threads;
|
||||
ar& currently_handling;
|
||||
ar& mapped_buffer_context;
|
||||
}
|
||||
SERIALIZE_IMPL(ServerSession)
|
||||
|
||||
ServerSession::ServerSession(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
|
||||
ServerSession::~ServerSession() {
|
||||
// This destructor will be called automatically when the last ServerSession handle is closed by
|
||||
|
@ -68,14 +85,15 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
|
|||
// If this ServerSession has an associated HLE handler, forward the request to it.
|
||||
if (hle_handler != nullptr) {
|
||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buf;
|
||||
Kernel::Process* current_process = thread->owner_process;
|
||||
auto current_process = thread->owner_process;
|
||||
kernel.memory.ReadBlock(*current_process, thread->GetCommandBufferAddress(), cmd_buf.data(),
|
||||
cmd_buf.size() * sizeof(u32));
|
||||
|
||||
Kernel::HLERequestContext context(kernel, SharedFrom(this), thread.get());
|
||||
context.PopulateFromIncomingCommandBuffer(cmd_buf.data(), *current_process);
|
||||
auto context =
|
||||
std::make_shared<Kernel::HLERequestContext>(kernel, SharedFrom(this), thread);
|
||||
context->PopulateFromIncomingCommandBuffer(cmd_buf.data(), current_process);
|
||||
|
||||
hle_handler->HandleSyncRequest(context);
|
||||
hle_handler->HandleSyncRequest(*context);
|
||||
|
||||
ASSERT(thread->status == Kernel::ThreadStatus::Running ||
|
||||
thread->status == Kernel::ThreadStatus::WaitHleEvent);
|
||||
|
@ -83,7 +101,7 @@ ResultCode ServerSession::HandleSyncRequest(std::shared_ptr<Thread> thread) {
|
|||
// put the thread to sleep then the writing of the command buffer will be deferred to the
|
||||
// wakeup callback.
|
||||
if (thread->status == Kernel::ThreadStatus::Running) {
|
||||
context.WriteToOutgoingCommandBuffer(cmd_buf.data(), *current_process);
|
||||
context->WriteToOutgoingCommandBuffer(cmd_buf.data(), *current_process);
|
||||
kernel.memory.WriteBlock(*current_process, thread->GetCommandBufferAddress(),
|
||||
cmd_buf.data(), cmd_buf.size() * sizeof(u32));
|
||||
}
|
||||
|
|
|
@ -6,10 +6,12 @@
|
|||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/ipc.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/wait_object.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
@ -103,6 +105,13 @@ private:
|
|||
|
||||
friend class KernelSystem;
|
||||
KernelSystem& kernel;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::ServerSession)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::ServerSession)
|
||||
|
|
|
@ -2,11 +2,22 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "core/hle/kernel/client_port.h"
|
||||
#include "core/hle/kernel/client_session.h"
|
||||
#include "core/hle/kernel/server_session.h"
|
||||
#include "core/hle/kernel/session.h"
|
||||
#include "core/hle/kernel/thread.h"
|
||||
|
||||
SERIALIZE_IMPL(Kernel::Session)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Session::Session() {}
|
||||
Session::~Session() {}
|
||||
template <class Archive>
|
||||
void Session::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& client;
|
||||
ar& server;
|
||||
ar& port;
|
||||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
namespace Kernel {
|
||||
|
@ -24,5 +25,10 @@ public:
|
|||
ClientSession* client = nullptr; ///< The client endpoint of the session.
|
||||
ServerSession* server = nullptr; ///< The server endpoint of the session.
|
||||
std::shared_ptr<ClientPort> port; ///< The port that this session is associated with (optional).
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -3,12 +3,15 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cstring>
|
||||
#include "common/archives.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
#include "core/hle/kernel/memory.h"
|
||||
#include "core/hle/kernel/shared_memory.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::SharedMemory)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
SharedMemory::SharedMemory(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
|
||||
|
@ -38,13 +41,13 @@ ResultVal<std::shared_ptr<SharedMemory>> KernelSystem::CreateSharedMemory(
|
|||
if (address == 0) {
|
||||
// We need to allocate a block from the Linear Heap ourselves.
|
||||
// We'll manually allocate some memory from the linear heap in the specified region.
|
||||
MemoryRegionInfo* memory_region = GetMemoryRegion(region);
|
||||
auto memory_region = GetMemoryRegion(region);
|
||||
auto offset = memory_region->LinearAllocate(size);
|
||||
|
||||
ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!");
|
||||
|
||||
std::fill(memory.GetFCRAMPointer(*offset), memory.GetFCRAMPointer(*offset + size), 0);
|
||||
shared_memory->backing_blocks = {{memory.GetFCRAMPointer(*offset), size}};
|
||||
shared_memory->backing_blocks = {{memory.GetFCRAMRef(*offset), size}};
|
||||
shared_memory->holding_memory += MemoryRegionInfo::Interval(*offset, *offset + size);
|
||||
shared_memory->linear_heap_phys_offset = *offset;
|
||||
|
||||
|
@ -75,7 +78,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
|
|||
auto shared_memory{std::make_shared<SharedMemory>(*this)};
|
||||
|
||||
// Allocate memory in heap
|
||||
MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
|
||||
auto memory_region = GetMemoryRegion(MemoryRegion::SYSTEM);
|
||||
auto backing_blocks = memory_region->HeapAllocate(size);
|
||||
ASSERT_MSG(!backing_blocks.empty(), "Not enough space in region to allocate shared memory!");
|
||||
shared_memory->holding_memory = backing_blocks;
|
||||
|
@ -86,7 +89,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
|
|||
shared_memory->other_permissions = other_permissions;
|
||||
for (const auto& interval : backing_blocks) {
|
||||
shared_memory->backing_blocks.push_back(
|
||||
{memory.GetFCRAMPointer(interval.lower()), interval.upper() - interval.lower()});
|
||||
{memory.GetFCRAMRef(interval.lower()), interval.upper() - interval.lower()});
|
||||
std::fill(memory.GetFCRAMPointer(interval.lower()),
|
||||
memory.GetFCRAMPointer(interval.upper()), 0);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@
|
|||
|
||||
#include <string>
|
||||
#include <utility>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/memory_ref.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
#include "core/hle/kernel/process.h"
|
||||
#include "core/hle/result.h"
|
||||
|
@ -86,7 +90,7 @@ private:
|
|||
/// during creation.
|
||||
PAddr linear_heap_phys_offset = 0;
|
||||
/// Backing memory for this shared memory block.
|
||||
std::vector<std::pair<u8*, u32>> backing_blocks;
|
||||
std::vector<std::pair<MemoryRef, u32>> backing_blocks;
|
||||
/// Size of the memory block. Page-aligned.
|
||||
u32 size = 0;
|
||||
/// Permission restrictions applied to the process which created the block.
|
||||
|
@ -104,6 +108,24 @@ private:
|
|||
|
||||
friend class KernelSystem;
|
||||
KernelSystem& kernel;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
ar& linear_heap_phys_offset;
|
||||
ar& backing_blocks;
|
||||
ar& size;
|
||||
ar& permissions;
|
||||
ar& other_permissions;
|
||||
ar& owner_process;
|
||||
ar& base_address;
|
||||
ar& name;
|
||||
ar& holding_memory;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::SharedMemory)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::SharedMemory)
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <chrono>
|
||||
#include <cstring>
|
||||
#include "common/archives.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/shared_page.h"
|
||||
|
@ -13,6 +14,19 @@
|
|||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(SharedPage::Handler)
|
||||
|
||||
namespace boost::serialization {
|
||||
|
||||
template <class Archive>
|
||||
void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int) {
|
||||
::new (t) SharedPage::Handler(Core::System::GetInstance().CoreTiming());
|
||||
}
|
||||
template void load_construct_data<iarchive>(iarchive& ar, SharedPage::Handler* t,
|
||||
const unsigned int);
|
||||
|
||||
} // namespace boost::serialization
|
||||
|
||||
namespace SharedPage {
|
||||
|
||||
static std::chrono::seconds GetInitTime() {
|
||||
|
|
|
@ -13,9 +13,13 @@
|
|||
#include <chrono>
|
||||
#include <ctime>
|
||||
#include <memory>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/binary_object.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/memory_ref.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
|
@ -82,7 +86,7 @@ struct SharedPageDef {
|
|||
static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE,
|
||||
"Shared page structure size is wrong");
|
||||
|
||||
class Handler {
|
||||
class Handler : public BackingMem {
|
||||
public:
|
||||
Handler(Core::Timing& timing);
|
||||
|
||||
|
@ -96,6 +100,18 @@ public:
|
|||
|
||||
SharedPageDef& GetSharedPage();
|
||||
|
||||
u8* GetPtr() override {
|
||||
return reinterpret_cast<u8*>(&shared_page);
|
||||
}
|
||||
|
||||
const u8* GetPtr() const override {
|
||||
return reinterpret_cast<const u8*>(&shared_page);
|
||||
}
|
||||
|
||||
std::size_t GetSize() const override {
|
||||
return sizeof(shared_page);
|
||||
}
|
||||
|
||||
private:
|
||||
u64 GetSystemTime() const;
|
||||
void UpdateTimeCallback(u64 userdata, int cycles_late);
|
||||
|
@ -104,6 +120,22 @@ private:
|
|||
std::chrono::seconds init_time;
|
||||
|
||||
SharedPageDef shared_page;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<BackingMem>(*this);
|
||||
ar& boost::serialization::make_binary_object(&shared_page, sizeof(shared_page));
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
} // namespace SharedPage
|
||||
|
||||
namespace boost::serialization {
|
||||
|
||||
template <class Archive>
|
||||
void load_construct_data(Archive& ar, SharedPage::Handler* t, const unsigned int);
|
||||
|
||||
} // namespace boost::serialization
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(SharedPage::Handler)
|
||||
|
|
|
@ -282,7 +282,7 @@ void SVC::ExitProcess() {
|
|||
// Stop all the process threads that are currently waiting for objects.
|
||||
auto& thread_list = kernel.GetCurrentThreadManager().GetThreadList();
|
||||
for (auto& thread : thread_list) {
|
||||
if (thread->owner_process != current_process.get())
|
||||
if (thread->owner_process != current_process)
|
||||
continue;
|
||||
|
||||
if (thread.get() == kernel.GetCurrentThreadManager().GetCurrentThread())
|
||||
|
@ -403,6 +403,76 @@ ResultCode SVC::CloseHandle(Handle handle) {
|
|||
return kernel.GetCurrentProcess()->handle_table.Close(handle);
|
||||
}
|
||||
|
||||
static ResultCode ReceiveIPCRequest(Kernel::KernelSystem& kernel, Memory::MemorySystem& memory,
|
||||
std::shared_ptr<ServerSession> server_session,
|
||||
std::shared_ptr<Thread> thread);
|
||||
|
||||
class SVC_SyncCallback : public Kernel::WakeupCallback {
|
||||
public:
|
||||
explicit SVC_SyncCallback(bool do_output_) : do_output(do_output_) {}
|
||||
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
|
||||
if (reason == ThreadWakeupReason::Timeout) {
|
||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||
|
||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||
|
||||
// The wait_all case does not update the output index.
|
||||
if (do_output) {
|
||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
bool do_output;
|
||||
|
||||
SVC_SyncCallback() = default;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
|
||||
ar& do_output;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class SVC_IPCCallback : public Kernel::WakeupCallback {
|
||||
public:
|
||||
explicit SVC_IPCCallback(Core::System& system_) : system(system_) {}
|
||||
|
||||
void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||
|
||||
ResultCode result = RESULT_SUCCESS;
|
||||
|
||||
if (object->GetHandleType() == HandleType::ServerSession) {
|
||||
auto server_session = DynamicObjectCast<ServerSession>(object);
|
||||
result = ReceiveIPCRequest(system.Kernel(), system.Memory(), server_session, thread);
|
||||
}
|
||||
|
||||
thread->SetWaitSynchronizationResult(result);
|
||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
||||
}
|
||||
|
||||
private:
|
||||
Core::System& system;
|
||||
|
||||
SVC_IPCCallback() : system(Core::Global<Core::System>()) {}
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& boost::serialization::base_object<Kernel::WakeupCallback>(*this);
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
/// Wait for a handle to synchronize, timeout after the specified nanoseconds
|
||||
ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
||||
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
|
||||
|
@ -426,21 +496,7 @@ ResultCode SVC::WaitSynchronization1(Handle handle, s64 nano_seconds) {
|
|||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||
thread->WakeAfterDelay(nano_seconds);
|
||||
|
||||
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||
|
||||
if (reason == ThreadWakeupReason::Timeout) {
|
||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||
|
||||
// WaitSynchronization1 doesn't have an output index like WaitSynchronizationN, so we
|
||||
// don't have to do anything else here.
|
||||
};
|
||||
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
|
||||
|
||||
system.PrepareReschedule();
|
||||
|
||||
|
@ -515,20 +571,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
|
|||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||
thread->WakeAfterDelay(nano_seconds);
|
||||
|
||||
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAll);
|
||||
|
||||
if (reason == ThreadWakeupReason::Timeout) {
|
||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||
|
||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||
// The wait_all case does not update the output index.
|
||||
};
|
||||
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(false);
|
||||
|
||||
system.PrepareReschedule();
|
||||
|
||||
|
@ -575,20 +618,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
|
|||
// Create an event to wake the thread up after the specified nanosecond delay has passed
|
||||
thread->WakeAfterDelay(nano_seconds);
|
||||
|
||||
thread->wakeup_callback = [](ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||
|
||||
if (reason == ThreadWakeupReason::Timeout) {
|
||||
thread->SetWaitSynchronizationResult(RESULT_TIMEOUT);
|
||||
return;
|
||||
}
|
||||
|
||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||
|
||||
thread->SetWaitSynchronizationResult(RESULT_SUCCESS);
|
||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
||||
};
|
||||
thread->wakeup_callback = std::make_shared<SVC_SyncCallback>(true);
|
||||
|
||||
system.PrepareReschedule();
|
||||
|
||||
|
@ -730,22 +760,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
|||
|
||||
thread->wait_objects = std::move(objects);
|
||||
|
||||
thread->wakeup_callback = [& kernel = this->kernel, &memory = this->memory](
|
||||
ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) {
|
||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||
|
||||
ResultCode result = RESULT_SUCCESS;
|
||||
|
||||
if (object->GetHandleType() == HandleType::ServerSession) {
|
||||
auto server_session = DynamicObjectCast<ServerSession>(object);
|
||||
result = ReceiveIPCRequest(kernel, memory, server_session, thread);
|
||||
}
|
||||
|
||||
thread->SetWaitSynchronizationResult(result);
|
||||
thread->SetWaitSynchronizationOutput(thread->GetWaitObjectIndex(object.get()));
|
||||
};
|
||||
thread->wakeup_callback = std::make_shared<SVC_IPCCallback>(system);
|
||||
|
||||
system.PrepareReschedule();
|
||||
|
||||
|
@ -916,7 +931,7 @@ ResultCode SVC::CreateThread(Handle* out_handle, u32 entry_point, u32 arg, VAddr
|
|||
|
||||
CASCADE_RESULT(std::shared_ptr<Thread> thread,
|
||||
kernel.CreateThread(name, entry_point, priority, arg, processor_id, stack_top,
|
||||
*current_process));
|
||||
current_process));
|
||||
|
||||
thread->context->SetFpscr(FPSCR_DEFAULT_NAN | FPSCR_FLUSH_TO_ZERO |
|
||||
FPSCR_ROUND_TOZERO); // 0x03C00000
|
||||
|
@ -1025,7 +1040,7 @@ ResultCode SVC::GetProcessIdOfThread(u32* process_id, Handle thread_handle) {
|
|||
if (thread == nullptr)
|
||||
return ERR_INVALID_HANDLE;
|
||||
|
||||
const std::shared_ptr<Process> process = SharedFrom(thread->owner_process);
|
||||
const std::shared_ptr<Process> process = thread->owner_process;
|
||||
|
||||
ASSERT_MSG(process != nullptr, "Invalid parent process for thread={:#010X}", thread_handle);
|
||||
|
||||
|
@ -1592,6 +1607,7 @@ void SVC::CallSVC(u32 immediate) {
|
|||
"Running threads from exiting processes is unimplemented");
|
||||
|
||||
const FunctionDef* info = GetSVCInfo(immediate);
|
||||
LOG_TRACE(Kernel_SVC, "calling {}", info->name);
|
||||
if (info) {
|
||||
if (info->func) {
|
||||
(this->*(info->func))();
|
||||
|
@ -1619,3 +1635,6 @@ void SVCContext::CallSVC(u32 immediate) {
|
|||
}
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::SVC_SyncCallback)
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::SVC_IPCCallback)
|
||||
|
|
|
@ -5,6 +5,7 @@
|
|||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include "common/common_types.h"
|
||||
|
||||
namespace Core {
|
||||
|
@ -25,4 +26,10 @@ private:
|
|||
std::unique_ptr<SVC> impl;
|
||||
};
|
||||
|
||||
class SVC_SyncCallback;
|
||||
class SVC_IPCCallback;
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::SVC_SyncCallback)
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::SVC_IPCCallback)
|
||||
|
|
|
@ -280,6 +280,26 @@ private:
|
|||
}
|
||||
};
|
||||
|
||||
template <typename SVCT>
|
||||
struct WrapPass<SVCT, ResultCode /*empty for T, Ts...*/> {
|
||||
// Call function R(Context::svc)(Us...) and transfer the return value to registers
|
||||
template <typename... Us>
|
||||
static void Call(Context& context, SVCT svc, Us... u) {
|
||||
static_assert(std::is_same_v<SVCT, ResultCode (Context::*)(Us...)>);
|
||||
if constexpr (std::is_void_v<ResultCode>) {
|
||||
(context.*svc)(u...);
|
||||
} else {
|
||||
ResultCode r = (context.*svc)(u...);
|
||||
if (r.IsError()) {
|
||||
LOG_ERROR(Kernel_SVC, "level={} summary={} module={} description={}",
|
||||
r.level.ExtractValue(r.raw), r.summary.ExtractValue(r.raw),
|
||||
r.module.ExtractValue(r.raw), r.description.ExtractValue(r.raw));
|
||||
}
|
||||
SetParam<INDEX_RETURN, ResultCode, ResultCode, Us...>(context, r);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct WrapHelper;
|
||||
|
||||
|
|
|
@ -6,10 +6,13 @@
|
|||
#include <list>
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/math_util.h"
|
||||
#include "common/serialization/boost_flat_set.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
#include "core/arm/skyeye_common/armstate.h"
|
||||
#include "core/core.h"
|
||||
|
@ -23,8 +26,34 @@
|
|||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::Thread)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
template <class Archive>
|
||||
void Thread::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar&* context.get();
|
||||
ar& thread_id;
|
||||
ar& status;
|
||||
ar& entry_point;
|
||||
ar& stack_top;
|
||||
ar& nominal_priority;
|
||||
ar& current_priority;
|
||||
ar& last_running_ticks;
|
||||
ar& processor_id;
|
||||
ar& tls_address;
|
||||
ar& held_mutexes;
|
||||
ar& pending_mutexes;
|
||||
ar& owner_process;
|
||||
ar& wait_objects;
|
||||
ar& wait_address;
|
||||
ar& name;
|
||||
ar& wakeup_callback;
|
||||
}
|
||||
|
||||
SERIALIZE_IMPL(Thread)
|
||||
|
||||
bool Thread::ShouldWait(const Thread* thread) const {
|
||||
return status != ThreadStatus::Dead;
|
||||
}
|
||||
|
@ -34,7 +63,7 @@ void Thread::Acquire(Thread* thread) {
|
|||
}
|
||||
|
||||
Thread::Thread(KernelSystem& kernel, u32 core_id)
|
||||
: WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()),
|
||||
: WaitObject(kernel), context(kernel.GetThreadManager(core_id).NewContext()), core_id(core_id),
|
||||
thread_manager(kernel.GetThreadManager(core_id)) {}
|
||||
Thread::~Thread() {}
|
||||
|
||||
|
@ -75,7 +104,7 @@ void Thread::Stop() {
|
|||
|
||||
void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||
Thread* previous_thread = GetCurrentThread();
|
||||
Process* previous_process = nullptr;
|
||||
std::shared_ptr<Process> previous_process = nullptr;
|
||||
|
||||
Core::Timing& timing = kernel.timing;
|
||||
|
||||
|
@ -107,7 +136,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
|
|||
new_thread->status = ThreadStatus::Running;
|
||||
|
||||
if (previous_process != current_thread->owner_process) {
|
||||
kernel.SetCurrentProcessForCPU(SharedFrom(current_thread->owner_process), cpu->GetID());
|
||||
kernel.SetCurrentProcessForCPU(current_thread->owner_process, cpu->GetID());
|
||||
}
|
||||
|
||||
cpu->LoadContext(new_thread->context);
|
||||
|
@ -164,7 +193,7 @@ void ThreadManager::ThreadWakeupCallback(u64 thread_id, s64 cycles_late) {
|
|||
|
||||
// Invoke the wakeup callback before clearing the wait objects
|
||||
if (thread->wakeup_callback)
|
||||
thread->wakeup_callback(ThreadWakeupReason::Timeout, thread, nullptr);
|
||||
thread->wakeup_callback->WakeUp(ThreadWakeupReason::Timeout, thread, nullptr);
|
||||
|
||||
// Remove the thread from each of its waiting objects' waitlists
|
||||
for (auto& object : thread->wait_objects)
|
||||
|
@ -282,10 +311,9 @@ static void ResetThreadContext(const std::unique_ptr<ARM_Interface::ThreadContex
|
|||
context->SetCpsr(USER32MODE | ((entry_point & 1) << 5)); // Usermode and THUMB mode
|
||||
}
|
||||
|
||||
ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name, VAddr entry_point,
|
||||
u32 priority, u32 arg,
|
||||
s32 processor_id, VAddr stack_top,
|
||||
Process& owner_process) {
|
||||
ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(
|
||||
std::string name, VAddr entry_point, u32 priority, u32 arg, s32 processor_id, VAddr stack_top,
|
||||
std::shared_ptr<Process> owner_process) {
|
||||
// Check if priority is in ranged. Lowest priority -> highest priority id.
|
||||
if (priority > ThreadPrioLowest) {
|
||||
LOG_ERROR(Kernel_SVC, "Invalid thread priority: {}", priority);
|
||||
|
@ -299,7 +327,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
|||
|
||||
// TODO(yuriks): Other checks, returning 0xD9001BEA
|
||||
|
||||
if (!Memory::IsValidVirtualAddress(owner_process, entry_point)) {
|
||||
if (!Memory::IsValidVirtualAddress(*owner_process, entry_point)) {
|
||||
LOG_ERROR(Kernel_SVC, "(name={}): invalid entry {:08x}", name, entry_point);
|
||||
// TODO: Verify error
|
||||
return ResultCode(ErrorDescription::InvalidAddress, ErrorModule::Kernel,
|
||||
|
@ -322,17 +350,17 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
|||
thread->wait_address = 0;
|
||||
thread->name = std::move(name);
|
||||
thread_managers[processor_id]->wakeup_callback_table[thread->thread_id] = thread.get();
|
||||
thread->owner_process = &owner_process;
|
||||
thread->owner_process = owner_process;
|
||||
|
||||
// Find the next available TLS index, and mark it as used
|
||||
auto& tls_slots = owner_process.tls_slots;
|
||||
auto& tls_slots = owner_process->tls_slots;
|
||||
|
||||
auto [available_page, available_slot, needs_allocation] = GetFreeThreadLocalSlot(tls_slots);
|
||||
|
||||
if (needs_allocation) {
|
||||
// There are no already-allocated pages with free slots, lets allocate a new one.
|
||||
// TLS pages are allocated from the BASE region in the linear heap.
|
||||
MemoryRegionInfo* memory_region = GetMemoryRegion(MemoryRegion::BASE);
|
||||
auto memory_region = GetMemoryRegion(MemoryRegion::BASE);
|
||||
|
||||
// Allocate some memory from the end of the linear heap for this region.
|
||||
auto offset = memory_region->LinearAllocate(Memory::PAGE_SIZE);
|
||||
|
@ -341,17 +369,17 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
|||
"Not enough space in region to allocate a new TLS page for thread");
|
||||
return ERR_OUT_OF_MEMORY;
|
||||
}
|
||||
owner_process.memory_used += Memory::PAGE_SIZE;
|
||||
owner_process->memory_used += Memory::PAGE_SIZE;
|
||||
|
||||
tls_slots.emplace_back(0); // The page is completely available at the start
|
||||
available_page = tls_slots.size() - 1;
|
||||
available_slot = 0; // Use the first slot in the new page
|
||||
|
||||
auto& vm_manager = owner_process.vm_manager;
|
||||
auto& vm_manager = owner_process->vm_manager;
|
||||
|
||||
// Map the page to the current process' address space.
|
||||
vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
||||
memory.GetFCRAMPointer(*offset), Memory::PAGE_SIZE,
|
||||
memory.GetFCRAMRef(*offset), Memory::PAGE_SIZE,
|
||||
MemoryState::Locked);
|
||||
}
|
||||
|
||||
|
@ -360,7 +388,7 @@ ResultVal<std::shared_ptr<Thread>> KernelSystem::CreateThread(std::string name,
|
|||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||
available_slot * Memory::TLS_ENTRY_SIZE;
|
||||
|
||||
memory.ZeroBlock(owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
|
||||
memory.ZeroBlock(*owner_process, thread->tls_address, Memory::TLS_ENTRY_SIZE);
|
||||
|
||||
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||
// to initialize the context
|
||||
|
@ -407,7 +435,7 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
|
|||
// Initialize new "main" thread
|
||||
auto thread_res =
|
||||
kernel.CreateThread("main", entry_point, priority, 0, owner_process->ideal_processor,
|
||||
Memory::HEAP_VADDR_END, *owner_process);
|
||||
Memory::HEAP_VADDR_END, owner_process);
|
||||
|
||||
std::shared_ptr<Thread> thread = std::move(thread_res).Unwrap();
|
||||
|
||||
|
|
|
@ -9,6 +9,10 @@
|
|||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <boost/container/flat_set.hpp>
|
||||
#include <boost/serialization/export.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/thread_queue_list.h"
|
||||
#include "core/arm/arm_interface.h"
|
||||
|
@ -57,6 +61,20 @@ enum class ThreadWakeupReason {
|
|||
Timeout // The thread was woken up due to a wait timeout.
|
||||
};
|
||||
|
||||
class Thread;
|
||||
|
||||
class WakeupCallback {
|
||||
public:
|
||||
virtual ~WakeupCallback() = default;
|
||||
virtual void WakeUp(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object) = 0;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
class ThreadManager {
|
||||
public:
|
||||
explicit ThreadManager(Kernel::KernelSystem& kernel, u32 core_id);
|
||||
|
@ -140,6 +158,15 @@ private:
|
|||
|
||||
friend class Thread;
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& current_thread;
|
||||
ar& ready_queue;
|
||||
ar& wakeup_callback_table;
|
||||
ar& thread_list;
|
||||
}
|
||||
};
|
||||
|
||||
class Thread final : public WaitObject {
|
||||
|
@ -276,30 +303,34 @@ public:
|
|||
VAddr tls_address; ///< Virtual address of the Thread Local Storage of the thread
|
||||
|
||||
/// Mutexes currently held by this thread, which will be released when it exits.
|
||||
boost::container::flat_set<std::shared_ptr<Mutex>> held_mutexes;
|
||||
boost::container::flat_set<std::shared_ptr<Mutex>> held_mutexes{};
|
||||
|
||||
/// Mutexes that this thread is currently waiting for.
|
||||
boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes;
|
||||
boost::container::flat_set<std::shared_ptr<Mutex>> pending_mutexes{};
|
||||
|
||||
Process* owner_process; ///< Process that owns this thread
|
||||
std::shared_ptr<Process> owner_process{}; ///< Process that owns this thread
|
||||
|
||||
/// Objects that the thread is waiting on, in the same order as they were
|
||||
// passed to WaitSynchronization1/N.
|
||||
std::vector<std::shared_ptr<WaitObject>> wait_objects;
|
||||
std::vector<std::shared_ptr<WaitObject>> wait_objects{};
|
||||
|
||||
VAddr wait_address; ///< If waiting on an AddressArbiter, this is the arbitration address
|
||||
|
||||
std::string name;
|
||||
std::string name{};
|
||||
|
||||
using WakeupCallback = void(ThreadWakeupReason reason, std::shared_ptr<Thread> thread,
|
||||
std::shared_ptr<WaitObject> object);
|
||||
// Callback that will be invoked when the thread is resumed from a waiting state. If the thread
|
||||
// was waiting via WaitSynchronizationN then the object will be the last object that became
|
||||
// available. In case of a timeout, the object will be nullptr.
|
||||
std::function<WakeupCallback> wakeup_callback;
|
||||
std::shared_ptr<WakeupCallback> wakeup_callback{};
|
||||
|
||||
const u32 core_id;
|
||||
|
||||
private:
|
||||
ThreadManager& thread_manager;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -314,3 +345,22 @@ std::shared_ptr<Thread> SetupMainThread(KernelSystem& kernel, u32 entry_point, u
|
|||
std::shared_ptr<Process> owner_process);
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::Thread)
|
||||
|
||||
namespace boost::serialization {
|
||||
|
||||
template <class Archive>
|
||||
inline void save_construct_data(Archive& ar, const Kernel::Thread* t,
|
||||
const unsigned int file_version) {
|
||||
ar << t->core_id;
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
inline void load_construct_data(Archive& ar, Kernel::Thread* t, const unsigned int file_version) {
|
||||
u32 core_id;
|
||||
ar >> core_id;
|
||||
::new (t) Kernel::Thread(Core::Global<Kernel::KernelSystem>(), core_id);
|
||||
}
|
||||
|
||||
} // namespace boost::serialization
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <cinttypes>
|
||||
#include <unordered_map>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
|
@ -12,6 +13,8 @@
|
|||
#include "core/hle/kernel/thread.h"
|
||||
#include "core/hle/kernel/timer.h"
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Kernel::Timer)
|
||||
|
||||
namespace Kernel {
|
||||
|
||||
Timer::Timer(KernelSystem& kernel)
|
||||
|
|
|
@ -4,6 +4,8 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <boost/serialization/string.hpp>
|
||||
#include <boost/serialization/unordered_map.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
@ -33,6 +35,13 @@ private:
|
|||
|
||||
friend class Timer;
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& next_timer_callback_id;
|
||||
ar& timer_callback_table;
|
||||
}
|
||||
};
|
||||
|
||||
class Timer final : public WaitObject {
|
||||
|
@ -103,6 +112,21 @@ private:
|
|||
TimerManager& timer_manager;
|
||||
|
||||
friend class KernelSystem;
|
||||
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<WaitObject>(*this);
|
||||
ar& reset_type;
|
||||
ar& initial_delay;
|
||||
ar& interval_delay;
|
||||
ar& signaled;
|
||||
ar& name;
|
||||
ar& callback_id;
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace Kernel
|
||||
|
||||
BOOST_CLASS_EXPORT_KEY(Kernel::Timer)
|
||||
CONSTRUCT_KERNEL_OBJECT(Kernel::Timer)
|
||||
|
|
|
@ -27,7 +27,8 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
|
|||
type != next.type) {
|
||||
return false;
|
||||
}
|
||||
if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) {
|
||||
if (type == VMAType::BackingMemory &&
|
||||
backing_memory.GetPtr() + size != next.backing_memory.GetPtr()) {
|
||||
return false;
|
||||
}
|
||||
if (type == VMAType::MMIO && paddr + size != next.paddr) {
|
||||
|
@ -36,7 +37,8 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const {
|
|||
return true;
|
||||
}
|
||||
|
||||
VMManager::VMManager(Memory::MemorySystem& memory) : memory(memory) {
|
||||
VMManager::VMManager(Memory::MemorySystem& memory)
|
||||
: memory(memory), page_table(std::make_shared<Memory::PageTable>()) {
|
||||
Reset();
|
||||
}
|
||||
|
||||
|
@ -50,8 +52,7 @@ void VMManager::Reset() {
|
|||
initial_vma.size = MAX_ADDRESS;
|
||||
vma_map.emplace(initial_vma.base, initial_vma);
|
||||
|
||||
page_table.pointers.fill(nullptr);
|
||||
page_table.attributes.fill(Memory::PageType::Unmapped);
|
||||
page_table->Clear();
|
||||
|
||||
UpdatePageTableForVMA(initial_vma);
|
||||
}
|
||||
|
@ -64,7 +65,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const {
|
|||
}
|
||||
}
|
||||
|
||||
ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory,
|
||||
ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory,
|
||||
u32 size, MemoryState state) {
|
||||
|
||||
// Find the first Free VMA.
|
||||
|
@ -93,9 +94,9 @@ ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size,
|
|||
return MakeResult<VAddr>(target);
|
||||
}
|
||||
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size,
|
||||
MemoryState state) {
|
||||
ASSERT(memory != nullptr);
|
||||
ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, MemoryRef memory,
|
||||
u32 size, MemoryState state) {
|
||||
ASSERT(memory.GetPtr() != nullptr);
|
||||
|
||||
// This is the appropriately sized VMA that will turn into our allocation.
|
||||
CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size));
|
||||
|
@ -351,20 +352,20 @@ VMManager::VMAIter VMManager::MergeAdjacent(VMAIter iter) {
|
|||
void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) {
|
||||
switch (vma.type) {
|
||||
case VMAType::Free:
|
||||
memory.UnmapRegion(page_table, vma.base, vma.size);
|
||||
memory.UnmapRegion(*page_table, vma.base, vma.size);
|
||||
break;
|
||||
case VMAType::BackingMemory:
|
||||
memory.MapMemoryRegion(page_table, vma.base, vma.size, vma.backing_memory);
|
||||
memory.MapMemoryRegion(*page_table, vma.base, vma.size, vma.backing_memory);
|
||||
break;
|
||||
case VMAType::MMIO:
|
||||
memory.MapIoRegion(page_table, vma.base, vma.size, vma.mmio_handler);
|
||||
memory.MapIoRegion(*page_table, vma.base, vma.size, vma.mmio_handler);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
ResultVal<std::vector<std::pair<u8*, u32>>> VMManager::GetBackingBlocksForRange(VAddr address,
|
||||
u32 size) {
|
||||
std::vector<std::pair<u8*, u32>> backing_blocks;
|
||||
ResultVal<std::vector<std::pair<MemoryRef, u32>>> VMManager::GetBackingBlocksForRange(VAddr address,
|
||||
u32 size) {
|
||||
std::vector<std::pair<MemoryRef, u32>> backing_blocks;
|
||||
VAddr interval_target = address;
|
||||
while (interval_target != address + size) {
|
||||
auto vma = FindVMA(interval_target);
|
||||
|
@ -375,7 +376,7 @@ ResultVal<std::vector<std::pair<u8*, u32>>> VMManager::GetBackingBlocksForRange(
|
|||
|
||||
VAddr interval_end = std::min(address + size, vma->second.base + vma->second.size);
|
||||
u32 interval_size = interval_end - interval_target;
|
||||
u8* backing_memory = vma->second.backing_memory + (interval_target - vma->second.base);
|
||||
auto backing_memory = vma->second.backing_memory + (interval_target - vma->second.base);
|
||||
backing_blocks.push_back({backing_memory, interval_size});
|
||||
|
||||
interval_target += interval_size;
|
||||
|
|
|
@ -8,7 +8,11 @@
|
|||
#include <memory>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
#include <boost/serialization/map.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/split_member.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "common/memory_ref.h"
|
||||
#include "core/hle/result.h"
|
||||
#include "core/memory.h"
|
||||
#include "core/mmio.h"
|
||||
|
@ -71,7 +75,7 @@ struct VirtualMemoryArea {
|
|||
|
||||
// Settings for type = BackingMemory
|
||||
/// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
|
||||
u8* backing_memory = nullptr;
|
||||
MemoryRef backing_memory{};
|
||||
|
||||
// Settings for type = MMIO
|
||||
/// Physical address of the register area this VMA maps to.
|
||||
|
@ -80,6 +84,20 @@ struct VirtualMemoryArea {
|
|||
|
||||
/// Tests if this area can be merged to the right with `next`.
|
||||
bool CanBeMergedWith(const VirtualMemoryArea& next) const;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& base;
|
||||
ar& size;
|
||||
ar& type;
|
||||
ar& permissions;
|
||||
ar& meminfo_state;
|
||||
ar& backing_memory;
|
||||
ar& paddr;
|
||||
ar& mmio_handler;
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -134,7 +152,7 @@ public:
|
|||
* @param state MemoryState tag to attach to the VMA.
|
||||
* @returns The address at which the memory was mapped.
|
||||
*/
|
||||
ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory, u32 size,
|
||||
ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory, u32 size,
|
||||
MemoryState state);
|
||||
/**
|
||||
* Maps an unmanaged host memory pointer at a given address.
|
||||
|
@ -144,7 +162,8 @@ public:
|
|||
* @param size Size of the mapping.
|
||||
* @param state MemoryState tag to attach to the VMA.
|
||||
*/
|
||||
ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state);
|
||||
ResultVal<VMAHandle> MapBackingMemory(VAddr target, MemoryRef memory, u32 size,
|
||||
MemoryState state);
|
||||
|
||||
/**
|
||||
* Maps a memory-mapped IO region at a given address.
|
||||
|
@ -186,11 +205,12 @@ public:
|
|||
void LogLayout(Log::Level log_level) const;
|
||||
|
||||
/// Gets a list of backing memory blocks for the specified range
|
||||
ResultVal<std::vector<std::pair<u8*, u32>>> GetBackingBlocksForRange(VAddr address, u32 size);
|
||||
ResultVal<std::vector<std::pair<MemoryRef, u32>>> GetBackingBlocksForRange(VAddr address,
|
||||
u32 size);
|
||||
|
||||
/// Each VMManager has its own page table, which is set as the main one when the owning process
|
||||
/// is scheduled.
|
||||
Memory::PageTable page_table;
|
||||
std::shared_ptr<Memory::PageTable> page_table;
|
||||
|
||||
private:
|
||||
using VMAIter = decltype(vma_map)::iterator;
|
||||
|
@ -229,5 +249,12 @@ private:
|
|||
void UpdatePageTableForVMA(const VirtualMemoryArea& vma);
|
||||
|
||||
Memory::MemorySystem& memory;
|
||||
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& vma_map;
|
||||
ar& page_table;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
} // namespace Kernel
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
#include <algorithm>
|
||||
#include <utility>
|
||||
#include "common/archives.h"
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/hle/kernel/errors.h"
|
||||
|
@ -16,6 +17,15 @@
|
|||
|
||||
namespace Kernel {
|
||||
|
||||
template <class Archive>
|
||||
void WaitObject::serialize(Archive& ar, const unsigned int file_version) {
|
||||
ar& boost::serialization::base_object<Object>(*this);
|
||||
ar& waiting_threads;
|
||||
// NB: hle_notifier *not* serialized since it's a callback!
|
||||
// Fortunately it's only used in one place (DSP) so we can reconstruct it there
|
||||
}
|
||||
SERIALIZE_IMPL(WaitObject)
|
||||
|
||||
void WaitObject::AddWaitingThread(std::shared_ptr<Thread> thread) {
|
||||
auto itr = std::find(waiting_threads.begin(), waiting_threads.end(), thread);
|
||||
if (itr == waiting_threads.end())
|
||||
|
@ -80,7 +90,7 @@ void WaitObject::WakeupAllWaitingThreads() {
|
|||
|
||||
// Invoke the wakeup callback before clearing the wait objects
|
||||
if (thread->wakeup_callback)
|
||||
thread->wakeup_callback(ThreadWakeupReason::Signal, thread, SharedFrom(this));
|
||||
thread->wakeup_callback->WakeUp(ThreadWakeupReason::Signal, thread, SharedFrom(this));
|
||||
|
||||
for (auto& object : thread->wait_objects)
|
||||
object->RemoveWaitingThread(thread.get());
|
||||
|
|
|
@ -7,6 +7,9 @@
|
|||
#include <functional>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <boost/serialization/base_object.hpp>
|
||||
#include <boost/serialization/shared_ptr.hpp>
|
||||
#include <boost/serialization/vector.hpp>
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/kernel/object.h"
|
||||
|
||||
|
@ -62,6 +65,11 @@ private:
|
|||
|
||||
/// Function to call when this object becomes available
|
||||
std::function<void()> hle_notifier;
|
||||
|
||||
private:
|
||||
friend class boost::serialization::access;
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
};
|
||||
|
||||
// Specialization of DynamicObjectCast for WaitObjects
|
||||
|
|
|
@ -6,6 +6,7 @@
|
|||
|
||||
#include <new>
|
||||
#include <utility>
|
||||
#include <boost/serialization/access.hpp>
|
||||
#include "common/assert.h"
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_funcs.h"
|
||||
|
@ -225,6 +226,13 @@ union ResultCode {
|
|||
constexpr bool IsError() const {
|
||||
return is_error.ExtractValue(raw) == 1;
|
||||
}
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int) {
|
||||
ar& raw;
|
||||
}
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
constexpr bool operator==(const ResultCode& a, const ResultCode& b) {
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
// Refer to the license.txt file included.
|
||||
|
||||
#include <vector>
|
||||
#include "common/archives.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
|
@ -179,4 +180,15 @@ void InstallInterfaces(Core::System& system) {
|
|||
std::make_shared<AC_U>(ac)->InstallAsService(service_manager);
|
||||
}
|
||||
|
||||
template <class Archive>
|
||||
void Module::serialize(Archive& ar, const unsigned int) {
|
||||
ar& ac_connected;
|
||||
ar& close_event;
|
||||
ar& connect_event;
|
||||
ar& disconnect_event;
|
||||
// default_config is never written to
|
||||
}
|
||||
|
||||
} // namespace Service::AC
|
||||
|
||||
SERIALIZE_IMPL(Service::AC::Module)
|
||||
|
|
|
@ -153,6 +153,11 @@ protected:
|
|||
std::shared_ptr<Kernel::Event> close_event;
|
||||
std::shared_ptr<Kernel::Event> connect_event;
|
||||
std::shared_ptr<Kernel::Event> disconnect_event;
|
||||
|
||||
private:
|
||||
template <class Archive>
|
||||
void serialize(Archive& ar, const unsigned int file_version);
|
||||
friend class boost::serialization::access;
|
||||
};
|
||||
|
||||
void InstallInterfaces(Core::System& system);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/archives.h"
|
||||
#include "core/hle/service/ac/ac_i.h"
|
||||
|
||||
namespace Service::AC {
|
||||
|
@ -33,3 +34,5 @@ AC_I::AC_I(std::shared_ptr<Module> ac) : Module::Interface(std::move(ac), "ac:i"
|
|||
}
|
||||
|
||||
} // namespace Service::AC
|
||||
|
||||
SERIALIZE_EXPORT_IMPL(Service::AC::AC_I)
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue