using Ryujinx.Memory.Range;
using System;
using System.Buffers;
using System.Collections.Generic;
namespace Ryujinx.Memory
{
public interface IVirtualMemoryManager
{
///
/// Indicates whenever the memory manager supports aliasing pages at 4KB granularity.
///
/// True if 4KB pages are supported by the memory manager, false otherwise
bool Supports4KBPages { get; }
///
/// Maps a virtual memory range into a physical memory range.
///
///
/// Addresses and size must be page aligned.
///
/// Virtual memory address
/// Physical memory address where the region should be mapped to
/// Size to be mapped
/// Flags controlling memory mapping
void Map(ulong va, ulong pa, ulong size, MemoryMapFlags flags);
///
/// Maps a virtual memory range into an arbitrary host memory range.
///
///
/// Addresses and size must be page aligned.
/// Not all memory managers supports this feature.
///
/// Virtual memory address
/// Host pointer where the virtual region should be mapped
/// Size to be mapped
void MapForeign(ulong va, nuint hostPointer, ulong size);
///
/// Unmaps a previously mapped range of virtual memory.
///
/// Virtual address of the range to be unmapped
/// Size of the range to be unmapped
void Unmap(ulong va, ulong size);
///
/// Reads data from CPU mapped memory.
///
/// Type of the data being read
/// Virtual address of the data in memory
/// The data
/// Throw for unhandled invalid or unmapped memory accesses
T Read(ulong va) where T : unmanaged;
///
/// Reads data from CPU mapped memory.
///
/// Virtual address of the data in memory
/// Span to store the data being read into
/// Throw for unhandled invalid or unmapped memory accesses
void Read(ulong va, Span data);
///
/// Writes data to CPU mapped memory.
///
/// Type of the data being written
/// Virtual address to write the data into
/// Data to be written
/// Throw for unhandled invalid or unmapped memory accesses
void Write(ulong va, T value) where T : unmanaged;
///
/// Writes data to CPU mapped memory, with write tracking.
///
/// Virtual address to write the data into
/// Data to be written
/// Throw for unhandled invalid or unmapped memory accesses
void Write(ulong va, ReadOnlySpan data);
///
/// Writes data to CPU mapped memory, with write tracking.
///
/// Virtual address to write the data into
/// Data to be written
/// Throw for unhandled invalid or unmapped memory accesses
public void Write(ulong va, ReadOnlySequence data)
{
foreach (ReadOnlyMemory segment in data)
{
Write(va, segment.Span);
va += (ulong)segment.Length;
}
}
///
/// Writes data to the application process, returning false if the data was not changed.
/// This triggers read memory tracking, as a redundancy check would be useless if the data is not up to date.
///
/// The memory manager can return that memory has changed when it hasn't to avoid expensive data copies.
/// Virtual address to write the data into
/// Data to be written
/// Throw for unhandled invalid or unmapped memory accesses
/// True if the data was changed, false otherwise
bool WriteWithRedundancyCheck(ulong va, ReadOnlySpan data);
void Fill(ulong va, ulong size, byte value)
{
const int MaxChunkSize = 1 << 24;
for (ulong subOffset = 0; subOffset < size; subOffset += MaxChunkSize)
{
int copySize = (int)Math.Min(MaxChunkSize, size - subOffset);
using var writableRegion = GetWritableRegion(va + subOffset, copySize);
writableRegion.Memory.Span.Fill(value);
}
}
///
/// Gets a read-only span of data from CPU mapped memory.
///
/// Virtual address of the data
/// Size of the data
/// True if read tracking is triggered on the span
/// A read-only span of the data
/// Throw for unhandled invalid or unmapped memory accesses
ReadOnlySpan GetSpan(ulong va, int size, bool tracked = false);
///
/// Gets a region of memory that can be written to.
///
/// Virtual address of the data
/// Size of the data
/// True if write tracking is triggered on the span
/// A writable region of memory containing the data
/// Throw for unhandled invalid or unmapped memory accesses
WritableRegion GetWritableRegion(ulong va, int size, bool tracked = false);
///
/// Gets a reference for the given type at the specified virtual memory address.
///
///
/// The data must be located at a contiguous memory region.
///
/// Type of the data to get the reference
/// Virtual address of the data
/// A reference to the data in memory
/// Throw if the specified memory region is not contiguous in physical memory
ref T GetRef(ulong va) where T : unmanaged;
///
/// Gets the host regions that make up the given virtual address region.
/// If any part of the virtual region is unmapped, null is returned.
///
/// Virtual address of the range
/// Size of the range
/// Array of host regions
IEnumerable GetHostRegions(ulong va, ulong size);
///
/// Gets the physical regions that make up the given virtual address region.
/// If any part of the virtual region is unmapped, null is returned.
///
/// Virtual address of the range
/// Size of the range
/// Array of physical regions
IEnumerable GetPhysicalRegions(ulong va, ulong size);
///
/// Checks if the page at a given CPU virtual address is mapped.
///
/// Virtual address to check
/// True if the address is mapped, false otherwise
bool IsMapped(ulong va);
///
/// Checks if a memory range is mapped.
///
/// Virtual address of the range
/// Size of the range in bytes
/// True if the entire range is mapped, false otherwise
bool IsRangeMapped(ulong va, ulong size);
///
/// Alerts the memory tracking that a given region has been read from or written to.
/// This should be called before read/write is performed.
///
/// Virtual address of the region
/// Size of the region
/// True if the region was written, false if read
/// True if the access is precise, false otherwise
/// Optional ID of the handles that should not be signalled
void SignalMemoryTracking(ulong va, ulong size, bool write, bool precise = false, int? exemptId = null);
///
/// Reprotect a region of virtual memory for tracking.
///
/// Virtual address base
/// Size of the region to protect
/// Memory protection to set
void TrackingReprotect(ulong va, ulong size, MemoryPermission protection);
}
}