mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 13:20:03 +00:00 
			
		
		
		
	core: Remove usage of MemoryRef
This commit is contained in:
		
							parent
							
								
									ac792f7b98
								
							
						
					
					
						commit
						e00a49e1e5
					
				
					 23 changed files with 151 additions and 293 deletions
				
			
		
							
								
								
									
										2
									
								
								externals/teakra
									
										
									
									
										vendored
									
									
								
							
							
						
						
									
										2
									
								
								externals/teakra
									
										
									
									
										vendored
									
									
								
							|  | @ -1 +1 @@ | ||||||
| Subproject commit 01db7cdd00aabcce559a8dddce8798dabb71949b | Subproject commit ad825418ef8b91e31bea678a9f470988bac6b568 | ||||||
|  | @ -87,7 +87,7 @@ public: | ||||||
|     virtual void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) = 0; |     virtual void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) = 0; | ||||||
| 
 | 
 | ||||||
|     /// Returns a reference to the array backing DSP memory
 |     /// Returns a reference to the array backing DSP memory
 | ||||||
|     virtual std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() = 0; |     virtual std::span<u8, Memory::DSP_RAM_SIZE> GetDspMemory() = 0; | ||||||
| 
 | 
 | ||||||
|     /// Sets the handler for the interrupts we trigger
 |     /// Sets the handler for the interrupts we trigger
 | ||||||
|     virtual void SetInterruptHandler( |     virtual void SetInterruptHandler( | ||||||
|  |  | ||||||
|  | @ -44,12 +44,9 @@ public: | ||||||
|     std::size_t GetPipeReadableSize(DspPipe pipe_number) const; |     std::size_t GetPipeReadableSize(DspPipe pipe_number) const; | ||||||
|     void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer); |     void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer); | ||||||
| 
 | 
 | ||||||
|     std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory(); |  | ||||||
| 
 |  | ||||||
|     void SetInterruptHandler( |     void SetInterruptHandler( | ||||||
|         std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler); |         std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler); | ||||||
| 
 | 
 | ||||||
| private: |  | ||||||
|     void ResetPipes(); |     void ResetPipes(); | ||||||
|     void WriteU16(DspPipe pipe_number, u16 value); |     void WriteU16(DspPipe pipe_number, u16 value); | ||||||
|     void AudioPipeWriteStructAddresses(); |     void AudioPipeWriteStructAddresses(); | ||||||
|  | @ -65,7 +62,7 @@ private: | ||||||
|     DspState dsp_state = DspState::Off; |     DspState dsp_state = DspState::Off; | ||||||
|     std::array<std::vector<u8>, num_dsp_pipe> pipe_data{}; |     std::array<std::vector<u8>, num_dsp_pipe> pipe_data{}; | ||||||
| 
 | 
 | ||||||
