Merge pull request #4616 from wwylele/core-global-clean
Cleanup System::GetInstance reference - Part 1
This commit is contained in:
commit
c265f3f507
|
@ -73,7 +73,7 @@ class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks {
|
||||||
public:
|
public:
|
||||||
explicit DynarmicUserCallbacks(ARM_Dynarmic& parent)
|
explicit DynarmicUserCallbacks(ARM_Dynarmic& parent)
|
||||||
: parent(parent), timing(parent.system.CoreTiming()), svc_context(parent.system),
|
: parent(parent), timing(parent.system.CoreTiming()), svc_context(parent.system),
|
||||||
memory(parent.system.Memory()) {}
|
memory(parent.memory) {}
|
||||||
~DynarmicUserCallbacks() = default;
|
~DynarmicUserCallbacks() = default;
|
||||||
|
|
||||||
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
||||||
|
@ -163,9 +163,10 @@ public:
|
||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode)
|
ARM_Dynarmic::ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory,
|
||||||
: system(system), cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
PrivilegeMode initial_mode)
|
||||||
interpreter_state = std::make_shared<ARMul_State>(system, initial_mode);
|
: system(*system), memory(memory), cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
||||||
|
interpreter_state = std::make_shared<ARMul_State>(system, memory, initial_mode);
|
||||||
PageTableChanged();
|
PageTableChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -174,7 +175,7 @@ ARM_Dynarmic::~ARM_Dynarmic() = default;
|
||||||
MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
|
MICROPROFILE_DEFINE(ARM_Jit, "ARM JIT", "ARM JIT", MP_RGB(255, 64, 64));
|
||||||
|
|
||||||
void ARM_Dynarmic::Run() {
|
void ARM_Dynarmic::Run() {
|
||||||
ASSERT(system.Memory().GetCurrentPageTable() == current_page_table);
|
ASSERT(memory.GetCurrentPageTable() == current_page_table);
|
||||||
MICROPROFILE_SCOPE(ARM_Jit);
|
MICROPROFILE_SCOPE(ARM_Jit);
|
||||||
|
|
||||||
jit->Run();
|
jit->Run();
|
||||||
|
@ -281,7 +282,7 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic::PageTableChanged() {
|
void ARM_Dynarmic::PageTableChanged() {
|
||||||
current_page_table = system.Memory().GetCurrentPageTable();
|
current_page_table = memory.GetCurrentPageTable();
|
||||||
|
|
||||||
auto iter = jits.find(current_page_table);
|
auto iter = jits.find(current_page_table);
|
||||||
if (iter != jits.end()) {
|
if (iter != jits.end()) {
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
|
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
struct PageTable;
|
struct PageTable;
|
||||||
|
class MemorySystem;
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
@ -23,7 +24,7 @@ class DynarmicUserCallbacks;
|
||||||
|
|
||||||
class ARM_Dynarmic final : public ARM_Interface {
|
class ARM_Dynarmic final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode);
|
ARM_Dynarmic(Core::System* system, Memory::MemorySystem& memory, PrivilegeMode initial_mode);
|
||||||
~ARM_Dynarmic();
|
~ARM_Dynarmic();
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
|
@ -55,6 +56,7 @@ public:
|
||||||
private:
|
private:
|
||||||
friend class DynarmicUserCallbacks;
|
friend class DynarmicUserCallbacks;
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
std::unique_ptr<DynarmicUserCallbacks> cb;
|
std::unique_ptr<DynarmicUserCallbacks> cb;
|
||||||
std::unique_ptr<Dynarmic::A32::Jit> MakeJit();
|
std::unique_ptr<Dynarmic::A32::Jit> MakeJit();
|
||||||
|
|
||||||
|
|
|
@ -68,14 +68,17 @@ private:
|
||||||
u32 fpexc;
|
u32 fpexc;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_DynCom::ARM_DynCom(Core::System& system, PrivilegeMode initial_mode) : system(system) {
|
ARM_DynCom::ARM_DynCom(Core::System* system, Memory::MemorySystem& memory,
|
||||||
state = std::make_unique<ARMul_State>(system, initial_mode);
|
PrivilegeMode initial_mode)
|
||||||
|
: system(system) {
|
||||||
|
state = std::make_unique<ARMul_State>(system, memory, initial_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARM_DynCom::~ARM_DynCom() {}
|
ARM_DynCom::~ARM_DynCom() {}
|
||||||
|
|
||||||
void ARM_DynCom::Run() {
|
void ARM_DynCom::Run() {
|
||||||
ExecuteInstructions(std::max<s64>(system.CoreTiming().GetDowncount(), 0));
|
DEBUG_ASSERT(system != nullptr);
|
||||||
|
ExecuteInstructions(std::max<s64>(system->CoreTiming().GetDowncount(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_DynCom::Step() {
|
void ARM_DynCom::Step() {
|
||||||
|
@ -146,7 +149,9 @@ void ARM_DynCom::SetCP15Register(CP15Register reg, u32 value) {
|
||||||
void ARM_DynCom::ExecuteInstructions(u64 num_instructions) {
|
void ARM_DynCom::ExecuteInstructions(u64 num_instructions) {
|
||||||
state->NumInstrsToExecute = num_instructions;
|
state->NumInstrsToExecute = num_instructions;
|
||||||
unsigned ticks_executed = InterpreterMainLoop(state.get());
|
unsigned ticks_executed = InterpreterMainLoop(state.get());
|
||||||
system.CoreTiming().AddTicks(ticks_executed);
|
if (system != nullptr) {
|
||||||
|
system->CoreTiming().AddTicks(ticks_executed);
|
||||||
|
}
|
||||||
state->ServeBreak();
|
state->ServeBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -14,9 +14,14 @@ namespace Core {
|
||||||
struct System;
|
struct System;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
class ARM_DynCom final : public ARM_Interface {
|
class ARM_DynCom final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
explicit ARM_DynCom(Core::System& system, PrivilegeMode initial_mode);
|
explicit ARM_DynCom(Core::System* system, Memory::MemorySystem& memory,
|
||||||
|
PrivilegeMode initial_mode);
|
||||||
~ARM_DynCom();
|
~ARM_DynCom();
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
|
@ -48,6 +53,6 @@ public:
|
||||||
private:
|
private:
|
||||||
void ExecuteInstructions(u64 num_instructions);
|
void ExecuteInstructions(u64 num_instructions);
|
||||||
|
|
||||||
Core::System& system;
|
Core::System* system;
|
||||||
std::unique_ptr<ARMul_State> state;
|
std::unique_ptr<ARMul_State> state;
|
||||||
};
|
};
|
||||||
|
|
|
@ -811,7 +811,7 @@ MICROPROFILE_DEFINE(DynCom_Decode, "DynCom", "Decode", MP_RGB(255, 64, 64));
|
||||||
static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr,
|
static unsigned int InterpreterTranslateInstruction(const ARMul_State* cpu, const u32 phys_addr,
|
||||||
ARM_INST_PTR& inst_base) {
|
ARM_INST_PTR& inst_base) {
|
||||||
u32 inst_size = 4;
|
u32 inst_size = 4;
|
||||||
u32 inst = cpu->system.Memory().Read32(phys_addr & 0xFFFFFFFC);
|
u32 inst = cpu->memory.Read32(phys_addr & 0xFFFFFFFC);
|
||||||
|
|
||||||
// If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM
|
// If we are in Thumb mode, we'll translate one Thumb instruction to the corresponding ARM
|
||||||
// instruction
|
// instruction
|
||||||
|
@ -3859,12 +3859,13 @@ SUB_INST : {
|
||||||
}
|
}
|
||||||
SWI_INST : {
|
SWI_INST : {
|
||||||
if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
|
if (inst_base->cond == ConditionCode::AL || CondPassed(cpu, inst_base->cond)) {
|
||||||
|
DEBUG_ASSERT(cpu->system != nullptr);
|
||||||
swi_inst* const inst_cream = (swi_inst*)inst_base->component;
|
swi_inst* const inst_cream = (swi_inst*)inst_base->component;
|
||||||
cpu->system.CoreTiming().AddTicks(num_instrs);
|
cpu->system->CoreTiming().AddTicks(num_instrs);
|
||||||
cpu->NumInstrsToExecute =
|
cpu->NumInstrsToExecute =
|
||||||
num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
|
num_instrs >= cpu->NumInstrsToExecute ? 0 : cpu->NumInstrsToExecute - num_instrs;
|
||||||
num_instrs = 0;
|
num_instrs = 0;
|
||||||
Kernel::SVCContext{cpu->system}.CallSVC(inst_cream->num & 0xFFFF);
|
Kernel::SVCContext{*cpu->system}.CallSVC(inst_cream->num & 0xFFFF);
|
||||||
// The kernel would call ERET to get here, which clears exclusive memory state.
|
// The kernel would call ERET to get here, which clears exclusive memory state.
|
||||||
cpu->UnsetExclusiveMemoryAddress();
|
cpu->UnsetExclusiveMemoryAddress();
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,7 +10,9 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
ARMul_State::ARMul_State(Core::System& system, PrivilegeMode initial_mode) : system(system) {
|
ARMul_State::ARMul_State(Core::System* system, Memory::MemorySystem& memory,
|
||||||
|
PrivilegeMode initial_mode)
|
||||||
|
: system(system), memory(memory) {
|
||||||
Reset();
|
Reset();
|
||||||
ChangePrivilegeMode(initial_mode);
|
ChangePrivilegeMode(initial_mode);
|
||||||
}
|
}
|
||||||
|
@ -191,13 +193,13 @@ static void CheckMemoryBreakpoint(u32 address, GDBStub::BreakpointType type) {
|
||||||
u8 ARMul_State::ReadMemory8(u32 address) const {
|
u8 ARMul_State::ReadMemory8(u32 address) const {
|
||||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||||
|
|
||||||
return system.Memory().Read8(address);
|
return memory.Read8(address);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 ARMul_State::ReadMemory16(u32 address) const {
|
u16 ARMul_State::ReadMemory16(u32 address) const {
|
||||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||||
|
|
||||||
u16 data = system.Memory().Read16(address);
|
u16 data = memory.Read16(address);
|
||||||
|
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap16(data);
|
data = Common::swap16(data);
|
||||||
|
@ -208,7 +210,7 @@ u16 ARMul_State::ReadMemory16(u32 address) const {
|
||||||
u32 ARMul_State::ReadMemory32(u32 address) const {
|
u32 ARMul_State::ReadMemory32(u32 address) const {
|
||||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||||
|
|
||||||
u32 data = system.Memory().Read32(address);
|
u32 data = memory.Read32(address);
|
||||||
|
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap32(data);
|
data = Common::swap32(data);
|
||||||
|
@ -219,7 +221,7 @@ u32 ARMul_State::ReadMemory32(u32 address) const {
|
||||||
u64 ARMul_State::ReadMemory64(u32 address) const {
|
u64 ARMul_State::ReadMemory64(u32 address) const {
|
||||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Read);
|
||||||
|
|
||||||
u64 data = system.Memory().Read64(address);
|
u64 data = memory.Read64(address);
|
||||||
|
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap64(data);
|
data = Common::swap64(data);
|
||||||
|
@ -230,7 +232,7 @@ u64 ARMul_State::ReadMemory64(u32 address) const {
|
||||||
void ARMul_State::WriteMemory8(u32 address, u8 data) {
|
void ARMul_State::WriteMemory8(u32 address, u8 data) {
|
||||||
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
CheckMemoryBreakpoint(address, GDBStub::BreakpointType::Write);
|
||||||
|
|
||||||
system.Memory().Write8(address, data);
|
memory.Write8(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
||||||
|
@ -239,7 +241,7 @@ void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap16(data);
|
data = Common::swap16(data);
|
||||||
|
|
||||||
system.Memory().Write16(address, data);
|
memory.Write16(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
||||||
|
@ -248,7 +250,7 @@ void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap32(data);
|
data = Common::swap32(data);
|
||||||
|
|
||||||
system.Memory().Write32(address, data);
|
memory.Write32(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
||||||
|
@ -257,7 +259,7 @@ void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap64(data);
|
data = Common::swap64(data);
|
||||||
|
|
||||||
system.Memory().Write64(address, data);
|
memory.Write64(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reads from the CP15 registers. Used with implementation of the MRC instruction.
|
// Reads from the CP15 registers. Used with implementation of the MRC instruction.
|
||||||
|
@ -603,8 +605,9 @@ void ARMul_State::ServeBreak() {
|
||||||
if (last_bkpt_hit) {
|
if (last_bkpt_hit) {
|
||||||
Reg[15] = last_bkpt.address;
|
Reg[15] = last_bkpt.address;
|
||||||
}
|
}
|
||||||
Kernel::Thread* thread = system.Kernel().GetThreadManager().GetCurrentThread();
|
DEBUG_ASSERT(system != nullptr);
|
||||||
system.CPU().SaveContext(thread->context);
|
Kernel::Thread* thread = system->Kernel().GetThreadManager().GetCurrentThread();
|
||||||
|
system->CPU().SaveContext(thread->context);
|
||||||
if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
|
if (last_bkpt_hit || GDBStub::GetCpuStepFlag()) {
|
||||||
last_bkpt_hit = false;
|
last_bkpt_hit = false;
|
||||||
GDBStub::Break();
|
GDBStub::Break();
|
||||||
|
|
|
@ -27,6 +27,10 @@ namespace Core {
|
||||||
class System;
|
class System;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
// Signal levels
|
// Signal levels
|
||||||
enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 };
|
enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 };
|
||||||
|
|
||||||
|
@ -143,7 +147,8 @@ enum {
|
||||||
|
|
||||||
struct ARMul_State final {
|
struct ARMul_State final {
|
||||||
public:
|
public:
|
||||||
explicit ARMul_State(Core::System& system, PrivilegeMode initial_mode);
|
explicit ARMul_State(Core::System* system, Memory::MemorySystem& memory,
|
||||||
|
PrivilegeMode initial_mode);
|
||||||
|
|
||||||
void ChangePrivilegeMode(u32 new_mode);
|
void ChangePrivilegeMode(u32 new_mode);
|
||||||
void Reset();
|
void Reset();
|
||||||
|
@ -201,7 +206,8 @@ public:
|
||||||
|
|
||||||
void ServeBreak();
|
void ServeBreak();
|
||||||
|
|
||||||
Core::System& system;
|
Core::System* system;
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
|
|
||||||
std::array<u32, 16> Reg{}; // The current register file
|
std::array<u32, 16> Reg{}; // The current register file
|
||||||
std::array<u32, 2> Reg_usr{};
|
std::array<u32, 2> Reg_usr{};
|
||||||
|
|
|
@ -174,19 +174,23 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
||||||
|
|
||||||
timing = std::make_unique<Timing>();
|
timing = std::make_unique<Timing>();
|
||||||
|
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(*memory, system_mode);
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing,
|
||||||
|
[this] { PrepareReschedule(); }, system_mode);
|
||||||
|
|
||||||
if (Settings::values.use_cpu_jit) {
|
if (Settings::values.use_cpu_jit) {
|
||||||
#ifdef ARCHITECTURE_x86_64
|
#ifdef ARCHITECTURE_x86_64
|
||||||
cpu_core = std::make_unique<ARM_Dynarmic>(*this, USER32MODE);
|
cpu_core = std::make_unique<ARM_Dynarmic>(this, *memory, USER32MODE);
|
||||||
#else
|
#else
|
||||||
cpu_core = std::make_unique<ARM_DynCom>(*this, USER32MODE);
|
cpu_core = std::make_unique<ARM_DynCom>(this, *memory, USER32MODE);
|
||||||
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
LOG_WARNING(Core, "CPU JIT requested, but Dynarmic not available");
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
cpu_core = std::make_unique<ARM_DynCom>(*this, USER32MODE);
|
cpu_core = std::make_unique<ARM_DynCom>(this, *memory, USER32MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
kernel->GetThreadManager().SetCPU(*cpu_core);
|
||||||
|
memory->SetCPU(*cpu_core);
|
||||||
|
|
||||||
if (Settings::values.enable_dsp_lle) {
|
if (Settings::values.enable_dsp_lle) {
|
||||||
dsp_core = std::make_unique<AudioCore::DspLle>(*memory,
|
dsp_core = std::make_unique<AudioCore::DspLle>(*memory,
|
||||||
Settings::values.enable_dsp_lle_multithread);
|
Settings::values.enable_dsp_lle_multithread);
|
||||||
|
|
|
@ -270,8 +270,6 @@ private:
|
||||||
|
|
||||||
std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
|
std::unique_ptr<Service::FS::ArchiveManager> archive_manager;
|
||||||
|
|
||||||
public: // HACK: this is temporary exposed for tests,
|
|
||||||
// due to WIP kernel refactor causing desync state in memory
|
|
||||||
std::unique_ptr<Memory::MemorySystem> memory;
|
std::unique_ptr<Memory::MemorySystem> memory;
|
||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
std::unique_ptr<Timing> timing;
|
std::unique_ptr<Timing> timing;
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread> dst_thread,
|
ResultCode TranslateCommandBuffer(Memory::MemorySystem& memory, SharedPtr<Thread> src_thread,
|
||||||
VAddr src_address, VAddr dst_address,
|
SharedPtr<Thread> dst_thread, VAddr src_address,
|
||||||
|
VAddr dst_address,
|
||||||
std::vector<MappedBufferContext>& mapped_buffer_context,
|
std::vector<MappedBufferContext>& mapped_buffer_context,
|
||||||
bool reply) {
|
bool reply) {
|
||||||
Memory::MemorySystem& memory = Core::System::GetInstance().Memory();
|
|
||||||
auto& src_process = src_thread->owner_process;
|
auto& src_process = src_thread->owner_process;
|
||||||
auto& dst_process = dst_thread->owner_process;
|
auto& dst_process = dst_thread->owner_process;
|
||||||
|
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/thread.h"
|
#include "core/hle/kernel/thread.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
struct MappedBufferContext {
|
struct MappedBufferContext {
|
||||||
|
@ -23,8 +27,9 @@ struct MappedBufferContext {
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Performs IPC command buffer translation from one process to another.
|
/// Performs IPC command buffer translation from one process to another.
|
||||||
ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread> dst_thread,
|
ResultCode TranslateCommandBuffer(Memory::MemorySystem& memory, SharedPtr<Thread> src_thread,
|
||||||
VAddr src_address, VAddr dst_address,
|
SharedPtr<Thread> dst_thread, VAddr src_address,
|
||||||
|
VAddr dst_address,
|
||||||
std::vector<MappedBufferContext>& mapped_buffer_context,
|
std::vector<MappedBufferContext>& mapped_buffer_context,
|
||||||
bool reply);
|
bool reply);
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -16,12 +16,15 @@
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
/// Initialize the kernel
|
/// Initialize the kernel
|
||||||
KernelSystem::KernelSystem(Memory::MemorySystem& memory, u32 system_mode) : memory(memory) {
|
KernelSystem::KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
|
||||||
|
std::function<void()> prepare_reschedule_callback, u32 system_mode)
|
||||||
|
: memory(memory), timing(timing),
|
||||||
|
prepare_reschedule_callback(std::move(prepare_reschedule_callback)) {
|
||||||
MemoryInit(system_mode);
|
MemoryInit(system_mode);
|
||||||
|
|
||||||
resource_limits = std::make_unique<ResourceLimitList>(*this);
|
resource_limits = std::make_unique<ResourceLimitList>(*this);
|
||||||
thread_manager = std::make_unique<ThreadManager>(*this);
|
thread_manager = std::make_unique<ThreadManager>(*this);
|
||||||
timer_manager = std::make_unique<TimerManager>();
|
timer_manager = std::make_unique<TimerManager>(timing);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Shutdown the kernel
|
/// Shutdown the kernel
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
|
#include <functional>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
|
@ -27,6 +28,10 @@ namespace Memory {
|
||||||
class MemorySystem;
|
class MemorySystem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class Timing;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class AddressArbiter;
|
class AddressArbiter;
|
||||||
|
@ -78,7 +83,8 @@ using SharedPtr = boost::intrusive_ptr<T>;
|
||||||
|
|
||||||
class KernelSystem {
|
class KernelSystem {
|
||||||
public:
|
public:
|
||||||
explicit KernelSystem(Memory::MemorySystem& memory, u32 system_mode);
|
explicit KernelSystem(Memory::MemorySystem& memory, Core::Timing& timing,
|
||||||
|
std::function<void()> prepare_reschedule_callback, u32 system_mode);
|
||||||
~KernelSystem();
|
~KernelSystem();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -224,14 +230,22 @@ public:
|
||||||
/// Adds a port to the named port table
|
/// Adds a port to the named port table
|
||||||
void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
|
void AddNamedPort(std::string name, SharedPtr<ClientPort> port);
|
||||||
|
|
||||||
|
void PrepareReschedule() {
|
||||||
|
prepare_reschedule_callback();
|
||||||
|
}
|
||||||
|
|
||||||
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
|
/// Map of named ports managed by the kernel, which can be retrieved using the ConnectToPort
|
||||||
std::unordered_map<std::string, SharedPtr<ClientPort>> named_ports;
|
std::unordered_map<std::string, SharedPtr<ClientPort>> named_ports;
|
||||||
|
|
||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
|
|
||||||
|
Core::Timing& timing;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MemoryInit(u32 mem_type);
|
void MemoryInit(u32 mem_type);
|
||||||
|
|
||||||
|
std::function<void()> prepare_reschedule_callback;
|
||||||
|
|
||||||
std::unique_ptr<ResourceLimitList> resource_limits;
|
std::unique_ptr<ResourceLimitList> resource_limits;
|
||||||
std::atomic<u32> next_object_id{0};
|
std::atomic<u32> next_object_id{0};
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ void KernelSystem::MemoryInit(u32 mem_type) {
|
||||||
config_mem.sys_mem_alloc = memory_regions[1].size;
|
config_mem.sys_mem_alloc = memory_regions[1].size;
|
||||||
config_mem.base_mem_alloc = memory_regions[2].size;
|
config_mem.base_mem_alloc = memory_regions[2].size;
|
||||||
|
|
||||||
shared_page_handler = std::make_unique<SharedPage::Handler>();
|
shared_page_handler = std::make_unique<SharedPage::Handler>(timing);
|
||||||
}
|
}
|
||||||
|
|
||||||
MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
|
MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
|
||||||
|
|
|
@ -24,7 +24,7 @@ void ReleaseThreadMutexes(Thread* thread) {
|
||||||
thread->held_mutexes.clear();
|
thread->held_mutexes.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
Mutex::Mutex(KernelSystem& kernel) : WaitObject(kernel) {}
|
Mutex::Mutex(KernelSystem& kernel) : WaitObject(kernel), kernel(kernel) {}
|
||||||
Mutex::~Mutex() {}
|
Mutex::~Mutex() {}
|
||||||
|
|
||||||
SharedPtr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name) {
|
SharedPtr<Mutex> KernelSystem::CreateMutex(bool initial_locked, std::string name) {
|
||||||
|
@ -54,7 +54,7 @@ void Mutex::Acquire(Thread* thread) {
|
||||||
thread->held_mutexes.insert(this);
|
thread->held_mutexes.insert(this);
|
||||||
holding_thread = thread;
|
holding_thread = thread;
|
||||||
thread->UpdatePriority();
|
thread->UpdatePriority();
|
||||||
Core::System::GetInstance().PrepareReschedule();
|
kernel.PrepareReschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
lock_count++;
|
lock_count++;
|
||||||
|
@ -87,7 +87,7 @@ ResultCode Mutex::Release(Thread* thread) {
|
||||||
holding_thread->UpdatePriority();
|
holding_thread->UpdatePriority();
|
||||||
holding_thread = nullptr;
|
holding_thread = nullptr;
|
||||||
WakeupAllWaitingThreads();
|
WakeupAllWaitingThreads();
|
||||||
Core::System::GetInstance().PrepareReschedule();
|
kernel.PrepareReschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
|
|
@ -57,6 +57,7 @@ private:
|
||||||
~Mutex() override;
|
~Mutex() override;
|
||||||
|
|
||||||
friend class KernelSystem;
|
friend class KernelSystem;
|
||||||
|
KernelSystem& kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -37,7 +37,7 @@ static std::chrono::seconds GetInitTime() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Handler::Handler() {
|
Handler::Handler(Core::Timing& timing) : timing(timing) {
|
||||||
std::memset(&shared_page, 0, sizeof(shared_page));
|
std::memset(&shared_page, 0, sizeof(shared_page));
|
||||||
|
|
||||||
shared_page.running_hw = 0x1; // product
|
shared_page.running_hw = 0x1; // product
|
||||||
|
@ -54,9 +54,9 @@ Handler::Handler() {
|
||||||
init_time = GetInitTime();
|
init_time = GetInitTime();
|
||||||
|
|
||||||
using namespace std::placeholders;
|
using namespace std::placeholders;
|
||||||
update_time_event = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
update_time_event = timing.RegisterEvent("SharedPage::UpdateTimeCallback",
|
||||||
"SharedPage::UpdateTimeCallback", std::bind(&Handler::UpdateTimeCallback, this, _1, _2));
|
std::bind(&Handler::UpdateTimeCallback, this, _1, _2));
|
||||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(0, update_time_event);
|
timing.ScheduleEvent(0, update_time_event);
|
||||||
|
|
||||||
float slidestate =
|
float slidestate =
|
||||||
Settings::values.toggle_3d ? (float_le)Settings::values.factor_3d / 100 : 0.0f;
|
Settings::values.toggle_3d ? (float_le)Settings::values.factor_3d / 100 : 0.0f;
|
||||||
|
@ -66,8 +66,7 @@ Handler::Handler() {
|
||||||
/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond.
|
/// Gets system time in 3DS format. The epoch is Jan 1900, and the unit is millisecond.
|
||||||
u64 Handler::GetSystemTime() const {
|
u64 Handler::GetSystemTime() const {
|
||||||
std::chrono::milliseconds now =
|
std::chrono::milliseconds now =
|
||||||
init_time + std::chrono::duration_cast<std::chrono::milliseconds>(
|
init_time + std::chrono::duration_cast<std::chrono::milliseconds>(timing.GetGlobalTimeUs());
|
||||||
Core::System::GetInstance().CoreTiming().GetGlobalTimeUs());
|
|
||||||
|
|
||||||
// 3DS system does't allow user to set a time before Jan 1 2000,
|
// 3DS system does't allow user to set a time before Jan 1 2000,
|
||||||
// so we use it as an auxiliary epoch to calculate the console time.
|
// so we use it as an auxiliary epoch to calculate the console time.
|
||||||
|
@ -98,15 +97,14 @@ void Handler::UpdateTimeCallback(u64 userdata, int cycles_late) {
|
||||||
shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1;
|
shared_page.date_time_counter % 2 ? shared_page.date_time_0 : shared_page.date_time_1;
|
||||||
|
|
||||||
date_time.date_time = GetSystemTime();
|
date_time.date_time = GetSystemTime();
|
||||||
date_time.update_tick = Core::System::GetInstance().CoreTiming().GetTicks();
|
date_time.update_tick = timing.GetTicks();
|
||||||
date_time.tick_to_second_coefficient = BASE_CLOCK_RATE_ARM11;
|
date_time.tick_to_second_coefficient = BASE_CLOCK_RATE_ARM11;
|
||||||
date_time.tick_offset = 0;
|
date_time.tick_offset = 0;
|
||||||
|
|
||||||
++shared_page.date_time_counter;
|
++shared_page.date_time_counter;
|
||||||
|
|
||||||
// system time is updated hourly
|
// system time is updated hourly
|
||||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late,
|
timing.ScheduleEvent(msToCycles(60 * 60 * 1000) - cycles_late, update_time_event);
|
||||||
update_time_event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Handler::SetMacAddress(const MacAddress& addr) {
|
void Handler::SetMacAddress(const MacAddress& addr) {
|
||||||
|
|
|
@ -23,7 +23,8 @@
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
struct TimingEventType;
|
struct TimingEventType;
|
||||||
}
|
class Timing;
|
||||||
|
} // namespace Core
|
||||||
|
|
||||||
namespace SharedPage {
|
namespace SharedPage {
|
||||||
|
|
||||||
|
@ -83,7 +84,7 @@ static_assert(sizeof(SharedPageDef) == Memory::SHARED_PAGE_SIZE,
|
||||||
|
|
||||||
class Handler {
|
class Handler {
|
||||||
public:
|
public:
|
||||||
Handler();
|
Handler(Core::Timing& timing);
|
||||||
|
|
||||||
void SetMacAddress(const MacAddress&);
|
void SetMacAddress(const MacAddress&);
|
||||||
|
|
||||||
|
@ -98,6 +99,7 @@ public:
|
||||||
private:
|
private:
|
||||||
u64 GetSystemTime() const;
|
u64 GetSystemTime() const;
|
||||||
void UpdateTimeCallback(u64 userdata, int cycles_late);
|
void UpdateTimeCallback(u64 userdata, int cycles_late);
|
||||||
|
Core::Timing& timing;
|
||||||
Core::TimingEventType* update_time_event;
|
Core::TimingEventType* update_time_event;
|
||||||
std::chrono::seconds init_time;
|
std::chrono::seconds init_time;
|
||||||
|
|
||||||
|
|
|
@ -592,7 +592,8 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static ResultCode ReceiveIPCRequest(SharedPtr<ServerSession> server_session,
|
static ResultCode ReceiveIPCRequest(Memory::MemorySystem& memory,
|
||||||
|
SharedPtr<ServerSession> server_session,
|
||||||
SharedPtr<Thread> thread) {
|
SharedPtr<Thread> thread) {
|
||||||
if (server_session->parent->client == nullptr) {
|
if (server_session->parent->client == nullptr) {
|
||||||
return ERR_SESSION_CLOSED_BY_REMOTE;
|
return ERR_SESSION_CLOSED_BY_REMOTE;
|
||||||
|
@ -602,7 +603,7 @@ static ResultCode ReceiveIPCRequest(SharedPtr<ServerSession> server_session,
|
||||||
VAddr source_address = server_session->currently_handling->GetCommandBufferAddress();
|
VAddr source_address = server_session->currently_handling->GetCommandBufferAddress();
|
||||||
|
|
||||||
ResultCode translation_result =
|
ResultCode translation_result =
|
||||||
TranslateCommandBuffer(server_session->currently_handling, thread, source_address,
|
TranslateCommandBuffer(memory, server_session->currently_handling, thread, source_address,
|
||||||
target_address, server_session->mapped_buffer_context, false);
|
target_address, server_session->mapped_buffer_context, false);
|
||||||
|
|
||||||
// If a translation error occurred, immediately resume the client thread.
|
// If a translation error occurred, immediately resume the client thread.
|
||||||
|
@ -669,7 +670,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
VAddr target_address = request_thread->GetCommandBufferAddress();
|
VAddr target_address = request_thread->GetCommandBufferAddress();
|
||||||
|
|
||||||
ResultCode translation_result =
|
ResultCode translation_result =
|
||||||
TranslateCommandBuffer(thread, request_thread, source_address, target_address,
|
TranslateCommandBuffer(memory, thread, request_thread, source_address, target_address,
|
||||||
session->mapped_buffer_context, true);
|
session->mapped_buffer_context, true);
|
||||||
|
|
||||||
// Note: The real kernel seems to always panic if the Server->Client buffer translation
|
// Note: The real kernel seems to always panic if the Server->Client buffer translation
|
||||||
|
@ -705,7 +706,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
|
||||||
auto server_session = static_cast<ServerSession*>(object);
|
auto server_session = static_cast<ServerSession*>(object);
|
||||||
return ReceiveIPCRequest(server_session, thread);
|
return ReceiveIPCRequest(memory, server_session, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
// No objects were ready to be acquired, prepare to suspend the thread.
|
// No objects were ready to be acquired, prepare to suspend the thread.
|
||||||
|
@ -721,7 +722,8 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
|
|
||||||
thread->wait_objects = std::move(objects);
|
thread->wait_objects = std::move(objects);
|
||||||
|
|
||||||
thread->wakeup_callback = [](ThreadWakeupReason reason, SharedPtr<Thread> thread,
|
thread->wakeup_callback = [& memory = this->memory](ThreadWakeupReason reason,
|
||||||
|
SharedPtr<Thread> thread,
|
||||||
SharedPtr<WaitObject> object) {
|
SharedPtr<WaitObject> object) {
|
||||||
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
ASSERT(thread->status == ThreadStatus::WaitSynchAny);
|
||||||
ASSERT(reason == ThreadWakeupReason::Signal);
|
ASSERT(reason == ThreadWakeupReason::Signal);
|
||||||
|
@ -730,7 +732,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
|
|
||||||
if (object->GetHandleType() == HandleType::ServerSession) {
|
if (object->GetHandleType() == HandleType::ServerSession) {
|
||||||
auto server_session = DynamicObjectCast<ServerSession>(object);
|
auto server_session = DynamicObjectCast<ServerSession>(object);
|
||||||
result = ReceiveIPCRequest(server_session, thread);
|
result = ReceiveIPCRequest(memory, server_session, thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
thread->SetWaitSynchronizationResult(result);
|
thread->SetWaitSynchronizationResult(result);
|
||||||
|
|
|
@ -38,7 +38,7 @@ u32 ThreadManager::NewThreadId() {
|
||||||
}
|
}
|
||||||
|
|
||||||
Thread::Thread(KernelSystem& kernel)
|
Thread::Thread(KernelSystem& kernel)
|
||||||
: WaitObject(kernel), context(Core::CPU().NewContext()),
|
: WaitObject(kernel), context(kernel.GetThreadManager().NewContext()),
|
||||||
thread_manager(kernel.GetThreadManager()) {}
|
thread_manager(kernel.GetThreadManager()) {}
|
||||||
Thread::~Thread() {}
|
Thread::~Thread() {}
|
||||||
|
|
||||||
|
@ -48,8 +48,7 @@ Thread* ThreadManager::GetCurrentThread() const {
|
||||||
|
|
||||||
void Thread::Stop() {
|
void Thread::Stop() {
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
Core::System::GetInstance().CoreTiming().UnscheduleEvent(thread_manager.ThreadWakeupEventType,
|
thread_manager.kernel.timing.UnscheduleEvent(thread_manager.ThreadWakeupEventType, thread_id);
|
||||||
thread_id);
|
|
||||||
thread_manager.wakeup_callback_table.erase(thread_id);
|
thread_manager.wakeup_callback_table.erase(thread_id);
|
||||||
|
|
||||||
// Clean up thread from ready queue
|
// Clean up thread from ready queue
|
||||||
|
@ -81,12 +80,12 @@ void Thread::Stop() {
|
||||||
void ThreadManager::SwitchContext(Thread* new_thread) {
|
void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||||
Thread* previous_thread = GetCurrentThread();
|
Thread* previous_thread = GetCurrentThread();
|
||||||
|
|
||||||
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
Core::Timing& timing = kernel.timing;
|
||||||
|
|
||||||
// Save context for previous thread
|
// Save context for previous thread
|
||||||
if (previous_thread) {
|
if (previous_thread) {
|
||||||
previous_thread->last_running_ticks = timing.GetTicks();
|
previous_thread->last_running_ticks = timing.GetTicks();
|
||||||
Core::CPU().SaveContext(previous_thread->context);
|
cpu->SaveContext(previous_thread->context);
|
||||||
|
|
||||||
if (previous_thread->status == ThreadStatus::Running) {
|
if (previous_thread->status == ThreadStatus::Running) {
|
||||||
// This is only the case when a reschedule is triggered without the current thread
|
// This is only the case when a reschedule is triggered without the current thread
|
||||||
|
@ -117,8 +116,8 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||||
¤t_thread->owner_process->vm_manager.page_table);
|
¤t_thread->owner_process->vm_manager.page_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::CPU().LoadContext(new_thread->context);
|
cpu->LoadContext(new_thread->context);
|
||||||
Core::CPU().SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
|
cpu->SetCP15Register(CP15_THREAD_URO, new_thread->GetTLSAddress());
|
||||||
} else {
|
} else {
|
||||||
current_thread = nullptr;
|
current_thread = nullptr;
|
||||||
// Note: We do not reset the current process and current page table when idling because
|
// Note: We do not reset the current process and current page table when idling because
|
||||||
|
@ -186,8 +185,8 @@ void Thread::WakeAfterDelay(s64 nanoseconds) {
|
||||||
if (nanoseconds == -1)
|
if (nanoseconds == -1)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
thread_manager.kernel.timing.ScheduleEvent(nsToCycles(nanoseconds),
|
||||||
nsToCycles(nanoseconds), thread_manager.ThreadWakeupEventType, thread_id);
|
thread_manager.ThreadWakeupEventType, thread_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Thread::ResumeFromWait() {
|
void Thread::ResumeFromWait() {
|
||||||
|
@ -225,7 +224,7 @@ void Thread::ResumeFromWait() {
|
||||||
|
|
||||||
thread_manager.ready_queue.push_back(current_priority, this);
|
thread_manager.ready_queue.push_back(current_priority, this);
|
||||||
status = ThreadStatus::Ready;
|
status = ThreadStatus::Ready;
|
||||||
Core::System::GetInstance().PrepareReschedule();
|
thread_manager.kernel.PrepareReschedule();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ThreadManager::DebugThreadQueue() {
|
void ThreadManager::DebugThreadQueue() {
|
||||||
|
@ -320,7 +319,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
||||||
thread->entry_point = entry_point;
|
thread->entry_point = entry_point;
|
||||||
thread->stack_top = stack_top;
|
thread->stack_top = stack_top;
|
||||||
thread->nominal_priority = thread->current_priority = priority;
|
thread->nominal_priority = thread->current_priority = priority;
|
||||||
thread->last_running_ticks = Core::System::GetInstance().CoreTiming().GetTicks();
|
thread->last_running_ticks = timing.GetTicks();
|
||||||
thread->processor_id = processor_id;
|
thread->processor_id = processor_id;
|
||||||
thread->wait_objects.clear();
|
thread->wait_objects.clear();
|
||||||
thread->wait_address = 0;
|
thread->wait_address = 0;
|
||||||
|
@ -462,9 +461,10 @@ VAddr Thread::GetCommandBufferAddress() const {
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::ThreadManager(Kernel::KernelSystem& kernel) : kernel(kernel) {
|
ThreadManager::ThreadManager(Kernel::KernelSystem& kernel) : kernel(kernel) {
|
||||||
ThreadWakeupEventType = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
ThreadWakeupEventType =
|
||||||
"ThreadWakeupCallback",
|
kernel.timing.RegisterEvent("ThreadWakeupCallback", [this](u64 thread_id, s64 cycle_late) {
|
||||||
[this](u64 thread_id, s64 cycle_late) { ThreadWakeupCallback(thread_id, cycle_late); });
|
ThreadWakeupCallback(thread_id, cycle_late);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::~ThreadManager() {
|
ThreadManager::~ThreadManager() {
|
||||||
|
|
|
@ -101,6 +101,14 @@ public:
|
||||||
*/
|
*/
|
||||||
const std::vector<SharedPtr<Thread>>& GetThreadList();
|
const std::vector<SharedPtr<Thread>>& GetThreadList();
|
||||||
|
|
||||||
|
void SetCPU(ARM_Interface& cpu) {
|
||||||
|
this->cpu = &cpu;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::unique_ptr<ARM_Interface::ThreadContext> NewContext() {
|
||||||
|
return cpu->NewContext();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* Switches the CPU's active thread context to that of the specified thread
|
* Switches the CPU's active thread context to that of the specified thread
|
||||||
|
@ -122,6 +130,7 @@ private:
|
||||||
void ThreadWakeupCallback(u64 thread_id, s64 cycles_late);
|
void ThreadWakeupCallback(u64 thread_id, s64 cycles_late);
|
||||||
|
|
||||||
Kernel::KernelSystem& kernel;
|
Kernel::KernelSystem& kernel;
|
||||||
|
ARM_Interface* cpu;
|
||||||
|
|
||||||
u32 next_thread_id = 1;
|
u32 next_thread_id = 1;
|
||||||
SharedPtr<Thread> current_thread;
|
SharedPtr<Thread> current_thread;
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
Timer::Timer(KernelSystem& kernel) : WaitObject(kernel), timer_manager(kernel.GetTimerManager()) {}
|
Timer::Timer(KernelSystem& kernel)
|
||||||
|
: WaitObject(kernel), kernel(kernel), timer_manager(kernel.GetTimerManager()) {}
|
||||||
Timer::~Timer() {
|
Timer::~Timer() {
|
||||||
Cancel();
|
Cancel();
|
||||||
timer_manager.timer_callback_table.erase(callback_id);
|
timer_manager.timer_callback_table.erase(callback_id);
|
||||||
|
@ -56,14 +57,13 @@ void Timer::Set(s64 initial, s64 interval) {
|
||||||
// Immediately invoke the callback
|
// Immediately invoke the callback
|
||||||
Signal(0);
|
Signal(0);
|
||||||
} else {
|
} else {
|
||||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
kernel.timing.ScheduleEvent(nsToCycles(initial), timer_manager.timer_callback_event_type,
|
||||||
nsToCycles(initial), timer_manager.timer_callback_event_type, callback_id);
|
callback_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Cancel() {
|
void Timer::Cancel() {
|
||||||
Core::System::GetInstance().CoreTiming().UnscheduleEvent(
|
kernel.timing.UnscheduleEvent(timer_manager.timer_callback_event_type, callback_id);
|
||||||
timer_manager.timer_callback_event_type, callback_id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Timer::Clear() {
|
void Timer::Clear() {
|
||||||
|
@ -87,9 +87,8 @@ void Timer::Signal(s64 cycles_late) {
|
||||||
|
|
||||||
if (interval_delay != 0) {
|
if (interval_delay != 0) {
|
||||||
// Reschedule the timer with the interval delay
|
// Reschedule the timer with the interval delay
|
||||||
Core::System::GetInstance().CoreTiming().ScheduleEvent(
|
kernel.timing.ScheduleEvent(nsToCycles(interval_delay) - cycles_late,
|
||||||
nsToCycles(interval_delay) - cycles_late, timer_manager.timer_callback_event_type,
|
timer_manager.timer_callback_event_type, callback_id);
|
||||||
callback_id);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,10 +104,11 @@ void TimerManager::TimerCallback(u64 callback_id, s64 cycles_late) {
|
||||||
timer->Signal(cycles_late);
|
timer->Signal(cycles_late);
|
||||||
}
|
}
|
||||||
|
|
||||||
TimerManager::TimerManager() {
|
TimerManager::TimerManager(Core::Timing& timing) : timing(timing) {
|
||||||
timer_callback_event_type = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
timer_callback_event_type =
|
||||||
"TimerCallback",
|
timing.RegisterEvent("TimerCallback", [this](u64 thread_id, s64 cycle_late) {
|
||||||
[this](u64 thread_id, s64 cycle_late) { TimerCallback(thread_id, cycle_late); });
|
TimerCallback(thread_id, cycle_late);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -9,16 +9,22 @@
|
||||||
#include "core/hle/kernel/object.h"
|
#include "core/hle/kernel/object.h"
|
||||||
#include "core/hle/kernel/wait_object.h"
|
#include "core/hle/kernel/wait_object.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class Timing;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class TimerManager {
|
class TimerManager {
|
||||||
public:
|
public:
|
||||||
TimerManager();
|
TimerManager(Core::Timing& timing);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/// The timer callback event, called when a timer is fired
|
/// The timer callback event, called when a timer is fired
|
||||||
void TimerCallback(u64 callback_id, s64 cycles_late);
|
void TimerCallback(u64 callback_id, s64 cycles_late);
|
||||||
|
|
||||||
|
Core::Timing& timing;
|
||||||
|
|
||||||
/// The event type of the generic timer callback event
|
/// The event type of the generic timer callback event
|
||||||
Core::TimingEventType* timer_callback_event_type = nullptr;
|
Core::TimingEventType* timer_callback_event_type = nullptr;
|
||||||
|
|
||||||
|
@ -93,6 +99,7 @@ private:
|
||||||
/// ID used as userdata to reference this object when inserting into the CoreTiming queue.
|
/// ID used as userdata to reference this object when inserting into the CoreTiming queue.
|
||||||
u64 callback_id;
|
u64 callback_id;
|
||||||
|
|
||||||
|
KernelSystem& kernel;
|
||||||
TimerManager& timer_manager;
|
TimerManager& timer_manager;
|
||||||
|
|
||||||
friend class KernelSystem;
|
friend class KernelSystem;
|
||||||
|
|
|
@ -72,11 +72,11 @@ ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType reloc
|
||||||
case RelocationType::AbsoluteAddress:
|
case RelocationType::AbsoluteAddress:
|
||||||
case RelocationType::AbsoluteAddress2:
|
case RelocationType::AbsoluteAddress2:
|
||||||
memory.Write32(target_address, symbol_address + addend);
|
memory.Write32(target_address, symbol_address + addend);
|
||||||
Core::CPU().InvalidateCacheRange(target_address, sizeof(u32));
|
cpu.InvalidateCacheRange(target_address, sizeof(u32));
|
||||||
break;
|
break;
|
||||||
case RelocationType::RelativeAddress:
|
case RelocationType::RelativeAddress:
|
||||||
memory.Write32(target_address, symbol_address + addend - target_future_address);
|
memory.Write32(target_address, symbol_address + addend - target_future_address);
|
||||||
Core::CPU().InvalidateCacheRange(target_address, sizeof(u32));
|
cpu.InvalidateCacheRange(target_address, sizeof(u32));
|
||||||
break;
|
break;
|
||||||
case RelocationType::ThumbBranch:
|
case RelocationType::ThumbBranch:
|
||||||
case RelocationType::ArmBranch:
|
case RelocationType::ArmBranch:
|
||||||
|
@ -99,7 +99,7 @@ ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType reloc
|
||||||
case RelocationType::AbsoluteAddress2:
|
case RelocationType::AbsoluteAddress2:
|
||||||
case RelocationType::RelativeAddress:
|
case RelocationType::RelativeAddress:
|
||||||
memory.Write32(target_address, 0);
|
memory.Write32(target_address, 0);
|
||||||
Core::CPU().InvalidateCacheRange(target_address, sizeof(u32));
|
cpu.InvalidateCacheRange(target_address, sizeof(u32));
|
||||||
break;
|
break;
|
||||||
case RelocationType::ThumbBranch:
|
case RelocationType::ThumbBranch:
|
||||||
case RelocationType::ArmBranch:
|
case RelocationType::ArmBranch:
|
||||||
|
@ -548,7 +548,7 @@ ResultCode CROHelper::ApplyStaticAnonymousSymbolToCRS(VAddr crs_address) {
|
||||||
static_relocation_table_offset +
|
static_relocation_table_offset +
|
||||||
GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
|
GetField(StaticRelocationNum) * sizeof(StaticRelocationEntry);
|
||||||
|
|
||||||
CROHelper crs(crs_address, process, memory);
|
CROHelper crs(crs_address, process, memory, cpu);
|
||||||
u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
|
u32 offset_export_num = GetField(StaticAnonymousSymbolNum);
|
||||||
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} static anonymous symbols", ModuleName(),
|
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} static anonymous symbols", ModuleName(),
|
||||||
offset_export_num);
|
offset_export_num);
|
||||||
|
@ -759,7 +759,7 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
|
||||||
|
|
||||||
if (!relocation_entry.is_batch_resolved) {
|
if (!relocation_entry.is_batch_resolved) {
|
||||||
ResultCode result = ForEachAutoLinkCRO(
|
ResultCode result = ForEachAutoLinkCRO(
|
||||||
process, memory, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
process, memory, cpu, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||||
std::string symbol_name =
|
std::string symbol_name =
|
||||||
memory.ReadCString(entry.name_offset, import_strings_size);
|
memory.ReadCString(entry.name_offset, import_strings_size);
|
||||||
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
|
u32 symbol_address = source.FindExportNamedSymbol(symbol_name);
|
||||||
|
@ -861,7 +861,7 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
|
||||||
std::string want_cro_name = memory.ReadCString(entry.name_offset, import_strings_size);
|
std::string want_cro_name = memory.ReadCString(entry.name_offset, import_strings_size);
|
||||||
|
|
||||||
ResultCode result = ForEachAutoLinkCRO(
|
ResultCode result = ForEachAutoLinkCRO(
|
||||||
process, memory, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
process, memory, cpu, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||||
if (want_cro_name == source.ModuleName()) {
|
if (want_cro_name == source.ModuleName()) {
|
||||||
LOG_INFO(Service_LDR, "CRO \"{}\" imports {} indexed symbols from \"{}\"",
|
LOG_INFO(Service_LDR, "CRO \"{}\" imports {} indexed symbols from \"{}\"",
|
||||||
ModuleName(), entry.import_indexed_symbol_num, source.ModuleName());
|
ModuleName(), entry.import_indexed_symbol_num, source.ModuleName());
|
||||||
|
@ -1071,7 +1071,7 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
|
||||||
|
|
||||||
if (memory.ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
|
if (memory.ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
|
||||||
ResultCode result = ForEachAutoLinkCRO(
|
ResultCode result = ForEachAutoLinkCRO(
|
||||||
process, memory, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
process, memory, cpu, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
||||||
u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
|
u32 symbol_address = source.FindExportNamedSymbol("nnroAeabiAtexit_");
|
||||||
|
|
||||||
if (symbol_address != 0) {
|
if (symbol_address != 0) {
|
||||||
|
@ -1301,7 +1301,7 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Exports symbols to other modules
|
// Exports symbols to other modules
|
||||||
result = ForEachAutoLinkCRO(process, memory, crs_address,
|
result = ForEachAutoLinkCRO(process, memory, cpu, crs_address,
|
||||||
[this](CROHelper target) -> ResultVal<bool> {
|
[this](CROHelper target) -> ResultVal<bool> {
|
||||||
ResultCode result = ApplyExportNamedSymbol(target);
|
ResultCode result = ApplyExportNamedSymbol(target);
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
|
@ -1346,7 +1346,7 @@ ResultCode CROHelper::Unlink(VAddr crs_address) {
|
||||||
|
|
||||||
// Resets all symbols in other modules imported from this module
|
// Resets all symbols in other modules imported from this module
|
||||||
// Note: the RO service seems only searching in auto-link modules
|
// Note: the RO service seems only searching in auto-link modules
|
||||||
result = ForEachAutoLinkCRO(process, memory, crs_address,
|
result = ForEachAutoLinkCRO(process, memory, cpu, crs_address,
|
||||||
[this](CROHelper target) -> ResultVal<bool> {
|
[this](CROHelper target) -> ResultVal<bool> {
|
||||||
ResultCode result = ResetExportNamedSymbol(target);
|
ResultCode result = ResetExportNamedSymbol(target);
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
|
@ -1387,13 +1387,13 @@ void CROHelper::InitCRS() {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CROHelper::Register(VAddr crs_address, bool auto_link) {
|
void CROHelper::Register(VAddr crs_address, bool auto_link) {
|
||||||
CROHelper crs(crs_address, process, memory);
|
CROHelper crs(crs_address, process, memory, cpu);
|
||||||
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process, memory);
|
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process, memory, cpu);
|
||||||
|
|
||||||
if (head.module_address) {
|
if (head.module_address) {
|
||||||
// there are already CROs registered
|
// there are already CROs registered
|
||||||
// register as the new tail
|
// register as the new tail
|
||||||
CROHelper tail(head.PreviousModule(), process, memory);
|
CROHelper tail(head.PreviousModule(), process, memory, cpu);
|
||||||
|
|
||||||
// link with the old tail
|
// link with the old tail
|
||||||
ASSERT(tail.NextModule() == 0);
|
ASSERT(tail.NextModule() == 0);
|
||||||
|
@ -1419,11 +1419,11 @@ void CROHelper::Register(VAddr crs_address, bool auto_link) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void CROHelper::Unregister(VAddr crs_address) {
|
void CROHelper::Unregister(VAddr crs_address) {
|
||||||
CROHelper crs(crs_address, process, memory);
|
CROHelper crs(crs_address, process, memory, cpu);
|
||||||
CROHelper next_head(crs.NextModule(), process, memory);
|
CROHelper next_head(crs.NextModule(), process, memory, cpu);
|
||||||
CROHelper previous_head(crs.PreviousModule(), process, memory);
|
CROHelper previous_head(crs.PreviousModule(), process, memory, cpu);
|
||||||
CROHelper next(NextModule(), process, memory);
|
CROHelper next(NextModule(), process, memory, cpu);
|
||||||
CROHelper previous(PreviousModule(), process, memory);
|
CROHelper previous(PreviousModule(), process, memory, cpu);
|
||||||
|
|
||||||
if (module_address == next_head.module_address ||
|
if (module_address == next_head.module_address ||
|
||||||
module_address == previous_head.module_address) {
|
module_address == previous_head.module_address) {
|
||||||
|
|
|
@ -15,6 +15,8 @@ namespace Kernel {
|
||||||
class Process;
|
class Process;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class ARM_Interface;
|
||||||
|
|
||||||
namespace Service::LDR {
|
namespace Service::LDR {
|
||||||
|
|
||||||
#define ASSERT_CRO_STRUCT(name, size) \
|
#define ASSERT_CRO_STRUCT(name, size) \
|
||||||
|
@ -31,8 +33,9 @@ static constexpr u32 CRO_HASH_SIZE = 0x80;
|
||||||
class CROHelper final {
|
class CROHelper final {
|
||||||
public:
|
public:
|
||||||
// TODO (wwylele): pass in the process handle for memory access
|
// TODO (wwylele): pass in the process handle for memory access
|
||||||
explicit CROHelper(VAddr cro_address, Kernel::Process& process, Memory::MemorySystem& memory)
|
explicit CROHelper(VAddr cro_address, Kernel::Process& process, Memory::MemorySystem& memory,
|
||||||
: module_address(cro_address), process(process), memory(memory) {}
|
ARM_Interface& cpu)
|
||||||
|
: module_address(cro_address), process(process), memory(memory), cpu(cpu) {}
|
||||||
|
|
||||||
std::string ModuleName() const {
|
std::string ModuleName() const {
|
||||||
return memory.ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
|
return memory.ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
|
||||||
|
@ -142,6 +145,7 @@ private:
|
||||||
const VAddr module_address; ///< the virtual address of this module
|
const VAddr module_address; ///< the virtual address of this module
|
||||||
Kernel::Process& process; ///< the owner process of this module
|
Kernel::Process& process; ///< the owner process of this module
|
||||||
Memory::MemorySystem& memory;
|
Memory::MemorySystem& memory;
|
||||||
|
ARM_Interface& cpu;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Each item in this enum represents a u32 field in the header begin from address+0x80,
|
* Each item in this enum represents a u32 field in the header begin from address+0x80,
|
||||||
|
@ -471,10 +475,11 @@ private:
|
||||||
*/
|
*/
|
||||||
template <typename FunctionObject>
|
template <typename FunctionObject>
|
||||||
static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, Memory::MemorySystem& memory,
|
static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, Memory::MemorySystem& memory,
|
||||||
VAddr crs_address, FunctionObject func) {
|
ARM_Interface& cpu, VAddr crs_address,
|
||||||
|
FunctionObject func) {
|
||||||
VAddr current = crs_address;
|
VAddr current = crs_address;
|
||||||
while (current != 0) {
|
while (current != 0) {
|
||||||
CROHelper cro(current, process, memory);
|
CROHelper cro(current, process, memory, cpu);
|
||||||
CASCADE_RESULT(bool next, func(cro));
|
CASCADE_RESULT(bool next, func(cro));
|
||||||
if (!next)
|
if (!next)
|
||||||
break;
|
break;
|
||||||
|
|
|
@ -115,7 +115,7 @@ void RO::Initialize(Kernel::HLERequestContext& ctx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CROHelper crs(crs_address, *process, system.Memory());
|
CROHelper crs(crs_address, *process, system.Memory(), system.CPU());
|
||||||
crs.InitCRS();
|
crs.InitCRS();
|
||||||
|
|
||||||
result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true);
|
result = crs.Rebase(0, crs_size, 0, 0, 0, 0, true);
|
||||||
|
@ -249,7 +249,7 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CROHelper cro(cro_address, *process, system.Memory());
|
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
|
||||||
|
|
||||||
result = cro.VerifyHash(cro_size, crr_address);
|
result = cro.VerifyHash(cro_size, crr_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
|
@ -313,7 +313,7 @@ void RO::LoadCRO(Kernel::HLERequestContext& ctx, bool link_on_load_bug_fix) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::CPU().InvalidateCacheRange(cro_address, cro_size);
|
system.CPU().InvalidateCacheRange(cro_address, cro_size);
|
||||||
|
|
||||||
LOG_INFO(Service_LDR, "CRO \"{}\" loaded at 0x{:08X}, fixed_end=0x{:08X}", cro.ModuleName(),
|
LOG_INFO(Service_LDR, "CRO \"{}\" loaded at 0x{:08X}, fixed_end=0x{:08X}", cro.ModuleName(),
|
||||||
cro_address, cro_address + fix_size);
|
cro_address, cro_address + fix_size);
|
||||||
|
@ -331,7 +331,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}, zero={}, cro_buffer_ptr=0x{:08X}",
|
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}, zero={}, cro_buffer_ptr=0x{:08X}",
|
||||||
cro_address, zero, cro_buffer_ptr);
|
cro_address, zero, cro_buffer_ptr);
|
||||||
|
|
||||||
CROHelper cro(cro_address, *process, system.Memory());
|
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
|
@ -386,7 +386,7 @@ void RO::UnloadCRO(Kernel::HLERequestContext& ctx) {
|
||||||
LOG_ERROR(Service_LDR, "Error unmapping CRO {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error unmapping CRO {:08X}", result.raw);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::CPU().InvalidateCacheRange(cro_address, fixed_size);
|
system.CPU().InvalidateCacheRange(cro_address, fixed_size);
|
||||||
|
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
}
|
}
|
||||||
|
@ -398,7 +398,7 @@ void RO::LinkCRO(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
|
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
|
||||||
|
|
||||||
CROHelper cro(cro_address, *process, system.Memory());
|
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
|
@ -438,7 +438,7 @@ void RO::UnlinkCRO(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
|
LOG_DEBUG(Service_LDR, "called, cro_address=0x{:08X}", cro_address);
|
||||||
|
|
||||||
CROHelper cro(cro_address, *process, system.Memory());
|
CROHelper cro(cro_address, *process, system.Memory(), system.CPU());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
|
@ -487,7 +487,7 @@ void RO::Shutdown(Kernel::HLERequestContext& ctx) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
CROHelper crs(slot->loaded_crs, *process, system.Memory());
|
CROHelper crs(slot->loaded_crs, *process, system.Memory(), system.CPU());
|
||||||
crs.Unrebase(true);
|
crs.Unrebase(true);
|
||||||
|
|
||||||
ResultCode result = RESULT_SUCCESS;
|
ResultCode result = RESULT_SUCCESS;
|
||||||
|
|
|
@ -65,15 +65,21 @@ public:
|
||||||
PageTable* current_page_table = nullptr;
|
PageTable* current_page_table = nullptr;
|
||||||
RasterizerCacheMarker cache_marker;
|
RasterizerCacheMarker cache_marker;
|
||||||
std::vector<PageTable*> page_table_list;
|
std::vector<PageTable*> page_table_list;
|
||||||
|
|
||||||
|
ARM_Interface* cpu = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
|
MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
|
||||||
MemorySystem::~MemorySystem() = default;
|
MemorySystem::~MemorySystem() = default;
|
||||||
|
|
||||||
|
void MemorySystem::SetCPU(ARM_Interface& cpu) {
|
||||||
|
impl->cpu = &cpu;
|
||||||
|
}
|
||||||
|
|
||||||
void MemorySystem::SetCurrentPageTable(PageTable* page_table) {
|
void MemorySystem::SetCurrentPageTable(PageTable* page_table) {
|
||||||
impl->current_page_table = page_table;
|
impl->current_page_table = page_table;
|
||||||
if (Core::System::GetInstance().IsPoweredOn()) {
|
if (impl->cpu != nullptr) {
|
||||||
Core::CPU().PageTableChanged();
|
impl->cpu->PageTableChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -12,6 +12,8 @@
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "core/mmio.h"
|
#include "core/mmio.h"
|
||||||
|
|
||||||
|
class ARM_Interface;
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
class Process;
|
class Process;
|
||||||
}
|
}
|
||||||
|
@ -214,6 +216,9 @@ public:
|
||||||
MemorySystem();
|
MemorySystem();
|
||||||
~MemorySystem();
|
~MemorySystem();
|
||||||
|
|
||||||
|
/// Sets CPU to notify page table change
|
||||||
|
void SetCPU(ARM_Interface& cpu);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Maps an allocated buffer onto a region of the emulated process address space.
|
* Maps an allocated buffer onto a region of the emulated process address space.
|
||||||
*
|
*
|
||||||
|
|
|
@ -20,17 +20,13 @@
|
||||||
#include "audio_fixures.h"
|
#include "audio_fixures.h"
|
||||||
|
|
||||||
TEST_CASE("DSP HLE Audio Decoder", "[audio_core]") {
|
TEST_CASE("DSP HLE Audio Decoder", "[audio_core]") {
|
||||||
// HACK: see comments of member timing
|
Memory::MemorySystem memory;
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
|
||||||
Core::System::GetInstance().memory = std::make_unique<Memory::MemorySystem>();
|
|
||||||
Kernel::KernelSystem kernel(*Core::System::GetInstance().memory, 0);
|
|
||||||
SECTION("decoder should produce correct samples") {
|
SECTION("decoder should produce correct samples") {
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
|
||||||
auto decoder =
|
auto decoder =
|
||||||
#ifdef HAVE_MF
|
#ifdef HAVE_MF
|
||||||
std::make_unique<AudioCore::HLE::WMFDecoder>(*Core::System::GetInstance().memory);
|
std::make_unique<AudioCore::HLE::WMFDecoder>(memory);
|
||||||
#elif HAVE_FFMPEG
|
#elif HAVE_FFMPEG
|
||||||
std::make_unique<AudioCore::HLE::FFMPEGDecoder>(*Core::System::GetInstance().memory);
|
std::make_unique<AudioCore::HLE::FFMPEGDecoder>(memory);
|
||||||
#endif
|
#endif
|
||||||
AudioCore::HLE::BinaryRequest request;
|
AudioCore::HLE::BinaryRequest request;
|
||||||
|
|
||||||
|
@ -40,7 +36,7 @@ TEST_CASE("DSP HLE Audio Decoder", "[audio_core]") {
|
||||||
std::optional<AudioCore::HLE::BinaryResponse> response = decoder->ProcessRequest(request);
|
std::optional<AudioCore::HLE::BinaryResponse> response = decoder->ProcessRequest(request);
|
||||||
|
|
||||||
request.cmd = AudioCore::HLE::DecoderCommand::Decode;
|
request.cmd = AudioCore::HLE::DecoderCommand::Decode;
|
||||||
u8* fcram = Core::System::GetInstance().memory->GetFCRAMPointer(0);
|
u8* fcram = memory.GetFCRAMPointer(0);
|
||||||
|
|
||||||
memcpy(fcram, fixure_buffer, fixure_buffer_size);
|
memcpy(fcram, fixure_buffer, fixure_buffer_size);
|
||||||
request.src_addr = Memory::FCRAM_PADDR;
|
request.src_addr = Memory::FCRAM_PADDR;
|
||||||
|
|
|
@ -15,14 +15,9 @@ static Memory::PageTable* page_table = nullptr;
|
||||||
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
: mutable_memory(mutable_memory_), test_memory(std::make_shared<TestMemory>(this)) {
|
||||||
|
|
||||||
// HACK: some memory functions are currently referring kernel from the global instance,
|
timing = std::make_unique<Core::Timing>();
|
||||||
// so we need to create the kernel object there.
|
memory = std::make_unique<Memory::MemorySystem>();
|
||||||
// Change this when all global states are eliminated.
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, *timing, [] {}, 0);
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
|
||||||
Core::System::GetInstance().memory = std::make_unique<Memory::MemorySystem>();
|
|
||||||
Memory::MemorySystem& memory = *Core::System::GetInstance().memory;
|
|
||||||
Core::System::GetInstance().kernel = std::make_unique<Kernel::KernelSystem>(memory, 0);
|
|
||||||
kernel = Core::System::GetInstance().kernel.get();
|
|
||||||
|
|
||||||
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
||||||
page_table = &kernel->GetCurrentProcess()->vm_manager.page_table;
|
page_table = &kernel->GetCurrentProcess()->vm_manager.page_table;
|
||||||
|
@ -30,17 +25,15 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
page_table->pointers.fill(nullptr);
|
page_table->pointers.fill(nullptr);
|
||||||
page_table->attributes.fill(Memory::PageType::Unmapped);
|
page_table->attributes.fill(Memory::PageType::Unmapped);
|
||||||
|
|
||||||
memory.MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
|
memory->MapIoRegion(*page_table, 0x00000000, 0x80000000, test_memory);
|
||||||
memory.MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
|
memory->MapIoRegion(*page_table, 0x80000000, 0x80000000, test_memory);
|
||||||
|
|
||||||
memory.SetCurrentPageTable(page_table);
|
memory->SetCurrentPageTable(page_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
TestEnvironment::~TestEnvironment() {
|
TestEnvironment::~TestEnvironment() {
|
||||||
Memory::MemorySystem& memory = *Core::System::GetInstance().memory;
|
memory->UnmapRegion(*page_table, 0x80000000, 0x80000000);
|
||||||
memory.UnmapRegion(*page_table, 0x80000000, 0x80000000);
|
memory->UnmapRegion(*page_table, 0x00000000, 0x80000000);
|
||||||
memory.UnmapRegion(*page_table, 0x00000000, 0x80000000);
|
|
||||||
Core::System::GetInstance().kernel.reset();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
|
void TestEnvironment::SetMemory64(VAddr vaddr, u64 value) {
|
||||||
|
|
|
@ -49,6 +49,10 @@ public:
|
||||||
/// Empties the internal write-record store.
|
/// Empties the internal write-record store.
|
||||||
void ClearWriteRecords();
|
void ClearWriteRecords();
|
||||||
|
|
||||||
|
Memory::MemorySystem& GetMemory() {
|
||||||
|
return *memory;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
friend struct TestMemory;
|
friend struct TestMemory;
|
||||||
struct TestMemory final : Memory::MMIORegion {
|
struct TestMemory final : Memory::MMIORegion {
|
||||||
|
@ -80,7 +84,9 @@ private:
|
||||||
std::shared_ptr<TestMemory> test_memory;
|
std::shared_ptr<TestMemory> test_memory;
|
||||||
std::vector<WriteRecord> write_records;
|
std::vector<WriteRecord> write_records;
|
||||||
|
|
||||||
Kernel::KernelSystem* kernel;
|
std::unique_ptr<Core::Timing> timing;
|
||||||
|
std::unique_ptr<Memory::MemorySystem> memory;
|
||||||
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ArmTests
|
} // namespace ArmTests
|
||||||
|
|
|
@ -23,7 +23,7 @@ TEST_CASE("ARM_DynCom (vfp): vadd", "[arm_dyncom]") {
|
||||||
test_env.SetMemory32(0, 0xEE321A03); // vadd.f32 s2, s4, s6
|
test_env.SetMemory32(0, 0xEE321A03); // vadd.f32 s2, s4, s6
|
||||||
test_env.SetMemory32(4, 0xEAFFFFFE); // b +#0
|
test_env.SetMemory32(4, 0xEAFFFFFE); // b +#0
|
||||||
|
|
||||||
ARM_DynCom dyncom(Core::System::GetInstance(), USER32MODE);
|
ARM_DynCom dyncom(nullptr, test_env.GetMemory(), USER32MODE);
|
||||||
|
|
||||||
std::vector<VfpTestCase> test_cases{{
|
std::vector<VfpTestCase> test_cases{{
|
||||||
#include "vfp_vadd_f32.inc"
|
#include "vfp_vadd_f32.inc"
|
||||||
|
|
|
@ -21,10 +21,9 @@ static SharedPtr<Object> MakeObject(Kernel::KernelSystem& kernel) {
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel]") {
|
||||||
// HACK: see comments of member timing
|
Core::Timing timing;
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Memory::MemorySystem memory;
|
||||||
auto memory = std::make_unique<Memory::MemorySystem>();
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
|
||||||
Kernel::KernelSystem kernel(*memory, 0);
|
|
||||||
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
||||||
HLERequestContext context(std::move(session));
|
HLERequestContext context(std::move(session));
|
||||||
|
|
||||||
|
@ -234,10 +233,9 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
}
|
}
|
||||||
|
|
||||||
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
// HACK: see comments of member timing
|
Core::Timing timing;
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Memory::MemorySystem memory;
|
||||||
auto memory = std::make_unique<Memory::MemorySystem>();
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
|
||||||
Kernel::KernelSystem kernel(*memory, 0);
|
|
||||||
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
auto session = std::get<SharedPtr<ServerSession>>(kernel.CreateSessionPair());
|
||||||
HLERequestContext context(std::move(session));
|
HLERequestContext context(std::move(session));
|
||||||
|
|
||||||
|
|
|
@ -11,10 +11,9 @@
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
||||||
// HACK: see comments of member timing
|
Core::Timing timing;
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Memory::MemorySystem memory;
|
||||||
Core::System::GetInstance().memory = std::make_unique<Memory::MemorySystem>();
|
Kernel::KernelSystem kernel(memory, timing, [] {}, 0);
|
||||||
Kernel::KernelSystem kernel(*Core::System::GetInstance().memory, 0);
|
|
||||||
SECTION("these regions should not be mapped on an empty process") {
|
SECTION("these regions should not be mapped on an empty process") {
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||||
CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
|
CHECK(Memory::IsValidVirtualAddress(*process, Memory::PROCESS_IMAGE_VADDR) == false);
|
||||||
|
|
Reference in New Issue