mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-31 13:50:03 +00:00 
			
		
		
		
	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…
	
	Add table
		Add a link
		
	
		Reference in a new issue