|     HLE::DspMemory dsp_memory; |     HLE::DspMemory* dsp_memory; | ||||||
|     std::array<HLE::Source, HLE::num_sources> sources{{ |     std::array<HLE::Source, HLE::num_sources> sources{{ | ||||||
|         HLE::Source(0),  HLE::Source(1),  HLE::Source(2),  HLE::Source(3),  HLE::Source(4), |         HLE::Source(0),  HLE::Source(1),  HLE::Source(2),  HLE::Source(3),  HLE::Source(4), | ||||||
|         HLE::Source(5),  HLE::Source(6),  HLE::Source(7),  HLE::Source(8),  HLE::Source(9), |         HLE::Source(5),  HLE::Source(6),  HLE::Source(7),  HLE::Source(8),  HLE::Source(9), | ||||||
|  | @ -86,7 +83,8 @@ private: | ||||||
| 
 | 
 | ||||||
| DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing) | DspHle::Impl::Impl(DspHle& parent_, Memory::MemorySystem& memory, Core::Timing& timing) | ||||||
|     : parent(parent_), core_timing(timing) { |     : parent(parent_), core_timing(timing) { | ||||||
|     dsp_memory.raw_memory.fill(0); |     dsp_memory = reinterpret_cast<HLE::DspMemory*>(memory.GetDspMemory().data()); | ||||||
|  |     dsp_memory->raw_memory.fill(0); | ||||||
| 
 | 
 | ||||||
|     for (auto& source : sources) { |     for (auto& source : sources) { | ||||||
|         source.SetMemory(memory); |         source.SetMemory(memory); | ||||||
|  | @ -257,10 +255,6 @@ void DspHle::Impl::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::array<u8, Memory::DSP_RAM_SIZE>& DspHle::Impl::GetDspMemory() { |  | ||||||
|     return dsp_memory.raw_memory; |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void DspHle::Impl::SetInterruptHandler( | void DspHle::Impl::SetInterruptHandler( | ||||||
|     std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) { |     std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) { | ||||||
|     interrupt_handler = handler; |     interrupt_handler = handler; | ||||||
|  | @ -316,8 +310,8 @@ void DspHle::Impl::AudioPipeWriteStructAddresses() { | ||||||
| size_t DspHle::Impl::CurrentRegionIndex() const { | size_t DspHle::Impl::CurrentRegionIndex() const { | ||||||
|     // The region with the higher frame counter is chosen unless there is wraparound.
 |     // The region with the higher frame counter is chosen unless there is wraparound.
 | ||||||
|     // This function only returns a 0 or 1.
 |     // This function only returns a 0 or 1.
 | ||||||
|     const u16 frame_counter_0 = dsp_memory.region_0.frame_counter; |     const u16 frame_counter_0 = dsp_memory->region_0.frame_counter; | ||||||
|     const u16 frame_counter_1 = dsp_memory.region_1.frame_counter; |     const u16 frame_counter_1 = dsp_memory->region_1.frame_counter; | ||||||
| 
 | 
 | ||||||
|     if (frame_counter_0 == 0xFFFFu && frame_counter_1 != 0xFFFEu) { |     if (frame_counter_0 == 0xFFFFu && frame_counter_1 != 0xFFFEu) { | ||||||
|         // Wraparound has occurred.
 |         // Wraparound has occurred.
 | ||||||
|  | @ -333,11 +327,11 @@ size_t DspHle::Impl::CurrentRegionIndex() const { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HLE::SharedMemory& DspHle::Impl::ReadRegion() { | HLE::SharedMemory& DspHle::Impl::ReadRegion() { | ||||||
|     return CurrentRegionIndex() == 0 ? dsp_memory.region_0 : dsp_memory.region_1; |     return CurrentRegionIndex() == 0 ? dsp_memory->region_0 : dsp_memory->region_1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| HLE::SharedMemory& DspHle::Impl::WriteRegion() { | HLE::SharedMemory& DspHle::Impl::WriteRegion() { | ||||||
|     return CurrentRegionIndex() != 0 ? dsp_memory.region_0 : dsp_memory.region_1; |     return CurrentRegionIndex() != 0 ? dsp_memory->region_0 : dsp_memory->region_1; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| StereoFrame16 DspHle::Impl::GenerateCurrentFrame() { | StereoFrame16 DspHle::Impl::GenerateCurrentFrame() { | ||||||
|  | @ -421,8 +415,8 @@ void DspHle::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) { | ||||||
|     impl->PipeWrite(pipe_number, buffer); |     impl->PipeWrite(pipe_number, buffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::array<u8, Memory::DSP_RAM_SIZE>& DspHle::GetDspMemory() { | std::span<u8, Memory::DSP_RAM_SIZE> DspHle::GetDspMemory() { | ||||||
|     return impl->GetDspMemory(); |     return impl->dsp_memory->raw_memory; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DspHle::SetInterruptHandler( | void DspHle::SetInterruptHandler( | ||||||
|  |  | ||||||
|  | @ -4,14 +4,11 @@ | ||||||
| 
 | 
 | ||||||
| #pragma once | #pragma once | ||||||
| 
 | 
 | ||||||
| #include <array> |  | ||||||
| #include <memory> | #include <memory> | ||||||
| #include <vector> | #include <vector> | ||||||
| #include "audio_core/audio_types.h" | #include "audio_core/audio_types.h" | ||||||
| #include "audio_core/dsp_interface.h" | #include "audio_core/dsp_interface.h" | ||||||
| #include "common/common_types.h" |  | ||||||
| #include "core/hle/service/dsp/dsp_dsp.h" | #include "core/hle/service/dsp/dsp_dsp.h" | ||||||
| #include "core/memory.h" |  | ||||||
| 
 | 
 | ||||||
| namespace Core { | namespace Core { | ||||||
| class Timing; | class Timing; | ||||||
|  | @ -36,7 +33,7 @@ public: | ||||||
|     std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; |     std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; | ||||||
|     void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) override; |     void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) override; | ||||||
| 
 | 
 | ||||||
|     std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override; |     std::span<u8, Memory::DSP_RAM_SIZE> GetDspMemory() override; | ||||||
| 
 | 
 | ||||||
|     void SetInterruptHandler( |     void SetInterruptHandler( | ||||||
|         std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) override; |         std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) override; | ||||||
|  |  | ||||||
|  | @ -121,7 +121,9 @@ static u8 PipeIndexToSlotIndex(u8 pipe_index, PipeDirection direction) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| struct DspLle::Impl final { | struct DspLle::Impl final { | ||||||
|     Impl(Core::Timing& timing, bool multithread) : core_timing(timing), multithread(multithread) { |     Impl(Memory::MemorySystem& memory, Core::Timing& timing, bool multithread_) | ||||||
|  |         : dsp_memory{memory.GetDspMemory()}, config{dsp_memory.data()}, teakra{config}, | ||||||
|  |           core_timing{timing}, multithread{multithread_} { | ||||||
|         teakra_slice_event = core_timing.RegisterEvent( |         teakra_slice_event = core_timing.RegisterEvent( | ||||||
|             "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast<u64>(late)); }); |             "DSP slice", [this](u64, int late) { TeakraSliceEvent(static_cast<u64>(late)); }); | ||||||
|     } |     } | ||||||
|  | @ -130,6 +132,8 @@ struct DspLle::Impl final { | ||||||
|         StopTeakraThread(); |         StopTeakraThread(); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  |     std::span<u8, Memory::DSP_RAM_SIZE> dsp_memory; | ||||||
|  |     Teakra::UserConfig config; | ||||||
|     Teakra::Teakra teakra; |     Teakra::Teakra teakra; | ||||||
|     u16 pipe_base_waddr = 0; |     u16 pipe_base_waddr = 0; | ||||||
| 
 | 
 | ||||||
|  | @ -189,13 +193,11 @@ struct DspLle::Impl final { | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     u8* GetDspDataPointer(u32 baddr) { |     u8* GetDspDataPointer(u32 baddr) { | ||||||
|         auto& memory = teakra.GetDspMemory(); |         return &dsp_memory[DspDataOffset + baddr]; | ||||||
|         return &memory[DspDataOffset + baddr]; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const u8* GetDspDataPointer(u32 baddr) const { |     const u8* GetDspDataPointer(u32 baddr) const { | ||||||
|         auto& memory = teakra.GetDspMemory(); |         return &dsp_memory[DspDataOffset + baddr]; | ||||||
|         return &memory[DspDataOffset + baddr]; |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     PipeStatus GetPipeStatus(u8 pipe_index, PipeDirection direction) const { |     PipeStatus GetPipeStatus(u8 pipe_index, PipeDirection direction) const { | ||||||
|  | @ -312,7 +314,6 @@ struct DspLle::Impl final { | ||||||
|         teakra.Reset(); |         teakra.Reset(); | ||||||
| 
 | 
 | ||||||
|         Dsp1 dsp(buffer); |         Dsp1 dsp(buffer); | ||||||
|         auto& dsp_memory = teakra.GetDspMemory(); |  | ||||||
|         u8* program = dsp_memory.data(); |         u8* program = dsp_memory.data(); | ||||||
|         u8* data = dsp_memory.data() + DspDataOffset; |         u8* data = dsp_memory.data() + DspDataOffset; | ||||||
|         for (const auto& segment : dsp.segments) { |         for (const auto& segment : dsp.segments) { | ||||||
|  | @ -403,8 +404,8 @@ void DspLle::PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) { | ||||||
|     impl->WritePipe(static_cast<u8>(pipe_number), buffer); |     impl->WritePipe(static_cast<u8>(pipe_number), buffer); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::array<u8, Memory::DSP_RAM_SIZE>& DspLle::GetDspMemory() { | std::span<u8, Memory::DSP_RAM_SIZE> DspLle::GetDspMemory() { | ||||||
|     return impl->teakra.GetDspMemory(); |     return impl->dsp_memory; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void DspLle::SetInterruptHandler( | void DspLle::SetInterruptHandler( | ||||||
|  | @ -469,7 +470,7 @@ DspLle::DspLle(Core::System& system, bool multithread) | ||||||
| 
 | 
 | ||||||
| DspLle::DspLle(Core::System& system, Memory::MemorySystem& memory, Core::Timing& timing, | DspLle::DspLle(Core::System& system, Memory::MemorySystem& memory, Core::Timing& timing, | ||||||
|                bool multithread) |                bool multithread) | ||||||
|     : DspInterface(system), impl(std::make_unique<Impl>(timing, multithread)) { |     : DspInterface(system), impl(std::make_unique<Impl>(memory, timing, multithread)) { | ||||||
|     Teakra::AHBMCallback ahbm; |     Teakra::AHBMCallback ahbm; | ||||||
|     ahbm.read8 = [&memory](u32 address) -> u8 { |     ahbm.read8 = [&memory](u32 address) -> u8 { | ||||||
|         return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); |         return *memory.GetFCRAMPointer(address - Memory::FCRAM_PADDR); | ||||||
|  |  | ||||||
|  | @ -31,7 +31,7 @@ public: | ||||||
|     std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; |     std::size_t GetPipeReadableSize(DspPipe pipe_number) const override; | ||||||
|     void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) override; |     void PipeWrite(DspPipe pipe_number, std::span<const u8> buffer) override; | ||||||
| 
 | 
 | ||||||
|     std::array<u8, Memory::DSP_RAM_SIZE>& GetDspMemory() override; |     std::span<u8, Memory::DSP_RAM_SIZE> GetDspMemory() override; | ||||||
| 
 | 
 | ||||||
|     void SetInterruptHandler( |     void SetInterruptHandler( | ||||||
|         std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) override; |         std::function<void(Service::DSP::InterruptType type, DspPipe pipe)> handler) override; | ||||||
|  |  | ||||||
|  | @ -298,7 +298,7 @@ std::unique_ptr<Dynarmic::A32::Jit> ARM_Dynarmic::MakeJit() { | ||||||
|     Dynarmic::A32::UserConfig config; |     Dynarmic::A32::UserConfig config; | ||||||
|     config.callbacks = cb.get(); |     config.callbacks = cb.get(); | ||||||
|     if (current_page_table) { |     if (current_page_table) { | ||||||
|         config.page_table = ¤t_page_table->GetPointerArray(); |         config.page_table = ¤t_page_table->pointers; | ||||||
|     } |     } | ||||||
|     config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state); |     config.coprocessors[15] = std::make_shared<DynarmicCP15>(cp15_state); | ||||||
|     config.define_unpredictable_behaviour = true; |     config.define_unpredictable_behaviour = true; | ||||||
|  |  | ||||||
|  | @ -429,8 +429,6 @@ System::ResultStatus System::Init(Frontend::EmuWindow& emu_window, | ||||||
|         dsp_core = std::make_unique<AudioCore::DspLle>(*this, multithread); |         dsp_core = std::make_unique<AudioCore::DspLle>(*this, multithread); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     memory->SetDSP(*dsp_core); |  | ||||||
| 
 |  | ||||||
|     dsp_core->SetSink(Settings::values.output_type.GetValue(), |     dsp_core->SetSink(Settings::values.output_type.GetValue(), | ||||||
|                       Settings::values.output_device.GetValue()); |                       Settings::values.output_device.GetValue()); | ||||||
|     dsp_core->EnableStretching(Settings::values.enable_audio_stretching.GetValue()); |     dsp_core->EnableStretching(Settings::values.enable_audio_stretching.GetValue()); | ||||||
|  |  | ||||||
|  | @ -194,9 +194,9 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( | ||||||
|                   plg_context.plugin_path); |                   plg_context.plugin_path); | ||||||
|         return Loader::ResultStatus::ErrorMemoryAllocationFailed; |         return Loader::ResultStatus::ErrorMemoryAllocationFailed; | ||||||
|     } |     } | ||||||
|     auto backing_memory_fb = kernel.memory.GetFCRAMRef(*offset_fb); |     auto backing_memory_fb = kernel.memory.GetFCRAMPointer(*offset_fb); | ||||||
|     plg_ldr.SetPluginFBAddr(Memory::FCRAM_PADDR + *offset_fb); |     plg_ldr.SetPluginFBAddr(Memory::FCRAM_PADDR + *offset_fb); | ||||||
|     std::fill(backing_memory_fb.GetPtr(), backing_memory_fb.GetPtr() + _3GX_fb_size, 0); |     std::memset(backing_memory_fb, 0, _3GX_fb_size); | ||||||
| 
 | 
 | ||||||
|     auto vma_heap_fb = process.vm_manager.MapBackingMemory( |     auto vma_heap_fb = process.vm_manager.MapBackingMemory( | ||||||
|         _3GX_heap_load_addr, backing_memory_fb, _3GX_fb_size, Kernel::MemoryState::Continuous); |         _3GX_heap_load_addr, backing_memory_fb, _3GX_fb_size, Kernel::MemoryState::Continuous); | ||||||
|  | @ -212,8 +212,8 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( | ||||||
|                   plg_context.plugin_path); |                   plg_context.plugin_path); | ||||||
|         return Loader::ResultStatus::ErrorMemoryAllocationFailed; |         return Loader::ResultStatus::ErrorMemoryAllocationFailed; | ||||||
|     } |     } | ||||||
|     auto backing_memory = kernel.memory.GetFCRAMRef(*offset); |     auto backing_memory = kernel.memory.GetFCRAMPointer(*offset); | ||||||
|     std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + block_size - _3GX_fb_size, 0); |     std::memset(backing_memory, 0, block_size - _3GX_fb_size); | ||||||
| 
 | 
 | ||||||
|     // Then we map part of the memory, which contains the executable
 |     // Then we map part of the memory, which contains the executable
 | ||||||
|     auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr, backing_memory, exe_size, |     auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr, backing_memory, exe_size, | ||||||
|  | @ -251,7 +251,7 @@ Loader::ResultStatus FileSys::Plugin3GXLoader::Map( | ||||||
|     kernel.memory.WriteBlock(process, _3GX_exe_load_addr, &plugin_header, sizeof(PluginHeader)); |     kernel.memory.WriteBlock(process, _3GX_exe_load_addr, &plugin_header, sizeof(PluginHeader)); | ||||||
| 
 | 
 | ||||||
|     // Map plugin heap
 |     // Map plugin heap
 | ||||||
|     auto backing_memory_heap = kernel.memory.GetFCRAMRef(*offset + exe_size); |     auto backing_memory_heap = kernel.memory.GetFCRAMPointer(*offset + exe_size); | ||||||
| 
 | 
 | ||||||
|     // Map the rest of the memory at the heap location
 |     // Map the rest of the memory at the heap location
 | ||||||
|     auto vma_heap = process.vm_manager.MapBackingMemory( |     auto vma_heap = process.vm_manager.MapBackingMemory( | ||||||
|  | @ -346,8 +346,8 @@ void FileSys::Plugin3GXLoader::MapBootloader(Kernel::Process& process, Kernel::K | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     // Map bootloader to the offset provided
 |     // Map bootloader to the offset provided
 | ||||||
|     auto backing_memory = kernel.memory.GetFCRAMRef(memory_offset); |     auto backing_memory = kernel.memory.GetFCRAMPointer(memory_offset); | ||||||
|     std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + bootloader_memory_size, 0); |     std::memset(backing_memory, 0, bootloader_memory_size); | ||||||
|     auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr - bootloader_memory_size, |     auto vma = process.vm_manager.MapBackingMemory(_3GX_exe_load_addr - bootloader_memory_size, | ||||||
|                                                    backing_memory, bootloader_memory_size, |                                                    backing_memory, bootloader_memory_size, | ||||||
|                                                    Kernel::MemoryState::Continuous); |                                                    Kernel::MemoryState::Continuous); | ||||||
|  |  | ||||||
|  | @ -5,7 +5,6 @@ | ||||||
| #include <algorithm> | #include <algorithm> | ||||||
| #include "common/alignment.h" | #include "common/alignment.h" | ||||||
| 
 | 
 | ||||||
| #include "common/memory_ref.h" |  | ||||||
| #include "core/core.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" | ||||||
|  | @ -196,23 +195,22 @@ Result TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySystem | ||||||
|             // TODO(Subv): Perform permission checks.
 |             // TODO(Subv): Perform permission checks.
 | ||||||
| 
 | 
 | ||||||
|             // Create a buffer which contains the mapped buffer and two additional guard pages.
 |             // Create a buffer which contains the mapped buffer and two additional guard pages.
 | ||||||
|             std::shared_ptr<BackingMem> buffer = |             const u32 buffer_size = (num_pages + 2) * Memory::CITRA_PAGE_SIZE; | ||||||
|                 std::make_shared<BufferMem>((num_pages + 2) * Memory::CITRA_PAGE_SIZE); |             auto buffer = std::make_unique<u8[]>(buffer_size); | ||||||
|             memory.ReadBlock(*src_process, source_address, |             memory.ReadBlock(*src_process, source_address, | ||||||
|                              buffer->GetPtr() + Memory::CITRA_PAGE_SIZE + page_offset, size); |                              buffer.get() + Memory::CITRA_PAGE_SIZE + page_offset, size); | ||||||
| 
 | 
 | ||||||
|             // Map the guard pages and mapped pages at once.
 |             // Map the guard pages and mapped pages at once.
 | ||||||
|             target_address = |             target_address = | ||||||
|                 dst_process->vm_manager |                 dst_process->vm_manager | ||||||
|                     .MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, |                     .MapBackingMemoryToBase(Memory::IPC_MAPPING_VADDR, Memory::IPC_MAPPING_SIZE, | ||||||
|                                             buffer, static_cast<u32>(buffer->GetSize()), |                                             buffer.get(), buffer_size, Kernel::MemoryState::Shared) | ||||||
|                                             Kernel::MemoryState::Shared) |  | ||||||
|                     .Unwrap(); |                     .Unwrap(); | ||||||
| 
 | 
 | ||||||
|             // Change the permissions and state of the guard pages.
 |             // Change the permissions and state of the guard pages.
 | ||||||
|             const VAddr low_guard_address = target_address; |             const VAddr low_guard_address = target_address; | ||||||
|             const VAddr high_guard_address = |             const VAddr high_guard_address = | ||||||
|                 low_guard_address + static_cast<VAddr>(buffer->GetSize()) - Memory::CITRA_PAGE_SIZE; |                 low_guard_address + buffer_size - Memory::CITRA_PAGE_SIZE; | ||||||
|             ASSERT(dst_process->vm_manager.ChangeMemoryState( |             ASSERT(dst_process->vm_manager.ChangeMemoryState( | ||||||
|                        low_guard_address, Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Shared, |                        low_guard_address, Memory::CITRA_PAGE_SIZE, Kernel::MemoryState::Shared, | ||||||
|                        Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Reserved, |                        Kernel::VMAPermission::ReadWrite, Kernel::MemoryState::Reserved, | ||||||
|  | @ -226,8 +224,8 @@ Result TranslateCommandBuffer(Kernel::KernelSystem& kernel, Memory::MemorySystem | ||||||
|             target_address += Memory::CITRA_PAGE_SIZE; |             target_address += Memory::CITRA_PAGE_SIZE; | ||||||
|             cmd_buf[i++] = target_address + page_offset; |             cmd_buf[i++] = target_address + page_offset; | ||||||
| 
 | 
 | ||||||
|             mapped_buffer_context.push_back({permissions, size, source_address, |             mapped_buffer_context.emplace_back(permissions, size, source_address, | ||||||
|                                              target_address + page_offset, std::move(buffer)}); |                                                target_address + page_offset, std::move(buffer)); | ||||||
| 
 | 
 | ||||||
|             break; |             break; | ||||||
|         } |         } | ||||||
|  |  | ||||||
|  | @ -23,8 +23,7 @@ struct MappedBufferContext { | ||||||
|     u32 size; |     u32 size; | ||||||
|     VAddr source_address; |     VAddr source_address; | ||||||
|     VAddr target_address; |     VAddr target_address; | ||||||
| 
 |     std::unique_ptr<u8[]> buffer; | ||||||
|     std::shared_ptr<BackingMem> buffer; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| /// Performs IPC command buffer translation from one process to another.
 | /// Performs IPC command buffer translation from one process to another.
 | ||||||
|  |  | ||||||
|  | @ -135,7 +135,7 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto target_pointer = memory.GetPhysicalRef(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; | ||||||
|  | @ -148,16 +148,18 @@ void KernelSystem::HandleSpecialMapping(VMManager& address_space, const AddressM | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void KernelSystem::MapSharedPages(VMManager& address_space) { | void KernelSystem::MapSharedPages(VMManager& address_space) { | ||||||
|     auto cfg_mem_vma = address_space |     auto cfg_mem_vma = | ||||||
|                            .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, {config_mem_handler}, |         address_space | ||||||
|                                              Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared) |             .MapBackingMemory(Memory::CONFIG_MEMORY_VADDR, config_mem_handler->GetPtr(), | ||||||
|                            .Unwrap(); |                               Memory::CONFIG_MEMORY_SIZE, MemoryState::Shared) | ||||||
|  |             .Unwrap(); | ||||||
|     address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); |     address_space.Reprotect(cfg_mem_vma, VMAPermission::Read); | ||||||
| 
 | 
 | ||||||
|     auto shared_page_vma = address_space |     auto shared_page_vma = | ||||||
|                                .MapBackingMemory(Memory::SHARED_PAGE_VADDR, {shared_page_handler}, |         address_space | ||||||
|                                                  Memory::SHARED_PAGE_SIZE, MemoryState::Shared) |             .MapBackingMemory(Memory::SHARED_PAGE_VADDR, shared_page_handler->GetPtr(), | ||||||
|                                .Unwrap(); |                               Memory::SHARED_PAGE_SIZE, MemoryState::Shared) | ||||||
|  |             .Unwrap(); | ||||||
|     address_space.Reprotect(shared_page_vma, VMAPermission::Read); |     address_space.Reprotect(shared_page_vma, VMAPermission::Read); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -242,13 +242,13 @@ Result Process::HeapAllocate(VAddr* out_addr, VAddr target, u32 size, VMAPermiss | ||||||
|     // Maps heap block by block
 |     // Maps heap block by block
 | ||||||
|     VAddr interval_target = target; |     VAddr interval_target = target; | ||||||
|     for (const auto& interval : allocated_fcram) { |     for (const auto& interval : allocated_fcram) { | ||||||
|         u32 interval_size = interval.upper() - interval.lower(); |         const 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(kernel.memory.GetFCRAMPointer(interval.lower()), |         std::fill(kernel.memory.GetFCRAMPointer(interval.lower()), | ||||||
|                   kernel.memory.GetFCRAMPointer(interval.upper()), 0); |                   kernel.memory.GetFCRAMPointer(interval.upper()), 0); | ||||||
|         auto vma = vm_manager.MapBackingMemory(interval_target, |         auto vma = vm_manager.MapBackingMemory(interval_target, | ||||||
|                                                kernel.memory.GetFCRAMRef(interval.lower()), |                                                kernel.memory.GetFCRAMPointer(interval.lower()), | ||||||
|                                                interval_size, memory_state); |                                                interval_size, memory_state); | ||||||
|         ASSERT(vma.Succeeded()); |         ASSERT(vma.Succeeded()); | ||||||
|         vm_manager.Reprotect(vma.Unwrap(), perms); |         vm_manager.Reprotect(vma.Unwrap(), perms); | ||||||
|  | @ -276,7 +276,7 @@ Result 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) { | ||||||
|         const auto backing_offset = kernel.memory.GetFCRAMOffset(backing_memory.GetPtr()); |         const auto backing_offset = kernel.memory.GetFCRAMOffset(backing_memory); | ||||||
|         memory_region->Free(backing_offset, block_size); |         memory_region->Free(backing_offset, block_size); | ||||||
|         holding_memory -= MemoryRegionInfo::Interval(backing_offset, backing_offset + block_size); |         holding_memory -= MemoryRegionInfo::Interval(backing_offset, backing_offset + block_size); | ||||||
|     } |     } | ||||||
|  | @ -322,9 +322,9 @@ Result Process::LinearAllocate(VAddr* out_addr, VAddr target, u32 size, VMAPermi | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     auto backing_memory = kernel.memory.GetFCRAMRef(physical_offset); |     auto backing_memory = kernel.memory.GetFCRAMPointer(physical_offset); | ||||||
| 
 | 
 | ||||||
|     std::fill(backing_memory.GetPtr(), backing_memory.GetPtr() + 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); | ||||||
|     ASSERT(vma.Succeeded()); |     ASSERT(vma.Succeeded()); | ||||||
|     vm_manager.Reprotect(vma.Unwrap(), perms); |     vm_manager.Reprotect(vma.Unwrap(), perms); | ||||||
|  | @ -410,7 +410,7 @@ ResultVal<VAddr> Process::AllocateThreadLocalStorage() { | ||||||
|         // Map the page to the current process' address space.
 |         // Map the page to the current process' address space.
 | ||||||
|         auto tls_page_addr = |         auto tls_page_addr = | ||||||
|             Memory::TLS_AREA_VADDR + static_cast<VAddr>(tls_page) * Memory::CITRA_PAGE_SIZE; |             Memory::TLS_AREA_VADDR + static_cast<VAddr>(tls_page) * Memory::CITRA_PAGE_SIZE; | ||||||
|         vm_manager.MapBackingMemory(tls_page_addr, kernel.memory.GetFCRAMRef(*offset), |         vm_manager.MapBackingMemory(tls_page_addr, kernel.memory.GetFCRAMPointer(*offset), | ||||||
|                                     Memory::CITRA_PAGE_SIZE, MemoryState::Locked); |                                     Memory::CITRA_PAGE_SIZE, MemoryState::Locked); | ||||||
| 
 | 
 | ||||||
|         LOG_DEBUG(Kernel, "Allocated TLS page at addr={:08X}", tls_page_addr); |         LOG_DEBUG(Kernel, "Allocated TLS page at addr={:08X}", tls_page_addr); | ||||||
|  |  | ||||||
|  | @ -52,7 +52,7 @@ ResultVal<std::shared_ptr<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.GetFCRAMPointer(*offset), memory.GetFCRAMPointer(*offset + size), 0); |         std::fill(memory.GetFCRAMPointer(*offset), memory.GetFCRAMPointer(*offset + size), 0); | ||||||
|         shared_memory->backing_blocks = {{memory.GetFCRAMRef(*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; | ||||||
| 
 | 
 | ||||||
|  | @ -94,7 +94,7 @@ std::shared_ptr<SharedMemory> KernelSystem::CreateSharedMemoryForApplet( | ||||||
|     shared_memory->permissions = permissions; |     shared_memory->permissions = permissions; | ||||||
|     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.emplace_back(memory.GetFCRAMRef(interval.lower()), |         shared_memory->backing_blocks.emplace_back(memory.GetFCRAMPointer(interval.lower()), | ||||||
|                                                    interval.upper() - interval.lower()); |                                                    interval.upper() - interval.lower()); | ||||||
|         std::fill(memory.GetFCRAMPointer(interval.lower()), |         std::fill(memory.GetFCRAMPointer(interval.lower()), | ||||||
|                   memory.GetFCRAMPointer(interval.upper()), 0); |                   memory.GetFCRAMPointer(interval.upper()), 0); | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ | ||||||
| #include <string> | #include <string> | ||||||
| #include <utility> | #include <utility> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/memory_ref.h" |  | ||||||
| #include "core/hle/kernel/object.h" | #include "core/hle/kernel/object.h" | ||||||
| #include "core/hle/kernel/process.h" | #include "core/hle/kernel/process.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
|  | @ -87,7 +86,7 @@ private: | ||||||
|     /// during creation.
 |     /// during creation.
 | ||||||
|     PAddr linear_heap_phys_offset = 0; |     PAddr linear_heap_phys_offset = 0; | ||||||
|     /// Backing memory for this shared memory block.
 |     /// Backing memory for this shared memory block.
 | ||||||
|     std::vector<std::pair<MemoryRef, u32>> backing_blocks; |     std::vector<std::pair<u8*, u32>> backing_blocks; | ||||||
|     /// Size of the memory block. Page-aligned.
 |     /// Size of the memory block. Page-aligned.
 | ||||||
|     u32 size = 0; |     u32 size = 0; | ||||||
|     /// Region of memory this block exists in.
 |     /// Region of memory this block exists in.
 | ||||||
|  |  | ||||||
|  | @ -1937,8 +1937,7 @@ u32 SVC::ConvertVaToPa(u32 addr) { | ||||||
|         vma->second.type != VMAType::BackingMemory) { |         vma->second.type != VMAType::BackingMemory) { | ||||||
|         return 0; |         return 0; | ||||||
|     } |     } | ||||||
|     return kernel.memory.GetFCRAMOffset(vma->second.backing_memory.GetPtr() + addr - |     return kernel.memory.GetFCRAMOffset(vma->second.backing_memory + addr - vma->second.base) + | ||||||
|                                         vma->second.base) + |  | ||||||
|            Memory::FCRAM_PADDR; |            Memory::FCRAM_PADDR; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -1967,8 +1966,8 @@ Result SVC::MapProcessMemoryEx(Handle dst_process_handle, u32 dst_address, | ||||||
| 
 | 
 | ||||||
|     auto vma_res = dst_process->vm_manager.MapBackingMemory( |     auto vma_res = dst_process->vm_manager.MapBackingMemory( | ||||||
|         dst_address, |         dst_address, | ||||||
|         memory.GetFCRAMRef(vma->second.backing_memory.GetPtr() + offset - |         memory.GetFCRAMPointer(vma->second.backing_memory + offset - | ||||||
|                            kernel.memory.GetFCRAMPointer(0)), |                                kernel.memory.GetFCRAMPointer(0)), | ||||||
|         size, Kernel::MemoryState::Continuous); |         size, Kernel::MemoryState::Continuous); | ||||||
| 
 | 
 | ||||||
|     if (!vma_res.Succeeded()) { |     if (!vma_res.Succeeded()) { | ||||||
|  |  | ||||||
|  | @ -29,8 +29,7 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { | ||||||
|         type != next.type) { |         type != next.type) { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     if (type == VMAType::BackingMemory && |     if (type == VMAType::BackingMemory && backing_memory + size != next.backing_memory) { | ||||||
|         backing_memory.GetPtr() + size != next.backing_memory.GetPtr()) { |  | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
|     return true; |     return true; | ||||||
|  | @ -38,24 +37,16 @@ bool VirtualMemoryArea::CanBeMergedWith(const VirtualMemoryArea& next) const { | ||||||
| 
 | 
 | ||||||
| VMManager::VMManager(Memory::MemorySystem& memory, Kernel::Process& proc) | VMManager::VMManager(Memory::MemorySystem& memory, Kernel::Process& proc) | ||||||
|     : page_table(std::make_shared<Memory::PageTable>()), memory(memory), process(proc) { |     : page_table(std::make_shared<Memory::PageTable>()), memory(memory), process(proc) { | ||||||
|     Reset(); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| VMManager::~VMManager() = default; |  | ||||||
| 
 |  | ||||||
| void VMManager::Reset() { |  | ||||||
|     vma_map.clear(); |  | ||||||
| 
 |  | ||||||
|     // Initialize the map with a single free region covering the entire managed space.
 |     // Initialize the map with a single free region covering the entire managed space.
 | ||||||
|     VirtualMemoryArea initial_vma; |     VirtualMemoryArea initial_vma; | ||||||
|     initial_vma.size = MAX_ADDRESS; |     initial_vma.size = MAX_ADDRESS; | ||||||
|     vma_map.emplace(initial_vma.base, initial_vma); |     vma_map.emplace(initial_vma.base, initial_vma); | ||||||
| 
 | 
 | ||||||
|     page_table->Clear(); |  | ||||||
| 
 |  | ||||||
|     UpdatePageTableForVMA(initial_vma); |     UpdatePageTableForVMA(initial_vma); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | VMManager::~VMManager() = default; | ||||||
|  | 
 | ||||||
| VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { | VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { | ||||||
|     if (target >= MAX_ADDRESS) { |     if (target >= MAX_ADDRESS) { | ||||||
|         return vma_map.end(); |         return vma_map.end(); | ||||||
|  | @ -64,7 +55,7 @@ VMManager::VMAHandle VMManager::FindVMA(VAddr target) const { | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory, | ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory, | ||||||
|                                                    u32 size, MemoryState state) { |                                                    u32 size, MemoryState state) { | ||||||
|     // Find the first Free VMA.
 |     // Find the first Free VMA.
 | ||||||
|     VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { |     VMAHandle vma_handle = std::find_if(vma_map.begin(), vma_map.end(), [&](const auto& vma) { | ||||||
|  | @ -92,9 +83,9 @@ ResultVal<VAddr> VMManager::MapBackingMemoryToBase(VAddr base, u32 region_size, | ||||||
|     return target; |     return target; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, MemoryRef memory, | ResultVal<VMManager::VMAHandle> VMManager::MapBackingMemory(VAddr target, u8* memory, u32 size, | ||||||
|                                                             u32 size, MemoryState state) { |                                                             MemoryState state) { | ||||||
|     ASSERT(memory.GetPtr() != nullptr); |     ASSERT(memory != nullptr); | ||||||
| 
 | 
 | ||||||
|     // This is the appropriately sized VMA that will turn into our allocation.
 |     // This is the appropriately sized VMA that will turn into our allocation.
 | ||||||
|     CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); |     CASCADE_RESULT(VMAIter vma_handle, CarveVMA(target, size)); | ||||||
|  | @ -339,9 +330,8 @@ void VMManager::UpdatePageTableForVMA(const VirtualMemoryArea& vma) { | ||||||
|         plgldr->OnMemoryChanged(process, Core::System::GetInstance().Kernel()); |         plgldr->OnMemoryChanged(process, Core::System::GetInstance().Kernel()); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| ResultVal<std::vector<std::pair<MemoryRef, u32>>> VMManager::GetBackingBlocksForRange(VAddr address, | ResultVal<VMManager::BackingBlocks> VMManager::GetBackingBlocksForRange(VAddr address, u32 size) { | ||||||
|                                                                                       u32 size) { |     BackingBlocks backing_blocks; | ||||||
|     std::vector<std::pair<MemoryRef, u32>> backing_blocks; |  | ||||||
|     VAddr interval_target = address; |     VAddr interval_target = address; | ||||||
|     while (interval_target != address + size) { |     while (interval_target != address + size) { | ||||||
|         auto vma = FindVMA(interval_target); |         auto vma = FindVMA(interval_target); | ||||||
|  |  | ||||||
|  | @ -68,7 +68,7 @@ struct VirtualMemoryArea { | ||||||
| 
 | 
 | ||||||
|     /// Settings for type = BackingMemory
 |     /// Settings for type = BackingMemory
 | ||||||
|     /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
 |     /// Pointer backing this VMA. It will not be destroyed or freed when the VMA is removed.
 | ||||||
|     MemoryRef backing_memory{}; |     u8* backing_memory{}; | ||||||
| 
 | 
 | ||||||
|     /// Tests if this area can be merged to the right with `next`.
 |     /// Tests if this area can be merged to the right with `next`.
 | ||||||
|     bool CanBeMergedWith(const VirtualMemoryArea& next) const; |     bool CanBeMergedWith(const VirtualMemoryArea& next) const; | ||||||
|  | @ -108,14 +108,9 @@ public: | ||||||
|     explicit VMManager(Memory::MemorySystem& memory, Kernel::Process& proc); |     explicit VMManager(Memory::MemorySystem& memory, Kernel::Process& proc); | ||||||
|     ~VMManager(); |     ~VMManager(); | ||||||
| 
 | 
 | ||||||
|     /// Clears the address space map, re-initializing with a single free area.
 |  | ||||||
|     void Reset(); |  | ||||||
| 
 |  | ||||||
|     /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
 |     /// Finds the VMA in which the given address is included in, or `vma_map.end()`.
 | ||||||
|     VMAHandle FindVMA(VAddr target) const; |     VMAHandle FindVMA(VAddr target) const; | ||||||
| 
 | 
 | ||||||
|     // TODO(yuriks): Should these functions actually return the handle?
 |  | ||||||
| 
 |  | ||||||
|     /**
 |     /**
 | ||||||
|      * Maps part of a ref-counted block of memory at the first free address after the given base. |      * Maps part of a ref-counted block of memory at the first free address after the given base. | ||||||
|      * |      * | ||||||
|  | @ -126,7 +121,7 @@ public: | ||||||
|      * @param state MemoryState tag to attach to the VMA. |      * @param state MemoryState tag to attach to the VMA. | ||||||
|      * @returns The address at which the memory was mapped. |      * @returns The address at which the memory was mapped. | ||||||
|      */ |      */ | ||||||
|     ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, MemoryRef memory, u32 size, |     ResultVal<VAddr> MapBackingMemoryToBase(VAddr base, u32 region_size, u8* memory, u32 size, | ||||||
|                                             MemoryState state); |                                             MemoryState state); | ||||||
|     /**
 |     /**
 | ||||||
|      * Maps an unmanaged host memory pointer at a given address. |      * Maps an unmanaged host memory pointer at a given address. | ||||||
|  | @ -136,8 +131,7 @@ public: | ||||||
|      * @param size Size of the mapping. |      * @param size Size of the mapping. | ||||||
|      * @param state MemoryState tag to attach to the VMA. |      * @param state MemoryState tag to attach to the VMA. | ||||||
|      */ |      */ | ||||||
|     ResultVal<VMAHandle> MapBackingMemory(VAddr target, MemoryRef memory, u32 size, |     ResultVal<VMAHandle> MapBackingMemory(VAddr target, u8* memory, u32 size, MemoryState state); | ||||||
|                                           MemoryState state); |  | ||||||
| 
 | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Updates the memory state and permissions of the specified range. The range's original memory |      * Updates the memory state and permissions of the specified range. The range's original memory | ||||||
|  | @ -167,8 +161,8 @@ public: | ||||||
|     void LogLayout(Common::Log::Level log_level) const; |     void LogLayout(Common::Log::Level log_level) const; | ||||||
| 
 | 
 | ||||||
|     /// Gets a list of backing memory blocks for the specified range
 |     /// Gets a list of backing memory blocks for the specified range
 | ||||||
|     ResultVal<std::vector<std::pair<MemoryRef, u32>>> GetBackingBlocksForRange(VAddr address, |     using BackingBlocks = std::vector<std::pair<u8*, u32>>; | ||||||
|                                                                                u32 size); |     ResultVal<BackingBlocks> GetBackingBlocksForRange(VAddr address, u32 size); | ||||||
| 
 | 
 | ||||||
|     /// Each VMManager has its own page table, which is set as the main one when the owning process
 |     /// Each VMManager has its own page table, which is set as the main one when the owning process
 | ||||||
|     /// is scheduled.
 |     /// is scheduled.
 | ||||||
|  |  | ||||||
|  | @ -4,7 +4,6 @@ | ||||||
| 
 | 
 | ||||||
| #include <array> | #include <array> | ||||||
| #include <cstring> | #include <cstring> | ||||||
| #include "audio_core/dsp_interface.h" |  | ||||||
| 
 | 
 | ||||||
| #include "common/assert.h" | #include "common/assert.h" | ||||||
| #include "common/atomic_ops.h" | #include "common/atomic_ops.h" | ||||||
|  | @ -22,12 +21,6 @@ | ||||||
| 
 | 
 | ||||||
| namespace Memory { | namespace Memory { | ||||||
| 
 | 
 | ||||||
| void PageTable::Clear() { |  | ||||||
|     pointers.raw.fill(nullptr); |  | ||||||
|     pointers.refs.fill(MemoryRef()); |  | ||||||
|     attributes.fill(PageType::Unmapped); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| class RasterizerCacheMarker { | class RasterizerCacheMarker { | ||||||
| public: | public: | ||||||
|     void Mark(VAddr addr, bool cached) { |     void Mark(VAddr addr, bool cached) { | ||||||
|  | @ -68,53 +61,17 @@ private: | ||||||
| 
 | 
 | ||||||
| class MemorySystem::Impl { | class MemorySystem::Impl { | ||||||
| public: | public: | ||||||
|  |     Core::System& system; | ||||||
|     std::unique_ptr<u8[]> fcram = std::make_unique<u8[]>(Memory::FCRAM_N3DS_SIZE); |     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[]> vram = std::make_unique<u8[]>(Memory::VRAM_SIZE); | ||||||
|     std::unique_ptr<u8[]> n3ds_extra_ram = std::make_unique<u8[]>(Memory::N3DS_EXTRA_RAM_SIZE); |     std::unique_ptr<u8[]> n3ds_extra_ram = std::make_unique<u8[]>(Memory::N3DS_EXTRA_RAM_SIZE); | ||||||
|  |     std::unique_ptr<u8[]> dsp_mem = std::make_unique<u8[]>(Memory::DSP_RAM_SIZE); | ||||||
| 
 | 
 | ||||||
|     Core::System& system; |  | ||||||
|     std::shared_ptr<PageTable> current_page_table = nullptr; |     std::shared_ptr<PageTable> current_page_table = nullptr; | ||||||
|     RasterizerCacheMarker cache_marker; |     RasterizerCacheMarker cache_marker; | ||||||
|     std::vector<std::shared_ptr<PageTable>> page_table_list; |     std::vector<std::shared_ptr<PageTable>> page_table_list; | ||||||
| 
 | 
 | ||||||
|     AudioCore::DspInterface* dsp = nullptr; |     Impl(Core::System& system_) : system{system_} {} | ||||||
| 
 |  | ||||||
|     std::shared_ptr<BackingMem> fcram_mem; |  | ||||||
|     std::shared_ptr<BackingMem> vram_mem; |  | ||||||
|     std::shared_ptr<BackingMem> n3ds_extra_ram_mem; |  | ||||||
|     std::shared_ptr<BackingMem> dsp_mem; |  | ||||||
| 
 |  | ||||||
|     Impl(Core::System& system_); |  | ||||||
| 
 |  | ||||||
|     const u8* GetPtr(Region r) const { |  | ||||||
|         switch (r) { |  | ||||||
|         case Region::VRAM: |  | ||||||
|             return vram.get(); |  | ||||||
|         case Region::DSP: |  | ||||||
|             return dsp->GetDspMemory().data(); |  | ||||||
|         case Region::FCRAM: |  | ||||||
|             return fcram.get(); |  | ||||||
|         case Region::N3DS: |  | ||||||
|             return n3ds_extra_ram.get(); |  | ||||||
|         default: |  | ||||||
|             UNREACHABLE(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     u8* GetPtr(Region r) { |  | ||||||
|         switch (r) { |  | ||||||
|         case Region::VRAM: |  | ||||||
|             return vram.get(); |  | ||||||
|         case Region::DSP: |  | ||||||
|             return dsp->GetDspMemory().data(); |  | ||||||
|         case Region::FCRAM: |  | ||||||
|             return fcram.get(); |  | ||||||
|         case Region::N3DS: |  | ||||||
|             return n3ds_extra_ram.get(); |  | ||||||
|         default: |  | ||||||
|             UNREACHABLE(); |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     u32 GetSize(Region r) const { |     u32 GetSize(Region r) const { | ||||||
|         switch (r) { |         switch (r) { | ||||||
|  | @ -233,26 +190,26 @@ public: | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     MemoryRef GetPointerForRasterizerCache(VAddr addr) const { |     u8* GetPointerForRasterizerCache(VAddr addr) const { | ||||||
|         if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { |         if (addr >= LINEAR_HEAP_VADDR && addr < LINEAR_HEAP_VADDR_END) { | ||||||
|             return {fcram_mem, addr - LINEAR_HEAP_VADDR}; |             return 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_mem, addr - NEW_LINEAR_HEAP_VADDR}; |             return 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_mem, addr - VRAM_VADDR}; |             return vram.get() + addr - VRAM_VADDR; | ||||||
|         } |         } | ||||||
|         if (addr >= PLUGIN_3GX_FB_VADDR && addr < PLUGIN_3GX_FB_VADDR_END) { |         if (addr >= PLUGIN_3GX_FB_VADDR && addr < PLUGIN_3GX_FB_VADDR_END) { | ||||||
|             auto plg_ldr = Service::PLGLDR::GetService(system); |             auto plg_ldr = Service::PLGLDR::GetService(system); | ||||||
|             if (plg_ldr) { |             if (plg_ldr) { | ||||||
|                 return {fcram_mem, |                 return fcram.get() + addr - PLUGIN_3GX_FB_VADDR + plg_ldr->GetPluginFBAddr() - | ||||||
|                         addr - PLUGIN_3GX_FB_VADDR + plg_ldr->GetPluginFBAddr() - FCRAM_PADDR}; |                        FCRAM_PADDR; | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|         return MemoryRef{}; |         return nullptr; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) { |     void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode) { | ||||||
|  | @ -294,33 +251,8 @@ public: | ||||||
|     } |     } | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| // We use this rather than BufferMem because we don't want new objects to be allocated when
 |  | ||||||
| // deserializing. This avoids unnecessary memory thrashing.
 |  | ||||||
| template <Region R> |  | ||||||
| class MemorySystem::BackingMemImpl : public BackingMem { |  | ||||||
| public: |  | ||||||
|     explicit BackingMemImpl(MemorySystem::Impl& impl_) : impl(impl_) {} |  | ||||||
|     u8* GetPtr() override { |  | ||||||
|         return impl.GetPtr(R); |  | ||||||
|     } |  | ||||||
|     const u8* GetPtr() const override { |  | ||||||
|         return impl.GetPtr(R); |  | ||||||
|     } |  | ||||||
|     std::size_t GetSize() const override { |  | ||||||
|         return impl.GetSize(R); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
| private: |  | ||||||
|     MemorySystem::Impl& impl; |  | ||||||
| }; |  | ||||||
| 
 |  | ||||||
| MemorySystem::Impl::Impl(Core::System& system_) |  | ||||||
|     : system{system_}, fcram_mem(std::make_shared<BackingMemImpl<Region::FCRAM>>(*this)), |  | ||||||
|       vram_mem(std::make_shared<BackingMemImpl<Region::VRAM>>(*this)), |  | ||||||
|       n3ds_extra_ram_mem(std::make_shared<BackingMemImpl<Region::N3DS>>(*this)), |  | ||||||
|       dsp_mem(std::make_shared<BackingMemImpl<Region::DSP>>(*this)) {} |  | ||||||
| 
 |  | ||||||
| MemorySystem::MemorySystem(Core::System& system) : impl(std::make_unique<Impl>(system)) {} | MemorySystem::MemorySystem(Core::System& system) : impl(std::make_unique<Impl>(system)) {} | ||||||
|  | 
 | ||||||
| MemorySystem::~MemorySystem() = default; | MemorySystem::~MemorySystem() = default; | ||||||
| 
 | 
 | ||||||
| void MemorySystem::SetCurrentPageTable(std::shared_ptr<PageTable> page_table) { | void MemorySystem::SetCurrentPageTable(std::shared_ptr<PageTable> page_table) { | ||||||
|  | @ -335,10 +267,9 @@ void MemorySystem::RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode | ||||||
|     impl->RasterizerFlushVirtualRegion(start, size, mode); |     impl->RasterizerFlushVirtualRegion(start, size, mode); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, | void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type) { | ||||||
|                             PageType type) { |     LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", fmt::ptr(memory), base * CITRA_PAGE_SIZE, | ||||||
|     LOG_DEBUG(HW_Memory, "Mapping {} onto {:08X}-{:08X}", (void*)memory.GetPtr(), |               (base + size) * CITRA_PAGE_SIZE); | ||||||
|               base * CITRA_PAGE_SIZE, (base + size) * CITRA_PAGE_SIZE); |  | ||||||
| 
 | 
 | ||||||
|     if (impl->system.IsPoweredOn()) { |     if (impl->system.IsPoweredOn()) { | ||||||
|         RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE, |         RasterizerFlushVirtualRegion(base << CITRA_PAGE_BITS, size * CITRA_PAGE_SIZE, | ||||||
|  | @ -347,7 +278,7 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef | ||||||
| 
 | 
 | ||||||
|     u32 end = base + size; |     u32 end = base + size; | ||||||
|     while (base != end) { |     while (base != end) { | ||||||
|         ASSERT_MSG(base < PAGE_TABLE_NUM_ENTRIES, "out of range mapping at {:08X}", base); |         ASSERT_MSG(base < PageTable::NUM_ENTRIES, "out of range mapping at {:08X}", base); | ||||||
| 
 | 
 | ||||||
|         page_table.attributes[base] = type; |         page_table.attributes[base] = type; | ||||||
|         page_table.pointers[base] = memory; |         page_table.pointers[base] = memory; | ||||||
|  | @ -359,12 +290,13 @@ void MemorySystem::MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         base += 1; |         base += 1; | ||||||
|         if (memory != nullptr && memory.GetSize() > CITRA_PAGE_SIZE) |         if (memory != nullptr /*&& memory.GetSize() > CITRA_PAGE_SIZE*/) { | ||||||
|             memory += CITRA_PAGE_SIZE; |             memory += CITRA_PAGE_SIZE; | ||||||
|  |         } | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target) { | void MemorySystem::MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, u8* target) { | ||||||
|     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); |     ASSERT_MSG((size & CITRA_PAGE_MASK) == 0, "non-page aligned size: {:08X}", size); | ||||||
|     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); |     ASSERT_MSG((base & CITRA_PAGE_MASK) == 0, "non-page aligned base: {:08X}", base); | ||||||
|     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory); |     MapPages(page_table, base / CITRA_PAGE_SIZE, size / CITRA_PAGE_SIZE, target, PageType::Memory); | ||||||
|  | @ -377,7 +309,7 @@ void MemorySystem::UnmapRegion(PageTable& page_table, VAddr base, u32 size) { | ||||||
|              PageType::Unmapped); |              PageType::Unmapped); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MemoryRef MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { | u8* MemorySystem::GetPointerForRasterizerCache(VAddr addr) const { | ||||||
|     return impl->GetPointerForRasterizerCache(addr); |     return impl->GetPointerForRasterizerCache(addr); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | @ -507,7 +439,7 @@ bool MemorySystem::WriteExclusive(const VAddr vaddr, const T data, const T expec | ||||||
|     case PageType::RasterizerCachedMemory: { |     case PageType::RasterizerCachedMemory: { | ||||||
|         RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate); |         RasterizerFlushVirtualRegion(vaddr, sizeof(T), FlushMode::Invalidate); | ||||||
|         const auto volatile_pointer = |         const auto volatile_pointer = | ||||||
|             reinterpret_cast<volatile T*>(GetPointerForRasterizerCache(vaddr).GetPtr()); |             reinterpret_cast<volatile T*>(GetPointerForRasterizerCache(vaddr)); | ||||||
|         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); |         return Common::AtomicCompareAndSwap(volatile_pointer, data, expected); | ||||||
|     } |     } | ||||||
|     default: |     default: | ||||||
|  | @ -532,7 +464,7 @@ bool MemorySystem::IsValidVirtualAddress(const Kernel::Process& process, const V | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const { | bool MemorySystem::IsValidPhysicalAddress(const PAddr paddr) const { | ||||||
|     return GetPhysicalRef(paddr); |     return !GetPhysicalSpan(paddr).empty(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8* MemorySystem::GetPointer(const VAddr vaddr) { | u8* MemorySystem::GetPointer(const VAddr vaddr) { | ||||||
|  | @ -583,10 +515,10 @@ std::string MemorySystem::ReadCString(VAddr vaddr, std::size_t max_length) { | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| u8* MemorySystem::GetPhysicalPointer(PAddr address) const { | u8* MemorySystem::GetPhysicalPointer(PAddr address) const { | ||||||
|     return GetPhysicalRef(address); |     return GetPhysicalSpan(address).data(); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const { | std::span<u8> MemorySystem::GetPhysicalSpan(PAddr address) const { | ||||||
|     constexpr std::array memory_areas = { |     constexpr std::array memory_areas = { | ||||||
|         std::make_pair(VRAM_PADDR, VRAM_SIZE), |         std::make_pair(VRAM_PADDR, VRAM_SIZE), | ||||||
|         std::make_pair(DSP_RAM_PADDR, DSP_RAM_SIZE), |         std::make_pair(DSP_RAM_PADDR, DSP_RAM_SIZE), | ||||||
|  | @ -603,33 +535,33 @@ MemoryRef MemorySystem::GetPhysicalRef(PAddr address) const { | ||||||
|     if (area == memory_areas.end()) { |     if (area == memory_areas.end()) { | ||||||
|         LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address, |         LOG_ERROR(HW_Memory, "Unknown GetPhysicalPointer @ {:#08X} at PC {:#08X}", address, | ||||||
|                   impl->GetPC()); |                   impl->GetPC()); | ||||||
|         return nullptr; |         return {}; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     u32 offset_into_region = address - area->first; |     const u32 offset_into_region = address - area->first; | ||||||
|  |     if (offset_into_region > area->second) { | ||||||
|  |         return {}; | ||||||
|  |     } | ||||||
| 
 | 
 | ||||||
|     std::shared_ptr<BackingMem> target_mem = nullptr; |     u8* target_mem = nullptr; | ||||||
|     switch (area->first) { |     switch (area->first) { | ||||||
|     case VRAM_PADDR: |     case VRAM_PADDR: | ||||||
|         target_mem = impl->vram_mem; |         target_mem = impl->vram.get(); | ||||||
|         break; |         break; | ||||||
|     case DSP_RAM_PADDR: |     case DSP_RAM_PADDR: | ||||||
|         target_mem = impl->dsp_mem; |         target_mem = impl->dsp_mem.get(); | ||||||
|         break; |         break; | ||||||
|     case FCRAM_PADDR: |     case FCRAM_PADDR: | ||||||
|         target_mem = impl->fcram_mem; |         target_mem = impl->fcram.get(); | ||||||
|         break; |         break; | ||||||
|     case N3DS_EXTRA_RAM_PADDR: |     case N3DS_EXTRA_RAM_PADDR: | ||||||
|         target_mem = impl->n3ds_extra_ram_mem; |         target_mem = impl->n3ds_extra_ram.get(); | ||||||
|         break; |         break; | ||||||
|     default: |     default: | ||||||
|         UNREACHABLE(); |         UNREACHABLE(); | ||||||
|     } |     } | ||||||
|     if (offset_into_region > target_mem->GetSize()) { |  | ||||||
|         return {nullptr}; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     return {target_mem, offset_into_region}; |     return std::span{target_mem + offset_into_region, area->second - offset_into_region}; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| std::vector<VAddr> MemorySystem::PhysicalToVirtualAddressForRasterizer(PAddr addr) { | std::vector<VAddr> MemorySystem::PhysicalToVirtualAddressForRasterizer(PAddr addr) { | ||||||
|  | @ -889,13 +821,8 @@ const u8* MemorySystem::GetFCRAMPointer(std::size_t offset) const { | ||||||
|     return impl->fcram.get() + offset; |     return impl->fcram.get() + offset; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MemoryRef MemorySystem::GetFCRAMRef(std::size_t offset) const { | std::span<u8, DSP_RAM_SIZE> MemorySystem::GetDspMemory() const { | ||||||
|     ASSERT(offset <= Memory::FCRAM_N3DS_SIZE); |     return std::span<u8, DSP_RAM_SIZE>{impl->dsp_mem.get(), DSP_RAM_SIZE}; | ||||||
|     return MemoryRef(impl->fcram_mem, offset); |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| void MemorySystem::SetDSP(AudioCore::DspInterface& dsp) { |  | ||||||
|     impl->dsp = &dsp; |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| } // namespace Memory
 | } // namespace Memory
 | ||||||
|  |  | ||||||
|  | @ -7,7 +7,6 @@ | ||||||
| #include <cstddef> | #include <cstddef> | ||||||
| #include <string> | #include <string> | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
| #include "common/memory_ref.h" |  | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| class Process; | class Process; | ||||||
|  | @ -30,7 +29,6 @@ namespace Memory { | ||||||
| constexpr u32 CITRA_PAGE_SIZE = 0x1000; | constexpr u32 CITRA_PAGE_SIZE = 0x1000; | ||||||
| constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1; | constexpr u32 CITRA_PAGE_MASK = CITRA_PAGE_SIZE - 1; | ||||||
| constexpr int CITRA_PAGE_BITS = 12; | constexpr int CITRA_PAGE_BITS = 12; | ||||||
| constexpr std::size_t PAGE_TABLE_NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS); |  | ||||||
| 
 | 
 | ||||||
| enum class PageType { | enum class PageType { | ||||||
|     /// Page is unmapped and should cause an access error.
 |     /// Page is unmapped and should cause an access error.
 | ||||||
|  | @ -49,54 +47,23 @@ enum class PageType { | ||||||
|  * requires an indexed fetch and a check for NULL. |  * requires an indexed fetch and a check for NULL. | ||||||
|  */ |  */ | ||||||
| struct PageTable { | struct PageTable { | ||||||
|  |     PageTable() = default; | ||||||
|  |     ~PageTable() noexcept = default; | ||||||
|  | 
 | ||||||
|  |     PageTable(const PageTable&) = delete; | ||||||
|  |     PageTable& operator=(const PageTable&) = delete; | ||||||
|  | 
 | ||||||
|  |     PageTable(PageTable&&) noexcept = default; | ||||||
|  |     PageTable& operator=(PageTable&&) noexcept = default; | ||||||
|  | 
 | ||||||
|  |     static constexpr std::size_t NUM_ENTRIES = 1 << (32 - CITRA_PAGE_BITS); | ||||||
|  | 
 | ||||||
|     /**
 |     /**
 | ||||||
|      * Array of memory pointers backing each page. An entry can only be non-null if the |      * Array of memory pointers backing each page. An entry can only be non-null if the | ||||||
|      * corresponding entry in the `attributes` array is of type `Memory`. |      * corresponding entry in the `attributes` array is of type `Memory`. | ||||||
|      */ |      */ | ||||||
| 
 |     std::array<u8*, NUM_ENTRIES> pointers{}; | ||||||
|     // The reason for this rigmarole is to keep the 'raw' and 'refs' arrays in sync.
 |     std::array<PageType, NUM_ENTRIES> attributes{}; | ||||||
|     // We need 'raw' for dynarmic and 'refs' for serialization
 |  | ||||||
|     struct Pointers { |  | ||||||
| 
 |  | ||||||
|         struct Entry { |  | ||||||
|             Entry(Pointers& pointers_, VAddr idx_) : pointers(pointers_), idx(idx_) {} |  | ||||||
| 
 |  | ||||||
|             Entry& operator=(MemoryRef value) { |  | ||||||
|                 pointers.raw[idx] = value.GetPtr(); |  | ||||||
|                 pointers.refs[idx] = std::move(value); |  | ||||||
|                 return *this; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|             operator u8*() { |  | ||||||
|                 return pointers.raw[idx]; |  | ||||||
|             } |  | ||||||
| 
 |  | ||||||
|         private: |  | ||||||
|             Pointers& pointers; |  | ||||||
|             VAddr idx; |  | ||||||
|         }; |  | ||||||
| 
 |  | ||||||
|         Entry operator[](std::size_t idx) { |  | ||||||
|             return Entry(*this, static_cast<VAddr>(idx)); |  | ||||||
|         } |  | ||||||
| 
 |  | ||||||
|     private: |  | ||||||
|         std::array<u8*, PAGE_TABLE_NUM_ENTRIES> raw; |  | ||||||
|         std::array<MemoryRef, PAGE_TABLE_NUM_ENTRIES> refs; |  | ||||||
|         friend struct PageTable; |  | ||||||
|     }; |  | ||||||
| 
 |  | ||||||
|     Pointers pointers; |  | ||||||
| 
 |  | ||||||
|     /**
 |  | ||||||
|      * Array of fine grained page attributes. If it is set to any value other than `Memory`, then |  | ||||||
|      * the corresponding entry in `pointers` MUST be set to null. |  | ||||||
|      */ |  | ||||||
|     std::array<PageType, PAGE_TABLE_NUM_ENTRIES> attributes; |  | ||||||
| 
 |  | ||||||
|     std::array<u8*, PAGE_TABLE_NUM_ENTRIES>& GetPointerArray() { |  | ||||||
|         return pointers.raw; |  | ||||||
|     } |  | ||||||
| 
 | 
 | ||||||
|     void Clear(); |     void Clear(); | ||||||
| }; | }; | ||||||
|  | @ -235,7 +202,7 @@ public: | ||||||
|      * @param size The amount of bytes to map. Must be page-aligned. |      * @param size The amount of bytes to map. Must be page-aligned. | ||||||
|      * @param target Buffer with the memory backing the mapping. Must be of length at least `size`. |      * @param target Buffer with the memory backing the mapping. Must be of length at least `size`. | ||||||
|      */ |      */ | ||||||
|     void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, MemoryRef target); |     void MapMemoryRegion(PageTable& page_table, VAddr base, u32 size, u8* target); | ||||||
| 
 | 
 | ||||||
|     void UnmapRegion(PageTable& page_table, VAddr base, u32 size); |     void UnmapRegion(PageTable& page_table, VAddr base, u32 size); | ||||||
| 
 | 
 | ||||||
|  | @ -510,7 +477,7 @@ public: | ||||||
|     u8* GetPhysicalPointer(PAddr address) const; |     u8* GetPhysicalPointer(PAddr address) const; | ||||||
| 
 | 
 | ||||||
|     /// Returns a reference to the memory region beginning at the specified physical address
 |     /// Returns a reference to the memory region beginning at the specified physical address
 | ||||||
|     MemoryRef GetPhysicalRef(PAddr address) const; |     std::span<u8> GetPhysicalSpan(PAddr address) const; | ||||||
| 
 | 
 | ||||||
|     /// Determines if the given VAddr is valid for the specified process.
 |     /// Determines if the given VAddr is valid for the specified process.
 | ||||||
|     bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); |     bool IsValidVirtualAddress(const Kernel::Process& process, VAddr vaddr); | ||||||
|  | @ -527,16 +494,13 @@ public: | ||||||
|     /// Gets pointer in FCRAM with given offset
 |     /// Gets pointer in FCRAM with given offset
 | ||||||
|     const u8* GetFCRAMPointer(std::size_t offset) const; |     const u8* GetFCRAMPointer(std::size_t offset) const; | ||||||
| 
 | 
 | ||||||
|     /// Gets a serializable ref to FCRAM with the given offset
 |  | ||||||
|     MemoryRef GetFCRAMRef(std::size_t offset) const; |  | ||||||
| 
 |  | ||||||
|     /// Registers page table for rasterizer cache marking
 |     /// Registers page table for rasterizer cache marking
 | ||||||
|     void RegisterPageTable(std::shared_ptr<PageTable> page_table); |     void RegisterPageTable(std::shared_ptr<PageTable> page_table); | ||||||
| 
 | 
 | ||||||
|     /// Unregisters page table for rasterizer cache marking
 |     /// Unregisters page table for rasterizer cache marking
 | ||||||
|     void UnregisterPageTable(std::shared_ptr<PageTable> page_table); |     void UnregisterPageTable(std::shared_ptr<PageTable> page_table); | ||||||
| 
 | 
 | ||||||
|     void SetDSP(AudioCore::DspInterface& dsp); |     std::span<u8, DSP_RAM_SIZE> GetDspMemory() const; | ||||||
| 
 | 
 | ||||||
|     void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode); |     void RasterizerFlushVirtualRegion(VAddr start, u32 size, FlushMode mode); | ||||||
| 
 | 
 | ||||||
|  | @ -556,17 +520,13 @@ private: | ||||||
|      * Since the cache only happens on linear heap or VRAM, we know the exact physical address and |      * Since the cache only happens on linear heap or VRAM, we know the exact physical address and | ||||||
|      * pointer of such virtual address |      * pointer of such virtual address | ||||||
|      */ |      */ | ||||||
|     MemoryRef GetPointerForRasterizerCache(VAddr addr) const; |     u8* GetPointerForRasterizerCache(VAddr addr) const; | ||||||
| 
 | 
 | ||||||
|     void MapPages(PageTable& page_table, u32 base, u32 size, MemoryRef memory, PageType type); |     void MapPages(PageTable& page_table, u32 base, u32 size, u8* memory, PageType type); | ||||||
| 
 | 
 | ||||||
| private: | private: | ||||||
|     class Impl; |     class Impl; | ||||||
|     std::unique_ptr<Impl> impl; |     std::unique_ptr<Impl> impl; | ||||||
| 
 |  | ||||||
| public: |  | ||||||
|     template <Region R> |  | ||||||
|     class BackingMemImpl; |  | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| } // namespace Memory
 | } // namespace Memory
 | ||||||
|  |  | ||||||
|  | @ -32,7 +32,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") { | ||||||
|         CHECK(vma != manager->vma_map.end()); |         CHECK(vma != manager->vma_map.end()); | ||||||
|         CHECK(vma->second.size == static_cast<u32>(block.GetSize())); |         CHECK(vma->second.size == static_cast<u32>(block.GetSize())); | ||||||
|         CHECK(vma->second.type == Kernel::VMAType::BackingMemory); |         CHECK(vma->second.type == Kernel::VMAType::BackingMemory); | ||||||
|         CHECK(vma->second.backing_memory.GetPtr() == block.GetPtr()); |         CHECK(vma->second.backing_memory == block.GetPtr()); | ||||||
|         CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private); |         CHECK(vma->second.meminfo_state == Kernel::MemoryState::Private); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|  | @ -50,7 +50,7 @@ TEST_CASE("Memory Basics", "[kernel][memory]") { | ||||||
|         auto vma = manager->FindVMA(Memory::HEAP_VADDR); |         auto vma = manager->FindVMA(Memory::HEAP_VADDR); | ||||||
|         CHECK(vma != manager->vma_map.end()); |         CHECK(vma != manager->vma_map.end()); | ||||||
|         CHECK(vma->second.type == Kernel::VMAType::Free); |         CHECK(vma->second.type == Kernel::VMAType::Free); | ||||||
|         CHECK(vma->second.backing_memory.GetPtr() == nullptr); |         CHECK(vma->second.backing_memory == nullptr); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     SECTION("changing memory permissions") { |     SECTION("changing memory permissions") { | ||||||
|  |  | ||||||
|  | @ -1000,12 +1000,12 @@ void RasterizerCache<T>::UploadSurface(Surface& surface, SurfaceInterval interva | ||||||
|     const auto staging = runtime.FindStaging( |     const auto staging = runtime.FindStaging( | ||||||
|         load_info.width * load_info.height * surface.GetInternalBytesPerPixel(), true); |         load_info.width * load_info.height * surface.GetInternalBytesPerPixel(), true); | ||||||
| 
 | 
 | ||||||
|     MemoryRef source_ptr = memory.GetPhysicalRef(load_info.addr); |     auto source_span = memory.GetPhysicalSpan(load_info.addr); | ||||||
|     if (!source_ptr) [[unlikely]] { |     if (source_span.empty()) [[unlikely]] { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr); |     const auto upload_data = source_span.subspan(0, load_info.end - load_info.addr); | ||||||
|     DecodeTexture(load_info, load_info.addr, load_info.end, upload_data, staging.mapped, |     DecodeTexture(load_info, load_info.addr, load_info.end, upload_data, staging.mapped, | ||||||
|                   runtime.NeedsConversion(surface.pixel_format)); |                   runtime.NeedsConversion(surface.pixel_format)); | ||||||
| 
 | 
 | ||||||
|  | @ -1048,12 +1048,12 @@ bool RasterizerCache<T>::UploadCustomSurface(SurfaceId surface_id, SurfaceInterv | ||||||
|     const SurfaceParams load_info = surface.FromInterval(interval); |     const SurfaceParams load_info = surface.FromInterval(interval); | ||||||
|     ASSERT(load_info.addr >= surface.addr && load_info.end <= surface.end); |     ASSERT(load_info.addr >= surface.addr && load_info.end <= surface.end); | ||||||
| 
 | 
 | ||||||
|     MemoryRef source_ptr = memory.GetPhysicalRef(load_info.addr); |     auto source_span = memory.GetPhysicalSpan(load_info.addr); | ||||||
|     if (!source_ptr) [[unlikely]] { |     if (source_span.empty()) [[unlikely]] { | ||||||
|         return false; |         return false; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const auto upload_data = source_ptr.GetWriteBytes(load_info.end - load_info.addr); |     const auto upload_data = source_span.subspan(0, load_info.end - load_info.addr); | ||||||
|     const u64 hash = ComputeHash(load_info, upload_data); |     const u64 hash = ComputeHash(load_info, upload_data); | ||||||
| 
 | 
 | ||||||
|     const u32 level = surface.LevelOf(load_info.addr); |     const u32 level = surface.LevelOf(load_info.addr); | ||||||
|  | @ -1108,12 +1108,12 @@ void RasterizerCache<T>::DownloadSurface(Surface& surface, SurfaceInterval inter | ||||||
|     }; |     }; | ||||||
|     surface.Download(download, staging); |     surface.Download(download, staging); | ||||||
| 
 | 
 | ||||||
|     MemoryRef dest_ptr = memory.GetPhysicalRef(flush_start); |     auto dest_span = memory.GetPhysicalSpan(flush_start); | ||||||
|     if (!dest_ptr) [[unlikely]] { |     if (dest_span.empty()) [[unlikely]] { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const auto download_dest = dest_ptr.GetWriteBytes(flush_end - flush_start); |     const auto download_dest = dest_span.subspan(0, flush_end - flush_start); | ||||||
|     EncodeTexture(flush_info, flush_start, flush_end, staging.mapped, download_dest, |     EncodeTexture(flush_info, flush_start, flush_end, staging.mapped, download_dest, | ||||||
|                   runtime.NeedsConversion(surface.pixel_format)); |                   runtime.NeedsConversion(surface.pixel_format)); | ||||||
| } | } | ||||||
|  | @ -1124,29 +1124,29 @@ void RasterizerCache<T>::DownloadFillSurface(Surface& surface, SurfaceInterval i | ||||||
|     const u32 flush_end = boost::icl::last_next(interval); |     const u32 flush_end = boost::icl::last_next(interval); | ||||||
|     ASSERT(flush_start >= surface.addr && flush_end <= surface.end); |     ASSERT(flush_start >= surface.addr && flush_end <= surface.end); | ||||||
| 
 | 
 | ||||||
|     MemoryRef dest_ptr = memory.GetPhysicalRef(flush_start); |     auto dest_span = memory.GetPhysicalSpan(flush_start); | ||||||
|     if (!dest_ptr) [[unlikely]] { |     if (dest_span.empty()) [[unlikely]] { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     const u32 start_offset = flush_start - surface.addr; |     const u32 start_offset = flush_start - surface.addr; | ||||||
|     const u32 download_size = |     const u32 download_size = | ||||||
|         std::clamp(flush_end - flush_start, 0u, static_cast<u32>(dest_ptr.GetSize())); |         std::clamp(flush_end - flush_start, 0u, static_cast<u32>(dest_span.size())); | ||||||
|     const u32 coarse_start_offset = start_offset - (start_offset % surface.fill_size); |     const u32 coarse_start_offset = start_offset - (start_offset % surface.fill_size); | ||||||
|     const u32 backup_bytes = start_offset % surface.fill_size; |     const u32 backup_bytes = start_offset % surface.fill_size; | ||||||
| 
 | 
 | ||||||
|     std::array<u8, 4> backup_data; |     std::array<u8, 4> backup_data; | ||||||
|     if (backup_bytes) { |     if (backup_bytes) { | ||||||
|         std::memcpy(backup_data.data(), &dest_ptr[coarse_start_offset], backup_bytes); |         std::memcpy(backup_data.data(), &dest_span[coarse_start_offset], backup_bytes); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     for (u32 offset = coarse_start_offset; offset < download_size; offset += surface.fill_size) { |     for (u32 offset = coarse_start_offset; offset < download_size; offset += surface.fill_size) { | ||||||
|         std::memcpy(&dest_ptr[offset], &surface.fill_data[0], |         std::memcpy(&dest_span[offset], &surface.fill_data[0], | ||||||
|                     std::min(surface.fill_size, download_size - offset)); |                     std::min(surface.fill_size, download_size - offset)); | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     if (backup_bytes) { |     if (backup_bytes) { | ||||||
|         std::memcpy(&dest_ptr[coarse_start_offset], &backup_data[0], backup_bytes); |         std::memcpy(&dest_span[coarse_start_offset], &backup_data[0], backup_bytes); | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  |  | ||||||
|  | @ -219,14 +219,14 @@ void RasterizerVulkan::SetupVertexArray() { | ||||||
|         u32 data_size = loader.byte_count * vertex_num; |         u32 data_size = loader.byte_count * vertex_num; | ||||||
|         res_cache.FlushRegion(data_addr, data_size); |         res_cache.FlushRegion(data_addr, data_size); | ||||||
| 
 | 
 | ||||||
|         const MemoryRef src_ref = memory.GetPhysicalRef(data_addr); |         const auto src_span = memory.GetPhysicalSpan(data_addr); | ||||||
|         if (src_ref.GetSize() < data_size) { |         if (src_span.size() < data_size) { | ||||||
|             LOG_ERROR(Render_Vulkan, |             LOG_ERROR(Render_Vulkan, | ||||||
|                       "Vertex buffer size {} exceeds available space {} at address {:#016X}", |                       "Vertex buffer size {} exceeds available space {} at address {:#016X}", | ||||||
|                       data_size, src_ref.GetSize(), data_addr); |                       data_size, src_span.size(), data_addr); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         const u8* src_ptr = src_ref.GetPtr(); |         const u8* src_ptr = src_span.data(); | ||||||
|         u8* dst_ptr = array_ptr + buffer_offset; |         u8* dst_ptr = array_ptr + buffer_offset; | ||||||
| 
 | 
 | ||||||
|         // Align stride up if required by Vulkan implementation.
 |         // Align stride up if required by Vulkan implementation.
 | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue