kernel: Clear pages allocated with SetHeapSize (#2776)
* kernel: Clear pages allocated with SetHeapSize Before this commit, all new pages allocated by SetHeapSize were not cleared by the kernel. This would cause undefined data to be pass to the userland and possibly resulting in weird memory corruption. This commit also add support for custom fill heap and ipc value (that is also supported by the official kernel) * Remove dots at the end of KPageTableBase.MapPages new documentation * Remove unused _stackFillValue
This commit is contained in:
parent
8c4e4ab3b3
commit
b4dc33efc2
5 changed files with 62 additions and 15 deletions
|
@ -86,7 +86,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission)
|
protected override KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
|
||||||
{
|
{
|
||||||
ulong size = pagesCount * PageSize;
|
ulong size = pagesCount * PageSize;
|
||||||
|
|
||||||
|
@ -99,11 +99,16 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
Context.MemoryManager.IncrementPagesReferenceCount(srcPa, pagesCount);
|
Context.MemoryManager.IncrementPagesReferenceCount(srcPa, pagesCount);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (shouldFillPages)
|
||||||
|
{
|
||||||
|
_cpuMemory.Fill(dstVa, size, fillValue);
|
||||||
|
}
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission)
|
protected override KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
|
||||||
{
|
{
|
||||||
using var scopedPageList = new KScopedPageList(Context.MemoryManager, pageList);
|
using var scopedPageList = new KScopedPageList(Context.MemoryManager, pageList);
|
||||||
|
|
||||||
|
@ -118,6 +123,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
_cpuMemory.Map(currentVa, Context.Memory.GetPointer(addr, size), size);
|
_cpuMemory.Map(currentVa, Context.Memory.GetPointer(addr, size), size);
|
||||||
|
|
||||||
|
if (shouldFillPages)
|
||||||
|
{
|
||||||
|
_cpuMemory.Fill(currentVa, size, fillValue);
|
||||||
|
}
|
||||||
|
|
||||||
currentVa += size;
|
currentVa += size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,6 +75,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
public abstract bool SupportsMemoryAliasing { get; }
|
public abstract bool SupportsMemoryAliasing { get; }
|
||||||
|
|
||||||
|
private MemoryFillValue _heapFillValue;
|
||||||
|
private MemoryFillValue _ipcFillValue;
|
||||||
|
|
||||||
public KPageTableBase(KernelContext context)
|
public KPageTableBase(KernelContext context)
|
||||||
{
|
{
|
||||||
Context = context;
|
Context = context;
|
||||||
|
@ -82,6 +85,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
_blockManager = new KMemoryBlockManager();
|
_blockManager = new KMemoryBlockManager();
|
||||||
|
|
||||||
_isKernel = false;
|
_isKernel = false;
|
||||||
|
|
||||||
|
_heapFillValue = MemoryFillValue.Zero;
|
||||||
|
_ipcFillValue = MemoryFillValue.Zero;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
|
private static readonly int[] AddrSpaceSizes = new int[] { 32, 36, 32, 39 };
|
||||||
|
@ -299,6 +305,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
TlsIoRegionStart = tlsIoRegion.Start;
|
TlsIoRegionStart = tlsIoRegion.Start;
|
||||||
TlsIoRegionEnd = tlsIoRegion.End;
|
TlsIoRegionEnd = tlsIoRegion.End;
|
||||||
|
|
||||||
|
// TODO: Check kernel configuration via secure monitor call when implemented to set memory fill values.
|
||||||
|
|
||||||
_currentHeapAddr = HeapRegionStart;
|
_currentHeapAddr = HeapRegionStart;
|
||||||
_heapCapacity = 0;
|
_heapCapacity = 0;
|
||||||
PhysicalMemoryUsage = 0;
|
PhysicalMemoryUsage = 0;
|
||||||
|
@ -738,7 +746,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
return KernelResult.InvalidMemState;
|
return KernelResult.InvalidMemState;
|
||||||
}
|
}
|
||||||
|
|
||||||
result = MapPages(_currentHeapAddr, pageList, KMemoryPermission.ReadAndWrite);
|
result = MapPages(_currentHeapAddr, pageList, KMemoryPermission.ReadAndWrite, true, (byte)_heapFillValue);
|
||||||
|
|
||||||
if (result != KernelResult.Success)
|
if (result != KernelResult.Success)
|
||||||
{
|
{
|
||||||
|
@ -1783,7 +1791,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
{
|
{
|
||||||
ulong unusedSizeBefore = address - addressTruncated;
|
ulong unusedSizeBefore = address - addressTruncated;
|
||||||
|
|
||||||
Context.Memory.ZeroFill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore);
|
Context.Memory.Fill(GetDramAddressFromPa(dstFirstPagePa), unusedSizeBefore, (byte)_ipcFillValue);
|
||||||
|
|
||||||
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
|
ulong copySize = addressRounded <= endAddr ? addressRounded - address : size;
|
||||||
var data = srcPageTable.GetSpan(addressTruncated + unusedSizeBefore, (int)copySize);
|
var data = srcPageTable.GetSpan(addressTruncated + unusedSizeBefore, (int)copySize);
|
||||||
|
@ -1801,7 +1809,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
|
||||||
if (unusedSizeAfter != 0)
|
if (unusedSizeAfter != 0)
|
||||||
{
|
{
|
||||||
Context.Memory.ZeroFill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter);
|
Context.Memory.Fill(GetDramAddressFromPa(firstPageFillAddress), unusedSizeAfter, (byte)_ipcFillValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
KernelResult result = MapPages(currentVa, 1, dstFirstPagePa, permission);
|
KernelResult result = MapPages(currentVa, 1, dstFirstPagePa, permission);
|
||||||
|
@ -1853,7 +1861,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
unusedSizeAfter = PageSize;
|
unusedSizeAfter = PageSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
Context.Memory.ZeroFill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter);
|
Context.Memory.Fill(GetDramAddressFromPa(lastPageFillAddr), unusedSizeAfter, (byte)_ipcFillValue);
|
||||||
|
|
||||||
KernelResult result = MapPages(currentVa, 1, dstLastPagePa, permission);
|
KernelResult result = MapPages(currentVa, 1, dstLastPagePa, permission);
|
||||||
|
|
||||||
|
@ -2779,8 +2787,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
/// <param name="pagesCount">Number of pages to map</param>
|
/// <param name="pagesCount">Number of pages to map</param>
|
||||||
/// <param name="srcPa">Physical address where the pages should be mapped. May be ignored if aliasing is not supported</param>
|
/// <param name="srcPa">Physical address where the pages should be mapped. May be ignored if aliasing is not supported</param>
|
||||||
/// <param name="permission">Permission of the region to be mapped</param>
|
/// <param name="permission">Permission of the region to be mapped</param>
|
||||||
|
/// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param>
|
||||||
|
/// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param>
|
||||||
/// <returns>Result of the mapping operation</returns>
|
/// <returns>Result of the mapping operation</returns>
|
||||||
protected abstract KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission);
|
protected abstract KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a region of memory into the specified physical memory region.
|
/// Maps a region of memory into the specified physical memory region.
|
||||||
|
@ -2788,8 +2798,10 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
/// <param name="address">Destination virtual address that should be mapped</param>
|
/// <param name="address">Destination virtual address that should be mapped</param>
|
||||||
/// <param name="pageList">List of physical memory pages where the pages should be mapped. May be ignored if aliasing is not supported</param>
|
/// <param name="pageList">List of physical memory pages where the pages should be mapped. May be ignored if aliasing is not supported</param>
|
||||||
/// <param name="permission">Permission of the region to be mapped</param>
|
/// <param name="permission">Permission of the region to be mapped</param>
|
||||||
|
/// <param name="shouldFillPages">Indicate if the pages should be filled with the <paramref name="fillValue"/> value</param>
|
||||||
|
/// <param name="fillValue">The value used to fill pages when <paramref name="shouldFillPages"/> is set to true</param>
|
||||||
/// <returns>Result of the mapping operation</returns>
|
/// <returns>Result of the mapping operation</returns>
|
||||||
protected abstract KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission);
|
protected abstract KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages = false, byte fillValue = 0);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Maps a region of memory into the specified host memory ranges.
|
/// Maps a region of memory into the specified host memory ranges.
|
||||||
|
|
|
@ -70,16 +70,30 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission)
|
protected override KernelResult MapPages(ulong dstVa, ulong pagesCount, ulong srcPa, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
|
||||||
{
|
{
|
||||||
_cpuMemory.Map(dstVa, 0, pagesCount * PageSize);
|
_cpuMemory.Map(dstVa, 0, pagesCount * PageSize);
|
||||||
|
|
||||||
|
if (shouldFillPages)
|
||||||
|
{
|
||||||
|
_cpuMemory.Fill(dstVa, pagesCount * PageSize, fillValue);
|
||||||
|
}
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
protected override KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission)
|
protected override KernelResult MapPages(ulong address, KPageList pageList, KMemoryPermission permission, bool shouldFillPages, byte fillValue)
|
||||||
{
|
{
|
||||||
_cpuMemory.Map(address, 0, pageList.GetPagesCount() * PageSize);
|
ulong pagesCount = pageList.GetPagesCount();
|
||||||
|
|
||||||
|
_cpuMemory.Map(address, 0, pagesCount * PageSize);
|
||||||
|
|
||||||
|
if (shouldFillPages)
|
||||||
|
{
|
||||||
|
_cpuMemory.Fill(address, pagesCount * PageSize, fillValue);
|
||||||
|
}
|
||||||
|
|
||||||
return KernelResult.Success;
|
return KernelResult.Success;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
10
Ryujinx.HLE/HOS/Kernel/Memory/MemoryFillValue.cs
Normal file
10
Ryujinx.HLE/HOS/Kernel/Memory/MemoryFillValue.cs
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
namespace Ryujinx.HLE.HOS.Kernel.Memory
|
||||||
|
{
|
||||||
|
enum MemoryFillValue : byte
|
||||||
|
{
|
||||||
|
Zero = 0,
|
||||||
|
Stack = 0x58,
|
||||||
|
Ipc = 0x59,
|
||||||
|
Heap = 0x5A,
|
||||||
|
}
|
||||||
|
}
|
|
@ -216,13 +216,14 @@ namespace Ryujinx.Memory
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Fills a region of memory with zeros.
|
/// Fills a region of memory with <paramref name="value"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="offset">Offset of the region to fill with zeros</param>
|
/// <param name="offset">Offset of the region to fill with <paramref name="value"/></param>
|
||||||
/// <param name="size">Size in bytes of the region to fill</param>
|
/// <param name="size">Size in bytes of the region to fill</param>
|
||||||
|
/// <param name="value">Value to use for the fill</param>
|
||||||
/// <exception cref="ObjectDisposedException">Throw when the memory block has already been disposed</exception>
|
/// <exception cref="ObjectDisposedException">Throw when the memory block has already been disposed</exception>
|
||||||
/// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception>
|
/// <exception cref="InvalidMemoryRegionException">Throw when either <paramref name="offset"/> or <paramref name="size"/> are out of range</exception>
|
||||||
public void ZeroFill(ulong offset, ulong size)
|
public void Fill(ulong offset, ulong size, byte value)
|
||||||
{
|
{
|
||||||
const int MaxChunkSize = 1 << 24;
|
const int MaxChunkSize = 1 << 24;
|
||||||
|
|
||||||
|
@ -230,7 +231,7 @@ namespace Ryujinx.Memory
|
||||||
{
|
{
|
||||||
int copySize = (int)Math.Min(MaxChunkSize, size - subOffset);
|
int copySize = (int)Math.Min(MaxChunkSize, size - subOffset);
|
||||||
|
|
||||||
GetSpan(offset + subOffset, copySize).Fill(0);
|
GetSpan(offset + subOffset, copySize).Fill(value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue