Merge pull request #4480 from wwylele/memory-global-2
Memory: eliminate global state
This commit is contained in:
commit
edbdbf0ba1
57 changed files with 670 additions and 491 deletions
|
@ -24,7 +24,7 @@ static constexpr u64 audio_frame_ticks = 1310252ull; ///< Units: ARM11 cycles
|
||||||
|
|
||||||
struct DspHle::Impl final {
|
struct DspHle::Impl final {
|
||||||
public:
|
public:
|
||||||
explicit Impl(DspHle& parent);
|
explicit Impl(DspHle& parent, Memory::MemorySystem& memory);
|
||||||
~Impl();
|
~Impl();
|
||||||
|
|
||||||
DspState GetDspState() const;
|
DspState GetDspState() const;
|
||||||
|
@ -69,9 +69,13 @@ private:
|
||||||
std::weak_ptr<DSP_DSP> dsp_dsp;
|
std::weak_ptr<DSP_DSP> dsp_dsp;
|
||||||
};
|
};
|
||||||
|
|
||||||
DspHle::Impl::Impl(DspHle& parent_) : parent(parent_) {
|
DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory) : parent(parent_) {
|
||||||
dsp_memory.raw_memory.fill(0);
|
dsp_memory.raw_memory.fill(0);
|
||||||
|
|
||||||
|
for (auto& source : sources) {
|
||||||
|
source.SetMemory(memory);
|
||||||
|
}
|
||||||
|
|
||||||
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
Core::Timing& timing = Core::System::GetInstance().CoreTiming();
|
||||||
tick_event =
|
tick_event =
|
||||||
timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
timing.RegisterEvent("AudioCore::DspHle::tick_event", [this](u64, s64 cycles_late) {
|
||||||
|
@ -335,7 +339,7 @@ void DspHle::Impl::AudioTickCallback(s64 cycles_late) {
|
||||||
timing.ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
|
timing.ScheduleEvent(audio_frame_ticks - cycles_late, tick_event);
|
||||||
}
|
}
|
||||||
|
|
||||||
DspHle::DspHle() : impl(std::make_unique<Impl>(*this)) {}
|
DspHle::DspHle(Memory::MemorySystem& memory) : impl(std::make_unique<Impl>(*this, memory)) {}
|
||||||
DspHle::~DspHle() = default;
|
DspHle::~DspHle() = default;
|
||||||
|
|
||||||
DspState DspHle::GetDspState() const {
|
DspState DspHle::GetDspState() const {
|
||||||
|
|
|
@ -13,11 +13,15 @@
|
||||||
#include "core/hle/service/dsp/dsp_dsp.h"
|
#include "core/hle/service/dsp/dsp_dsp.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
|
|
||||||
class DspHle final : public DspInterface {
|
class DspHle final : public DspInterface {
|
||||||
public:
|
public:
|
||||||
DspHle();
|
explicit DspHle(Memory::MemorySystem& memory);
|
||||||
~DspHle();
|
~DspHle();
|
||||||
|
|
||||||
DspState GetDspState() const override;
|
DspState GetDspState() const override;
|
||||||
|
|
|
@ -45,6 +45,10 @@ void Source::Reset() {
|
||||||
state = {};
|
state = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Source::SetMemory(Memory::MemorySystem& memory) {
|
||||||
|
memory_system = &memory;
|
||||||
|
}
|
||||||
|
|
||||||
void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
void Source::ParseConfig(SourceConfiguration::Configuration& config,
|
||||||
const s16_le (&adpcm_coeffs)[16]) {
|
const s16_le (&adpcm_coeffs)[16]) {
|
||||||
if (!config.dirty_raw) {
|
if (!config.dirty_raw) {
|
||||||
|
@ -286,7 +290,7 @@ bool Source::DequeueBuffer() {
|
||||||
|
|
||||||
// This physical address masking occurs due to how the DSP DMA hardware is configured by the
|
// This physical address masking occurs due to how the DSP DMA hardware is configured by the
|
||||||
// firmware.
|
// firmware.
|
||||||
const u8* const memory = Memory::GetPhysicalPointer(buf.physical_address & 0xFFFFFFFC);
|
const u8* const memory = memory_system->GetPhysicalPointer(buf.physical_address & 0xFFFFFFFC);
|
||||||
if (memory) {
|
if (memory) {
|
||||||
const unsigned num_channels = buf.mono_or_stereo == MonoOrStereo::Stereo ? 2 : 1;
|
const unsigned num_channels = buf.mono_or_stereo == MonoOrStereo::Stereo ? 2 : 1;
|
||||||
switch (buf.format) {
|
switch (buf.format) {
|
||||||
|
|
|
@ -14,6 +14,10 @@
|
||||||
#include "audio_core/interpolate.h"
|
#include "audio_core/interpolate.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
namespace HLE {
|
namespace HLE {
|
||||||
|
|
||||||
|
@ -35,6 +39,9 @@ public:
|
||||||
/// Resets internal state.
|
/// Resets internal state.
|
||||||
void Reset();
|
void Reset();
|
||||||
|
|
||||||
|
/// Sets the memory system to read data from
|
||||||
|
void SetMemory(Memory::MemorySystem& memory);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is called once every audio frame. This performs per-source processing every frame.
|
* This is called once every audio frame. This performs per-source processing every frame.
|
||||||
* @param config The new configuration we've got for this Source from the application.
|
* @param config The new configuration we've got for this Source from the application.
|
||||||
|
@ -56,6 +63,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const std::size_t source_id;
|
const std::size_t source_id;
|
||||||
|
Memory::MemorySystem* memory_system;
|
||||||
StereoFrame16 current_frame;
|
StereoFrame16 current_frame;
|
||||||
|
|
||||||
using Format = SourceConfiguration::Configuration::Format;
|
using Format = SourceConfiguration::Configuration::Format;
|
||||||
|
|
|
@ -17,6 +17,7 @@
|
||||||
#include "citra_qt/util/spinbox.h"
|
#include "citra_qt/util/spinbox.h"
|
||||||
#include "citra_qt/util/util.h"
|
#include "citra_qt/util/util.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/debug_utils/debug_utils.h"
|
#include "video_core/debug_utils/debug_utils.h"
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
|
@ -166,7 +167,8 @@ void GPUCommandListWidget::SetCommandInfo(const QModelIndex& index) {
|
||||||
const auto format = texture.format;
|
const auto format = texture.format;
|
||||||
|
|
||||||
const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config, format);
|
const auto info = Pica::Texture::TextureInfo::FromPicaRegister(config, format);
|
||||||
const u8* src = Memory::GetPhysicalPointer(config.GetPhysicalAddress());
|
const u8* src =
|
||||||
|
Core::System::GetInstance().Memory().GetPhysicalPointer(config.GetPhysicalAddress());
|
||||||
new_info_widget = new TextureInfoWidget(src, info);
|
new_info_widget = new TextureInfoWidget(src, info);
|
||||||
}
|
}
|
||||||
if (command_info_widget) {
|
if (command_info_widget) {
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "citra_qt/debugger/graphics/graphics_surface.h"
|
#include "citra_qt/debugger/graphics/graphics_surface.h"
|
||||||
#include "citra_qt/util/spinbox.h"
|
#include "citra_qt/util/spinbox.h"
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hw/gpu.h"
|
#include "core/hw/gpu.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "video_core/pica_state.h"
|
#include "video_core/pica_state.h"
|
||||||
|
@ -283,7 +284,7 @@ void GraphicsSurfaceWidget::Pick(int x, int y) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* buffer = Memory::GetPhysicalPointer(surface_address);
|
u8* buffer = Core::System::GetInstance().Memory().GetPhysicalPointer(surface_address);
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
surface_info_label->setText(tr("(unable to access pixel data)"));
|
surface_info_label->setText(tr("(unable to access pixel data)"));
|
||||||
surface_info_label->setAlignment(Qt::AlignCenter);
|
surface_info_label->setAlignment(Qt::AlignCenter);
|
||||||
|
@ -549,7 +550,7 @@ void GraphicsSurfaceWidget::OnUpdate() {
|
||||||
// TODO: Implement a good way to visualize alpha components!
|
// TODO: Implement a good way to visualize alpha components!
|
||||||
|
|
||||||
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
|
QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32);
|
||||||
u8* buffer = Memory::GetPhysicalPointer(surface_address);
|
u8* buffer = Core::System::GetInstance().Memory().GetPhysicalPointer(surface_address);
|
||||||
|
|
||||||
if (buffer == nullptr) {
|
if (buffer == nullptr) {
|
||||||
surface_picture_label->hide();
|
surface_picture_label->hide();
|
||||||
|
@ -679,7 +680,7 @@ void GraphicsSurfaceWidget::SaveSurface() {
|
||||||
if (pixmap)
|
if (pixmap)
|
||||||
pixmap->save(&file, "PNG");
|
pixmap->save(&file, "PNG");
|
||||||
} else if (selectedFilter == bin_filter) {
|
} else if (selectedFilter == bin_filter) {
|
||||||
const u8* buffer = Memory::GetPhysicalPointer(surface_address);
|
const u8* buffer = Core::System::GetInstance().Memory().GetPhysicalPointer(surface_address);
|
||||||
ASSERT_MSG(buffer != nullptr, "Memory not accessible");
|
ASSERT_MSG(buffer != nullptr, "Memory not accessible");
|
||||||
|
|
||||||
QFile file(filename);
|
QFile file(filename);
|
||||||
|
|
|
@ -72,33 +72,34 @@ private:
|
||||||
class DynarmicUserCallbacks final : public Dynarmic::A32::UserCallbacks {
|
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()) {}
|
||||||
~DynarmicUserCallbacks() = default;
|
~DynarmicUserCallbacks() = default;
|
||||||
|
|
||||||
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
std::uint8_t MemoryRead8(VAddr vaddr) override {
|
||||||
return Memory::Read8(vaddr);
|
return memory.Read8(vaddr);
|
||||||
}
|
}
|
||||||
std::uint16_t MemoryRead16(VAddr vaddr) override {
|
std::uint16_t MemoryRead16(VAddr vaddr) override {
|
||||||
return Memory::Read16(vaddr);
|
return memory.Read16(vaddr);
|
||||||
}
|
}
|
||||||
std::uint32_t MemoryRead32(VAddr vaddr) override {
|
std::uint32_t MemoryRead32(VAddr vaddr) override {
|
||||||
return Memory::Read32(vaddr);
|
return memory.Read32(vaddr);
|
||||||
}
|
}
|
||||||
std::uint64_t MemoryRead64(VAddr vaddr) override {
|
std::uint64_t MemoryRead64(VAddr vaddr) override {
|
||||||
return Memory::Read64(vaddr);
|
return memory.Read64(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MemoryWrite8(VAddr vaddr, std::uint8_t value) override {
|
void MemoryWrite8(VAddr vaddr, std::uint8_t value) override {
|
||||||
Memory::Write8(vaddr, value);
|
memory.Write8(vaddr, value);
|
||||||
}
|
}
|
||||||
void MemoryWrite16(VAddr vaddr, std::uint16_t value) override {
|
void MemoryWrite16(VAddr vaddr, std::uint16_t value) override {
|
||||||
Memory::Write16(vaddr, value);
|
memory.Write16(vaddr, value);
|
||||||
}
|
}
|
||||||
void MemoryWrite32(VAddr vaddr, std::uint32_t value) override {
|
void MemoryWrite32(VAddr vaddr, std::uint32_t value) override {
|
||||||
Memory::Write32(vaddr, value);
|
memory.Write32(vaddr, value);
|
||||||
}
|
}
|
||||||
void MemoryWrite64(VAddr vaddr, std::uint64_t value) override {
|
void MemoryWrite64(VAddr vaddr, std::uint64_t value) override {
|
||||||
Memory::Write64(vaddr, value);
|
memory.Write64(vaddr, value);
|
||||||
}
|
}
|
||||||
|
|
||||||
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
|
void InterpreterFallback(VAddr pc, std::size_t num_instructions) override {
|
||||||
|
@ -136,7 +137,7 @@ public:
|
||||||
parent.jit->HaltExecution();
|
parent.jit->HaltExecution();
|
||||||
parent.SetPC(pc);
|
parent.SetPC(pc);
|
||||||
Kernel::Thread* thread =
|
Kernel::Thread* thread =
|
||||||
Core::System::GetInstance().Kernel().GetThreadManager().GetCurrentThread();
|
parent.system.Kernel().GetThreadManager().GetCurrentThread();
|
||||||
parent.SaveContext(thread->context);
|
parent.SaveContext(thread->context);
|
||||||
GDBStub::Break();
|
GDBStub::Break();
|
||||||
GDBStub::SendTrap(thread, 5);
|
GDBStub::SendTrap(thread, 5);
|
||||||
|
@ -159,11 +160,12 @@ public:
|
||||||
ARM_Dynarmic& parent;
|
ARM_Dynarmic& parent;
|
||||||
Core::Timing& timing;
|
Core::Timing& timing;
|
||||||
Kernel::SVCContext svc_context;
|
Kernel::SVCContext svc_context;
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode)
|
ARM_Dynarmic::ARM_Dynarmic(Core::System& system, PrivilegeMode initial_mode)
|
||||||
: system(system), cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
: system(system), cb(std::make_unique<DynarmicUserCallbacks>(*this)) {
|
||||||
interpreter_state = std::make_shared<ARMul_State>(initial_mode);
|
interpreter_state = std::make_shared<ARMul_State>(system, initial_mode);
|
||||||
PageTableChanged();
|
PageTableChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,7 +174,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(Memory::GetCurrentPageTable() == current_page_table);
|
ASSERT(system.Memory().GetCurrentPageTable() == current_page_table);
|
||||||
MICROPROFILE_SCOPE(ARM_Jit);
|
MICROPROFILE_SCOPE(ARM_Jit);
|
||||||
|
|
||||||
jit->Run();
|
jit->Run();
|
||||||
|
@ -279,7 +281,7 @@ void ARM_Dynarmic::InvalidateCacheRange(u32 start_address, std::size_t length) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_Dynarmic::PageTableChanged() {
|
void ARM_Dynarmic::PageTableChanged() {
|
||||||
current_page_table = Memory::GetCurrentPageTable();
|
current_page_table = system.Memory().GetCurrentPageTable();
|
||||||
|
|
||||||
auto iter = jits.find(current_page_table);
|
auto iter = jits.find(current_page_table);
|
||||||
if (iter != jits.end()) {
|
if (iter != jits.end()) {
|
||||||
|
|
|
@ -68,14 +68,14 @@ private:
|
||||||
u32 fpexc;
|
u32 fpexc;
|
||||||
};
|
};
|
||||||
|
|
||||||
ARM_DynCom::ARM_DynCom(PrivilegeMode initial_mode) {
|
ARM_DynCom::ARM_DynCom(Core::System& system, PrivilegeMode initial_mode) : system(system) {
|
||||||
state = std::make_unique<ARMul_State>(initial_mode);
|
state = std::make_unique<ARMul_State>(system, initial_mode);
|
||||||
}
|
}
|
||||||
|
|
||||||
ARM_DynCom::~ARM_DynCom() {}
|
ARM_DynCom::~ARM_DynCom() {}
|
||||||
|
|
||||||
void ARM_DynCom::Run() {
|
void ARM_DynCom::Run() {
|
||||||
ExecuteInstructions(std::max<s64>(Core::System::GetInstance().CoreTiming().GetDowncount(), 0));
|
ExecuteInstructions(std::max<s64>(system.CoreTiming().GetDowncount(), 0));
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARM_DynCom::Step() {
|
void ARM_DynCom::Step() {
|
||||||
|
@ -146,7 +146,7 @@ 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());
|
||||||
Core::System::GetInstance().CoreTiming().AddTicks(ticks_executed);
|
system.CoreTiming().AddTicks(ticks_executed);
|
||||||
state->ServeBreak();
|
state->ServeBreak();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -10,9 +10,13 @@
|
||||||
#include "core/arm/skyeye_common/arm_regformat.h"
|
#include "core/arm/skyeye_common/arm_regformat.h"
|
||||||
#include "core/arm/skyeye_common/armstate.h"
|
#include "core/arm/skyeye_common/armstate.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
struct System;
|
||||||
|
}
|
||||||
|
|
||||||
class ARM_DynCom final : public ARM_Interface {
|
class ARM_DynCom final : public ARM_Interface {
|
||||||
public:
|
public:
|
||||||
explicit ARM_DynCom(PrivilegeMode initial_mode);
|
explicit ARM_DynCom(Core::System& system, PrivilegeMode initial_mode);
|
||||||
~ARM_DynCom();
|
~ARM_DynCom();
|
||||||
|
|
||||||
void Run() override;
|
void Run() override;
|
||||||
|
@ -44,5 +48,6 @@ public:
|
||||||
private:
|
private:
|
||||||
void ExecuteInstructions(u64 num_instructions);
|
void ExecuteInstructions(u64 num_instructions);
|
||||||
|
|
||||||
|
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 = Memory::Read32(phys_addr & 0xFFFFFFFC);
|
u32 inst = cpu->system.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
|
||||||
|
@ -3860,11 +3860,11 @@ 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)) {
|
||||||
swi_inst* const inst_cream = (swi_inst*)inst_base->component;
|
swi_inst* const inst_cream = (swi_inst*)inst_base->component;
|
||||||
Core::System::GetInstance().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{Core::System::GetInstance()}.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,7 @@
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
|
||||||
ARMul_State::ARMul_State(PrivilegeMode initial_mode) {
|
ARMul_State::ARMul_State(Core::System& system, PrivilegeMode initial_mode) : system(system) {
|
||||||
Reset();
|
Reset();
|
||||||
ChangePrivilegeMode(initial_mode);
|
ChangePrivilegeMode(initial_mode);
|
||||||
}
|
}
|
||||||
|
@ -191,13 +191,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 Memory::Read8(address);
|
return system.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 = Memory::Read16(address);
|
u16 data = system.Memory().Read16(address);
|
||||||
|
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap16(data);
|
data = Common::swap16(data);
|
||||||
|
@ -208,7 +208,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 = Memory::Read32(address);
|
u32 data = system.Memory().Read32(address);
|
||||||
|
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap32(data);
|
data = Common::swap32(data);
|
||||||
|
@ -219,7 +219,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 = Memory::Read64(address);
|
u64 data = system.Memory().Read64(address);
|
||||||
|
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap64(data);
|
data = Common::swap64(data);
|
||||||
|
@ -230,7 +230,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);
|
||||||
|
|
||||||
Memory::Write8(address, data);
|
system.Memory().Write8(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
||||||
|
@ -239,7 +239,7 @@ void ARMul_State::WriteMemory16(u32 address, u16 data) {
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap16(data);
|
data = Common::swap16(data);
|
||||||
|
|
||||||
Memory::Write16(address, data);
|
system.Memory().Write16(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
||||||
|
@ -248,7 +248,7 @@ void ARMul_State::WriteMemory32(u32 address, u32 data) {
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap32(data);
|
data = Common::swap32(data);
|
||||||
|
|
||||||
Memory::Write32(address, data);
|
system.Memory().Write32(address, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
||||||
|
@ -257,7 +257,7 @@ void ARMul_State::WriteMemory64(u32 address, u64 data) {
|
||||||
if (InBigEndianMode())
|
if (InBigEndianMode())
|
||||||
data = Common::swap64(data);
|
data = Common::swap64(data);
|
||||||
|
|
||||||
Memory::Write64(address, data);
|
system.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,9 +603,8 @@ 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 =
|
Kernel::Thread* thread = system.Kernel().GetThreadManager().GetCurrentThread();
|
||||||
Core::System::GetInstance().Kernel().GetThreadManager().GetCurrentThread();
|
system.CPU().SaveContext(thread->context);
|
||||||
Core::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();
|
||||||
|
|
|
@ -23,6 +23,10 @@
|
||||||
#include "core/arm/skyeye_common/arm_regformat.h"
|
#include "core/arm/skyeye_common/arm_regformat.h"
|
||||||
#include "core/gdbstub/gdbstub.h"
|
#include "core/gdbstub/gdbstub.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class System;
|
||||||
|
}
|
||||||
|
|
||||||
// Signal levels
|
// Signal levels
|
||||||
enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 };
|
enum { LOW = 0, HIGH = 1, LOWHIGH = 1, HIGHLOW = 2 };
|
||||||
|
|
||||||
|
@ -139,7 +143,7 @@ enum {
|
||||||
|
|
||||||
struct ARMul_State final {
|
struct ARMul_State final {
|
||||||
public:
|
public:
|
||||||
explicit ARMul_State(PrivilegeMode initial_mode);
|
explicit ARMul_State(Core::System& system, PrivilegeMode initial_mode);
|
||||||
|
|
||||||
void ChangePrivilegeMode(u32 new_mode);
|
void ChangePrivilegeMode(u32 new_mode);
|
||||||
void Reset();
|
void Reset();
|
||||||
|
@ -197,6 +201,8 @@ public:
|
||||||
|
|
||||||
void ServeBreak();
|
void ServeBreak();
|
||||||
|
|
||||||
|
Core::System& system;
|
||||||
|
|
||||||
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{};
|
||||||
std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC
|
std::array<u32, 2> Reg_svc{}; // R13_SVC R14_SVC
|
||||||
|
|
|
@ -49,9 +49,10 @@ static inline std::enable_if_t<std::is_integral_v<T>> CompOp(const GatewayCheat:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void LoadOffsetOp(const GatewayCheat::CheatLine& line, State& state) {
|
static inline void LoadOffsetOp(Memory::MemorySystem& memory, const GatewayCheat::CheatLine& line,
|
||||||
|
State& state) {
|
||||||
u32 addr = line.address + state.offset;
|
u32 addr = line.address + state.offset;
|
||||||
state.offset = Memory::Read32(addr);
|
state.offset = memory.Read32(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
static inline void LoopOp(const GatewayCheat::CheatLine& line, State& state) {
|
static inline void LoopOp(const GatewayCheat::CheatLine& line, State& state) {
|
||||||
|
@ -154,7 +155,7 @@ static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Co
|
||||||
state.current_line_nr++;
|
state.current_line_nr++;
|
||||||
}
|
}
|
||||||
first = !first;
|
first = !first;
|
||||||
Memory::Write32(addr, tmp);
|
system.Memory().Write32(addr, tmp);
|
||||||
addr += 4;
|
addr += 4;
|
||||||
num_bytes -= 4;
|
num_bytes -= 4;
|
||||||
}
|
}
|
||||||
|
@ -162,7 +163,7 @@ static inline void PatchOp(const GatewayCheat::CheatLine& line, State& state, Co
|
||||||
u32 tmp = (first ? cheat_lines[state.current_line_nr].first
|
u32 tmp = (first ? cheat_lines[state.current_line_nr].first
|
||||||
: cheat_lines[state.current_line_nr].value) >>
|
: cheat_lines[state.current_line_nr].value) >>
|
||||||
bit_offset;
|
bit_offset;
|
||||||
Memory::Write8(addr, tmp);
|
system.Memory().Write8(addr, tmp);
|
||||||
addr += 1;
|
addr += 1;
|
||||||
num_bytes -= 1;
|
num_bytes -= 1;
|
||||||
bit_offset += 8;
|
bit_offset += 8;
|
||||||
|
@ -205,6 +206,14 @@ GatewayCheat::~GatewayCheat() = default;
|
||||||
void GatewayCheat::Execute(Core::System& system) {
|
void GatewayCheat::Execute(Core::System& system) {
|
||||||
State state;
|
State state;
|
||||||
|
|
||||||
|
Memory::MemorySystem& memory = system.Memory();
|
||||||
|
auto Read8 = [&memory](VAddr addr) { return memory.Read8(addr); };
|
||||||
|
auto Read16 = [&memory](VAddr addr) { return memory.Read16(addr); };
|
||||||
|
auto Read32 = [&memory](VAddr addr) { return memory.Read32(addr); };
|
||||||
|
auto Write8 = [&memory](VAddr addr, u8 value) { memory.Write8(addr, value); };
|
||||||
|
auto Write16 = [&memory](VAddr addr, u16 value) { memory.Write16(addr, value); };
|
||||||
|
auto Write32 = [&memory](VAddr addr, u32 value) { memory.Write32(addr, value); };
|
||||||
|
|
||||||
for (state.current_line_nr = 0; state.current_line_nr < cheat_lines.size();
|
for (state.current_line_nr = 0; state.current_line_nr < cheat_lines.size();
|
||||||
state.current_line_nr++) {
|
state.current_line_nr++) {
|
||||||
auto line = cheat_lines[state.current_line_nr];
|
auto line = cheat_lines[state.current_line_nr];
|
||||||
|
@ -247,63 +256,61 @@ void GatewayCheat::Execute(Core::System& system) {
|
||||||
break;
|
break;
|
||||||
case CheatType::Write32:
|
case CheatType::Write32:
|
||||||
// 0XXXXXXX YYYYYYYY - word[XXXXXXX+offset] = YYYYYYYY
|
// 0XXXXXXX YYYYYYYY - word[XXXXXXX+offset] = YYYYYYYY
|
||||||
WriteOp<u32>(line, state, &Memory::Write32, system);
|
WriteOp<u32>(line, state, Write32, system);
|
||||||
break;
|
break;
|
||||||
case CheatType::Write16:
|
case CheatType::Write16:
|
||||||
// 1XXXXXXX 0000YYYY - half[XXXXXXX+offset] = YYYY
|
// 1XXXXXXX 0000YYYY - half[XXXXXXX+offset] = YYYY
|
||||||
WriteOp<u16>(line, state, &Memory::Write16, system);
|
WriteOp<u16>(line, state, Write16, system);
|
||||||
break;
|
break;
|
||||||
case CheatType::Write8:
|
case CheatType::Write8:
|
||||||
// 2XXXXXXX 000000YY - byte[XXXXXXX+offset] = YY
|
// 2XXXXXXX 000000YY - byte[XXXXXXX+offset] = YY
|
||||||
WriteOp<u8>(line, state, &Memory::Write8, system);
|
WriteOp<u8>(line, state, Write8, system);
|
||||||
break;
|
break;
|
||||||
case CheatType::GreaterThan32:
|
case CheatType::GreaterThan32:
|
||||||
// 3XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY > word[XXXXXXX] ;unsigned
|
// 3XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY > word[XXXXXXX] ;unsigned
|
||||||
CompOp<u32>(line, state, &Memory::Read32,
|
CompOp<u32>(line, state, Read32, [&line](u32 val) -> bool { return line.value > val; });
|
||||||
[&line](u32 val) -> bool { return line.value > val; });
|
|
||||||
break;
|
break;
|
||||||
case CheatType::LessThan32:
|
case CheatType::LessThan32:
|
||||||
// 4XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY < word[XXXXXXX] ;unsigned
|
// 4XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY < word[XXXXXXX] ;unsigned
|
||||||
CompOp<u32>(line, state, &Memory::Read32,
|
CompOp<u32>(line, state, Read32, [&line](u32 val) -> bool { return line.value < val; });
|
||||||
[&line](u32 val) -> bool { return line.value < val; });
|
|
||||||
break;
|
break;
|
||||||
case CheatType::EqualTo32:
|
case CheatType::EqualTo32:
|
||||||
// 5XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY == word[XXXXXXX] ;unsigned
|
// 5XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY == word[XXXXXXX] ;unsigned
|
||||||
CompOp<u32>(line, state, &Memory::Read32,
|
CompOp<u32>(line, state, Read32,
|
||||||
[&line](u32 val) -> bool { return line.value == val; });
|
[&line](u32 val) -> bool { return line.value == val; });
|
||||||
break;
|
break;
|
||||||
case CheatType::NotEqualTo32:
|
case CheatType::NotEqualTo32:
|
||||||
// 6XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY != word[XXXXXXX] ;unsigned
|
// 6XXXXXXX YYYYYYYY - Execute next block IF YYYYYYYY != word[XXXXXXX] ;unsigned
|
||||||
CompOp<u32>(line, state, &Memory::Read32,
|
CompOp<u32>(line, state, Read32,
|
||||||
[&line](u32 val) -> bool { return line.value != val; });
|
[&line](u32 val) -> bool { return line.value != val; });
|
||||||
break;
|
break;
|
||||||
case CheatType::GreaterThan16WithMask:
|
case CheatType::GreaterThan16WithMask:
|
||||||
// 7XXXXXXX ZZZZYYYY - Execute next block IF YYYY > ((not ZZZZ) AND half[XXXXXXX])
|
// 7XXXXXXX ZZZZYYYY - Execute next block IF YYYY > ((not ZZZZ) AND half[XXXXXXX])
|
||||||
CompOp<u16>(line, state, &Memory::Read16, [&line](u16 val) -> bool {
|
CompOp<u16>(line, state, Read16, [&line](u16 val) -> bool {
|
||||||
return static_cast<u16>(line.value) > (static_cast<u16>(~line.value >> 16) & val);
|
return static_cast<u16>(line.value) > (static_cast<u16>(~line.value >> 16) & val);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case CheatType::LessThan16WithMask:
|
case CheatType::LessThan16WithMask:
|
||||||
// 8XXXXXXX ZZZZYYYY - Execute next block IF YYYY < ((not ZZZZ) AND half[XXXXXXX])
|
// 8XXXXXXX ZZZZYYYY - Execute next block IF YYYY < ((not ZZZZ) AND half[XXXXXXX])
|
||||||
CompOp<u16>(line, state, &Memory::Read16, [&line](u16 val) -> bool {
|
CompOp<u16>(line, state, Read16, [&line](u16 val) -> bool {
|
||||||
return static_cast<u16>(line.value) < (static_cast<u16>(~line.value >> 16) & val);
|
return static_cast<u16>(line.value) < (static_cast<u16>(~line.value >> 16) & val);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case CheatType::EqualTo16WithMask:
|
case CheatType::EqualTo16WithMask:
|
||||||
// 9XXXXXXX ZZZZYYYY - Execute next block IF YYYY = ((not ZZZZ) AND half[XXXXXXX])
|
// 9XXXXXXX ZZZZYYYY - Execute next block IF YYYY = ((not ZZZZ) AND half[XXXXXXX])
|
||||||
CompOp<u16>(line, state, &Memory::Read16, [&line](u16 val) -> bool {
|
CompOp<u16>(line, state, Read16, [&line](u16 val) -> bool {
|
||||||
return static_cast<u16>(line.value) == (static_cast<u16>(~line.value >> 16) & val);
|
return static_cast<u16>(line.value) == (static_cast<u16>(~line.value >> 16) & val);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case CheatType::NotEqualTo16WithMask:
|
case CheatType::NotEqualTo16WithMask:
|
||||||
// AXXXXXXX ZZZZYYYY - Execute next block IF YYYY <> ((not ZZZZ) AND half[XXXXXXX])
|
// AXXXXXXX ZZZZYYYY - Execute next block IF YYYY <> ((not ZZZZ) AND half[XXXXXXX])
|
||||||
CompOp<u16>(line, state, &Memory::Read16, [&line](u16 val) -> bool {
|
CompOp<u16>(line, state, Read16, [&line](u16 val) -> bool {
|
||||||
return static_cast<u16>(line.value) != (static_cast<u16>(~line.value >> 16) & val);
|
return static_cast<u16>(line.value) != (static_cast<u16>(~line.value >> 16) & val);
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
case CheatType::LoadOffset:
|
case CheatType::LoadOffset:
|
||||||
// BXXXXXXX 00000000 - offset = word[XXXXXXX+offset]
|
// BXXXXXXX 00000000 - offset = word[XXXXXXX+offset]
|
||||||
LoadOffsetOp(line, state);
|
LoadOffsetOp(system.Memory(), line, state);
|
||||||
break;
|
break;
|
||||||
case CheatType::Loop: {
|
case CheatType::Loop: {
|
||||||
// C0000000 YYYYYYYY - LOOP next block YYYYYYYY times
|
// C0000000 YYYYYYYY - LOOP next block YYYYYYYY times
|
||||||
|
@ -343,32 +350,32 @@ void GatewayCheat::Execute(Core::System& system) {
|
||||||
}
|
}
|
||||||
case CheatType::IncrementiveWrite32: {
|
case CheatType::IncrementiveWrite32: {
|
||||||
// D6000000 XXXXXXXX – (32bit) [XXXXXXXX+offset] = reg ; offset += 4
|
// D6000000 XXXXXXXX – (32bit) [XXXXXXXX+offset] = reg ; offset += 4
|
||||||
IncrementiveWriteOp<u32>(line, state, &Memory::Write32, system);
|
IncrementiveWriteOp<u32>(line, state, Write32, system);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CheatType::IncrementiveWrite16: {
|
case CheatType::IncrementiveWrite16: {
|
||||||
// D7000000 XXXXXXXX – (16bit) [XXXXXXXX+offset] = reg & 0xffff ; offset += 2
|
// D7000000 XXXXXXXX – (16bit) [XXXXXXXX+offset] = reg & 0xffff ; offset += 2
|
||||||
IncrementiveWriteOp<u16>(line, state, &Memory::Write16, system);
|
IncrementiveWriteOp<u16>(line, state, Write16, system);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CheatType::IncrementiveWrite8: {
|
case CheatType::IncrementiveWrite8: {
|
||||||
// D8000000 XXXXXXXX – (16bit) [XXXXXXXX+offset] = reg & 0xff ; offset++
|
// D8000000 XXXXXXXX – (16bit) [XXXXXXXX+offset] = reg & 0xff ; offset++
|
||||||
IncrementiveWriteOp<u8>(line, state, &Memory::Write8, system);
|
IncrementiveWriteOp<u8>(line, state, Write8, system);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CheatType::Load32: {
|
case CheatType::Load32: {
|
||||||
// D9000000 XXXXXXXX – reg = [XXXXXXXX+offset]
|
// D9000000 XXXXXXXX – reg = [XXXXXXXX+offset]
|
||||||
LoadOp<u32>(line, state, &Memory::Read32);
|
LoadOp<u32>(line, state, Read32);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CheatType::Load16: {
|
case CheatType::Load16: {
|
||||||
// DA000000 XXXXXXXX – reg = [XXXXXXXX+offset] & 0xFFFF
|
// DA000000 XXXXXXXX – reg = [XXXXXXXX+offset] & 0xFFFF
|
||||||
LoadOp<u16>(line, state, &Memory::Read16);
|
LoadOp<u16>(line, state, Read16);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CheatType::Load8: {
|
case CheatType::Load8: {
|
||||||
// DB000000 XXXXXXXX – reg = [XXXXXXXX+offset] & 0xFF
|
// DB000000 XXXXXXXX – reg = [XXXXXXXX+offset] & 0xFF
|
||||||
LoadOp<u8>(line, state, &Memory::Read8);
|
LoadOp<u8>(line, state, Read8);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case CheatType::AddOffset: {
|
case CheatType::AddOffset: {
|
||||||
|
|
|
@ -143,7 +143,7 @@ System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& file
|
||||||
return ResultStatus::ErrorLoader;
|
return ResultStatus::ErrorLoader;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Memory::SetCurrentPageTable(&kernel->GetCurrentProcess()->vm_manager.page_table);
|
memory->SetCurrentPageTable(&kernel->GetCurrentProcess()->vm_manager.page_table);
|
||||||
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
cheat_engine = std::make_unique<Cheats::CheatEngine>(*this);
|
||||||
status = ResultStatus::Success;
|
status = ResultStatus::Success;
|
||||||
m_emu_window = &emu_window;
|
m_emu_window = &emu_window;
|
||||||
|
@ -172,22 +172,24 @@ void System::Reschedule() {
|
||||||
System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
||||||
LOG_DEBUG(HW_Memory, "initialized OK");
|
LOG_DEBUG(HW_Memory, "initialized OK");
|
||||||
|
|
||||||
|
memory = std::make_unique<Memory::MemorySystem>();
|
||||||
|
|
||||||
timing = std::make_unique<Timing>();
|
timing = std::make_unique<Timing>();
|
||||||
|
|
||||||
kernel = std::make_unique<Kernel::KernelSystem>(system_mode);
|
kernel = std::make_unique<Kernel::KernelSystem>(*memory, 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, USER32MODE);
|
||||||
#else
|
#else
|
||||||
cpu_core = std::make_unique<ARM_DynCom>(USER32MODE);
|
cpu_core = std::make_unique<ARM_DynCom>(*this, 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>(USER32MODE);
|
cpu_core = std::make_unique<ARM_DynCom>(*this, USER32MODE);
|
||||||
}
|
}
|
||||||
|
|
||||||
dsp_core = std::make_unique<AudioCore::DspHle>();
|
dsp_core = std::make_unique<AudioCore::DspHle>(*memory);
|
||||||
dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
|
dsp_core->SetSink(Settings::values.sink_id, Settings::values.audio_device_id);
|
||||||
dsp_core->EnableStretching(Settings::values.enable_audio_stretching);
|
dsp_core->EnableStretching(Settings::values.enable_audio_stretching);
|
||||||
|
|
||||||
|
@ -200,11 +202,11 @@ System::ResultStatus System::Init(EmuWindow& emu_window, u32 system_mode) {
|
||||||
service_manager = std::make_shared<Service::SM::ServiceManager>(*this);
|
service_manager = std::make_shared<Service::SM::ServiceManager>(*this);
|
||||||
archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
|
archive_manager = std::make_unique<Service::FS::ArchiveManager>(*this);
|
||||||
|
|
||||||
HW::Init();
|
HW::Init(*memory);
|
||||||
Service::Init(*this);
|
Service::Init(*this);
|
||||||
GDBStub::Init();
|
GDBStub::Init();
|
||||||
|
|
||||||
ResultStatus result = VideoCore::Init(emu_window);
|
ResultStatus result = VideoCore::Init(emu_window, *memory);
|
||||||
if (result != ResultStatus::Success) {
|
if (result != ResultStatus::Success) {
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
@ -250,6 +252,14 @@ const Timing& System::CoreTiming() const {
|
||||||
return *timing;
|
return *timing;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Memory::MemorySystem& System::Memory() {
|
||||||
|
return *memory;
|
||||||
|
}
|
||||||
|
|
||||||
|
const Memory::MemorySystem& System::Memory() const {
|
||||||
|
return *memory;
|
||||||
|
}
|
||||||
|
|
||||||
Cheats::CheatEngine& System::CheatEngine() {
|
Cheats::CheatEngine& System::CheatEngine() {
|
||||||
return *cheat_engine;
|
return *cheat_engine;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,6 +16,10 @@
|
||||||
class EmuWindow;
|
class EmuWindow;
|
||||||
class ARM_Interface;
|
class ARM_Interface;
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace AudioCore {
|
namespace AudioCore {
|
||||||
class DspInterface;
|
class DspInterface;
|
||||||
}
|
}
|
||||||
|
@ -188,6 +192,12 @@ public:
|
||||||
/// Gets a const reference to the timing system
|
/// Gets a const reference to the timing system
|
||||||
const Timing& CoreTiming() const;
|
const Timing& CoreTiming() const;
|
||||||
|
|
||||||
|
/// Gets a reference to the memory system
|
||||||
|
Memory::MemorySystem& Memory();
|
||||||
|
|
||||||
|
/// Gets a const reference to the memory system
|
||||||
|
const Memory::MemorySystem& Memory() const;
|
||||||
|
|
||||||
/// Gets a reference to the cheat engine
|
/// Gets a reference to the cheat engine
|
||||||
Cheats::CheatEngine& CheatEngine();
|
Cheats::CheatEngine& CheatEngine();
|
||||||
|
|
||||||
|
@ -269,6 +279,9 @@ public: // HACK: this is temporary exposed for tests,
|
||||||
std::unique_ptr<Kernel::KernelSystem> kernel;
|
std::unique_ptr<Kernel::KernelSystem> kernel;
|
||||||
std::unique_ptr<Timing> timing;
|
std::unique_ptr<Timing> timing;
|
||||||
|
|
||||||
|
/// Memory system
|
||||||
|
std::unique_ptr<Memory::MemorySystem> memory;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static System s_instance;
|
static System s_instance;
|
||||||
|
|
||||||
|
|
|
@ -409,7 +409,8 @@ static void RemoveBreakpoint(BreakpointType type, VAddr addr) {
|
||||||
|
|
||||||
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}",
|
LOG_DEBUG(Debug_GDBStub, "gdb: removed a breakpoint: {:08x} bytes at {:08x} of type {}",
|
||||||
bp->second.len, bp->second.addr, static_cast<int>(type));
|
bp->second.len, bp->second.addr, static_cast<int>(type));
|
||||||
Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), bp->second.addr,
|
Core::System::GetInstance().Memory().WriteBlock(
|
||||||
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), bp->second.addr,
|
||||||
bp->second.inst.data(), bp->second.inst.size());
|
bp->second.inst.data(), bp->second.inst.size());
|
||||||
Core::CPU().ClearInstructionCache();
|
Core::CPU().ClearInstructionCache();
|
||||||
p.erase(addr);
|
p.erase(addr);
|
||||||
|
@ -837,8 +838,8 @@ static void ReadMemory() {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<u8> data(len);
|
std::vector<u8> data(len);
|
||||||
Memory::ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(),
|
Core::System::GetInstance().Memory().ReadBlock(
|
||||||
len);
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len);
|
||||||
|
|
||||||
MemToGdbHex(reply, data.data(), len);
|
MemToGdbHex(reply, data.data(), len);
|
||||||
reply[len * 2] = '\0';
|
reply[len * 2] = '\0';
|
||||||
|
@ -863,8 +864,8 @@ static void WriteMemory() {
|
||||||
std::vector<u8> data(len);
|
std::vector<u8> data(len);
|
||||||
|
|
||||||
GdbHexToMem(data.data(), len_pos + 1, len);
|
GdbHexToMem(data.data(), len_pos + 1, len);
|
||||||
Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(),
|
Core::System::GetInstance().Memory().WriteBlock(
|
||||||
len);
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, data.data(), len);
|
||||||
Core::CPU().ClearInstructionCache();
|
Core::CPU().ClearInstructionCache();
|
||||||
SendReply("OK");
|
SendReply("OK");
|
||||||
}
|
}
|
||||||
|
@ -917,11 +918,13 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u32 len) {
|
||||||
breakpoint.active = true;
|
breakpoint.active = true;
|
||||||
breakpoint.addr = addr;
|
breakpoint.addr = addr;
|
||||||
breakpoint.len = len;
|
breakpoint.len = len;
|
||||||
Memory::ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr,
|
Core::System::GetInstance().Memory().ReadBlock(
|
||||||
breakpoint.inst.data(), breakpoint.inst.size());
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, breakpoint.inst.data(),
|
||||||
|
breakpoint.inst.size());
|
||||||
static constexpr std::array<u8, 4> btrap{0x70, 0x00, 0x20, 0xe1};
|
static constexpr std::array<u8, 4> btrap{0x70, 0x00, 0x20, 0xe1};
|
||||||
Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr,
|
Core::System::GetInstance().Memory().WriteBlock(
|
||||||
btrap.data(), btrap.size());
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), addr, btrap.data(),
|
||||||
|
btrap.size());
|
||||||
Core::CPU().ClearInstructionCache();
|
Core::CPU().ClearInstructionCache();
|
||||||
p.insert({addr, breakpoint});
|
p.insert({addr, breakpoint});
|
||||||
|
|
||||||
|
|
|
@ -65,7 +65,7 @@ SharedPtr<Thread> AddressArbiter::ResumeHighestPriorityThread(VAddr address) {
|
||||||
return thread;
|
return thread;
|
||||||
}
|
}
|
||||||
|
|
||||||
AddressArbiter::AddressArbiter(KernelSystem& kernel) : Object(kernel) {}
|
AddressArbiter::AddressArbiter(KernelSystem& kernel) : Object(kernel), kernel(kernel) {}
|
||||||
AddressArbiter::~AddressArbiter() {}
|
AddressArbiter::~AddressArbiter() {}
|
||||||
|
|
||||||
SharedPtr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string name) {
|
SharedPtr<AddressArbiter> KernelSystem::CreateAddressArbiter(std::string name) {
|
||||||
|
@ -103,31 +103,31 @@ ResultCode AddressArbiter::ArbitrateAddress(SharedPtr<Thread> thread, Arbitratio
|
||||||
|
|
||||||
// Wait current thread (acquire the arbiter)...
|
// Wait current thread (acquire the arbiter)...
|
||||||
case ArbitrationType::WaitIfLessThan:
|
case ArbitrationType::WaitIfLessThan:
|
||||||
if ((s32)Memory::Read32(address) < value) {
|
if ((s32)kernel.memory.Read32(address) < value) {
|
||||||
WaitThread(std::move(thread), address);
|
WaitThread(std::move(thread), address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ArbitrationType::WaitIfLessThanWithTimeout:
|
case ArbitrationType::WaitIfLessThanWithTimeout:
|
||||||
if ((s32)Memory::Read32(address) < value) {
|
if ((s32)kernel.memory.Read32(address) < value) {
|
||||||
thread->wakeup_callback = timeout_callback;
|
thread->wakeup_callback = timeout_callback;
|
||||||
thread->WakeAfterDelay(nanoseconds);
|
thread->WakeAfterDelay(nanoseconds);
|
||||||
WaitThread(std::move(thread), address);
|
WaitThread(std::move(thread), address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case ArbitrationType::DecrementAndWaitIfLessThan: {
|
case ArbitrationType::DecrementAndWaitIfLessThan: {
|
||||||
s32 memory_value = Memory::Read32(address);
|
s32 memory_value = kernel.memory.Read32(address);
|
||||||
if (memory_value < value) {
|
if (memory_value < value) {
|
||||||
// Only change the memory value if the thread should wait
|
// Only change the memory value if the thread should wait
|
||||||
Memory::Write32(address, (s32)memory_value - 1);
|
kernel.memory.Write32(address, (s32)memory_value - 1);
|
||||||
WaitThread(std::move(thread), address);
|
WaitThread(std::move(thread), address);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: {
|
case ArbitrationType::DecrementAndWaitIfLessThanWithTimeout: {
|
||||||
s32 memory_value = Memory::Read32(address);
|
s32 memory_value = kernel.memory.Read32(address);
|
||||||
if (memory_value < value) {
|
if (memory_value < value) {
|
||||||
// Only change the memory value if the thread should wait
|
// Only change the memory value if the thread should wait
|
||||||
Memory::Write32(address, (s32)memory_value - 1);
|
kernel.memory.Write32(address, (s32)memory_value - 1);
|
||||||
thread->wakeup_callback = timeout_callback;
|
thread->wakeup_callback = timeout_callback;
|
||||||
thread->WakeAfterDelay(nanoseconds);
|
thread->WakeAfterDelay(nanoseconds);
|
||||||
WaitThread(std::move(thread), address);
|
WaitThread(std::move(thread), address);
|
||||||
|
|
|
@ -52,6 +52,8 @@ private:
|
||||||
explicit AddressArbiter(KernelSystem& kernel);
|
explicit AddressArbiter(KernelSystem& kernel);
|
||||||
~AddressArbiter() override;
|
~AddressArbiter() override;
|
||||||
|
|
||||||
|
KernelSystem& kernel;
|
||||||
|
|
||||||
/// Puts the thread to wait on the specified arbitration address under this address arbiter.
|
/// Puts the thread to wait on the specified arbitration address under this address arbiter.
|
||||||
void WaitThread(SharedPtr<Thread> thread, VAddr wait_address);
|
void WaitThread(SharedPtr<Thread> thread, VAddr wait_address);
|
||||||
|
|
||||||
|
|
|
@ -48,11 +48,12 @@ SharedPtr<Event> HLERequestContext::SleepClientThread(SharedPtr<Thread> thread,
|
||||||
// the translation might need to read from it in order to retrieve the StaticBuffer
|
// the translation might need to read from it in order to retrieve the StaticBuffer
|
||||||
// target addresses.
|
// target addresses.
|
||||||
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
std::array<u32_le, IPC::COMMAND_BUFFER_LENGTH + 2 * IPC::MAX_STATIC_BUFFERS> cmd_buff;
|
||||||
Memory::ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
Memory::MemorySystem& memory = Core::System::GetInstance().Memory();
|
||||||
|
memory.ReadBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||||
cmd_buff.size() * sizeof(u32));
|
cmd_buff.size() * sizeof(u32));
|
||||||
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
context.WriteToOutgoingCommandBuffer(cmd_buff.data(), *process);
|
||||||
// Copy the translated command buffer back into the thread's command buffer area.
|
// Copy the translated command buffer back into the thread's command buffer area.
|
||||||
Memory::WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
memory.WriteBlock(*process, thread->GetCommandBufferAddress(), cmd_buff.data(),
|
||||||
cmd_buff.size() * sizeof(u32));
|
cmd_buff.size() * sizeof(u32));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -142,7 +143,8 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const u32_le* sr
|
||||||
|
|
||||||
// Copy the input buffer into our own vector and store it.
|
// Copy the input buffer into our own vector and store it.
|
||||||
std::vector<u8> data(buffer_info.size);
|
std::vector<u8> data(buffer_info.size);
|
||||||
Memory::ReadBlock(src_process, source_address, data.data(), data.size());
|
Core::System::GetInstance().Memory().ReadBlock(src_process, source_address, data.data(),
|
||||||
|
data.size());
|
||||||
|
|
||||||
AddStaticBuffer(buffer_info.buffer_id, std::move(data));
|
AddStaticBuffer(buffer_info.buffer_id, std::move(data));
|
||||||
cmd_buf[i++] = source_address;
|
cmd_buf[i++] = source_address;
|
||||||
|
@ -209,7 +211,8 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(u32_le* dst_cmdbuf,
|
||||||
|
|
||||||
ASSERT_MSG(target_descriptor.size >= data.size(), "Static buffer data is too big");
|
ASSERT_MSG(target_descriptor.size >= data.size(), "Static buffer data is too big");
|
||||||
|
|
||||||
Memory::WriteBlock(dst_process, target_address, data.data(), data.size());
|
Core::System::GetInstance().Memory().WriteBlock(dst_process, target_address,
|
||||||
|
data.data(), data.size());
|
||||||
|
|
||||||
dst_cmdbuf[i++] = target_address;
|
dst_cmdbuf[i++] = target_address;
|
||||||
break;
|
break;
|
||||||
|
@ -242,13 +245,15 @@ MappedBuffer::MappedBuffer(const Process& process, u32 descriptor, VAddr address
|
||||||
void MappedBuffer::Read(void* dest_buffer, std::size_t offset, std::size_t size) {
|
void MappedBuffer::Read(void* dest_buffer, std::size_t offset, std::size_t size) {
|
||||||
ASSERT(perms & IPC::R);
|
ASSERT(perms & IPC::R);
|
||||||
ASSERT(offset + size <= this->size);
|
ASSERT(offset + size <= this->size);
|
||||||
Memory::ReadBlock(*process, address + static_cast<VAddr>(offset), dest_buffer, size);
|
Core::System::GetInstance().Memory().ReadBlock(*process, address + static_cast<VAddr>(offset),
|
||||||
|
dest_buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t size) {
|
void MappedBuffer::Write(const void* src_buffer, std::size_t offset, std::size_t size) {
|
||||||
ASSERT(perms & IPC::W);
|
ASSERT(perms & IPC::W);
|
||||||
ASSERT(offset + size <= this->size);
|
ASSERT(offset + size <= this->size);
|
||||||
Memory::WriteBlock(*process, address + static_cast<VAddr>(offset), src_buffer, size);
|
Core::System::GetInstance().Memory().WriteBlock(*process, address + static_cast<VAddr>(offset),
|
||||||
|
src_buffer, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -4,6 +4,7 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/ipc.h"
|
#include "core/hle/ipc.h"
|
||||||
#include "core/hle/kernel/handle_table.h"
|
#include "core/hle/kernel/handle_table.h"
|
||||||
#include "core/hle/kernel/ipc.h"
|
#include "core/hle/kernel/ipc.h"
|
||||||
|
@ -19,13 +20,13 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
VAddr src_address, VAddr dst_address,
|
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;
|
||||||
|
|
||||||
IPC::Header header;
|
IPC::Header header;
|
||||||
// TODO(Subv): Replace by Memory::Read32 when possible.
|
// TODO(Subv): Replace by Memory::Read32 when possible.
|
||||||
Memory::ReadBlock(*src_process, src_address, &header.raw, sizeof(header.raw));
|
memory.ReadBlock(*src_process, src_address, &header.raw, sizeof(header.raw));
|
||||||
|
|
||||||
std::size_t untranslated_size = 1u + header.normal_params_size;
|
std::size_t untranslated_size = 1u + header.normal_params_size;
|
||||||
std::size_t command_size = untranslated_size + header.translate_params_size;
|
std::size_t command_size = untranslated_size + header.translate_params_size;
|
||||||
|
@ -34,7 +35,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH);
|
ASSERT(command_size <= IPC::COMMAND_BUFFER_LENGTH);
|
||||||
|
|
||||||
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
|
||||||
Memory::ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32));
|
memory.ReadBlock(*src_process, src_address, cmd_buf.data(), command_size * sizeof(u32));
|
||||||
|
|
||||||
std::size_t i = untranslated_size;
|
std::size_t i = untranslated_size;
|
||||||
while (i < command_size) {
|
while (i < command_size) {
|
||||||
|
@ -90,7 +91,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
VAddr static_buffer_src_address = cmd_buf[i];
|
VAddr static_buffer_src_address = cmd_buf[i];
|
||||||
|
|
||||||
std::vector<u8> data(bufferInfo.size);
|
std::vector<u8> data(bufferInfo.size);
|
||||||
Memory::ReadBlock(*src_process, static_buffer_src_address, data.data(), data.size());
|
memory.ReadBlock(*src_process, static_buffer_src_address, data.data(), data.size());
|
||||||
|
|
||||||
// Grab the address that the target thread set up to receive the response static buffer
|
// Grab the address that the target thread set up to receive the response static buffer
|
||||||
// and write our data there. The static buffers area is located right after the command
|
// and write our data there. The static buffers area is located right after the command
|
||||||
|
@ -106,7 +107,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
|
|
||||||
u32 static_buffer_offset = IPC::COMMAND_BUFFER_LENGTH * sizeof(u32) +
|
u32 static_buffer_offset = IPC::COMMAND_BUFFER_LENGTH * sizeof(u32) +
|
||||||
sizeof(StaticBuffer) * bufferInfo.buffer_id;
|
sizeof(StaticBuffer) * bufferInfo.buffer_id;
|
||||||
Memory::ReadBlock(*dst_process, dst_address + static_buffer_offset, &target_buffer,
|
memory.ReadBlock(*dst_process, dst_address + static_buffer_offset, &target_buffer,
|
||||||
sizeof(target_buffer));
|
sizeof(target_buffer));
|
||||||
|
|
||||||
// Note: The real kernel doesn't seem to have any error recovery mechanisms for this
|
// Note: The real kernel doesn't seem to have any error recovery mechanisms for this
|
||||||
|
@ -114,7 +115,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
ASSERT_MSG(target_buffer.descriptor.size >= data.size(),
|
ASSERT_MSG(target_buffer.descriptor.size >= data.size(),
|
||||||
"Static buffer data is too big");
|
"Static buffer data is too big");
|
||||||
|
|
||||||
Memory::WriteBlock(*dst_process, target_buffer.address, data.data(), data.size());
|
memory.WriteBlock(*dst_process, target_buffer.address, data.data(), data.size());
|
||||||
|
|
||||||
cmd_buf[i++] = target_buffer.address;
|
cmd_buf[i++] = target_buffer.address;
|
||||||
break;
|
break;
|
||||||
|
@ -153,7 +154,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
|
|
||||||
if (permissions != IPC::MappedBufferPermissions::R) {
|
if (permissions != IPC::MappedBufferPermissions::R) {
|
||||||
// Copy the modified buffer back into the target process
|
// Copy the modified buffer back into the target process
|
||||||
Memory::CopyBlock(*src_process, *dst_process, found->target_address,
|
memory.CopyBlock(*src_process, *dst_process, found->target_address,
|
||||||
found->source_address, size);
|
found->source_address, size);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,7 +188,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
|
Memory::PAGE_SIZE, Kernel::MemoryState::Reserved);
|
||||||
|
|
||||||
auto buffer = std::make_unique<u8[]>(num_pages * Memory::PAGE_SIZE);
|
auto buffer = std::make_unique<u8[]>(num_pages * Memory::PAGE_SIZE);
|
||||||
Memory::ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
|
memory.ReadBlock(*src_process, source_address, buffer.get() + page_offset, size);
|
||||||
|
|
||||||
// Map the page(s) into the target process' address space.
|
// Map the page(s) into the target process' address space.
|
||||||
target_address =
|
target_address =
|
||||||
|
@ -215,7 +216,7 @@ ResultCode TranslateCommandBuffer(SharedPtr<Thread> src_thread, SharedPtr<Thread
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Memory::WriteBlock(*dst_process, dst_address, cmd_buf.data(), command_size * sizeof(u32));
|
memory.WriteBlock(*dst_process, dst_address, cmd_buf.data(), command_size * sizeof(u32));
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
|
@ -16,11 +16,11 @@
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
/// Initialize the kernel
|
/// Initialize the kernel
|
||||||
KernelSystem::KernelSystem(u32 system_mode) {
|
KernelSystem::KernelSystem(Memory::MemorySystem& memory, u32 system_mode) : memory(memory) {
|
||||||
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>();
|
thread_manager = std::make_unique<ThreadManager>(*this);
|
||||||
timer_manager = std::make_unique<TimerManager>();
|
timer_manager = std::make_unique<TimerManager>();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -23,6 +23,10 @@ namespace SharedPage {
|
||||||
class Handler;
|
class Handler;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Kernel {
|
namespace Kernel {
|
||||||
|
|
||||||
class AddressArbiter;
|
class AddressArbiter;
|
||||||
|
@ -42,6 +46,7 @@ class SharedMemory;
|
||||||
class ThreadManager;
|
class ThreadManager;
|
||||||
class TimerManager;
|
class TimerManager;
|
||||||
class VMManager;
|
class VMManager;
|
||||||
|
struct AddressMapping;
|
||||||
|
|
||||||
enum class ResetType {
|
enum class ResetType {
|
||||||
OneShot,
|
OneShot,
|
||||||
|
@ -73,7 +78,7 @@ using SharedPtr = boost::intrusive_ptr<T>;
|
||||||
|
|
||||||
class KernelSystem {
|
class KernelSystem {
|
||||||
public:
|
public:
|
||||||
explicit KernelSystem(u32 system_mode);
|
explicit KernelSystem(Memory::MemorySystem& memory, u32 system_mode);
|
||||||
~KernelSystem();
|
~KernelSystem();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -212,6 +217,8 @@ public:
|
||||||
|
|
||||||
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
|
MemoryRegionInfo* GetMemoryRegion(MemoryRegion region);
|
||||||
|
|
||||||
|
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
|
||||||
|
|
||||||
std::array<MemoryRegionInfo, 3> memory_regions;
|
std::array<MemoryRegionInfo, 3> memory_regions;
|
||||||
|
|
||||||
/// Adds a port to the named port table
|
/// Adds a port to the named port table
|
||||||
|
@ -220,6 +227,8 @@ public:
|
||||||
/// 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;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void MemoryInit(u32 mem_type);
|
void MemoryInit(u32 mem_type);
|
||||||
|
|
||||||
|
|
|
@ -83,7 +83,7 @@ MemoryRegionInfo* KernelSystem::GetMemoryRegion(MemoryRegion region) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {
|
void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping) {
|
||||||
using namespace Memory;
|
using namespace Memory;
|
||||||
|
|
||||||
struct MemoryArea {
|
struct MemoryArea {
|
||||||
|
@ -128,7 +128,7 @@ void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mappin
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* target_pointer = Memory::GetPhysicalPointer(area->paddr_base + offset_into_region);
|
u8* target_pointer = memory.GetPhysicalPointer(area->paddr_base + offset_into_region);
|
||||||
|
|
||||||
// TODO(yuriks): This flag seems to have some other effect, but it's unknown what
|
// 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;
|
MemoryState memory_state = mapping.unk_flag ? MemoryState::Static : MemoryState::IO;
|
||||||
|
|
|
@ -62,6 +62,4 @@ struct MemoryRegionInfo {
|
||||||
void Free(u32 offset, u32 size);
|
void Free(u32 offset, u32 size);
|
||||||
};
|
};
|
||||||
|
|
||||||
void HandleSpecialMapping(VMManager& address_space, const AddressMapping& mapping);
|
|
||||||
|
|
||||||
} // namespace Kernel
|
} // namespace Kernel
|
||||||
|
|
|
@ -120,7 +120,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
||||||
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
|
auto MapSegment = [&](CodeSet::Segment& segment, VMAPermission permissions,
|
||||||
MemoryState memory_state) {
|
MemoryState memory_state) {
|
||||||
HeapAllocate(segment.addr, segment.size, permissions, memory_state, true);
|
HeapAllocate(segment.addr, segment.size, permissions, memory_state, true);
|
||||||
Memory::WriteBlock(*this, segment.addr, codeset->memory->data() + segment.offset,
|
kernel.memory.WriteBlock(*this, segment.addr, codeset->memory->data() + segment.offset,
|
||||||
segment.size);
|
segment.size);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -136,7 +136,7 @@ void Process::Run(s32 main_thread_priority, u32 stack_size) {
|
||||||
// Map special address mappings
|
// Map special address mappings
|
||||||
kernel.MapSharedPages(vm_manager);
|
kernel.MapSharedPages(vm_manager);
|
||||||
for (const auto& mapping : address_mappings) {
|
for (const auto& mapping : address_mappings) {
|
||||||
HandleSpecialMapping(vm_manager, mapping);
|
kernel.HandleSpecialMapping(vm_manager, mapping);
|
||||||
}
|
}
|
||||||
|
|
||||||
status = ProcessStatus::Running;
|
status = ProcessStatus::Running;
|
||||||
|
@ -188,10 +188,11 @@ ResultVal<VAddr> Process::HeapAllocate(VAddr target, u32 size, VMAPermission per
|
||||||
u32 interval_size = interval.upper() - interval.lower();
|
u32 interval_size = interval.upper() - interval.lower();
|
||||||
LOG_DEBUG(Kernel, "Allocated FCRAM region lower={:08X}, upper={:08X}", interval.lower(),
|
LOG_DEBUG(Kernel, "Allocated FCRAM region lower={:08X}, upper={:08X}", interval.lower(),
|
||||||
interval.upper());
|
interval.upper());
|
||||||
std::fill(Memory::fcram.begin() + interval.lower(),
|
std::fill(kernel.memory.GetFCRAMPointer(interval.lower()),
|
||||||
Memory::fcram.begin() + interval.upper(), 0);
|
kernel.memory.GetFCRAMPointer(interval.upper()), 0);
|
||||||
auto vma = vm_manager.MapBackingMemory(
|
auto vma = vm_manager.MapBackingMemory(interval_target,
|
||||||
interval_target, Memory::fcram.data() + interval.lower(), interval_size, memory_state);
|
kernel.memory.GetFCRAMPointer(interval.lower()),
|
||||||
|
interval_size, memory_state);
|
||||||
ASSERT(vma.Succeeded());
|
ASSERT(vma.Succeeded());
|
||||||
vm_manager.Reprotect(vma.Unwrap(), perms);
|
vm_manager.Reprotect(vma.Unwrap(), perms);
|
||||||
interval_target += interval_size;
|
interval_target += interval_size;
|
||||||
|
@ -218,7 +219,7 @@ ResultCode Process::HeapFree(VAddr target, u32 size) {
|
||||||
// Free heaps block by block
|
// Free heaps block by block
|
||||||
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
|
CASCADE_RESULT(auto backing_blocks, vm_manager.GetBackingBlocksForRange(target, size));
|
||||||
for (const auto [backing_memory, block_size] : backing_blocks) {
|
for (const auto [backing_memory, block_size] : backing_blocks) {
|
||||||
memory_region->Free(Memory::GetFCRAMOffset(backing_memory), block_size);
|
memory_region->Free(kernel.memory.GetFCRAMOffset(backing_memory), block_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
ResultCode result = vm_manager.UnmapRange(target, size);
|
ResultCode result = vm_manager.UnmapRange(target, size);
|
||||||
|
@ -262,7 +263,7 @@ ResultVal<VAddr> Process::LinearAllocate(VAddr target, u32 size, VMAPermission p
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* backing_memory = Memory::fcram.data() + physical_offset;
|
u8* backing_memory = kernel.memory.GetFCRAMPointer(physical_offset);
|
||||||
|
|
||||||
std::fill(backing_memory, backing_memory + size, 0);
|
std::fill(backing_memory, backing_memory + size, 0);
|
||||||
auto vma = vm_manager.MapBackingMemory(target, backing_memory, size, MemoryState::Continuous);
|
auto vma = vm_manager.MapBackingMemory(target, backing_memory, size, MemoryState::Continuous);
|
||||||
|
|
|
@ -43,8 +43,8 @@ ResultVal<SharedPtr<SharedMemory>> KernelSystem::CreateSharedMemory(
|
||||||
|
|
||||||
ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!");
|
ASSERT_MSG(offset, "Not enough space in region to allocate shared memory!");
|
||||||
|
|
||||||
std::fill(Memory::fcram.data() + *offset, Memory::fcram.data() + *offset + size, 0);
|
std::fill(memory.GetFCRAMPointer(*offset), memory.GetFCRAMPointer(*offset + size), 0);
|
||||||
shared_memory->backing_blocks = {{Memory::fcram.data() + *offset, size}};
|
shared_memory->backing_blocks = {{memory.GetFCRAMPointer(*offset), size}};
|
||||||
shared_memory->holding_memory += MemoryRegionInfo::Interval(*offset, *offset + size);
|
shared_memory->holding_memory += MemoryRegionInfo::Interval(*offset, *offset + size);
|
||||||
shared_memory->linear_heap_phys_offset = *offset;
|
shared_memory->linear_heap_phys_offset = *offset;
|
||||||
|
|
||||||
|
@ -86,9 +86,9 @@ SharedPtr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet(
|
||||||
shared_memory->other_permissions = other_permissions;
|
shared_memory->other_permissions = other_permissions;
|
||||||
for (const auto& interval : backing_blocks) {
|
for (const auto& interval : backing_blocks) {
|
||||||
shared_memory->backing_blocks.push_back(
|
shared_memory->backing_blocks.push_back(
|
||||||
{Memory::fcram.data() + interval.lower(), interval.upper() - interval.lower()});
|
{memory.GetFCRAMPointer(interval.lower()), interval.upper() - interval.lower()});
|
||||||
std::fill(Memory::fcram.data() + interval.lower(), Memory::fcram.data() + interval.upper(),
|
std::fill(memory.GetFCRAMPointer(interval.lower()),
|
||||||
0);
|
memory.GetFCRAMPointer(interval.upper()), 0);
|
||||||
}
|
}
|
||||||
shared_memory->base_address = Memory::HEAP_VADDR + offset;
|
shared_memory->base_address = Memory::HEAP_VADDR + offset;
|
||||||
|
|
||||||
|
|
|
@ -105,6 +105,7 @@ public:
|
||||||
private:
|
private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
Kernel::KernelSystem& kernel;
|
Kernel::KernelSystem& kernel;
|
||||||
|
Memory::MemorySystem& memory;
|
||||||
|
|
||||||
friend class SVCWrapper<SVC>;
|
friend class SVCWrapper<SVC>;
|
||||||
|
|
||||||
|
@ -351,7 +352,7 @@ ResultCode SVC::ConnectToPort(Handle* out_handle, VAddr port_name_address) {
|
||||||
|
|
||||||
static constexpr std::size_t PortNameMaxLength = 11;
|
static constexpr std::size_t PortNameMaxLength = 11;
|
||||||
// Read 1 char beyond the max allowed port name to detect names that are too long.
|
// Read 1 char beyond the max allowed port name to detect names that are too long.
|
||||||
std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1);
|
std::string port_name = memory.ReadCString(port_name_address, PortNameMaxLength + 1);
|
||||||
if (port_name.size() > PortNameMaxLength)
|
if (port_name.size() > PortNameMaxLength)
|
||||||
return ERR_PORT_NAME_TOO_LONG;
|
return ERR_PORT_NAME_TOO_LONG;
|
||||||
|
|
||||||
|
@ -466,7 +467,7 @@ ResultCode SVC::WaitSynchronizationN(s32* out, VAddr handles_address, s32 handle
|
||||||
std::vector<ObjectPtr> objects(handle_count);
|
std::vector<ObjectPtr> objects(handle_count);
|
||||||
|
|
||||||
for (int i = 0; i < handle_count; ++i) {
|
for (int i = 0; i < handle_count; ++i) {
|
||||||
Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
|
||||||
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
|
auto object = kernel.GetCurrentProcess()->handle_table.Get<WaitObject>(handle);
|
||||||
if (object == nullptr)
|
if (object == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
@ -635,7 +636,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
SharedPtr<Process> current_process = kernel.GetCurrentProcess();
|
SharedPtr<Process> current_process = kernel.GetCurrentProcess();
|
||||||
|
|
||||||
for (int i = 0; i < handle_count; ++i) {
|
for (int i = 0; i < handle_count; ++i) {
|
||||||
Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
|
Handle handle = memory.Read32(handles_address + i * sizeof(Handle));
|
||||||
auto object = current_process->handle_table.Get<WaitObject>(handle);
|
auto object = current_process->handle_table.Get<WaitObject>(handle);
|
||||||
if (object == nullptr)
|
if (object == nullptr)
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
@ -645,7 +646,7 @@ ResultCode SVC::ReplyAndReceive(s32* index, VAddr handles_address, s32 handle_co
|
||||||
// We are also sending a command reply.
|
// We are also sending a command reply.
|
||||||
// Do not send a reply if the command id in the command buffer is 0xFFFF.
|
// Do not send a reply if the command id in the command buffer is 0xFFFF.
|
||||||
Thread* thread = kernel.GetThreadManager().GetCurrentThread();
|
Thread* thread = kernel.GetThreadManager().GetCurrentThread();
|
||||||
u32 cmd_buff_header = Memory::Read32(thread->GetCommandBufferAddress());
|
u32 cmd_buff_header = memory.Read32(thread->GetCommandBufferAddress());
|
||||||
IPC::Header header{cmd_buff_header};
|
IPC::Header header{cmd_buff_header};
|
||||||
if (reply_target != 0 && header.command_id != 0xFFFF) {
|
if (reply_target != 0 && header.command_id != 0xFFFF) {
|
||||||
auto session = current_process->handle_table.Get<ServerSession>(reply_target);
|
auto session = current_process->handle_table.Get<ServerSession>(reply_target);
|
||||||
|
@ -801,7 +802,7 @@ void SVC::OutputDebugString(VAddr address, s32 len) {
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string string(len, ' ');
|
std::string string(len, ' ');
|
||||||
Memory::ReadBlock(*kernel.GetCurrentProcess(), address, string.data(), len);
|
memory.ReadBlock(*kernel.GetCurrentProcess(), address, string.data(), len);
|
||||||
LOG_DEBUG(Debug_Emulated, "{}", string);
|
LOG_DEBUG(Debug_Emulated, "{}", string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -831,9 +832,9 @@ ResultCode SVC::GetResourceLimitCurrentValues(VAddr values, Handle resource_limi
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < name_count; ++i) {
|
for (unsigned int i = 0; i < name_count; ++i) {
|
||||||
u32 name = Memory::Read32(names + i * sizeof(u32));
|
u32 name = memory.Read32(names + i * sizeof(u32));
|
||||||
s64 value = resource_limit->GetCurrentResourceValue(name);
|
s64 value = resource_limit->GetCurrentResourceValue(name);
|
||||||
Memory::Write64(values + i * sizeof(u64), value);
|
memory.Write64(values + i * sizeof(u64), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -851,9 +852,9 @@ ResultCode SVC::GetResourceLimitLimitValues(VAddr values, Handle resource_limit_
|
||||||
return ERR_INVALID_HANDLE;
|
return ERR_INVALID_HANDLE;
|
||||||
|
|
||||||
for (unsigned int i = 0; i < name_count; ++i) {
|
for (unsigned int i = 0; i < name_count; ++i) {
|
||||||
u32 name = Memory::Read32(names + i * sizeof(u32));
|
u32 name = memory.Read32(names + i * sizeof(u32));
|
||||||
s64 value = resource_limit->GetMaxResourceValue(name);
|
s64 value = resource_limit->GetMaxResourceValue(name);
|
||||||
Memory::Write64(values + i * sizeof(u64), value);
|
memory.Write64(values + i * sizeof(u64), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -1584,7 +1585,7 @@ void SVC::CallSVC(u32 immediate) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SVC::SVC(Core::System& system) : system(system), kernel(system.Kernel()) {}
|
SVC::SVC(Core::System& system) : system(system), kernel(system.Kernel()), memory(system.Memory()) {}
|
||||||
|
|
||||||
u32 SVC::GetReg(std::size_t n) {
|
u32 SVC::GetReg(std::size_t n) {
|
||||||
return system.CPU().GetReg(static_cast<int>(n));
|
return system.CPU().GetReg(static_cast<int>(n));
|
||||||
|
|
|
@ -104,7 +104,7 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||||
// Cancel any outstanding wakeup events for this thread
|
// Cancel any outstanding wakeup events for this thread
|
||||||
timing.UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id);
|
timing.UnscheduleEvent(ThreadWakeupEventType, new_thread->thread_id);
|
||||||
|
|
||||||
auto previous_process = Core::System::GetInstance().Kernel().GetCurrentProcess();
|
auto previous_process = kernel.GetCurrentProcess();
|
||||||
|
|
||||||
current_thread = new_thread;
|
current_thread = new_thread;
|
||||||
|
|
||||||
|
@ -112,8 +112,9 @@ void ThreadManager::SwitchContext(Thread* new_thread) {
|
||||||
new_thread->status = ThreadStatus::Running;
|
new_thread->status = ThreadStatus::Running;
|
||||||
|
|
||||||
if (previous_process != current_thread->owner_process) {
|
if (previous_process != current_thread->owner_process) {
|
||||||
Core::System::GetInstance().Kernel().SetCurrentProcess(current_thread->owner_process);
|
kernel.SetCurrentProcess(current_thread->owner_process);
|
||||||
SetCurrentPageTable(¤t_thread->owner_process->vm_manager.page_table);
|
kernel.memory.SetCurrentPageTable(
|
||||||
|
¤t_thread->owner_process->vm_manager.page_table);
|
||||||
}
|
}
|
||||||
|
|
||||||
Core::CPU().LoadContext(new_thread->context);
|
Core::CPU().LoadContext(new_thread->context);
|
||||||
|
@ -354,7 +355,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
||||||
|
|
||||||
// Map the page to the current process' address space.
|
// Map the page to the current process' address space.
|
||||||
vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
vm_manager.MapBackingMemory(Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE,
|
||||||
Memory::fcram.data() + *offset, Memory::PAGE_SIZE,
|
memory.GetFCRAMPointer(*offset), Memory::PAGE_SIZE,
|
||||||
MemoryState::Locked);
|
MemoryState::Locked);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -363,7 +364,7 @@ ResultVal<SharedPtr<Thread>> KernelSystem::CreateThread(std::string name, VAddr
|
||||||
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
thread->tls_address = Memory::TLS_AREA_VADDR + available_page * Memory::PAGE_SIZE +
|
||||||
available_slot * Memory::TLS_ENTRY_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
|
// TODO(peachum): move to ScheduleThread() when scheduler is added so selected core is used
|
||||||
// to initialize the context
|
// to initialize the context
|
||||||
|
@ -460,7 +461,7 @@ VAddr Thread::GetCommandBufferAddress() const {
|
||||||
return GetTLSAddress() + CommandHeaderOffset;
|
return GetTLSAddress() + CommandHeaderOffset;
|
||||||
}
|
}
|
||||||
|
|
||||||
ThreadManager::ThreadManager() {
|
ThreadManager::ThreadManager(Kernel::KernelSystem& kernel) : kernel(kernel) {
|
||||||
ThreadWakeupEventType = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
ThreadWakeupEventType = Core::System::GetInstance().CoreTiming().RegisterEvent(
|
||||||
"ThreadWakeupCallback",
|
"ThreadWakeupCallback",
|
||||||
[this](u64 thread_id, s64 cycle_late) { ThreadWakeupCallback(thread_id, cycle_late); });
|
[this](u64 thread_id, s64 cycle_late) { ThreadWakeupCallback(thread_id, cycle_late); });
|
||||||
|
|
|
@ -57,7 +57,7 @@ enum class ThreadWakeupReason {
|
||||||
|
|
||||||
class ThreadManager {
|
class ThreadManager {
|
||||||
public:
|
public:
|
||||||
ThreadManager();
|
explicit ThreadManager(Kernel::KernelSystem& kernel);
|
||||||
~ThreadManager();
|
~ThreadManager();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -121,6 +121,8 @@ private:
|
||||||
*/
|
*/
|
||||||
void ThreadWakeupCallback(u64 thread_id, s64 cycles_late);
|
void ThreadWakeupCallback(u64 thread_id, s64 cycles_late);
|
||||||
|
|
||||||
|
Kernel::KernelSystem& kernel;
|
||||||
|
|
||||||
u32 next_thread_id = 1;
|
u32 next_thread_id = 1;
|
||||||
SharedPtr<Thread> current_thread;
|
SharedPtr<Thread> current_thread;
|
||||||
Common::ThreadQueueList<Thread*, ThreadPrioLowest + 1> ready_queue;
|
Common::ThreadQueueList<Thread*, ThreadPrioLowest + 1> ready_queue;
|
||||||
|
|
|
@ -113,7 +113,7 @@ void Module::CompletionEventCallBack(u64 port_id, s64) {
|
||||||
if (copy_length <= 0) {
|
if (copy_length <= 0) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
Memory::WriteBlock(*port.dest_process, dest_ptr, src_ptr, copy_length);
|
system.Memory().WriteBlock(*port.dest_process, dest_ptr, src_ptr, copy_length);
|
||||||
dest_ptr += copy_length;
|
dest_ptr += copy_length;
|
||||||
dest_size_left -= copy_length;
|
dest_size_left -= copy_length;
|
||||||
src_ptr += original_width;
|
src_ptr += original_width;
|
||||||
|
@ -125,7 +125,7 @@ void Module::CompletionEventCallBack(u64 port_id, s64) {
|
||||||
LOG_ERROR(Service_CAM, "The destination size ({}) doesn't match the source ({})!",
|
LOG_ERROR(Service_CAM, "The destination size ({}) doesn't match the source ({})!",
|
||||||
port.dest_size, buffer_size);
|
port.dest_size, buffer_size);
|
||||||
}
|
}
|
||||||
Memory::WriteBlock(*port.dest_process, port.dest, buffer.data(),
|
system.Memory().WriteBlock(*port.dest_process, port.dest, buffer.data(),
|
||||||
std::min<std::size_t>(port.dest_size, buffer_size));
|
std::min<std::size_t>(port.dest_size, buffer_size));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -491,6 +491,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||||
// GX request DMA - typically used for copying memory from GSP heap to VRAM
|
// GX request DMA - typically used for copying memory from GSP heap to VRAM
|
||||||
case CommandId::REQUEST_DMA: {
|
case CommandId::REQUEST_DMA: {
|
||||||
MICROPROFILE_SCOPE(GPU_GSP_DMA);
|
MICROPROFILE_SCOPE(GPU_GSP_DMA);
|
||||||
|
Memory::MemorySystem& memory = Core::System::GetInstance().Memory();
|
||||||
|
|
||||||
// TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever
|
// TODO: Consider attempting rasterizer-accelerated surface blit if that usage is ever
|
||||||
// possible/likely
|
// possible/likely
|
||||||
|
@ -502,7 +503,7 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||||
|
|
||||||
// TODO(Subv): These memory accesses should not go through the application's memory mapping.
|
// TODO(Subv): These memory accesses should not go through the application's memory mapping.
|
||||||
// They should go through the GSP module's memory mapping.
|
// They should go through the GSP module's memory mapping.
|
||||||
Memory::CopyBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(),
|
memory.CopyBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(),
|
||||||
command.dma_request.dest_address, command.dma_request.source_address,
|
command.dma_request.dest_address, command.dma_request.source_address,
|
||||||
command.dma_request.size);
|
command.dma_request.size);
|
||||||
SignalInterrupt(InterruptId::DMA);
|
SignalInterrupt(InterruptId::DMA);
|
||||||
|
|
|
@ -55,7 +55,7 @@ VAddr CROHelper::SegmentTagToAddress(SegmentTag segment_tag) const {
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
SegmentEntry entry;
|
SegmentEntry entry;
|
||||||
GetEntry(segment_tag.segment_index, entry);
|
GetEntry(memory, segment_tag.segment_index, entry);
|
||||||
|
|
||||||
if (segment_tag.offset_into_segment >= entry.size)
|
if (segment_tag.offset_into_segment >= entry.size)
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -71,11 +71,11 @@ ResultCode CROHelper::ApplyRelocation(VAddr target_address, RelocationType reloc
|
||||||
break;
|
break;
|
||||||
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));
|
Core::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));
|
Core::CPU().InvalidateCacheRange(target_address, sizeof(u32));
|
||||||
break;
|
break;
|
||||||
case RelocationType::ThumbBranch:
|
case RelocationType::ThumbBranch:
|
||||||
|
@ -98,7 +98,7 @@ ResultCode CROHelper::ClearRelocation(VAddr target_address, RelocationType reloc
|
||||||
case RelocationType::AbsoluteAddress:
|
case RelocationType::AbsoluteAddress:
|
||||||
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));
|
Core::CPU().InvalidateCacheRange(target_address, sizeof(u32));
|
||||||
break;
|
break;
|
||||||
case RelocationType::ThumbBranch:
|
case RelocationType::ThumbBranch:
|
||||||
|
@ -121,7 +121,7 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
|
||||||
VAddr relocation_address = batch;
|
VAddr relocation_address = batch;
|
||||||
while (true) {
|
while (true) {
|
||||||
RelocationEntry relocation;
|
RelocationEntry relocation;
|
||||||
Memory::ReadBlock(process, relocation_address, &relocation, sizeof(RelocationEntry));
|
memory.ReadBlock(process, relocation_address, &relocation, sizeof(RelocationEntry));
|
||||||
|
|
||||||
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
||||||
if (relocation_target == 0) {
|
if (relocation_target == 0) {
|
||||||
|
@ -142,9 +142,9 @@ ResultCode CROHelper::ApplyRelocationBatch(VAddr batch, u32 symbol_address, bool
|
||||||
}
|
}
|
||||||
|
|
||||||
RelocationEntry relocation;
|
RelocationEntry relocation;
|
||||||
Memory::ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
|
memory.ReadBlock(process, batch, &relocation, sizeof(RelocationEntry));
|
||||||
relocation.is_batch_resolved = reset ? 0 : 1;
|
relocation.is_batch_resolved = reset ? 0 : 1;
|
||||||
Memory::WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
|
memory.WriteBlock(process, batch, &relocation, sizeof(RelocationEntry));
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -154,13 +154,13 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
|
||||||
|
|
||||||
std::size_t len = name.size();
|
std::size_t len = name.size();
|
||||||
ExportTreeEntry entry;
|
ExportTreeEntry entry;
|
||||||
GetEntry(0, entry);
|
GetEntry(memory, 0, entry);
|
||||||
ExportTreeEntry::Child next;
|
ExportTreeEntry::Child next;
|
||||||
next.raw = entry.left.raw;
|
next.raw = entry.left.raw;
|
||||||
u32 found_id;
|
u32 found_id;
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
GetEntry(next.next_index, entry);
|
GetEntry(memory, next.next_index, entry);
|
||||||
|
|
||||||
if (next.is_end) {
|
if (next.is_end) {
|
||||||
found_id = entry.export_table_index;
|
found_id = entry.export_table_index;
|
||||||
|
@ -186,9 +186,9 @@ VAddr CROHelper::FindExportNamedSymbol(const std::string& name) const {
|
||||||
|
|
||||||
u32 export_strings_size = GetField(ExportStringsSize);
|
u32 export_strings_size = GetField(ExportStringsSize);
|
||||||
ExportNamedSymbolEntry symbol_entry;
|
ExportNamedSymbolEntry symbol_entry;
|
||||||
GetEntry(found_id, symbol_entry);
|
GetEntry(memory, found_id, symbol_entry);
|
||||||
|
|
||||||
if (Memory::ReadCString(symbol_entry.name_offset, export_strings_size) != name)
|
if (memory.ReadCString(symbol_entry.name_offset, export_strings_size) != name)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
return SegmentTagToAddress(symbol_entry.symbol_position);
|
return SegmentTagToAddress(symbol_entry.symbol_position);
|
||||||
|
@ -279,7 +279,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
|
||||||
u32 segment_num = GetField(SegmentNum);
|
u32 segment_num = GetField(SegmentNum);
|
||||||
for (u32 i = 0; i < segment_num; ++i) {
|
for (u32 i = 0; i < segment_num; ++i) {
|
||||||
SegmentEntry segment;
|
SegmentEntry segment;
|
||||||
GetEntry(i, segment);
|
GetEntry(memory, i, segment);
|
||||||
if (segment.type == SegmentType::Data) {
|
if (segment.type == SegmentType::Data) {
|
||||||
if (segment.size != 0) {
|
if (segment.size != 0) {
|
||||||
if (segment.size > data_segment_size)
|
if (segment.size > data_segment_size)
|
||||||
|
@ -298,7 +298,7 @@ ResultVal<VAddr> CROHelper::RebaseSegmentTable(u32 cro_size, VAddr data_segment_
|
||||||
if (segment.offset > module_address + cro_size)
|
if (segment.offset > module_address + cro_size)
|
||||||
return CROFormatError(0x19);
|
return CROFormatError(0x19);
|
||||||
}
|
}
|
||||||
SetEntry(i, segment);
|
SetEntry(memory, i, segment);
|
||||||
}
|
}
|
||||||
return MakeResult<u32>(prev_data_segment + module_address);
|
return MakeResult<u32>(prev_data_segment + module_address);
|
||||||
}
|
}
|
||||||
|
@ -310,7 +310,7 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
|
||||||
u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
|
u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < export_named_symbol_num; ++i) {
|
for (u32 i = 0; i < export_named_symbol_num; ++i) {
|
||||||
ExportNamedSymbolEntry entry;
|
ExportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.name_offset != 0) {
|
if (entry.name_offset != 0) {
|
||||||
entry.name_offset += module_address;
|
entry.name_offset += module_address;
|
||||||
|
@ -320,7 +320,7 @@ ResultCode CROHelper::RebaseExportNamedSymbolTable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -329,7 +329,7 @@ ResultCode CROHelper::VerifyExportTreeTable() const {
|
||||||
u32 tree_num = GetField(ExportTreeNum);
|
u32 tree_num = GetField(ExportTreeNum);
|
||||||
for (u32 i = 0; i < tree_num; ++i) {
|
for (u32 i = 0; i < tree_num; ++i) {
|
||||||
ExportTreeEntry entry;
|
ExportTreeEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) {
|
if (entry.left.next_index >= tree_num || entry.right.next_index >= tree_num) {
|
||||||
return CROFormatError(0x11);
|
return CROFormatError(0x11);
|
||||||
|
@ -353,7 +353,7 @@ ResultCode CROHelper::RebaseImportModuleTable() {
|
||||||
u32 module_num = GetField(ImportModuleNum);
|
u32 module_num = GetField(ImportModuleNum);
|
||||||
for (u32 i = 0; i < module_num; ++i) {
|
for (u32 i = 0; i < module_num; ++i) {
|
||||||
ImportModuleEntry entry;
|
ImportModuleEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.name_offset != 0) {
|
if (entry.name_offset != 0) {
|
||||||
entry.name_offset += module_address;
|
entry.name_offset += module_address;
|
||||||
|
@ -379,7 +379,7 @@ ResultCode CROHelper::RebaseImportModuleTable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -395,7 +395,7 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
|
||||||
u32 num = GetField(ImportNamedSymbolNum);
|
u32 num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < num; ++i) {
|
for (u32 i = 0; i < num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.name_offset != 0) {
|
if (entry.name_offset != 0) {
|
||||||
entry.name_offset += module_address;
|
entry.name_offset += module_address;
|
||||||
|
@ -413,7 +413,7 @@ ResultCode CROHelper::RebaseImportNamedSymbolTable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -427,7 +427,7 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
|
||||||
u32 num = GetField(ImportIndexedSymbolNum);
|
u32 num = GetField(ImportIndexedSymbolNum);
|
||||||
for (u32 i = 0; i < num; ++i) {
|
for (u32 i = 0; i < num; ++i) {
|
||||||
ImportIndexedSymbolEntry entry;
|
ImportIndexedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.relocation_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.relocation_batch_offset += module_address;
|
entry.relocation_batch_offset += module_address;
|
||||||
|
@ -437,7 +437,7 @@ ResultCode CROHelper::RebaseImportIndexedSymbolTable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -451,7 +451,7 @@ ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
|
||||||
u32 num = GetField(ImportAnonymousSymbolNum);
|
u32 num = GetField(ImportAnonymousSymbolNum);
|
||||||
for (u32 i = 0; i < num; ++i) {
|
for (u32 i = 0; i < num; ++i) {
|
||||||
ImportAnonymousSymbolEntry entry;
|
ImportAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.relocation_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.relocation_batch_offset += module_address;
|
entry.relocation_batch_offset += module_address;
|
||||||
|
@ -461,7 +461,7 @@ ResultCode CROHelper::RebaseImportAnonymousSymbolTable() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
@ -476,14 +476,14 @@ ResultCode CROHelper::ResetExternalRelocations() {
|
||||||
ExternalRelocationEntry relocation;
|
ExternalRelocationEntry relocation;
|
||||||
|
|
||||||
// Verifies that the last relocation is the end of a batch
|
// Verifies that the last relocation is the end of a batch
|
||||||
GetEntry(external_relocation_num - 1, relocation);
|
GetEntry(memory, external_relocation_num - 1, relocation);
|
||||||
if (!relocation.is_batch_end) {
|
if (!relocation.is_batch_end) {
|
||||||
return CROFormatError(0x12);
|
return CROFormatError(0x12);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool batch_begin = true;
|
bool batch_begin = true;
|
||||||
for (u32 i = 0; i < external_relocation_num; ++i) {
|
for (u32 i = 0; i < external_relocation_num; ++i) {
|
||||||
GetEntry(i, relocation);
|
GetEntry(memory, i, relocation);
|
||||||
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
||||||
|
|
||||||
if (relocation_target == 0) {
|
if (relocation_target == 0) {
|
||||||
|
@ -500,7 +500,7 @@ ResultCode CROHelper::ResetExternalRelocations() {
|
||||||
if (batch_begin) {
|
if (batch_begin) {
|
||||||
// resets to unresolved state
|
// resets to unresolved state
|
||||||
relocation.is_batch_resolved = 0;
|
relocation.is_batch_resolved = 0;
|
||||||
SetEntry(i, relocation);
|
SetEntry(memory, i, relocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if current is an end, then the next is a beginning
|
// if current is an end, then the next is a beginning
|
||||||
|
@ -516,7 +516,7 @@ ResultCode CROHelper::ClearExternalRelocations() {
|
||||||
|
|
||||||
bool batch_begin = true;
|
bool batch_begin = true;
|
||||||
for (u32 i = 0; i < external_relocation_num; ++i) {
|
for (u32 i = 0; i < external_relocation_num; ++i) {
|
||||||
GetEntry(i, relocation);
|
GetEntry(memory, i, relocation);
|
||||||
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
VAddr relocation_target = SegmentTagToAddress(relocation.target_position);
|
||||||
|
|
||||||
if (relocation_target == 0) {
|
if (relocation_target == 0) {
|
||||||
|
@ -532,7 +532,7 @@ ResultCode CROHelper::ClearExternalRelocations() {
|
||||||
if (batch_begin) {
|
if (batch_begin) {
|
||||||
// resets to unresolved state
|
// resets to unresolved state
|
||||||
relocation.is_batch_resolved = 0;
|
relocation.is_batch_resolved = 0;
|
||||||
SetEntry(i, relocation);
|
SetEntry(memory, i, relocation);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if current is an end, then the next is a beginning
|
// if current is an end, then the next is a beginning
|
||||||
|
@ -548,13 +548,13 @@ 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);
|
CROHelper crs(crs_address, process, memory);
|
||||||
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);
|
||||||
for (u32 i = 0; i < offset_export_num; ++i) {
|
for (u32 i = 0; i < offset_export_num; ++i) {
|
||||||
StaticAnonymousSymbolEntry entry;
|
StaticAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
u32 batch_address = entry.relocation_batch_offset + module_address;
|
u32 batch_address = entry.relocation_batch_offset + module_address;
|
||||||
|
|
||||||
if (batch_address < static_relocation_table_offset ||
|
if (batch_address < static_relocation_table_offset ||
|
||||||
|
@ -579,7 +579,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
|
||||||
u32 internal_relocation_num = GetField(InternalRelocationNum);
|
u32 internal_relocation_num = GetField(InternalRelocationNum);
|
||||||
for (u32 i = 0; i < internal_relocation_num; ++i) {
|
for (u32 i = 0; i < internal_relocation_num; ++i) {
|
||||||
InternalRelocationEntry relocation;
|
InternalRelocationEntry relocation;
|
||||||
GetEntry(i, relocation);
|
GetEntry(memory, i, relocation);
|
||||||
VAddr target_addressB = SegmentTagToAddress(relocation.target_position);
|
VAddr target_addressB = SegmentTagToAddress(relocation.target_position);
|
||||||
if (target_addressB == 0) {
|
if (target_addressB == 0) {
|
||||||
return CROFormatError(0x15);
|
return CROFormatError(0x15);
|
||||||
|
@ -587,7 +587,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
|
||||||
|
|
||||||
VAddr target_address;
|
VAddr target_address;
|
||||||
SegmentEntry target_segment;
|
SegmentEntry target_segment;
|
||||||
GetEntry(relocation.target_position.segment_index, target_segment);
|
GetEntry(memory, relocation.target_position.segment_index, target_segment);
|
||||||
|
|
||||||
if (target_segment.type == SegmentType::Data) {
|
if (target_segment.type == SegmentType::Data) {
|
||||||
// If the relocation is to the .data segment, we need to relocate it in the old buffer
|
// If the relocation is to the .data segment, we need to relocate it in the old buffer
|
||||||
|
@ -602,7 +602,7 @@ ResultCode CROHelper::ApplyInternalRelocations(u32 old_data_segment_address) {
|
||||||
}
|
}
|
||||||
|
|
||||||
SegmentEntry symbol_segment;
|
SegmentEntry symbol_segment;
|
||||||
GetEntry(relocation.symbol_segment, symbol_segment);
|
GetEntry(memory, relocation.symbol_segment, symbol_segment);
|
||||||
LOG_TRACE(Service_LDR, "Internally relocates 0x{:08X} with 0x{:08X}", target_address,
|
LOG_TRACE(Service_LDR, "Internally relocates 0x{:08X} with 0x{:08X}", target_address,
|
||||||
symbol_segment.offset);
|
symbol_segment.offset);
|
||||||
ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend,
|
ResultCode result = ApplyRelocation(target_address, relocation.type, relocation.addend,
|
||||||
|
@ -619,7 +619,7 @@ ResultCode CROHelper::ClearInternalRelocations() {
|
||||||
u32 internal_relocation_num = GetField(InternalRelocationNum);
|
u32 internal_relocation_num = GetField(InternalRelocationNum);
|
||||||
for (u32 i = 0; i < internal_relocation_num; ++i) {
|
for (u32 i = 0; i < internal_relocation_num; ++i) {
|
||||||
InternalRelocationEntry relocation;
|
InternalRelocationEntry relocation;
|
||||||
GetEntry(i, relocation);
|
GetEntry(memory, i, relocation);
|
||||||
VAddr target_address = SegmentTagToAddress(relocation.target_position);
|
VAddr target_address = SegmentTagToAddress(relocation.target_position);
|
||||||
|
|
||||||
if (target_address == 0) {
|
if (target_address == 0) {
|
||||||
|
@ -639,13 +639,13 @@ void CROHelper::UnrebaseImportAnonymousSymbolTable() {
|
||||||
u32 num = GetField(ImportAnonymousSymbolNum);
|
u32 num = GetField(ImportAnonymousSymbolNum);
|
||||||
for (u32 i = 0; i < num; ++i) {
|
for (u32 i = 0; i < num; ++i) {
|
||||||
ImportAnonymousSymbolEntry entry;
|
ImportAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.relocation_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.relocation_batch_offset -= module_address;
|
entry.relocation_batch_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -653,13 +653,13 @@ void CROHelper::UnrebaseImportIndexedSymbolTable() {
|
||||||
u32 num = GetField(ImportIndexedSymbolNum);
|
u32 num = GetField(ImportIndexedSymbolNum);
|
||||||
for (u32 i = 0; i < num; ++i) {
|
for (u32 i = 0; i < num; ++i) {
|
||||||
ImportIndexedSymbolEntry entry;
|
ImportIndexedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.relocation_batch_offset != 0) {
|
if (entry.relocation_batch_offset != 0) {
|
||||||
entry.relocation_batch_offset -= module_address;
|
entry.relocation_batch_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -667,7 +667,7 @@ void CROHelper::UnrebaseImportNamedSymbolTable() {
|
||||||
u32 num = GetField(ImportNamedSymbolNum);
|
u32 num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < num; ++i) {
|
for (u32 i = 0; i < num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.name_offset != 0) {
|
if (entry.name_offset != 0) {
|
||||||
entry.name_offset -= module_address;
|
entry.name_offset -= module_address;
|
||||||
|
@ -677,7 +677,7 @@ void CROHelper::UnrebaseImportNamedSymbolTable() {
|
||||||
entry.relocation_batch_offset -= module_address;
|
entry.relocation_batch_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -685,7 +685,7 @@ void CROHelper::UnrebaseImportModuleTable() {
|
||||||
u32 module_num = GetField(ImportModuleNum);
|
u32 module_num = GetField(ImportModuleNum);
|
||||||
for (u32 i = 0; i < module_num; ++i) {
|
for (u32 i = 0; i < module_num; ++i) {
|
||||||
ImportModuleEntry entry;
|
ImportModuleEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.name_offset != 0) {
|
if (entry.name_offset != 0) {
|
||||||
entry.name_offset -= module_address;
|
entry.name_offset -= module_address;
|
||||||
|
@ -699,7 +699,7 @@ void CROHelper::UnrebaseImportModuleTable() {
|
||||||
entry.import_anonymous_symbol_table_offset -= module_address;
|
entry.import_anonymous_symbol_table_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -707,13 +707,13 @@ void CROHelper::UnrebaseExportNamedSymbolTable() {
|
||||||
u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
|
u32 export_named_symbol_num = GetField(ExportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < export_named_symbol_num; ++i) {
|
for (u32 i = 0; i < export_named_symbol_num; ++i) {
|
||||||
ExportNamedSymbolEntry entry;
|
ExportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (entry.name_offset != 0) {
|
if (entry.name_offset != 0) {
|
||||||
entry.name_offset -= module_address;
|
entry.name_offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, entry);
|
SetEntry(memory, i, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -721,7 +721,7 @@ void CROHelper::UnrebaseSegmentTable() {
|
||||||
u32 segment_num = GetField(SegmentNum);
|
u32 segment_num = GetField(SegmentNum);
|
||||||
for (u32 i = 0; i < segment_num; ++i) {
|
for (u32 i = 0; i < segment_num; ++i) {
|
||||||
SegmentEntry segment;
|
SegmentEntry segment;
|
||||||
GetEntry(i, segment);
|
GetEntry(memory, i, segment);
|
||||||
|
|
||||||
if (segment.type == SegmentType::BSS) {
|
if (segment.type == SegmentType::BSS) {
|
||||||
segment.offset = 0;
|
segment.offset = 0;
|
||||||
|
@ -729,7 +729,7 @@ void CROHelper::UnrebaseSegmentTable() {
|
||||||
segment.offset -= module_address;
|
segment.offset -= module_address;
|
||||||
}
|
}
|
||||||
|
|
||||||
SetEntry(i, segment);
|
SetEntry(memory, i, segment);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -751,17 +751,17 @@ ResultCode CROHelper::ApplyImportNamedSymbol(VAddr crs_address) {
|
||||||
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < symbol_import_num; ++i) {
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (!relocation_entry.is_batch_resolved) {
|
if (!relocation_entry.is_batch_resolved) {
|
||||||
ResultCode result =
|
ResultCode result = ForEachAutoLinkCRO(
|
||||||
ForEachAutoLinkCRO(process, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
process, memory, 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);
|
||||||
|
|
||||||
if (symbol_address != 0) {
|
if (symbol_address != 0) {
|
||||||
|
@ -794,10 +794,10 @@ ResultCode CROHelper::ResetImportNamedSymbol() {
|
||||||
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < symbol_import_num; ++i) {
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
|
@ -815,10 +815,10 @@ ResultCode CROHelper::ResetImportIndexedSymbol() {
|
||||||
u32 import_num = GetField(ImportIndexedSymbolNum);
|
u32 import_num = GetField(ImportIndexedSymbolNum);
|
||||||
for (u32 i = 0; i < import_num; ++i) {
|
for (u32 i = 0; i < import_num; ++i) {
|
||||||
ImportIndexedSymbolEntry entry;
|
ImportIndexedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
|
@ -836,10 +836,10 @@ ResultCode CROHelper::ResetImportAnonymousSymbol() {
|
||||||
u32 import_num = GetField(ImportAnonymousSymbolNum);
|
u32 import_num = GetField(ImportAnonymousSymbolNum);
|
||||||
for (u32 i = 0; i < import_num; ++i) {
|
for (u32 i = 0; i < import_num; ++i) {
|
||||||
ImportAnonymousSymbolEntry entry;
|
ImportAnonymousSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
ResultCode result = ApplyRelocationBatch(relocation_addr, unresolved_symbol, true);
|
||||||
|
@ -857,19 +857,19 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
|
||||||
u32 import_module_num = GetField(ImportModuleNum);
|
u32 import_module_num = GetField(ImportModuleNum);
|
||||||
for (u32 i = 0; i < import_module_num; ++i) {
|
for (u32 i = 0; i < import_module_num; ++i) {
|
||||||
ImportModuleEntry entry;
|
ImportModuleEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
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 =
|
ResultCode result = ForEachAutoLinkCRO(
|
||||||
ForEachAutoLinkCRO(process, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
process, memory, 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());
|
||||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||||
ImportIndexedSymbolEntry im;
|
ImportIndexedSymbolEntry im;
|
||||||
entry.GetImportIndexedSymbolEntry(process, j, im);
|
entry.GetImportIndexedSymbolEntry(process, memory, j, im);
|
||||||
ExportIndexedSymbolEntry ex;
|
ExportIndexedSymbolEntry ex;
|
||||||
source.GetEntry(im.index, ex);
|
source.GetEntry(memory, im.index, ex);
|
||||||
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
|
u32 symbol_address = source.SegmentTagToAddress(ex.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
|
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
|
||||||
ResultCode result =
|
ResultCode result =
|
||||||
|
@ -884,7 +884,7 @@ ResultCode CROHelper::ApplyModuleImport(VAddr crs_address) {
|
||||||
ModuleName(), entry.import_anonymous_symbol_num, source.ModuleName());
|
ModuleName(), entry.import_anonymous_symbol_num, source.ModuleName());
|
||||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||||
ImportAnonymousSymbolEntry im;
|
ImportAnonymousSymbolEntry im;
|
||||||
entry.GetImportAnonymousSymbolEntry(process, j, im);
|
entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
|
||||||
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
|
u32 symbol_address = source.SegmentTagToAddress(im.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
|
LOG_TRACE(Service_LDR, " Imports 0x{:08X}", symbol_address);
|
||||||
ResultCode result =
|
ResultCode result =
|
||||||
|
@ -913,15 +913,15 @@ ResultCode CROHelper::ApplyExportNamedSymbol(CROHelper target) {
|
||||||
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
target.GetEntry(i, entry);
|
target.GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (!relocation_entry.is_batch_resolved) {
|
if (!relocation_entry.is_batch_resolved) {
|
||||||
std::string symbol_name =
|
std::string symbol_name =
|
||||||
Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
memory.ReadCString(entry.name_offset, target_import_strings_size);
|
||||||
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
||||||
if (symbol_address != 0) {
|
if (symbol_address != 0) {
|
||||||
LOG_TRACE(Service_LDR, " exports symbol \"{}\"", symbol_name);
|
LOG_TRACE(Service_LDR, " exports symbol \"{}\"", symbol_name);
|
||||||
|
@ -944,15 +944,15 @@ ResultCode CROHelper::ResetExportNamedSymbol(CROHelper target) {
|
||||||
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
u32 target_symbol_import_num = target.GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
for (u32 i = 0; i < target_symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
target.GetEntry(i, entry);
|
target.GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (relocation_entry.is_batch_resolved) {
|
if (relocation_entry.is_batch_resolved) {
|
||||||
std::string symbol_name =
|
std::string symbol_name =
|
||||||
Memory::ReadCString(entry.name_offset, target_import_strings_size);
|
memory.ReadCString(entry.name_offset, target_import_strings_size);
|
||||||
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
u32 symbol_address = FindExportNamedSymbol(symbol_name);
|
||||||
if (symbol_address != 0) {
|
if (symbol_address != 0) {
|
||||||
LOG_TRACE(Service_LDR, " unexports symbol \"{}\"", symbol_name);
|
LOG_TRACE(Service_LDR, " unexports symbol \"{}\"", symbol_name);
|
||||||
|
@ -974,18 +974,18 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
|
||||||
u32 target_import_module_num = target.GetField(ImportModuleNum);
|
u32 target_import_module_num = target.GetField(ImportModuleNum);
|
||||||
for (u32 i = 0; i < target_import_module_num; ++i) {
|
for (u32 i = 0; i < target_import_module_num; ++i) {
|
||||||
ImportModuleEntry entry;
|
ImportModuleEntry entry;
|
||||||
target.GetEntry(i, entry);
|
target.GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
if (memory.ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} indexed symbols to \"{}\"", module_name,
|
LOG_INFO(Service_LDR, "CRO \"{}\" exports {} indexed symbols to \"{}\"", module_name,
|
||||||
entry.import_indexed_symbol_num, target.ModuleName());
|
entry.import_indexed_symbol_num, target.ModuleName());
|
||||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||||
ImportIndexedSymbolEntry im;
|
ImportIndexedSymbolEntry im;
|
||||||
entry.GetImportIndexedSymbolEntry(process, j, im);
|
entry.GetImportIndexedSymbolEntry(process, memory, j, im);
|
||||||
ExportIndexedSymbolEntry ex;
|
ExportIndexedSymbolEntry ex;
|
||||||
GetEntry(im.index, ex);
|
GetEntry(memory, im.index, ex);
|
||||||
u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
|
u32 symbol_address = SegmentTagToAddress(ex.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
|
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
|
||||||
ResultCode result =
|
ResultCode result =
|
||||||
|
@ -1000,7 +1000,7 @@ ResultCode CROHelper::ApplyModuleExport(CROHelper target) {
|
||||||
entry.import_anonymous_symbol_num, target.ModuleName());
|
entry.import_anonymous_symbol_num, target.ModuleName());
|
||||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||||
ImportAnonymousSymbolEntry im;
|
ImportAnonymousSymbolEntry im;
|
||||||
entry.GetImportAnonymousSymbolEntry(process, j, im);
|
entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
|
||||||
u32 symbol_address = SegmentTagToAddress(im.symbol_position);
|
u32 symbol_address = SegmentTagToAddress(im.symbol_position);
|
||||||
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
|
LOG_TRACE(Service_LDR, " exports symbol 0x{:08X}", symbol_address);
|
||||||
ResultCode result =
|
ResultCode result =
|
||||||
|
@ -1023,16 +1023,16 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
|
||||||
u32 target_import_module_num = target.GetField(ImportModuleNum);
|
u32 target_import_module_num = target.GetField(ImportModuleNum);
|
||||||
for (u32 i = 0; i < target_import_module_num; ++i) {
|
for (u32 i = 0; i < target_import_module_num; ++i) {
|
||||||
ImportModuleEntry entry;
|
ImportModuleEntry entry;
|
||||||
target.GetEntry(i, entry);
|
target.GetEntry(memory, i, entry);
|
||||||
|
|
||||||
if (Memory::ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
if (memory.ReadCString(entry.name_offset, target_import_string_size) != module_name)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
LOG_DEBUG(Service_LDR, "CRO \"{}\" unexports indexed symbols to \"{}\"", module_name,
|
LOG_DEBUG(Service_LDR, "CRO \"{}\" unexports indexed symbols to \"{}\"", module_name,
|
||||||
target.ModuleName());
|
target.ModuleName());
|
||||||
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_indexed_symbol_num; ++j) {
|
||||||
ImportIndexedSymbolEntry im;
|
ImportIndexedSymbolEntry im;
|
||||||
entry.GetImportIndexedSymbolEntry(process, j, im);
|
entry.GetImportIndexedSymbolEntry(process, memory, j, im);
|
||||||
ResultCode result =
|
ResultCode result =
|
||||||
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
|
@ -1045,7 +1045,7 @@ ResultCode CROHelper::ResetModuleExport(CROHelper target) {
|
||||||
target.ModuleName());
|
target.ModuleName());
|
||||||
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
for (u32 j = 0; j < entry.import_anonymous_symbol_num; ++j) {
|
||||||
ImportAnonymousSymbolEntry im;
|
ImportAnonymousSymbolEntry im;
|
||||||
entry.GetImportAnonymousSymbolEntry(process, j, im);
|
entry.GetImportAnonymousSymbolEntry(process, memory, j, im);
|
||||||
ResultCode result =
|
ResultCode result =
|
||||||
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
target.ApplyRelocationBatch(im.relocation_batch_offset, unresolved_symbol, true);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
|
@ -1063,15 +1063,15 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
|
||||||
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
u32 symbol_import_num = GetField(ImportNamedSymbolNum);
|
||||||
for (u32 i = 0; i < symbol_import_num; ++i) {
|
for (u32 i = 0; i < symbol_import_num; ++i) {
|
||||||
ImportNamedSymbolEntry entry;
|
ImportNamedSymbolEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
VAddr relocation_addr = entry.relocation_batch_offset;
|
VAddr relocation_addr = entry.relocation_batch_offset;
|
||||||
ExternalRelocationEntry relocation_entry;
|
ExternalRelocationEntry relocation_entry;
|
||||||
Memory::ReadBlock(process, relocation_addr, &relocation_entry,
|
memory.ReadBlock(process, relocation_addr, &relocation_entry,
|
||||||
sizeof(ExternalRelocationEntry));
|
sizeof(ExternalRelocationEntry));
|
||||||
|
|
||||||
if (Memory::ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
|
if (memory.ReadCString(entry.name_offset, import_strings_size) == "__aeabi_atexit") {
|
||||||
ResultCode result =
|
ResultCode result = ForEachAutoLinkCRO(
|
||||||
ForEachAutoLinkCRO(process, crs_address, [&](CROHelper source) -> ResultVal<bool> {
|
process, memory, 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) {
|
||||||
|
@ -1108,9 +1108,9 @@ ResultCode CROHelper::ApplyExitRelocations(VAddr crs_address) {
|
||||||
* @param size the size of the string (table), including the terminating 0
|
* @param size the size of the string (table), including the terminating 0
|
||||||
* @returns ResultCode RESULT_SUCCESS if the size matches, otherwise error code.
|
* @returns ResultCode RESULT_SUCCESS if the size matches, otherwise error code.
|
||||||
*/
|
*/
|
||||||
static ResultCode VerifyStringTableLength(VAddr address, u32 size) {
|
static ResultCode VerifyStringTableLength(Memory::MemorySystem& memory, VAddr address, u32 size) {
|
||||||
if (size != 0) {
|
if (size != 0) {
|
||||||
if (Memory::Read8(address + size - 1) != 0)
|
if (memory.Read8(address + size - 1) != 0)
|
||||||
return CROFormatError(0x0B);
|
return CROFormatError(0x0B);
|
||||||
}
|
}
|
||||||
return RESULT_SUCCESS;
|
return RESULT_SUCCESS;
|
||||||
|
@ -1126,7 +1126,7 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = VerifyStringTableLength(GetField(ModuleNameOffset), GetField(ModuleNameSize));
|
result = VerifyStringTableLength(memory, GetField(ModuleNameOffset), GetField(ModuleNameSize));
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error verifying module name {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error verifying module name {:08X}", result.raw);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1155,7 +1155,8 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = VerifyStringTableLength(GetField(ExportStringsOffset), GetField(ExportStringsSize));
|
result =
|
||||||
|
VerifyStringTableLength(memory, GetField(ExportStringsOffset), GetField(ExportStringsSize));
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error verifying export strings {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error verifying export strings {:08X}", result.raw);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1191,7 +1192,8 @@ ResultCode CROHelper::Rebase(VAddr crs_address, u32 cro_size, VAddr data_segment
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = VerifyStringTableLength(GetField(ImportStringsOffset), GetField(ImportStringsSize));
|
result =
|
||||||
|
VerifyStringTableLength(memory, GetField(ImportStringsOffset), GetField(ImportStringsSize));
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
LOG_ERROR(Service_LDR, "Error verifying import strings {:08X}", result.raw);
|
LOG_ERROR(Service_LDR, "Error verifying import strings {:08X}", result.raw);
|
||||||
return result;
|
return result;
|
||||||
|
@ -1264,11 +1266,11 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
|
||||||
// so we do the same
|
// so we do the same
|
||||||
if (GetField(SegmentNum) >= 2) { // means we have .data segment
|
if (GetField(SegmentNum) >= 2) { // means we have .data segment
|
||||||
SegmentEntry entry;
|
SegmentEntry entry;
|
||||||
GetEntry(2, entry);
|
GetEntry(memory, 2, entry);
|
||||||
ASSERT(entry.type == SegmentType::Data);
|
ASSERT(entry.type == SegmentType::Data);
|
||||||
data_segment_address = entry.offset;
|
data_segment_address = entry.offset;
|
||||||
entry.offset = GetField(DataOffset);
|
entry.offset = GetField(DataOffset);
|
||||||
SetEntry(2, entry);
|
SetEntry(memory, 2, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SCOPE_EXIT({
|
SCOPE_EXIT({
|
||||||
|
@ -1276,9 +1278,9 @@ ResultCode CROHelper::Link(VAddr crs_address, bool link_on_load_bug_fix) {
|
||||||
if (link_on_load_bug_fix) {
|
if (link_on_load_bug_fix) {
|
||||||
if (GetField(SegmentNum) >= 2) {
|
if (GetField(SegmentNum) >= 2) {
|
||||||
SegmentEntry entry;
|
SegmentEntry entry;
|
||||||
GetEntry(2, entry);
|
GetEntry(memory, 2, entry);
|
||||||
entry.offset = data_segment_address;
|
entry.offset = data_segment_address;
|
||||||
SetEntry(2, entry);
|
SetEntry(memory, 2, entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -1299,7 +1301,8 @@ 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, crs_address, [this](CROHelper target) -> ResultVal<bool> {
|
result = ForEachAutoLinkCRO(process, memory, crs_address,
|
||||||
|
[this](CROHelper target) -> ResultVal<bool> {
|
||||||
ResultCode result = ApplyExportNamedSymbol(target);
|
ResultCode result = ApplyExportNamedSymbol(target);
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
return result;
|
return result;
|
||||||
|
@ -1343,7 +1346,8 @@ 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, crs_address, [this](CROHelper target) -> ResultVal<bool> {
|
result = ForEachAutoLinkCRO(process, memory, crs_address,
|
||||||
|
[this](CROHelper target) -> ResultVal<bool> {
|
||||||
ResultCode result = ResetExportNamedSymbol(target);
|
ResultCode result = ResetExportNamedSymbol(target);
|
||||||
if (result.IsError())
|
if (result.IsError())
|
||||||
return result;
|
return result;
|
||||||
|
@ -1383,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);
|
CROHelper crs(crs_address, process, memory);
|
||||||
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process);
|
CROHelper head(auto_link ? crs.NextModule() : crs.PreviousModule(), process, memory);
|
||||||
|
|
||||||
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);
|
CROHelper tail(head.PreviousModule(), process, memory);
|
||||||
|
|
||||||
// link with the old tail
|
// link with the old tail
|
||||||
ASSERT(tail.NextModule() == 0);
|
ASSERT(tail.NextModule() == 0);
|
||||||
|
@ -1415,9 +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);
|
CROHelper crs(crs_address, process, memory);
|
||||||
CROHelper next_head(crs.NextModule(), process), previous_head(crs.PreviousModule(), process);
|
CROHelper next_head(crs.NextModule(), process, memory);
|
||||||
CROHelper next(NextModule(), process), previous(PreviousModule(), process);
|
CROHelper previous_head(crs.PreviousModule(), process, memory);
|
||||||
|
CROHelper next(NextModule(), process, memory);
|
||||||
|
CROHelper previous(PreviousModule(), process, memory);
|
||||||
|
|
||||||
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) {
|
||||||
|
@ -1511,7 +1517,7 @@ std::tuple<VAddr, u32> CROHelper::GetExecutablePages() const {
|
||||||
u32 segment_num = GetField(SegmentNum);
|
u32 segment_num = GetField(SegmentNum);
|
||||||
for (u32 i = 0; i < segment_num; ++i) {
|
for (u32 i = 0; i < segment_num; ++i) {
|
||||||
SegmentEntry entry;
|
SegmentEntry entry;
|
||||||
GetEntry(i, entry);
|
GetEntry(memory, i, entry);
|
||||||
if (entry.type == SegmentType::Code && entry.size != 0) {
|
if (entry.type == SegmentType::Code && entry.size != 0) {
|
||||||
VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
|
VAddr begin = Common::AlignDown(entry.offset, Memory::PAGE_SIZE);
|
||||||
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);
|
VAddr end = Common::AlignUp(entry.offset + entry.size, Memory::PAGE_SIZE);
|
||||||
|
|
|
@ -40,11 +40,11 @@ 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)
|
explicit CROHelper(VAddr cro_address, Kernel::Process& process, Memory::MemorySystem& memory)
|
||||||
: module_address(cro_address), process(process) {}
|
: module_address(cro_address), process(process), memory(memory) {}
|
||||||
|
|
||||||
std::string ModuleName() const {
|
std::string ModuleName() const {
|
||||||
return Memory::ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
|
return memory.ReadCString(GetField(ModuleNameOffset), GetField(ModuleNameSize));
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetFileSize() const {
|
u32 GetFileSize() const {
|
||||||
|
@ -150,6 +150,7 @@ public:
|
||||||
private:
|
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;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 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,
|
||||||
|
@ -317,17 +318,17 @@ private:
|
||||||
|
|
||||||
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset;
|
static constexpr HeaderField TABLE_OFFSET_FIELD = ImportModuleTableOffset;
|
||||||
|
|
||||||
void GetImportIndexedSymbolEntry(Kernel::Process& process, u32 index,
|
void GetImportIndexedSymbolEntry(Kernel::Process& process, Memory::MemorySystem& memory,
|
||||||
ImportIndexedSymbolEntry& entry) {
|
u32 index, ImportIndexedSymbolEntry& entry) {
|
||||||
Memory::ReadBlock(process,
|
memory.ReadBlock(process,
|
||||||
import_indexed_symbol_table_offset +
|
import_indexed_symbol_table_offset +
|
||||||
index * sizeof(ImportIndexedSymbolEntry),
|
index * sizeof(ImportIndexedSymbolEntry),
|
||||||
&entry, sizeof(ImportIndexedSymbolEntry));
|
&entry, sizeof(ImportIndexedSymbolEntry));
|
||||||
}
|
}
|
||||||
|
|
||||||
void GetImportAnonymousSymbolEntry(Kernel::Process& process, u32 index,
|
void GetImportAnonymousSymbolEntry(Kernel::Process& process, Memory::MemorySystem& memory,
|
||||||
ImportAnonymousSymbolEntry& entry) {
|
u32 index, ImportAnonymousSymbolEntry& entry) {
|
||||||
Memory::ReadBlock(process,
|
memory.ReadBlock(process,
|
||||||
import_anonymous_symbol_table_offset +
|
import_anonymous_symbol_table_offset +
|
||||||
index * sizeof(ImportAnonymousSymbolEntry),
|
index * sizeof(ImportAnonymousSymbolEntry),
|
||||||
&entry, sizeof(ImportAnonymousSymbolEntry));
|
&entry, sizeof(ImportAnonymousSymbolEntry));
|
||||||
|
@ -407,11 +408,11 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetField(HeaderField field) const {
|
u32 GetField(HeaderField field) const {
|
||||||
return Memory::Read32(Field(field));
|
return memory.Read32(Field(field));
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetField(HeaderField field, u32 value) {
|
void SetField(HeaderField field, u32 value) {
|
||||||
Memory::Write32(Field(field), value);
|
memory.Write32(Field(field), value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -422,8 +423,8 @@ private:
|
||||||
* indicating which table the entry is in.
|
* indicating which table the entry is in.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void GetEntry(std::size_t index, T& data) const {
|
void GetEntry(Memory::MemorySystem& memory, std::size_t index, T& data) const {
|
||||||
Memory::ReadBlock(process,
|
memory.ReadBlock(process,
|
||||||
GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
|
GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
|
||||||
&data, sizeof(T));
|
&data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
@ -436,8 +437,8 @@ private:
|
||||||
* indicating which table the entry is in.
|
* indicating which table the entry is in.
|
||||||
*/
|
*/
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void SetEntry(std::size_t index, const T& data) {
|
void SetEntry(Memory::MemorySystem& memory, std::size_t index, const T& data) {
|
||||||
Memory::WriteBlock(process,
|
memory.WriteBlock(process,
|
||||||
GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
|
GetField(T::TABLE_OFFSET_FIELD) + static_cast<u32>(index * sizeof(T)),
|
||||||
&data, sizeof(T));
|
&data, sizeof(T));
|
||||||
}
|
}
|
||||||
|
@ -478,11 +479,11 @@ private:
|
||||||
* otherwise error code of the last iteration.
|
* otherwise error code of the last iteration.
|
||||||
*/
|
*/
|
||||||
template <typename FunctionObject>
|
template <typename FunctionObject>
|
||||||
static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, VAddr crs_address,
|
static ResultCode ForEachAutoLinkCRO(Kernel::Process& process, Memory::MemorySystem& memory,
|
||||||
FunctionObject func) {
|
VAddr crs_address, FunctionObject func) {
|
||||||
VAddr current = crs_address;
|
VAddr current = crs_address;
|
||||||
while (current != 0) {
|
while (current != 0) {
|
||||||
CROHelper cro(current, process);
|
CROHelper cro(current, process, memory);
|
||||||
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);
|
CROHelper crs(crs_address, *process, system.Memory());
|
||||||
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);
|
CROHelper cro(cro_address, *process, system.Memory());
|
||||||
|
|
||||||
result = cro.VerifyHash(cro_size, crr_address);
|
result = cro.VerifyHash(cro_size, crr_address);
|
||||||
if (result.IsError()) {
|
if (result.IsError()) {
|
||||||
|
@ -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);
|
CROHelper cro(cro_address, *process, system.Memory());
|
||||||
|
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
IPC::RequestBuilder rb = rp.MakeBuilder(1, 0);
|
||||||
|
|
||||||
|
@ -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);
|
CROHelper cro(cro_address, *process, system.Memory());
|
||||||
|
|
||||||
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);
|
CROHelper cro(cro_address, *process, system.Memory());
|
||||||
|
|
||||||
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);
|
CROHelper crs(slot->loaded_crs, *process, system.Memory());
|
||||||
crs.Unrebase(true);
|
crs.Unrebase(true);
|
||||||
|
|
||||||
ResultCode result = RESULT_SUCCESS;
|
ResultCode result = RESULT_SUCCESS;
|
||||||
|
@ -502,7 +502,7 @@ void RO::Shutdown(Kernel::HLERequestContext& ctx) {
|
||||||
rb.Push(result);
|
rb.Push(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
RO::RO() : ServiceFramework("ldr:ro", 2) {
|
RO::RO(Core::System& system) : ServiceFramework("ldr:ro", 2), system(system) {
|
||||||
static const FunctionInfo functions[] = {
|
static const FunctionInfo functions[] = {
|
||||||
{0x000100C2, &RO::Initialize, "Initialize"},
|
{0x000100C2, &RO::Initialize, "Initialize"},
|
||||||
{0x00020082, &RO::LoadCRR, "LoadCRR"},
|
{0x00020082, &RO::LoadCRR, "LoadCRR"},
|
||||||
|
@ -519,7 +519,7 @@ RO::RO() : ServiceFramework("ldr:ro", 2) {
|
||||||
|
|
||||||
void InstallInterfaces(Core::System& system) {
|
void InstallInterfaces(Core::System& system) {
|
||||||
auto& service_manager = system.ServiceManager();
|
auto& service_manager = system.ServiceManager();
|
||||||
std::make_shared<RO>()->InstallAsService(service_manager);
|
std::make_shared<RO>(system)->InstallAsService(service_manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Service::LDR
|
} // namespace Service::LDR
|
||||||
|
|
|
@ -18,7 +18,7 @@ struct ClientSlot : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||||
|
|
||||||
class RO final : public ServiceFramework<RO, ClientSlot> {
|
class RO final : public ServiceFramework<RO, ClientSlot> {
|
||||||
public:
|
public:
|
||||||
RO();
|
explicit RO(Core::System& system);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
|
@ -149,6 +149,8 @@ private:
|
||||||
* 1 : Result of function, 0 on success, otherwise error code
|
* 1 : Result of function, 0 on success, otherwise error code
|
||||||
*/
|
*/
|
||||||
void Shutdown(Kernel::HLERequestContext& self);
|
void Shutdown(Kernel::HLERequestContext& self);
|
||||||
|
|
||||||
|
Core::System& system;
|
||||||
};
|
};
|
||||||
|
|
||||||
void InstallInterfaces(Core::System& system);
|
void InstallInterfaces(Core::System& system);
|
||||||
|
|
|
@ -180,7 +180,8 @@ void ServiceFrameworkBase::HandleSyncRequest(SharedPtr<ServerSession> server_ses
|
||||||
Kernel::KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
Kernel::KernelSystem& kernel = Core::System::GetInstance().Kernel();
|
||||||
auto thread = kernel.GetThreadManager().GetCurrentThread();
|
auto thread = kernel.GetThreadManager().GetCurrentThread();
|
||||||
// TODO(wwylele): avoid GetPointer
|
// TODO(wwylele): avoid GetPointer
|
||||||
u32* cmd_buf = reinterpret_cast<u32*>(Memory::GetPointer(thread->GetCommandBufferAddress()));
|
u32* cmd_buf = reinterpret_cast<u32*>(
|
||||||
|
Core::System::GetInstance().Memory().GetPointer(thread->GetCommandBufferAddress()));
|
||||||
|
|
||||||
u32 header_code = cmd_buf[0];
|
u32 header_code = cmd_buf[0];
|
||||||
auto itr = handlers.find(header_code);
|
auto itr = handlers.find(header_code);
|
||||||
|
|
|
@ -27,6 +27,7 @@
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
|
||||||
Regs g_regs;
|
Regs g_regs;
|
||||||
|
Memory::MemorySystem* g_memory;
|
||||||
|
|
||||||
/// 268MHz CPU clocks / 60Hz frames per second
|
/// 268MHz CPU clocks / 60Hz frames per second
|
||||||
const u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE);
|
const u64 frame_ticks = static_cast<u64>(BASE_CLOCK_RATE_ARM11 / SCREEN_REFRESH_RATE);
|
||||||
|
@ -78,12 +79,12 @@ static void MemoryFill(const Regs::MemoryFillConfig& config) {
|
||||||
const PAddr end_addr = config.GetEndAddress();
|
const PAddr end_addr = config.GetEndAddress();
|
||||||
|
|
||||||
// TODO: do hwtest with these cases
|
// TODO: do hwtest with these cases
|
||||||
if (!Memory::IsValidPhysicalAddress(start_addr)) {
|
if (!g_memory->IsValidPhysicalAddress(start_addr)) {
|
||||||
LOG_CRITICAL(HW_GPU, "invalid start address {:#010X}", start_addr);
|
LOG_CRITICAL(HW_GPU, "invalid start address {:#010X}", start_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Memory::IsValidPhysicalAddress(end_addr)) {
|
if (!g_memory->IsValidPhysicalAddress(end_addr)) {
|
||||||
LOG_CRITICAL(HW_GPU, "invalid end address {:#010X}", end_addr);
|
LOG_CRITICAL(HW_GPU, "invalid end address {:#010X}", end_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -94,8 +95,8 @@ static void MemoryFill(const Regs::MemoryFillConfig& config) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* start = Memory::GetPhysicalPointer(start_addr);
|
u8* start = g_memory->GetPhysicalPointer(start_addr);
|
||||||
u8* end = Memory::GetPhysicalPointer(end_addr);
|
u8* end = g_memory->GetPhysicalPointer(end_addr);
|
||||||
|
|
||||||
if (VideoCore::g_renderer->Rasterizer()->AccelerateFill(config))
|
if (VideoCore::g_renderer->Rasterizer()->AccelerateFill(config))
|
||||||
return;
|
return;
|
||||||
|
@ -131,12 +132,12 @@ static void DisplayTransfer(const Regs::DisplayTransferConfig& config) {
|
||||||
const PAddr dst_addr = config.GetPhysicalOutputAddress();
|
const PAddr dst_addr = config.GetPhysicalOutputAddress();
|
||||||
|
|
||||||
// TODO: do hwtest with these cases
|
// TODO: do hwtest with these cases
|
||||||
if (!Memory::IsValidPhysicalAddress(src_addr)) {
|
if (!g_memory->IsValidPhysicalAddress(src_addr)) {
|
||||||
LOG_CRITICAL(HW_GPU, "invalid input address {:#010X}", src_addr);
|
LOG_CRITICAL(HW_GPU, "invalid input address {:#010X}", src_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Memory::IsValidPhysicalAddress(dst_addr)) {
|
if (!g_memory->IsValidPhysicalAddress(dst_addr)) {
|
||||||
LOG_CRITICAL(HW_GPU, "invalid output address {:#010X}", dst_addr);
|
LOG_CRITICAL(HW_GPU, "invalid output address {:#010X}", dst_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -164,8 +165,8 @@ static void DisplayTransfer(const Regs::DisplayTransferConfig& config) {
|
||||||
if (VideoCore::g_renderer->Rasterizer()->AccelerateDisplayTransfer(config))
|
if (VideoCore::g_renderer->Rasterizer()->AccelerateDisplayTransfer(config))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u8* src_pointer = Memory::GetPhysicalPointer(src_addr);
|
u8* src_pointer = g_memory->GetPhysicalPointer(src_addr);
|
||||||
u8* dst_pointer = Memory::GetPhysicalPointer(dst_addr);
|
u8* dst_pointer = g_memory->GetPhysicalPointer(dst_addr);
|
||||||
|
|
||||||
if (config.scaling > config.ScaleXY) {
|
if (config.scaling > config.ScaleXY) {
|
||||||
LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode {}",
|
LOG_CRITICAL(HW_GPU, "Unimplemented display transfer scaling mode {}",
|
||||||
|
@ -307,12 +308,12 @@ static void TextureCopy(const Regs::DisplayTransferConfig& config) {
|
||||||
const PAddr dst_addr = config.GetPhysicalOutputAddress();
|
const PAddr dst_addr = config.GetPhysicalOutputAddress();
|
||||||
|
|
||||||
// TODO: do hwtest with invalid addresses
|
// TODO: do hwtest with invalid addresses
|
||||||
if (!Memory::IsValidPhysicalAddress(src_addr)) {
|
if (!g_memory->IsValidPhysicalAddress(src_addr)) {
|
||||||
LOG_CRITICAL(HW_GPU, "invalid input address {:#010X}", src_addr);
|
LOG_CRITICAL(HW_GPU, "invalid input address {:#010X}", src_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!Memory::IsValidPhysicalAddress(dst_addr)) {
|
if (!g_memory->IsValidPhysicalAddress(dst_addr)) {
|
||||||
LOG_CRITICAL(HW_GPU, "invalid output address {:#010X}", dst_addr);
|
LOG_CRITICAL(HW_GPU, "invalid output address {:#010X}", dst_addr);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -320,8 +321,8 @@ static void TextureCopy(const Regs::DisplayTransferConfig& config) {
|
||||||
if (VideoCore::g_renderer->Rasterizer()->AccelerateTextureCopy(config))
|
if (VideoCore::g_renderer->Rasterizer()->AccelerateTextureCopy(config))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
u8* src_pointer = Memory::GetPhysicalPointer(src_addr);
|
u8* src_pointer = g_memory->GetPhysicalPointer(src_addr);
|
||||||
u8* dst_pointer = Memory::GetPhysicalPointer(dst_addr);
|
u8* dst_pointer = g_memory->GetPhysicalPointer(dst_addr);
|
||||||
|
|
||||||
u32 remaining_size = Common::AlignDown(config.texture_copy.size, 16);
|
u32 remaining_size = Common::AlignDown(config.texture_copy.size, 16);
|
||||||
|
|
||||||
|
@ -470,7 +471,7 @@ inline void Write(u32 addr, const T data) {
|
||||||
if (config.trigger & 1) {
|
if (config.trigger & 1) {
|
||||||
MICROPROFILE_SCOPE(GPU_CmdlistProcessing);
|
MICROPROFILE_SCOPE(GPU_CmdlistProcessing);
|
||||||
|
|
||||||
u32* buffer = (u32*)Memory::GetPhysicalPointer(config.GetPhysicalAddress());
|
u32* buffer = (u32*)g_memory->GetPhysicalPointer(config.GetPhysicalAddress());
|
||||||
|
|
||||||
if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
|
if (Pica::g_debug_context && Pica::g_debug_context->recorder) {
|
||||||
Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size,
|
Pica::g_debug_context->recorder->MemoryAccessed((u8*)buffer, config.size,
|
||||||
|
@ -526,7 +527,8 @@ static void VBlankCallback(u64 userdata, s64 cycles_late) {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
void Init() {
|
void Init(Memory::MemorySystem& memory) {
|
||||||
|
g_memory = &memory;
|
||||||
memset(&g_regs, 0, sizeof(g_regs));
|
memset(&g_regs, 0, sizeof(g_regs));
|
||||||
|
|
||||||
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
auto& framebuffer_top = g_regs.framebuffer_config[0];
|
||||||
|
|
|
@ -11,6 +11,10 @@
|
||||||
#include "common/common_funcs.h"
|
#include "common/common_funcs.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace GPU {
|
namespace GPU {
|
||||||
|
|
||||||
constexpr float SCREEN_REFRESH_RATE = 60;
|
constexpr float SCREEN_REFRESH_RATE = 60;
|
||||||
|
@ -326,7 +330,7 @@ template <typename T>
|
||||||
void Write(u32 addr, const T data);
|
void Write(u32 addr, const T data);
|
||||||
|
|
||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
void Init();
|
void Init(Memory::MemorySystem& memory);
|
||||||
|
|
||||||
/// Shutdown hardware
|
/// Shutdown hardware
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
|
@ -86,9 +86,9 @@ template void Write<u8>(u32 addr, const u8 data);
|
||||||
void Update() {}
|
void Update() {}
|
||||||
|
|
||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
void Init() {
|
void Init(Memory::MemorySystem& memory) {
|
||||||
AES::InitKeys();
|
AES::InitKeys();
|
||||||
GPU::Init();
|
GPU::Init(memory);
|
||||||
LCD::Init();
|
LCD::Init();
|
||||||
LOG_DEBUG(HW, "initialized OK");
|
LOG_DEBUG(HW, "initialized OK");
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,10 @@
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
namespace HW {
|
namespace HW {
|
||||||
|
|
||||||
/// Beginnings of IO register regions, in the user VA space.
|
/// Beginnings of IO register regions, in the user VA space.
|
||||||
|
@ -42,7 +46,7 @@ void Write(u32 addr, const T data);
|
||||||
void Update();
|
void Update();
|
||||||
|
|
||||||
/// Initialize hardware
|
/// Initialize hardware
|
||||||
void Init();
|
void Init(Memory::MemorySystem& memory);
|
||||||
|
|
||||||
/// Shutdown hardware
|
/// Shutdown hardware
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
|
@ -10,6 +10,7 @@
|
||||||
#include "common/color.h"
|
#include "common/color.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/vector_math.h"
|
#include "common/vector_math.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/hle/service/y2r_u.h"
|
#include "core/hle/service/y2r_u.h"
|
||||||
#include "core/hw/y2r.h"
|
#include "core/hw/y2r.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
|
@ -80,7 +81,7 @@ static void ConvertYUVToRGB(InputFormat input_format, const u8* input_Y, const u
|
||||||
/// formats to 8-bit.
|
/// formats to 8-bit.
|
||||||
template <std::size_t N>
|
template <std::size_t N>
|
||||||
static void ReceiveData(u8* output, ConversionBuffer& buf, std::size_t amount_of_data) {
|
static void ReceiveData(u8* output, ConversionBuffer& buf, std::size_t amount_of_data) {
|
||||||
const u8* input = Memory::GetPointer(buf.address);
|
const u8* input = Core::System::GetInstance().Memory().GetPointer(buf.address);
|
||||||
|
|
||||||
std::size_t output_unit = buf.transfer_unit / N;
|
std::size_t output_unit = buf.transfer_unit / N;
|
||||||
ASSERT(amount_of_data % output_unit == 0);
|
ASSERT(amount_of_data % output_unit == 0);
|
||||||
|
@ -104,7 +105,7 @@ static void ReceiveData(u8* output, ConversionBuffer& buf, std::size_t amount_of
|
||||||
static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data,
|
static void SendData(const u32* input, ConversionBuffer& buf, int amount_of_data,
|
||||||
OutputFormat output_format, u8 alpha) {
|
OutputFormat output_format, u8 alpha) {
|
||||||
|
|
||||||
u8* output = Memory::GetPointer(buf.address);
|
u8* output = Core::System::GetInstance().Memory().GetPointer(buf.address);
|
||||||
|
|
||||||
while (amount_of_data > 0) {
|
while (amount_of_data > 0) {
|
||||||
u8* unit_end = output + buf.transfer_unit;
|
u8* unit_end = output + buf.transfer_unit;
|
||||||
|
|
|
@ -21,21 +21,35 @@
|
||||||
|
|
||||||
namespace Memory {
|
namespace Memory {
|
||||||
|
|
||||||
static std::array<u8, Memory::VRAM_SIZE> vram;
|
class MemorySystem::Impl {
|
||||||
static std::array<u8, Memory::N3DS_EXTRA_RAM_SIZE> n3ds_extra_ram;
|
public:
|
||||||
std::array<u8, Memory::FCRAM_N3DS_SIZE> fcram;
|
Impl() {
|
||||||
|
std::fill(fcram.get(), fcram.get() + Memory::FCRAM_N3DS_SIZE, 0);
|
||||||
|
std::fill(vram.get(), vram.get() + Memory::VRAM_SIZE, 0);
|
||||||
|
std::fill(n3ds_extra_ram.get(), n3ds_extra_ram.get() + Memory::N3DS_EXTRA_RAM_SIZE, 0);
|
||||||
|
}
|
||||||
|
|
||||||
static PageTable* current_page_table = nullptr;
|
// Visual Studio would try to allocate these on compile time if they are std::array, which would
|
||||||
|
// exceed the memory limit.
|
||||||
|
std::unique_ptr<u8[]> fcram = std::make_unique<u8[]>(Memory::FCRAM_N3DS_SIZE);
|
||||||
|
std::unique_ptr<u8[]> vram = std::make_unique<u8[]>(Memory::VRAM_SIZE);
|
||||||
|
std::unique_ptr<u8[]> n3ds_extra_ram = std::make_unique<u8[]>(Memory::N3DS_EXTRA_RAM_SIZE);
|
||||||
|
|
||||||
void SetCurrentPageTable(PageTable* page_table) {
|
PageTable* current_page_table = nullptr;
|
||||||
current_page_table = page_table;
|
};
|
||||||
|
|
||||||
|
MemorySystem::MemorySystem() : impl(std::make_unique<Impl>()) {}
|
||||||
|
MemorySystem::~MemorySystem() = default;
|
||||||
|
|
||||||
|
void MemorySystem::SetCurrentPageTable(PageTable* page_table) {
|
||||||
|
impl->current_page_table = page_table;
|
||||||
if (Core::System::GetInstance().IsPoweredOn()) {
|
if (Core::System::GetInstance().IsPoweredOn()) {
|
||||||
Core::CPU().PageTableChanged();
|
Core::CPU().PageTableChanged();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
PageTable* GetCurrentPageTable() {
|
PageTable* MemorySystem::GetCurrentPageTable() const {
|
||||||
return current_page_table;
|
return impl->current_page_table;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) {
|
static void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) {
|
||||||
|
@ -78,21 +92,15 @@ void UnmapRegion(PageTable& page_table, VAddr base, u32 size) {
|
||||||
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
|
MapPages(page_table, base / PAGE_SIZE, size / PAGE_SIZE, nullptr, PageType::Unmapped);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
u8* MemorySystem::GetPointerForRasterizerCache(VAddr addr) {
|
||||||
* Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
|
|
||||||
* This is used to access the memory where the page pointer is nullptr due to rasterizer cache.
|
|
||||||
* Since the cache only happens on linear heap or VRAM, we know the exact physical address and
|
|
||||||
* pointer of such virtual address
|
|
||||||
*/
|
|
||||||
static u8* GetPointerForRasterizerCache(VAddr addr) {
|
|
||||||
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
|
if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) {
|
||||||
return fcram.data() + (addr - LINEAR_HEAP_VADDR);
|
return impl->fcram.get() + (addr - LINEAR_HEAP_VADDR);
|
||||||
}
|
}
|
||||||
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
|
if (addr >= NEW_LINEAR_HEAP_VADDR && addr < NEW_LINEAR_HEAP_VADDR_END) {
|
||||||
return fcram.data() + (addr - NEW_LINEAR_HEAP_VADDR);
|
return impl->fcram.get() + (addr - NEW_LINEAR_HEAP_VADDR);
|
||||||
}
|
}
|
||||||
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
|
if (addr >= VRAM_VADDR && addr < VRAM_VADDR_END) {
|
||||||
return vram.data() + (addr - VRAM_VADDR);
|
return impl->vram.get() + (addr - VRAM_VADDR);
|
||||||
}
|
}
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -114,8 +122,8 @@ template <typename T>
|
||||||
T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
|
T ReadMMIO(MMIORegionPointer mmio_handler, VAddr addr);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
T Read(const VAddr vaddr) {
|
T MemorySystem::Read(const VAddr vaddr) {
|
||||||
const u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
const u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||||
if (page_pointer) {
|
if (page_pointer) {
|
||||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||||
T value;
|
T value;
|
||||||
|
@ -126,7 +134,7 @@ T Read(const VAddr vaddr) {
|
||||||
// The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
|
// The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
|
||||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||||
|
|
||||||
PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PageType::Unmapped:
|
case PageType::Unmapped:
|
||||||
LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
|
LOG_ERROR(HW_Memory, "unmapped Read{} @ 0x{:08X}", sizeof(T) * 8, vaddr);
|
||||||
|
@ -142,7 +150,7 @@ T Read(const VAddr vaddr) {
|
||||||
return value;
|
return value;
|
||||||
}
|
}
|
||||||
case PageType::Special:
|
case PageType::Special:
|
||||||
return ReadMMIO<T>(GetMMIOHandler(*current_page_table, vaddr), vaddr);
|
return ReadMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr);
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
}
|
}
|
||||||
|
@ -152,8 +160,8 @@ template <typename T>
|
||||||
void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
|
void WriteMMIO(MMIORegionPointer mmio_handler, VAddr addr, const T data);
|
||||||
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
void Write(const VAddr vaddr, const T data) {
|
void MemorySystem::Write(const VAddr vaddr, const T data) {
|
||||||
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||||
if (page_pointer) {
|
if (page_pointer) {
|
||||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||||
std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
|
std::memcpy(&page_pointer[vaddr & PAGE_MASK], &data, sizeof(T));
|
||||||
|
@ -163,7 +171,7 @@ void Write(const VAddr vaddr, const T data) {
|
||||||
// The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
|
// The memory access might do an MMIO or cached access, so we have to lock the HLE kernel state
|
||||||
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
std::lock_guard<std::recursive_mutex> lock(HLE::g_hle_lock);
|
||||||
|
|
||||||
PageType type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
PageType type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case PageType::Unmapped:
|
case PageType::Unmapped:
|
||||||
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, (u32)data,
|
LOG_ERROR(HW_Memory, "unmapped Write{} 0x{:08X} @ 0x{:08X}", sizeof(data) * 8, (u32)data,
|
||||||
|
@ -178,7 +186,7 @@ void Write(const VAddr vaddr, const T data) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PageType::Special:
|
case PageType::Special:
|
||||||
WriteMMIO<T>(GetMMIOHandler(*current_page_table, vaddr), vaddr, data);
|
WriteMMIO<T>(GetMMIOHandler(*impl->current_page_table, vaddr), vaddr, data);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -206,17 +214,18 @@ bool IsValidVirtualAddress(const Kernel::Process& process, const VAddr vaddr) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsValidPhysicalAddress(const PAddr paddr) {
|
bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) {
|
||||||
return GetPhysicalPointer(paddr) != nullptr;
|
return GetPhysicalPointer(paddr) != nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* GetPointer(const VAddr vaddr) {
|
u8* MemorySystem::GetPointer(const VAddr vaddr) {
|
||||||
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
u8* page_pointer = impl->current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||||
if (page_pointer) {
|
if (page_pointer) {
|
||||||
return page_pointer + (vaddr & PAGE_MASK);
|
return page_pointer + (vaddr & PAGE_MASK);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (current_page_table->attributes[vaddr >> PAGE_BITS] == PageType::RasterizerCachedMemory) {
|
if (impl->current_page_table->attributes[vaddr >> PAGE_BITS] ==
|
||||||
|
PageType::RasterizerCachedMemory) {
|
||||||
return GetPointerForRasterizerCache(vaddr);
|
return GetPointerForRasterizerCache(vaddr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -224,7 +233,7 @@ u8* GetPointer(const VAddr vaddr) {
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ReadCString(VAddr vaddr, std::size_t max_length) {
|
std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) {
|
||||||
std::string string;
|
std::string string;
|
||||||
string.reserve(max_length);
|
string.reserve(max_length);
|
||||||
for (std::size_t i = 0; i < max_length; ++i) {
|
for (std::size_t i = 0; i < max_length; ++i) {
|
||||||
|
@ -238,7 +247,7 @@ std::string ReadCString(VAddr vaddr, std::size_t max_length) {
|
||||||
return string;
|
return string;
|
||||||
}
|
}
|
||||||
|
|
||||||
u8* GetPhysicalPointer(PAddr address) {
|
u8* MemorySystem::GetPhysicalPointer(PAddr address) {
|
||||||
struct MemoryArea {
|
struct MemoryArea {
|
||||||
PAddr paddr_base;
|
PAddr paddr_base;
|
||||||
u32 size;
|
u32 size;
|
||||||
|
@ -268,16 +277,16 @@ u8* GetPhysicalPointer(PAddr address) {
|
||||||
u8* target_pointer = nullptr;
|
u8* target_pointer = nullptr;
|
||||||
switch (area->paddr_base) {
|
switch (area->paddr_base) {
|
||||||
case VRAM_PADDR:
|
case VRAM_PADDR:
|
||||||
target_pointer = vram.data() + offset_into_region;
|
target_pointer = impl->vram.get() + offset_into_region;
|
||||||
break;
|
break;
|
||||||
case DSP_RAM_PADDR:
|
case DSP_RAM_PADDR:
|
||||||
target_pointer = Core::DSP().GetDspMemory().data() + offset_into_region;
|
target_pointer = Core::DSP().GetDspMemory().data() + offset_into_region;
|
||||||
break;
|
break;
|
||||||
case FCRAM_PADDR:
|
case FCRAM_PADDR:
|
||||||
target_pointer = fcram.data() + offset_into_region;
|
target_pointer = impl->fcram.get() + offset_into_region;
|
||||||
break;
|
break;
|
||||||
case N3DS_EXTRA_RAM_PADDR:
|
case N3DS_EXTRA_RAM_PADDR:
|
||||||
target_pointer = n3ds_extra_ram.data() + offset_into_region;
|
target_pointer = impl->n3ds_extra_ram.get() + offset_into_region;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -305,7 +314,7 @@ static std::vector<VAddr> PhysicalToVirtualAddressForRasterizer(PAddr addr) {
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
void MemorySystem::RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
||||||
if (start == 0) {
|
if (start == 0) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -315,7 +324,7 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
||||||
|
|
||||||
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
|
for (unsigned i = 0; i < num_pages; ++i, paddr += PAGE_SIZE) {
|
||||||
for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
|
for (VAddr vaddr : PhysicalToVirtualAddressForRasterizer(paddr)) {
|
||||||
PageType& page_type = current_page_table->attributes[vaddr >> PAGE_BITS];
|
PageType& page_type = impl->current_page_table->attributes[vaddr >> PAGE_BITS];
|
||||||
|
|
||||||
if (cached) {
|
if (cached) {
|
||||||
// Switch page type to cached if now cached
|
// Switch page type to cached if now cached
|
||||||
|
@ -326,7 +335,7 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
||||||
break;
|
break;
|
||||||
case PageType::Memory:
|
case PageType::Memory:
|
||||||
page_type = PageType::RasterizerCachedMemory;
|
page_type = PageType::RasterizerCachedMemory;
|
||||||
current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
|
impl->current_page_table->pointers[vaddr >> PAGE_BITS] = nullptr;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
UNREACHABLE();
|
UNREACHABLE();
|
||||||
|
@ -340,7 +349,7 @@ void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached) {
|
||||||
break;
|
break;
|
||||||
case PageType::RasterizerCachedMemory: {
|
case PageType::RasterizerCachedMemory: {
|
||||||
page_type = PageType::Memory;
|
page_type = PageType::Memory;
|
||||||
current_page_table->pointers[vaddr >> PAGE_BITS] =
|
impl->current_page_table->pointers[vaddr >> PAGE_BITS] =
|
||||||
GetPointerForRasterizerCache(vaddr & ~PAGE_MASK);
|
GetPointerForRasterizerCache(vaddr & ~PAGE_MASK);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -417,24 +426,24 @@ void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) {
|
||||||
CheckRegion(VRAM_VADDR, VRAM_VADDR_END, VRAM_PADDR);
|
CheckRegion(VRAM_VADDR, VRAM_VADDR_END, VRAM_PADDR);
|
||||||
}
|
}
|
||||||
|
|
||||||
u8 Read8(const VAddr addr) {
|
u8 MemorySystem::Read8(const VAddr addr) {
|
||||||
return Read<u8>(addr);
|
return Read<u8>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u16 Read16(const VAddr addr) {
|
u16 MemorySystem::Read16(const VAddr addr) {
|
||||||
return Read<u16_le>(addr);
|
return Read<u16_le>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 Read32(const VAddr addr) {
|
u32 MemorySystem::Read32(const VAddr addr) {
|
||||||
return Read<u32_le>(addr);
|
return Read<u32_le>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 Read64(const VAddr addr) {
|
u64 MemorySystem::Read64(const VAddr addr) {
|
||||||
return Read<u64_le>(addr);
|
return Read<u64_le>(addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_buffer,
|
void MemorySystem::ReadBlock(const Kernel::Process& process, const VAddr src_addr,
|
||||||
const std::size_t size) {
|
void* dest_buffer, const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
auto& page_table = process.vm_manager.page_table;
|
||||||
|
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
|
@ -483,24 +492,24 @@ void ReadBlock(const Kernel::Process& process, const VAddr src_addr, void* dest_
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write8(const VAddr addr, const u8 data) {
|
void MemorySystem::Write8(const VAddr addr, const u8 data) {
|
||||||
Write<u8>(addr, data);
|
Write<u8>(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write16(const VAddr addr, const u16 data) {
|
void MemorySystem::Write16(const VAddr addr, const u16 data) {
|
||||||
Write<u16_le>(addr, data);
|
Write<u16_le>(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write32(const VAddr addr, const u32 data) {
|
void MemorySystem::Write32(const VAddr addr, const u32 data) {
|
||||||
Write<u32_le>(addr, data);
|
Write<u32_le>(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Write64(const VAddr addr, const u64 data) {
|
void MemorySystem::Write64(const VAddr addr, const u64 data) {
|
||||||
Write<u64_le>(addr, data);
|
Write<u64_le>(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const void* src_buffer,
|
void MemorySystem::WriteBlock(const Kernel::Process& process, const VAddr dest_addr,
|
||||||
const std::size_t size) {
|
const void* src_buffer, const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
auto& page_table = process.vm_manager.page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = dest_addr >> PAGE_BITS;
|
std::size_t page_index = dest_addr >> PAGE_BITS;
|
||||||
|
@ -547,7 +556,8 @@ void WriteBlock(const Kernel::Process& process, const VAddr dest_addr, const voi
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std::size_t size) {
|
void MemorySystem::ZeroBlock(const Kernel::Process& process, const VAddr dest_addr,
|
||||||
|
const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
auto& page_table = process.vm_manager.page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = dest_addr >> PAGE_BITS;
|
std::size_t page_index = dest_addr >> PAGE_BITS;
|
||||||
|
@ -595,7 +605,7 @@ void ZeroBlock(const Kernel::Process& process, const VAddr dest_addr, const std:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
void MemorySystem::CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
||||||
const std::size_t size) {
|
const std::size_t size) {
|
||||||
auto& page_table = process.vm_manager.page_table;
|
auto& page_table = process.vm_manager.page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
|
@ -647,8 +657,9 @@ void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process,
|
void MemorySystem::CopyBlock(const Kernel::Process& src_process,
|
||||||
VAddr src_addr, VAddr dest_addr, std::size_t size) {
|
const Kernel::Process& dest_process, VAddr src_addr, VAddr dest_addr,
|
||||||
|
std::size_t size) {
|
||||||
auto& page_table = src_process.vm_manager.page_table;
|
auto& page_table = src_process.vm_manager.page_table;
|
||||||
std::size_t remaining_size = size;
|
std::size_t remaining_size = size;
|
||||||
std::size_t page_index = src_addr >> PAGE_BITS;
|
std::size_t page_index = src_addr >> PAGE_BITS;
|
||||||
|
@ -739,9 +750,14 @@ void WriteMMIO<u64>(MMIORegionPointer mmio_handler, VAddr addr, const u64 data)
|
||||||
mmio_handler->Write64(addr, data);
|
mmio_handler->Write64(addr, data);
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 GetFCRAMOffset(u8* pointer) {
|
u32 MemorySystem::GetFCRAMOffset(u8* pointer) {
|
||||||
ASSERT(pointer >= fcram.data() && pointer < fcram.data() + fcram.size());
|
ASSERT(pointer >= impl->fcram.get() && pointer <= impl->fcram.get() + Memory::FCRAM_N3DS_SIZE);
|
||||||
return pointer - fcram.data();
|
return pointer - impl->fcram.get();
|
||||||
|
}
|
||||||
|
|
||||||
|
u8* MemorySystem::GetFCRAMPointer(u32 offset) {
|
||||||
|
ASSERT(offset <= Memory::FCRAM_N3DS_SIZE);
|
||||||
|
return impl->fcram.get() + offset;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
#include <string>
|
#include <string>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -178,49 +179,6 @@ enum : VAddr {
|
||||||
NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
|
NEW_LINEAR_HEAP_VADDR_END = NEW_LINEAR_HEAP_VADDR + NEW_LINEAR_HEAP_SIZE,
|
||||||
};
|
};
|
||||||
|
|
||||||
extern std::array<u8, Memory::FCRAM_N3DS_SIZE> fcram;
|
|
||||||
|
|
||||||
/// Currently active page table
|
|
||||||
void SetCurrentPageTable(PageTable* page_table);
|
|
||||||
PageTable* GetCurrentPageTable();
|
|
||||||
|
|
||||||
/// Determines if the given VAddr is valid for the specified process.
|
|
||||||
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
|
|
||||||
|
|
||||||
bool IsValidPhysicalAddress(PAddr paddr);
|
|
||||||
|
|
||||||
u8 Read8(VAddr addr);
|
|
||||||
u16 Read16(VAddr addr);
|
|
||||||
u32 Read32(VAddr addr);
|
|
||||||
u64 Read64(VAddr addr);
|
|
||||||
|
|
||||||
void Write8(VAddr addr, u8 data);
|
|
||||||
void Write16(VAddr addr, u16 data);
|
|
||||||
void Write32(VAddr addr, u32 data);
|
|
||||||
void Write64(VAddr addr, u64 data);
|
|
||||||
|
|
||||||
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer, std::size_t size);
|
|
||||||
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
|
||||||
std::size_t size);
|
|
||||||
void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size);
|
|
||||||
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr, std::size_t size);
|
|
||||||
void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process,
|
|
||||||
VAddr src_addr, VAddr dest_addr, std::size_t size);
|
|
||||||
|
|
||||||
u8* GetPointer(VAddr vaddr);
|
|
||||||
|
|
||||||
std::string ReadCString(VAddr vaddr, std::size_t max_length);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets a pointer to the memory region beginning at the specified physical address.
|
|
||||||
*/
|
|
||||||
u8* GetPhysicalPointer(PAddr address);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Mark each page touching the region as cached.
|
|
||||||
*/
|
|
||||||
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Flushes any externally cached rasterizer resources touching the given region.
|
* Flushes any externally cached rasterizer resources touching the given region.
|
||||||
*/
|
*/
|
||||||
|
@ -251,7 +209,78 @@ enum class FlushMode {
|
||||||
*/
|
*/
|
||||||
void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode);
|
void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode);
|
||||||
|
|
||||||
/// Gets offset in FCRAM from a pointer inside FCRAM range
|
class MemorySystem {
|
||||||
u32 GetFCRAMOffset(u8* pointer);
|
public:
|
||||||
|
MemorySystem();
|
||||||
|
~MemorySystem();
|
||||||
|
|
||||||
|
/// Currently active page table
|
||||||
|
void SetCurrentPageTable(PageTable* page_table);
|
||||||
|
PageTable* GetCurrentPageTable() const;
|
||||||
|
|
||||||
|
u8 Read8(VAddr addr);
|
||||||
|
u16 Read16(VAddr addr);
|
||||||
|
u32 Read32(VAddr addr);
|
||||||
|
u64 Read64(VAddr addr);
|
||||||
|
|
||||||
|
void Write8(VAddr addr, u8 data);
|
||||||
|
void Write16(VAddr addr, u16 data);
|
||||||
|
void Write32(VAddr addr, u32 data);
|
||||||
|
void Write64(VAddr addr, u64 data);
|
||||||
|
|
||||||
|
void ReadBlock(const Kernel::Process& process, VAddr src_addr, void* dest_buffer,
|
||||||
|
std::size_t size);
|
||||||
|
void WriteBlock(const Kernel::Process& process, VAddr dest_addr, const void* src_buffer,
|
||||||
|
std::size_t size);
|
||||||
|
void ZeroBlock(const Kernel::Process& process, VAddr dest_addr, const std::size_t size);
|
||||||
|
void CopyBlock(const Kernel::Process& process, VAddr dest_addr, VAddr src_addr,
|
||||||
|
std::size_t size);
|
||||||
|
void CopyBlock(const Kernel::Process& src_process, const Kernel::Process& dest_process,
|
||||||
|
VAddr src_addr, VAddr dest_addr, std::size_t size);
|
||||||
|
|
||||||
|
std::string ReadCString(VAddr vaddr, std::size_t max_length);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a pointer to the memory region beginning at the specified physical address.
|
||||||
|
*/
|
||||||
|
u8* GetPhysicalPointer(PAddr address);
|
||||||
|
|
||||||
|
u8* GetPointer(VAddr vaddr);
|
||||||
|
|
||||||
|
bool IsValidPhysicalAddress(PAddr paddr);
|
||||||
|
|
||||||
|
/// Gets offset in FCRAM from a pointer inside FCRAM range
|
||||||
|
u32 GetFCRAMOffset(u8* pointer);
|
||||||
|
|
||||||
|
/// Gets pointer in FCRAM with given offset
|
||||||
|
u8* GetFCRAMPointer(u32 offset);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Mark each page touching the region as cached.
|
||||||
|
*/
|
||||||
|
void RasterizerMarkRegionCached(PAddr start, u32 size, bool cached);
|
||||||
|
|
||||||
|
private:
|
||||||
|
template <typename T>
|
||||||
|
T Read(const VAddr vaddr);
|
||||||
|
|
||||||
|
template <typename T>
|
||||||
|
void Write(const VAddr vaddr, const T data);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets the pointer for virtual memory where the page is marked as RasterizerCachedMemory.
|
||||||
|
* This is used to access the memory where the page pointer is nullptr due to rasterizer cache.
|
||||||
|
* Since the cache only happens on linear heap or VRAM, we know the exact physical address and
|
||||||
|
* pointer of such virtual address
|
||||||
|
*/
|
||||||
|
u8* GetPointerForRasterizerCache(VAddr addr);
|
||||||
|
|
||||||
|
class Impl;
|
||||||
|
|
||||||
|
std::unique_ptr<Impl> impl;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// Determines if the given VAddr is valid for the specified process.
|
||||||
|
bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr);
|
||||||
|
|
||||||
} // namespace Memory
|
} // namespace Memory
|
||||||
|
|
|
@ -30,7 +30,8 @@ void RPCServer::HandleReadMemory(Packet& packet, u32 address, u32 data_size) {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Note: Memory read occurs asynchronously from the state of the emulator
|
// Note: Memory read occurs asynchronously from the state of the emulator
|
||||||
Memory::ReadBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), address,
|
Core::System::GetInstance().Memory().ReadBlock(
|
||||||
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), address,
|
||||||
packet.GetPacketData().data(), data_size);
|
packet.GetPacketData().data(), data_size);
|
||||||
packet.SetPacketDataSize(data_size);
|
packet.SetPacketDataSize(data_size);
|
||||||
packet.SendReply();
|
packet.SendReply();
|
||||||
|
@ -42,8 +43,8 @@ void RPCServer::HandleWriteMemory(Packet& packet, u32 address, const u8* data, u
|
||||||
(address >= Memory::HEAP_VADDR && address <= Memory::HEAP_VADDR_END) ||
|
(address >= Memory::HEAP_VADDR && address <= Memory::HEAP_VADDR_END) ||
|
||||||
(address >= Memory::N3DS_EXTRA_RAM_VADDR && address <= Memory::N3DS_EXTRA_RAM_VADDR_END)) {
|
(address >= Memory::N3DS_EXTRA_RAM_VADDR && address <= Memory::N3DS_EXTRA_RAM_VADDR_END)) {
|
||||||
// Note: Memory write occurs asynchronously from the state of the emulator
|
// Note: Memory write occurs asynchronously from the state of the emulator
|
||||||
Memory::WriteBlock(*Core::System::GetInstance().Kernel().GetCurrentProcess(), address, data,
|
Core::System::GetInstance().Memory().WriteBlock(
|
||||||
data_size);
|
*Core::System::GetInstance().Kernel().GetCurrentProcess(), address, data, data_size);
|
||||||
// If the memory happens to be executable code, make sure the changes become visible
|
// If the memory happens to be executable code, make sure the changes become visible
|
||||||
Core::CPU().InvalidateCacheRange(address, data_size);
|
Core::CPU().InvalidateCacheRange(address, data_size);
|
||||||
}
|
}
|
||||||
|
|
|
@ -20,7 +20,9 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
// so we need to create the kernel object there.
|
// so we need to create the kernel object there.
|
||||||
// Change this when all global states are eliminated.
|
// Change this when all global states are eliminated.
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Core::System::GetInstance().kernel = std::make_unique<Kernel::KernelSystem>(0);
|
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 = Core::System::GetInstance().kernel.get();
|
||||||
|
|
||||||
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
kernel->SetCurrentProcess(kernel->CreateProcess(kernel->CreateCodeSet("", 0)));
|
||||||
|
@ -32,7 +34,7 @@ TestEnvironment::TestEnvironment(bool mutable_memory_)
|
||||||
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() {
|
||||||
|
|
|
@ -3,8 +3,8 @@
|
||||||
// Refer to the license.txt file included.
|
// Refer to the license.txt file included.
|
||||||
|
|
||||||
#include <catch2/catch.hpp>
|
#include <catch2/catch.hpp>
|
||||||
|
|
||||||
#include "core/arm/dyncom/arm_dyncom.h"
|
#include "core/arm/dyncom/arm_dyncom.h"
|
||||||
|
#include "core/core.h"
|
||||||
#include "core/core_timing.h"
|
#include "core/core_timing.h"
|
||||||
#include "tests/core/arm/arm_test_common.h"
|
#include "tests/core/arm/arm_test_common.h"
|
||||||
|
|
||||||
|
@ -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(USER32MODE);
|
ARM_DynCom dyncom(Core::System::GetInstance(), USER32MODE);
|
||||||
|
|
||||||
std::vector<VfpTestCase> test_cases{{
|
std::vector<VfpTestCase> test_cases{{
|
||||||
#include "vfp_vadd_f32.inc"
|
#include "vfp_vadd_f32.inc"
|
||||||
|
|
|
@ -23,7 +23,8 @@ 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
|
// HACK: see comments of member timing
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Kernel::KernelSystem kernel(0);
|
auto memory = std::make_unique<Memory::MemorySystem>();
|
||||||
|
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));
|
||||||
|
|
||||||
|
@ -235,7 +236,8 @@ TEST_CASE("HLERequestContext::PopulateFromIncomingCommandBuffer", "[core][kernel
|
||||||
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
TEST_CASE("HLERequestContext::WriteToOutgoingCommandBuffer", "[core][kernel]") {
|
||||||
// HACK: see comments of member timing
|
// HACK: see comments of member timing
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Kernel::KernelSystem kernel(0);
|
auto memory = std::make_unique<Memory::MemorySystem>();
|
||||||
|
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));
|
||||||
|
|
||||||
|
|
|
@ -13,7 +13,8 @@
|
||||||
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
||||||
// HACK: see comments of member timing
|
// HACK: see comments of member timing
|
||||||
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
Core::System::GetInstance().timing = std::make_unique<Core::Timing>();
|
||||||
Kernel::KernelSystem kernel(0);
|
Core::System::GetInstance().memory = std::make_unique<Memory::MemorySystem>();
|
||||||
|
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);
|
||||||
|
@ -35,13 +36,13 @@ TEST_CASE("Memory::IsValidVirtualAddress", "[core][memory]") {
|
||||||
SECTION("special regions should be valid after mapping them") {
|
SECTION("special regions should be valid after mapping them") {
|
||||||
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
auto process = kernel.CreateProcess(kernel.CreateCodeSet("", 0));
|
||||||
SECTION("VRAM") {
|
SECTION("VRAM") {
|
||||||
Kernel::HandleSpecialMapping(process->vm_manager,
|
kernel.HandleSpecialMapping(process->vm_manager,
|
||||||
{Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
|
{Memory::VRAM_VADDR, Memory::VRAM_SIZE, false, false});
|
||||||
CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true);
|
CHECK(Memory::IsValidVirtualAddress(*process, Memory::VRAM_VADDR) == true);
|
||||||
}
|
}
|
||||||
|
|
||||||
SECTION("IO (Not yet implemented)") {
|
SECTION("IO (Not yet implemented)") {
|
||||||
Kernel::HandleSpecialMapping(
|
kernel.HandleSpecialMapping(
|
||||||
process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false});
|
process->vm_manager, {Memory::IO_AREA_VADDR, Memory::IO_AREA_SIZE, false, false});
|
||||||
CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true);
|
CHECK_FALSE(Memory::IsValidVirtualAddress(*process, Memory::IO_AREA_VADDR) == true);
|
||||||
}
|
}
|
||||||
|
|
|
@ -269,7 +269,7 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
|
case PICA_REG_INDEX_WORKAROUND(pipeline.command_buffer.trigger[1], 0x23d): {
|
||||||
unsigned index =
|
unsigned index =
|
||||||
static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
|
static_cast<unsigned>(id - PICA_REG_INDEX(pipeline.command_buffer.trigger[0]));
|
||||||
u32* head_ptr = (u32*)Memory::GetPhysicalPointer(
|
u32* head_ptr = (u32*)VideoCore::g_memory->GetPhysicalPointer(
|
||||||
regs.pipeline.command_buffer.GetPhysicalAddress(index));
|
regs.pipeline.command_buffer.GetPhysicalAddress(index));
|
||||||
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
|
g_state.cmd_list.head_ptr = g_state.cmd_list.current_ptr = head_ptr;
|
||||||
g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
|
g_state.cmd_list.length = regs.pipeline.command_buffer.GetSize(index) / sizeof(u32);
|
||||||
|
@ -328,7 +328,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
|
|
||||||
// Load vertices
|
// Load vertices
|
||||||
const auto& index_info = regs.pipeline.index_array;
|
const auto& index_info = regs.pipeline.index_array;
|
||||||
const u8* index_address_8 = Memory::GetPhysicalPointer(base_address + index_info.offset);
|
const u8* index_address_8 =
|
||||||
|
VideoCore::g_memory->GetPhysicalPointer(base_address + index_info.offset);
|
||||||
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
|
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
|
||||||
bool index_u16 = index_info.format != 0;
|
bool index_u16 = index_info.format != 0;
|
||||||
|
|
||||||
|
@ -338,7 +339,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
if (!texture.enabled)
|
if (!texture.enabled)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
u8* texture_data = Memory::GetPhysicalPointer(texture.config.GetPhysicalAddress());
|
u8* texture_data =
|
||||||
|
VideoCore::g_memory->GetPhysicalPointer(texture.config.GetPhysicalAddress());
|
||||||
g_debug_context->recorder->MemoryAccessed(
|
g_debug_context->recorder->MemoryAccessed(
|
||||||
texture_data,
|
texture_data,
|
||||||
Pica::TexturingRegs::NibblesPerPixel(texture.format) * texture.config.width /
|
Pica::TexturingRegs::NibblesPerPixel(texture.format) * texture.config.width /
|
||||||
|
@ -424,8 +426,8 @@ static void WritePicaReg(u32 id, u32 value, u32 mask) {
|
||||||
}
|
}
|
||||||
|
|
||||||
for (auto& range : memory_accesses.ranges) {
|
for (auto& range : memory_accesses.ranges) {
|
||||||
g_debug_context->recorder->MemoryAccessed(Memory::GetPhysicalPointer(range.first),
|
g_debug_context->recorder->MemoryAccessed(
|
||||||
range.second, range.first);
|
VideoCore::g_memory->GetPhysicalPointer(range.first), range.second, range.first);
|
||||||
}
|
}
|
||||||
|
|
||||||
VideoCore::g_renderer->Rasterizer()->DrawTriangles();
|
VideoCore::g_renderer->Rasterizer()->DrawTriangles();
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
#include "video_core/renderer_opengl/gl_shader_gen.h"
|
||||||
#include "video_core/renderer_opengl/pica_to_gl.h"
|
#include "video_core/renderer_opengl/pica_to_gl.h"
|
||||||
#include "video_core/renderer_opengl/renderer_opengl.h"
|
#include "video_core/renderer_opengl/renderer_opengl.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
|
||||||
|
@ -259,7 +260,7 @@ RasterizerOpenGL::VertexArrayInfo RasterizerOpenGL::AnalyzeVertexArray(bool is_i
|
||||||
if (is_indexed) {
|
if (is_indexed) {
|
||||||
const auto& index_info = regs.pipeline.index_array;
|
const auto& index_info = regs.pipeline.index_array;
|
||||||
PAddr address = vertex_attributes.GetPhysicalBaseAddress() + index_info.offset;
|
PAddr address = vertex_attributes.GetPhysicalBaseAddress() + index_info.offset;
|
||||||
const u8* index_address_8 = Memory::GetPhysicalPointer(address);
|
const u8* index_address_8 = VideoCore::g_memory->GetPhysicalPointer(address);
|
||||||
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
|
const u16* index_address_16 = reinterpret_cast<const u16*>(index_address_8);
|
||||||
bool index_u16 = index_info.format != 0;
|
bool index_u16 = index_info.format != 0;
|
||||||
|
|
||||||
|
@ -340,7 +341,7 @@ void RasterizerOpenGL::SetupVertexArray(u8* array_ptr, GLintptr buffer_offset,
|
||||||
u32 data_size = loader.byte_count * vertex_num;
|
u32 data_size = loader.byte_count * vertex_num;
|
||||||
|
|
||||||
res_cache.FlushRegion(data_addr, data_size, nullptr);
|
res_cache.FlushRegion(data_addr, data_size, nullptr);
|
||||||
std::memcpy(array_ptr, Memory::GetPhysicalPointer(data_addr), data_size);
|
std::memcpy(array_ptr, VideoCore::g_memory->GetPhysicalPointer(data_addr), data_size);
|
||||||
|
|
||||||
array_ptr += data_size;
|
array_ptr += data_size;
|
||||||
buffer_offset += data_size;
|
buffer_offset += data_size;
|
||||||
|
@ -471,8 +472,8 @@ bool RasterizerOpenGL::AccelerateDrawBatchInternal(bool is_indexed, bool use_gs)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const u8* index_data =
|
const u8* index_data = VideoCore::g_memory->GetPhysicalPointer(
|
||||||
Memory::GetPhysicalPointer(regs.pipeline.vertex_attributes.GetPhysicalBaseAddress() +
|
regs.pipeline.vertex_attributes.GetPhysicalBaseAddress() +
|
||||||
regs.pipeline.index_array.offset);
|
regs.pipeline.index_array.offset);
|
||||||
std::tie(buffer_ptr, buffer_offset, std::ignore) = index_buffer.Map(index_buffer_size, 4);
|
std::tie(buffer_ptr, buffer_offset, std::ignore) = index_buffer.Map(index_buffer_size, 4);
|
||||||
std::memcpy(buffer_ptr, index_data, index_buffer_size);
|
std::memcpy(buffer_ptr, index_data, index_buffer_size);
|
||||||
|
|
|
@ -134,7 +134,7 @@ static void MortonCopy(u32 stride, u32 height, u8* gl_buffer, PAddr base, PAddr
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
u8* tile_buffer = Memory::GetPhysicalPointer(start);
|
u8* tile_buffer = VideoCore::g_memory->GetPhysicalPointer(start);
|
||||||
|
|
||||||
if (start < aligned_start && !morton_to_gl) {
|
if (start < aligned_start && !morton_to_gl) {
|
||||||
std::array<u8, tile_size> tmp_buf;
|
std::array<u8, tile_size> tmp_buf;
|
||||||
|
@ -625,7 +625,7 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 19
|
||||||
void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
||||||
ASSERT(type != SurfaceType::Fill);
|
ASSERT(type != SurfaceType::Fill);
|
||||||
|
|
||||||
const u8* const texture_src_data = Memory::GetPhysicalPointer(addr);
|
const u8* const texture_src_data = VideoCore::g_memory->GetPhysicalPointer(addr);
|
||||||
if (texture_src_data == nullptr)
|
if (texture_src_data == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -680,7 +680,7 @@ void CachedSurface::LoadGLBuffer(PAddr load_start, PAddr load_end) {
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
MICROPROFILE_DEFINE(OpenGL_SurfaceFlush, "OpenGL", "Surface Flush", MP_RGB(128, 192, 64));
|
||||||
void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
|
void CachedSurface::FlushGLBuffer(PAddr flush_start, PAddr flush_end) {
|
||||||
u8* const dst_buffer = Memory::GetPhysicalPointer(addr);
|
u8* const dst_buffer = VideoCore::g_memory->GetPhysicalPointer(addr);
|
||||||
if (dst_buffer == nullptr)
|
if (dst_buffer == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
@ -1718,9 +1718,11 @@ void RasterizerCacheOpenGL::UpdatePagesCachedCount(PAddr addr, u32 size, int del
|
||||||
const u32 interval_size = interval_end_addr - interval_start_addr;
|
const u32 interval_size = interval_end_addr - interval_start_addr;
|
||||||
|
|
||||||
if (delta > 0 && count == delta)
|
if (delta > 0 && count == delta)
|
||||||
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, true);
|
VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size,
|
||||||
|
true);
|
||||||
else if (delta < 0 && count == -delta)
|
else if (delta < 0 && count == -delta)
|
||||||
Memory::RasterizerMarkRegionCached(interval_start_addr, interval_size, false);
|
VideoCore::g_memory->RasterizerMarkRegionCached(interval_start_addr, interval_size,
|
||||||
|
false);
|
||||||
else
|
else
|
||||||
ASSERT(count >= 0);
|
ASSERT(count >= 0);
|
||||||
}
|
}
|
||||||
|
|
|
@ -228,7 +228,7 @@ void RendererOpenGL::LoadFBToScreenInfo(const GPU::Regs::FramebufferConfig& fram
|
||||||
|
|
||||||
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
|
Memory::RasterizerFlushRegion(framebuffer_addr, framebuffer.stride * framebuffer.height);
|
||||||
|
|
||||||
const u8* framebuffer_data = Memory::GetPhysicalPointer(framebuffer_addr);
|
const u8* framebuffer_data = VideoCore::g_memory->GetPhysicalPointer(framebuffer_addr);
|
||||||
|
|
||||||
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
|
state.texture_units[0].texture_2d = screen_info.texture.resource.handle;
|
||||||
state.Apply();
|
state.Apply();
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "video_core/regs_framebuffer.h"
|
#include "video_core/regs_framebuffer.h"
|
||||||
#include "video_core/swrasterizer/framebuffer.h"
|
#include "video_core/swrasterizer/framebuffer.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
namespace Rasterizer {
|
namespace Rasterizer {
|
||||||
|
@ -31,7 +32,7 @@ void DrawPixel(int x, int y, const Math::Vec4<u8>& color) {
|
||||||
GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
|
GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
|
||||||
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
|
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
|
||||||
coarse_y * framebuffer.width * bytes_per_pixel;
|
coarse_y * framebuffer.width * bytes_per_pixel;
|
||||||
u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
|
u8* dst_pixel = VideoCore::g_memory->GetPhysicalPointer(addr) + dst_offset;
|
||||||
|
|
||||||
switch (framebuffer.color_format) {
|
switch (framebuffer.color_format) {
|
||||||
case FramebufferRegs::ColorFormat::RGBA8:
|
case FramebufferRegs::ColorFormat::RGBA8:
|
||||||
|
@ -72,7 +73,7 @@ const Math::Vec4<u8> GetPixel(int x, int y) {
|
||||||
GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
|
GPU::Regs::BytesPerPixel(GPU::Regs::PixelFormat(framebuffer.color_format.Value()));
|
||||||
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
|
u32 src_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
|
||||||
coarse_y * framebuffer.width * bytes_per_pixel;
|
coarse_y * framebuffer.width * bytes_per_pixel;
|
||||||
u8* src_pixel = Memory::GetPhysicalPointer(addr) + src_offset;
|
u8* src_pixel = VideoCore::g_memory->GetPhysicalPointer(addr) + src_offset;
|
||||||
|
|
||||||
switch (framebuffer.color_format) {
|
switch (framebuffer.color_format) {
|
||||||
case FramebufferRegs::ColorFormat::RGBA8:
|
case FramebufferRegs::ColorFormat::RGBA8:
|
||||||
|
@ -102,7 +103,7 @@ const Math::Vec4<u8> GetPixel(int x, int y) {
|
||||||
u32 GetDepth(int x, int y) {
|
u32 GetDepth(int x, int y) {
|
||||||
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
||||||
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = VideoCore::g_memory->GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
|
@ -131,7 +132,7 @@ u32 GetDepth(int x, int y) {
|
||||||
u8 GetStencil(int x, int y) {
|
u8 GetStencil(int x, int y) {
|
||||||
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
||||||
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = VideoCore::g_memory->GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
|
@ -158,7 +159,7 @@ u8 GetStencil(int x, int y) {
|
||||||
void SetDepth(int x, int y, u32 value) {
|
void SetDepth(int x, int y, u32 value) {
|
||||||
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
||||||
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = VideoCore::g_memory->GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
|
@ -193,7 +194,7 @@ void SetDepth(int x, int y, u32 value) {
|
||||||
void SetStencil(int x, int y, u8 value) {
|
void SetStencil(int x, int y, u8 value) {
|
||||||
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
const auto& framebuffer = g_state.regs.framebuffer.framebuffer;
|
||||||
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
const PAddr addr = framebuffer.GetDepthBufferPhysicalAddress();
|
||||||
u8* depth_buffer = Memory::GetPhysicalPointer(addr);
|
u8* depth_buffer = VideoCore::g_memory->GetPhysicalPointer(addr);
|
||||||
|
|
||||||
y = framebuffer.height - y;
|
y = framebuffer.height - y;
|
||||||
|
|
||||||
|
@ -384,7 +385,7 @@ void DrawShadowMapPixel(int x, int y, u32 depth, u8 stencil) {
|
||||||
u32 bytes_per_pixel = 4;
|
u32 bytes_per_pixel = 4;
|
||||||
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
|
u32 dst_offset = VideoCore::GetMortonOffset(x, y, bytes_per_pixel) +
|
||||||
coarse_y * framebuffer.width * bytes_per_pixel;
|
coarse_y * framebuffer.width * bytes_per_pixel;
|
||||||
u8* dst_pixel = Memory::GetPhysicalPointer(addr) + dst_offset;
|
u8* dst_pixel = VideoCore::g_memory->GetPhysicalPointer(addr) + dst_offset;
|
||||||
|
|
||||||
auto ref = DecodeD24S8Shadow(dst_pixel);
|
auto ref = DecodeD24S8Shadow(dst_pixel);
|
||||||
u32 ref_z = ref.x;
|
u32 ref_z = ref.x;
|
||||||
|
|
|
@ -30,6 +30,7 @@
|
||||||
#include "video_core/swrasterizer/texturing.h"
|
#include "video_core/swrasterizer/texturing.h"
|
||||||
#include "video_core/texture/texture_decode.h"
|
#include "video_core/texture/texture_decode.h"
|
||||||
#include "video_core/utils.h"
|
#include "video_core/utils.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
namespace Rasterizer {
|
namespace Rasterizer {
|
||||||
|
@ -402,7 +403,8 @@ static void ProcessTriangleInternal(const Vertex& v0, const Vertex& v1, const Ve
|
||||||
t = texture.config.height - 1 -
|
t = texture.config.height - 1 -
|
||||||
GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
|
GetWrappedTexCoord(texture.config.wrap_t, t, texture.config.height);
|
||||||
|
|
||||||
const u8* texture_data = Memory::GetPhysicalPointer(texture_address);
|
const u8* texture_data =
|
||||||
|
VideoCore::g_memory->GetPhysicalPointer(texture_address);
|
||||||
auto info =
|
auto info =
|
||||||
Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
|
Texture::TextureInfo::FromPicaRegister(texture.config, texture.format);
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
#include "video_core/regs_pipeline.h"
|
#include "video_core/regs_pipeline.h"
|
||||||
#include "video_core/shader/shader.h"
|
#include "video_core/shader/shader.h"
|
||||||
#include "video_core/vertex_loader.h"
|
#include "video_core/vertex_loader.h"
|
||||||
|
#include "video_core/video_core.h"
|
||||||
|
|
||||||
namespace Pica {
|
namespace Pica {
|
||||||
|
|
||||||
|
@ -95,32 +96,32 @@ void VertexLoader::LoadVertex(u32 base_address, int index, int vertex,
|
||||||
|
|
||||||
switch (vertex_attribute_formats[i]) {
|
switch (vertex_attribute_formats[i]) {
|
||||||
case PipelineRegs::VertexAttributeFormat::BYTE: {
|
case PipelineRegs::VertexAttributeFormat::BYTE: {
|
||||||
const s8* srcdata =
|
const s8* srcdata = reinterpret_cast<const s8*>(
|
||||||
reinterpret_cast<const s8*>(Memory::GetPhysicalPointer(source_addr));
|
VideoCore::g_memory->GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
||||||
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PipelineRegs::VertexAttributeFormat::UBYTE: {
|
case PipelineRegs::VertexAttributeFormat::UBYTE: {
|
||||||
const u8* srcdata =
|
const u8* srcdata = reinterpret_cast<const u8*>(
|
||||||
reinterpret_cast<const u8*>(Memory::GetPhysicalPointer(source_addr));
|
VideoCore::g_memory->GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
||||||
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PipelineRegs::VertexAttributeFormat::SHORT: {
|
case PipelineRegs::VertexAttributeFormat::SHORT: {
|
||||||
const s16* srcdata =
|
const s16* srcdata = reinterpret_cast<const s16*>(
|
||||||
reinterpret_cast<const s16*>(Memory::GetPhysicalPointer(source_addr));
|
VideoCore::g_memory->GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
||||||
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case PipelineRegs::VertexAttributeFormat::FLOAT: {
|
case PipelineRegs::VertexAttributeFormat::FLOAT: {
|
||||||
const float* srcdata =
|
const float* srcdata = reinterpret_cast<const float*>(
|
||||||
reinterpret_cast<const float*>(Memory::GetPhysicalPointer(source_addr));
|
VideoCore::g_memory->GetPhysicalPointer(source_addr));
|
||||||
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
for (unsigned int comp = 0; comp < vertex_attribute_elements[i]; ++comp) {
|
||||||
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
input.attr[i][comp] = float24::FromFloat32(srcdata[comp]);
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,8 +29,11 @@ void* g_screenshot_bits;
|
||||||
std::function<void()> g_screenshot_complete_callback;
|
std::function<void()> g_screenshot_complete_callback;
|
||||||
Layout::FramebufferLayout g_screenshot_framebuffer_layout;
|
Layout::FramebufferLayout g_screenshot_framebuffer_layout;
|
||||||
|
|
||||||
|
Memory::MemorySystem* g_memory;
|
||||||
|
|
||||||
/// Initialize the video core
|
/// Initialize the video core
|
||||||
Core::System::ResultStatus Init(EmuWindow& emu_window) {
|
Core::System::ResultStatus Init(EmuWindow& emu_window, Memory::MemorySystem& memory) {
|
||||||
|
g_memory = &memory;
|
||||||
Pica::Init();
|
Pica::Init();
|
||||||
|
|
||||||
g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window);
|
g_renderer = std::make_unique<OpenGL::RendererOpenGL>(emu_window);
|
||||||
|
|
|
@ -12,6 +12,10 @@
|
||||||
class EmuWindow;
|
class EmuWindow;
|
||||||
class RendererBase;
|
class RendererBase;
|
||||||
|
|
||||||
|
namespace Memory {
|
||||||
|
class MemorySystem;
|
||||||
|
}
|
||||||
|
|
||||||
////////////////////////////////////////////////////////////////////////////////////////////////////
|
////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
// Video Core namespace
|
// Video Core namespace
|
||||||
|
|
||||||
|
@ -33,8 +37,10 @@ extern void* g_screenshot_bits;
|
||||||
extern std::function<void()> g_screenshot_complete_callback;
|
extern std::function<void()> g_screenshot_complete_callback;
|
||||||
extern Layout::FramebufferLayout g_screenshot_framebuffer_layout;
|
extern Layout::FramebufferLayout g_screenshot_framebuffer_layout;
|
||||||
|
|
||||||
|
extern Memory::MemorySystem* g_memory;
|
||||||
|
|
||||||
/// Initialize the video core
|
/// Initialize the video core
|
||||||
Core::System::ResultStatus Init(EmuWindow& emu_window);
|
Core::System::ResultStatus Init(EmuWindow& emu_window, Memory::MemorySystem& memory);
|
||||||
|
|
||||||
/// Shutdown the video core
|
/// Shutdown the video core
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
|
|
Loading…
Reference in a new issue