Implement partial support for device address space SVCs, CreateInterruptEvent, initial work to support devices
This commit is contained in:
parent
d215478b9e
commit
72d972d70c
23 changed files with 772 additions and 106 deletions
|
@ -1,14 +0,0 @@
|
|||
using System;
|
||||
|
||||
namespace ChocolArm64.Events
|
||||
{
|
||||
public class MemoryAccessEventArgs : EventArgs
|
||||
{
|
||||
public long Position { get; private set; }
|
||||
|
||||
public MemoryAccessEventArgs(long position)
|
||||
{
|
||||
Position = position;
|
||||
}
|
||||
}
|
||||
}
|
14
ChocolArm64/Events/MemoryAccessEventArgs.cs
Normal file
14
ChocolArm64/Events/MemoryAccessEventArgs.cs
Normal file
|
@ -0,0 +1,14 @@
|
|||
using System;
|
||||
|
||||
namespace ChocolArm64.Events
|
||||
{
|
||||
public class MemoryAccessEventArgs : EventArgs
|
||||
{
|
||||
public long VirtualAddress { get; }
|
||||
|
||||
public MemoryAccessEventArgs(long va)
|
||||
{
|
||||
VirtualAddress = va;
|
||||
}
|
||||
}
|
||||
}
|
15
ChocolArm64/Memory/IBus.cs
Normal file
15
ChocolArm64/Memory/IBus.cs
Normal file
|
@ -0,0 +1,15 @@
|
|||
namespace ChocolArm64.Memory
|
||||
{
|
||||
public interface IBus
|
||||
{
|
||||
byte ReadByte(ulong address);
|
||||
ushort ReadUInt16(ulong address);
|
||||
uint ReadUInt32(ulong address);
|
||||
ulong ReadUInt64(ulong address);
|
||||
|
||||
void WriteByte(ulong address, byte value);
|
||||
void WriteUInt16(ulong address, ushort value);
|
||||
void WriteUInt32(ulong address, uint value);
|
||||
void WriteUInt64(ulong address, ulong value);
|
||||
}
|
||||
}
|
|
@ -45,29 +45,33 @@ namespace ChocolArm64.Memory
|
|||
|
||||
private Dictionary<int, ArmMonitor> _monitors;
|
||||
|
||||
private ConcurrentDictionary<long, IntPtr> _observedPages;
|
||||
private ConcurrentDictionary<long, Pte> _observedPages;
|
||||
|
||||
public IntPtr Ram { get; private set; }
|
||||
private IBus _bus;
|
||||
|
||||
private byte* _ramPtr;
|
||||
private struct Pte
|
||||
{
|
||||
public byte* ptr;
|
||||
|
||||
private byte*** _pageTable;
|
||||
public long pa;
|
||||
|
||||
public bool IsUnmapped => ptr == null && pa == 0;
|
||||
}
|
||||
|
||||
private Pte** _pageTable;
|
||||
|
||||
public event EventHandler<MemoryAccessEventArgs> InvalidAccess;
|
||||
|
||||
public event EventHandler<MemoryAccessEventArgs> ObservedAccess;
|
||||
|
||||
public MemoryManager(IntPtr ram)
|
||||
public MemoryManager(IBus bus = null)
|
||||
{
|
||||
_monitors = new Dictionary<int, ArmMonitor>();
|
||||
|
||||
_observedPages = new ConcurrentDictionary<long, IntPtr>();
|
||||
_observedPages = new ConcurrentDictionary<long, Pte>();
|
||||
|
||||
Ram = ram;
|
||||
_bus = bus;
|
||||
|
||||
_ramPtr = (byte*)ram;
|
||||
|
||||
_pageTable = (byte***)Marshal.AllocHGlobal(PtLvl0Size * IntPtr.Size);
|
||||
_pageTable = (Pte**)Marshal.AllocHGlobal(PtLvl0Size * IntPtr.Size);
|
||||
|
||||
for (int l0 = 0; l0 < PtLvl0Size; l0++)
|
||||
{
|
||||
|
@ -197,14 +201,48 @@ namespace ChocolArm64.Memory
|
|||
|
||||
public byte ReadByte(long position)
|
||||
{
|
||||
return *((byte*)Translate(position));
|
||||
Pte pte = GetPtEntry(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
return *((byte*)(pte.ptr + pageOffset));
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
return _bus?.ReadByte((ulong)(pte.pa + pageOffset)) ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public ushort ReadUInt16(long position)
|
||||
{
|
||||
if ((position & 1) == 0)
|
||||
{
|
||||
return *((ushort*)Translate(position));
|
||||
Pte pte = GetPtEntry(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
return *((ushort*)(pte.ptr + pageOffset));
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
return _bus?.ReadUInt16((ulong)(pte.pa + pageOffset)) ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -217,7 +255,24 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
if ((position & 3) == 0)
|
||||
{
|
||||
return *((uint*)Translate(position));
|
||||
Pte pte = GetPtEntry(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
return *((uint*)(pte.ptr + pageOffset));
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
return _bus?.ReadUInt32((ulong)(pte.pa + pageOffset)) ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -230,7 +285,24 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
if ((position & 7) == 0)
|
||||
{
|
||||
return *((ulong*)Translate(position));
|
||||
Pte pte = GetPtEntry(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
return *((ulong*)(pte.ptr + pageOffset));
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
return _bus?.ReadUInt64((ulong)(pte.pa + pageOffset)) ?? 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -419,14 +491,44 @@ namespace ChocolArm64.Memory
|
|||
|
||||
public void WriteByte(long position, byte value)
|
||||
{
|
||||
*((byte*)TranslateWrite(position)) = value;
|
||||
Pte pte = GetPtEntryForWrite(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
*((byte*)(pte.ptr + pageOffset)) = value;
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
_bus?.WriteByte((ulong)(pte.pa + pageOffset), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
}
|
||||
}
|
||||
|
||||
public void WriteUInt16(long position, ushort value)
|
||||
{
|
||||
if ((position & 1) == 0)
|
||||
{
|
||||
*((ushort*)TranslateWrite(position)) = value;
|
||||
Pte pte = GetPtEntryForWrite(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
*((ushort*)(pte.ptr + pageOffset)) = value;
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
_bus?.WriteUInt16((ulong)(pte.pa + pageOffset), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -439,7 +541,22 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
if ((position & 3) == 0)
|
||||
{
|
||||
*((uint*)TranslateWrite(position)) = value;
|
||||
Pte pte = GetPtEntryForWrite(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
*((uint*)(pte.ptr + pageOffset)) = value;
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
_bus?.WriteUInt32((ulong)(pte.pa + pageOffset), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -452,7 +569,22 @@ namespace ChocolArm64.Memory
|
|||
{
|
||||
if ((position & 7) == 0)
|
||||
{
|
||||
*((ulong*)TranslateWrite(position)) = value;
|
||||
Pte pte = GetPtEntryForWrite(position);
|
||||
|
||||
long pageOffset = position & PageMask;
|
||||
|
||||
if (pte.ptr != null)
|
||||
{
|
||||
*((ulong*)(pte.ptr + pageOffset)) = value;
|
||||
}
|
||||
else if (pte.pa != 0)
|
||||
{
|
||||
_bus?.WriteUInt64((ulong)(pte.pa + pageOffset), value);
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -607,14 +739,14 @@ namespace ChocolArm64.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public void Map(long va, long pa, long size)
|
||||
public void Map(long va, long pa, IntPtr ptr, long size)
|
||||
{
|
||||
SetPtEntries(va, _ramPtr + pa, size);
|
||||
SetPtEntries(va, pa, (byte*)ptr, size);
|
||||
}
|
||||
|
||||
public void Unmap(long position, long size)
|
||||
{
|
||||
SetPtEntries(position, null, size);
|
||||
SetPtEntries(position, 0, null, size);
|
||||
|
||||
StopObservingRegion(position, size);
|
||||
}
|
||||
|
@ -634,14 +766,64 @@ namespace ChocolArm64.Memory
|
|||
return false;
|
||||
}
|
||||
|
||||
return _pageTable[l0][l1] != null || _observedPages.ContainsKey(position >> PageBits);
|
||||
return _pageTable[l0][l1].ptr != null || _observedPages.ContainsKey(position >> PageBits);
|
||||
}
|
||||
|
||||
public IEnumerable<(long, long)> IteratePages(long address)
|
||||
{
|
||||
long l0 = (address >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (address >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
||||
long currPa = 0;
|
||||
long size = 0;
|
||||
|
||||
for (; l0 < PtLvl0Size; l0++, l1 = 0)
|
||||
{
|
||||
if (IsL0Null((int)l0))
|
||||
{
|
||||
if (currPa != 0)
|
||||
{
|
||||
yield return (currPa, size);
|
||||
|
||||
currPa = 0;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
size += PtLvl1Size * PageSize;
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
for (; l1 < PtLvl1Size; l1++)
|
||||
{
|
||||
Pte pte = GetPtEntry((l0 << PtLvl0Bit) | (l1 << PtLvl1Bit));
|
||||
|
||||
if ((currPa != 0 || pte.pa != 0) && pte.pa != currPa + size)
|
||||
{
|
||||
yield return (currPa, size);
|
||||
|
||||
currPa = pte.pa;
|
||||
size = 0;
|
||||
}
|
||||
|
||||
size += PageSize;
|
||||
}
|
||||
}
|
||||
|
||||
if (size != 0)
|
||||
{
|
||||
yield return (currPa, size);
|
||||
}
|
||||
}
|
||||
|
||||
private bool IsL0Null(int l0)
|
||||
{
|
||||
return _pageTable[l0] == null;
|
||||
}
|
||||
|
||||
public long GetPhysicalAddress(long virtualAddress)
|
||||
{
|
||||
byte* ptr = Translate(virtualAddress);
|
||||
|
||||
return (long)(ptr - _ramPtr);
|
||||
return GetPtEntry(virtualAddress).pa + (virtualAddress & PageMask);
|
||||
}
|
||||
|
||||
internal byte* Translate(long position)
|
||||
|
@ -651,7 +833,7 @@ namespace ChocolArm64.Memory
|
|||
|
||||
long old = position;
|
||||
|
||||
byte** lvl1 = _pageTable[l0];
|
||||
Pte* lvl1 = _pageTable[l0];
|
||||
|
||||
if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0)
|
||||
{
|
||||
|
@ -665,7 +847,7 @@ namespace ChocolArm64.Memory
|
|||
|
||||
position &= PageMask;
|
||||
|
||||
byte* ptr = lvl1[l1];
|
||||
byte* ptr = lvl1[l1].ptr;
|
||||
|
||||
if (ptr == null)
|
||||
{
|
||||
|
@ -682,9 +864,9 @@ Unmapped:
|
|||
{
|
||||
long key = position >> PageBits;
|
||||
|
||||
if (_observedPages.TryGetValue(key, out IntPtr ptr))
|
||||
if (_observedPages.TryGetValue(key, out Pte pte))
|
||||
{
|
||||
return (byte*)ptr + (position & PageMask);
|
||||
return pte.ptr + (position & PageMask);
|
||||
}
|
||||
|
||||
InvalidAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
|
@ -699,7 +881,7 @@ Unmapped:
|
|||
|
||||
long old = position;
|
||||
|
||||
byte** lvl1 = _pageTable[l0];
|
||||
Pte* lvl1 = _pageTable[l0];
|
||||
|
||||
if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0)
|
||||
{
|
||||
|
@ -713,7 +895,7 @@ Unmapped:
|
|||
|
||||
position &= PageMask;
|
||||
|
||||
byte* ptr = lvl1[l1];
|
||||
byte* ptr = lvl1[l1].ptr;
|
||||
|
||||
if (ptr == null)
|
||||
{
|
||||
|
@ -728,17 +910,17 @@ Unmapped:
|
|||
|
||||
private byte* HandleNullPteWrite(long position)
|
||||
{
|
||||
long key = position >> PageBits;
|
||||
|
||||
MemoryAccessEventArgs e = new MemoryAccessEventArgs(position);
|
||||
|
||||
if (_observedPages.TryGetValue(key, out IntPtr ptr))
|
||||
long key = position >> PageBits;
|
||||
|
||||
if (_observedPages.TryGetValue(key, out Pte pte))
|
||||
{
|
||||
SetPtEntry(position, (byte*)ptr);
|
||||
SetPtEntry(position, pte.pa, pte.ptr);
|
||||
|
||||
ObservedAccess?.Invoke(this, e);
|
||||
|
||||
return (byte*)ptr + (position & PageMask);
|
||||
return (byte*)pte.ptr + (position & PageMask);
|
||||
}
|
||||
|
||||
InvalidAccess?.Invoke(this, e);
|
||||
|
@ -746,15 +928,87 @@ Unmapped:
|
|||
throw new VmmPageFaultException(position);
|
||||
}
|
||||
|
||||
private void SetPtEntries(long va, byte* ptr, long size)
|
||||
private Pte GetPtEntry(long position)
|
||||
{
|
||||
long l0 = (position >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (position >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
||||
long old = position;
|
||||
|
||||
Pte* lvl1 = _pageTable[l0];
|
||||
|
||||
if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0)
|
||||
{
|
||||
return default(Pte);
|
||||
}
|
||||
|
||||
if (lvl1 == null)
|
||||
{
|
||||
return default(Pte);
|
||||
}
|
||||
|
||||
position &= PageMask;
|
||||
|
||||
Pte pte = lvl1[l1];
|
||||
|
||||
if (pte.IsUnmapped && !_observedPages.TryGetValue(old >> PageBits, out pte))
|
||||
{
|
||||
return default(Pte);
|
||||
}
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
private Pte GetPtEntryForWrite(long position)
|
||||
{
|
||||
long l0 = (position >> PtLvl0Bit) & PtLvl0Mask;
|
||||
long l1 = (position >> PtLvl1Bit) & PtLvl1Mask;
|
||||
|
||||
long old = position;
|
||||
|
||||
Pte* lvl1 = _pageTable[l0];
|
||||
|
||||
if ((position >> (PtLvl0Bit + PtLvl0Bits)) != 0)
|
||||
{
|
||||
return default(Pte);
|
||||
}
|
||||
|
||||
if (lvl1 == null)
|
||||
{
|
||||
return default(Pte);
|
||||
}
|
||||
|
||||
position &= PageMask;
|
||||
|
||||
Pte pte = lvl1[l1];
|
||||
|
||||
if (pte.IsUnmapped)
|
||||
{
|
||||
if (!_observedPages.TryGetValue(old >> PageBits, out pte))
|
||||
{
|
||||
return default(Pte);
|
||||
}
|
||||
else
|
||||
{
|
||||
SetPtEntry(position, pte.pa, pte.ptr);
|
||||
|
||||
ObservedAccess?.Invoke(this, new MemoryAccessEventArgs(position));
|
||||
}
|
||||
}
|
||||
|
||||
return pte;
|
||||
}
|
||||
|
||||
private void SetPtEntries(long va, long pa, byte* ptr, long size)
|
||||
{
|
||||
long endPosition = (va + size + PageMask) & ~PageMask;
|
||||
|
||||
while ((ulong)va < (ulong)endPosition)
|
||||
{
|
||||
SetPtEntry(va, ptr);
|
||||
SetPtEntry(va, pa, ptr);
|
||||
|
||||
va += PageSize;
|
||||
pa += PageSize;
|
||||
|
||||
if (ptr != null)
|
||||
{
|
||||
|
@ -763,7 +1017,7 @@ Unmapped:
|
|||
}
|
||||
}
|
||||
|
||||
private void SetPtEntry(long position, byte* ptr)
|
||||
private void SetPtEntry(long position, long pa, byte* ptr)
|
||||
{
|
||||
if (!IsValidPosition(position))
|
||||
{
|
||||
|
@ -775,11 +1029,11 @@ Unmapped:
|
|||
|
||||
if (_pageTable[l0] == null)
|
||||
{
|
||||
byte** lvl1 = (byte**)Marshal.AllocHGlobal(PtLvl1Size * IntPtr.Size);
|
||||
Pte* lvl1 = (Pte*)Marshal.AllocHGlobal(PtLvl1Size * sizeof(Pte));
|
||||
|
||||
for (int zl1 = 0; zl1 < PtLvl1Size; zl1++)
|
||||
{
|
||||
lvl1[zl1] = null;
|
||||
lvl1[zl1] = default(Pte);
|
||||
}
|
||||
|
||||
Thread.MemoryBarrier();
|
||||
|
@ -787,7 +1041,8 @@ Unmapped:
|
|||
_pageTable[l0] = lvl1;
|
||||
}
|
||||
|
||||
_pageTable[l0][l1] = ptr;
|
||||
_pageTable[l0][l1].ptr = ptr;
|
||||
_pageTable[l0][l1].pa = pa;
|
||||
}
|
||||
|
||||
public void StartObservingRegion(long position, long size)
|
||||
|
@ -798,9 +1053,9 @@ Unmapped:
|
|||
|
||||
while ((ulong)position < (ulong)endPosition)
|
||||
{
|
||||
_observedPages[position >> PageBits] = (IntPtr)Translate(position);
|
||||
_observedPages[position >> PageBits] = GetPtEntry(position);
|
||||
|
||||
SetPtEntry(position, null);
|
||||
SetPtEntry(position, 0, null);
|
||||
|
||||
position += PageSize;
|
||||
}
|
||||
|
@ -814,9 +1069,9 @@ Unmapped:
|
|||
{
|
||||
lock (_observedPages)
|
||||
{
|
||||
if (_observedPages.TryRemove(position >> PageBits, out IntPtr ptr))
|
||||
if (_observedPages.TryRemove(position >> PageBits, out Pte pte))
|
||||
{
|
||||
SetPtEntry(position, (byte*)ptr);
|
||||
SetPtEntry(position, pte.pa, pte.ptr);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -31,6 +31,7 @@ namespace Ryujinx.Common.Logging
|
|||
ServiceNs,
|
||||
ServiceNv,
|
||||
ServicePctl,
|
||||
ServicePcv,
|
||||
ServicePl,
|
||||
ServicePrepo,
|
||||
ServicePsm,
|
||||
|
|
|
@ -26,14 +26,14 @@ namespace Ryujinx.Graphics.Memory
|
|||
|
||||
private void MemoryAccessHandler(object sender, MemoryAccessEventArgs e)
|
||||
{
|
||||
long pa = _memory.GetPhysicalAddress(e.Position);
|
||||
long pa = _memory.GetPhysicalAddress(e.VirtualAddress) - 0x80000000;
|
||||
|
||||
CachedPages[pa >> PageBits]?.Clear();
|
||||
}
|
||||
|
||||
public bool IsRegionModified(long position, long size, NvGpuBufferType bufferType)
|
||||
{
|
||||
long pa = _memory.GetPhysicalAddress(position);
|
||||
long pa = _memory.GetPhysicalAddress(position) - 0x80000000;
|
||||
|
||||
long addr = pa;
|
||||
|
||||
|
|
|
@ -113,6 +113,24 @@ namespace Ryujinx.HLE
|
|||
}
|
||||
}
|
||||
|
||||
public IntPtr GetRamPointer(ulong address, ulong size)
|
||||
{
|
||||
if (address + size < address)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(size));
|
||||
}
|
||||
|
||||
if (address + size > RamSize)
|
||||
{
|
||||
throw new ArgumentOutOfRangeException(nameof(address));
|
||||
}
|
||||
|
||||
unsafe
|
||||
{
|
||||
return new IntPtr(_ramPtr + address);
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(ulong address, byte value, ulong size)
|
||||
{
|
||||
if (address + size < address)
|
||||
|
|
19
Ryujinx.HLE/HOS/Kernel/Interrupt/KInterruptEvent.cs
Normal file
19
Ryujinx.HLE/HOS/Kernel/Interrupt/KInterruptEvent.cs
Normal file
|
@ -0,0 +1,19 @@
|
|||
using Ryujinx.HLE.HOS.Kernel.Threading;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Kernel.Interrupt
|
||||
{
|
||||
class KInterruptEvent
|
||||
{
|
||||
public KReadableEvent Event { get; }
|
||||
|
||||
public int IrqId { get; private set; }
|
||||
public bool Enabled { get; private set; }
|
||||
|
||||
public KInterruptEvent(Horizon system)
|
||||
{
|
||||
Event = new KReadableEvent(system);
|
||||
|
||||
IrqId = -1;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -464,15 +464,72 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult MapNormalMemory(long address, long size, MemoryPermission permission)
|
||||
public KernelResult MapPhysical(ulong address, ulong size, MemoryPermission permission)
|
||||
{
|
||||
//TODO.
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
public KernelResult MapIoMemory(long address, long size, MemoryPermission permission)
|
||||
public KernelResult MapIo(ulong pa, ulong size, MemoryPermission permission)
|
||||
{
|
||||
//TODO.
|
||||
ulong endAddr = pa + size;
|
||||
|
||||
if (pa >> 31 <= 4 && (endAddr >> 31) != 0)
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
if (!ValidateIoPhysicalAddress(pa, size))
|
||||
{
|
||||
return KernelResult.InvalidAddress;
|
||||
}
|
||||
|
||||
ulong neededPagesCount = size / PageSize;
|
||||
|
||||
ulong regionPagesCount = (TlsIoRegionEnd - TlsIoRegionStart) / PageSize;
|
||||
|
||||
if (regionPagesCount < neededPagesCount)
|
||||
{
|
||||
return KernelResult.OutOfMemory;
|
||||
}
|
||||
|
||||
lock (_blocks)
|
||||
{
|
||||
ulong va = 0;
|
||||
|
||||
for (int unit = MappingUnitSizes.Length - 1; unit >= 0 && va == 0; unit--)
|
||||
{
|
||||
int alignemnt = MappingUnitSizes[unit];
|
||||
|
||||
va = AllocateVa(TlsIoRegionStart, regionPagesCount, neededPagesCount, alignemnt);
|
||||
}
|
||||
|
||||
if (va == 0)
|
||||
{
|
||||
return KernelResult.OutOfVaSpace;
|
||||
}
|
||||
|
||||
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
|
||||
{
|
||||
return KernelResult.OutOfResource;
|
||||
}
|
||||
|
||||
KernelResult result = DoMmuOperation(
|
||||
va,
|
||||
neededPagesCount,
|
||||
pa,
|
||||
true,
|
||||
permission,
|
||||
MemoryOperation.MapPa);
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
InsertBlock(va, neededPagesCount, MemoryState.Io, permission);
|
||||
}
|
||||
|
||||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
|
@ -940,6 +997,64 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
}
|
||||
}
|
||||
|
||||
public KernelResult QueryIoMapping(ulong pa, ulong size, out ulong va)
|
||||
{
|
||||
va = 0;
|
||||
|
||||
KernelResult result = KernelResult.NotFound;
|
||||
|
||||
ulong paEnd = pa + size;
|
||||
|
||||
ulong tlsIoRegionSize = TlsIoRegionEnd - TlsIoRegionStart;
|
||||
|
||||
lock (_blocks)
|
||||
{
|
||||
ulong offset = 0;
|
||||
|
||||
foreach ((long mapPa, long mapSize) in _cpuMemory.IteratePages((long)TlsIoRegionStart))
|
||||
{
|
||||
ulong mapPaEnd = (ulong)mapPa + (ulong)mapSize;
|
||||
|
||||
if ((ulong)mapPa <= pa && paEnd <= mapPaEnd)
|
||||
{
|
||||
ulong paSubOffs = pa - (ulong)mapPa;
|
||||
|
||||
ulong ioAddr = TlsIoRegionStart + offset + paSubOffs;
|
||||
|
||||
if (CheckRange(
|
||||
ioAddr,
|
||||
size,
|
||||
MemoryState.Mask,
|
||||
MemoryState.Io,
|
||||
MemoryPermission.Read,
|
||||
MemoryPermission.Read,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.None,
|
||||
MemoryAttribute.IpcAndDeviceMapped,
|
||||
out _,
|
||||
out _,
|
||||
out _))
|
||||
{
|
||||
va = ioAddr;
|
||||
|
||||
result = KernelResult.Success;
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
offset += (ulong)mapSize;
|
||||
|
||||
if (offset >= tlsIoRegionSize)
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
public KernelResult Map(ulong dst, ulong src, ulong size)
|
||||
{
|
||||
bool success;
|
||||
|
@ -1958,6 +2073,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
mappedVa = 0;
|
||||
|
||||
if (AliasRegionEnd - AliasRegionStart <= size)
|
||||
{
|
||||
return KernelResult.OutOfVaSpace;
|
||||
}
|
||||
|
||||
lock (_blocks)
|
||||
{
|
||||
if (!_blockAllocator.CanAllocate(MaxBlocksNeededForInsertion))
|
||||
|
@ -2718,16 +2838,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
ulong regionEndAddr = regionStart + regionPagesCount * PageSize;
|
||||
|
||||
LinkedListNode<KMemoryBlock> node = FindBlockNode(regionStart);
|
||||
|
||||
KMemoryInfo info = node.Value.GetInfo();
|
||||
|
||||
while (regionEndAddr >= info.Address)
|
||||
foreach (KMemoryInfo info in IterateOverRange(regionStart, regionEndAddr))
|
||||
{
|
||||
if (info.State == MemoryState.Unmapped)
|
||||
{
|
||||
ulong currBaseAddr = info.Address + reservedSize;
|
||||
ulong currEndAddr = info.Address + info.Size - 1;
|
||||
ulong currBaseAddr = GetAddrInRange(info, regionStart) + reservedSize;
|
||||
|
||||
ulong address = BitUtils.AlignDown(currBaseAddr, alignment) + reservedStart;
|
||||
|
||||
|
@ -2738,22 +2853,15 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
|
||||
ulong allocationEndAddr = address + totalNeededSize - 1;
|
||||
|
||||
if (allocationEndAddr <= regionEndAddr &&
|
||||
allocationEndAddr <= currEndAddr &&
|
||||
ulong currEndAddr = info.Address + info.Size - 1;
|
||||
|
||||
if (allocationEndAddr <= regionEndAddr - 1 &&
|
||||
allocationEndAddr <= currEndAddr &&
|
||||
address < allocationEndAddr)
|
||||
{
|
||||
return address;
|
||||
}
|
||||
}
|
||||
|
||||
node = node.Next;
|
||||
|
||||
if (node == null)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
info = node.Value.GetInfo();
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
@ -2788,6 +2896,60 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return null;
|
||||
}
|
||||
|
||||
private static bool ValidateIoPhysicalAddress(ulong pa, ulong size)
|
||||
{
|
||||
//Size would cause an overflow (or the address is invalid).
|
||||
if (pa + size < pa)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
ulong endAddr = pa + size - 1;
|
||||
|
||||
//ARM registers, interrupt controller, etc region.
|
||||
if (0x50040000 <= endAddr && pa <= 0x5005ffff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check exception vectors region.
|
||||
if (0x6000f000 <= endAddr && pa <= 0x6000ffff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//Check IPATCH region.
|
||||
if (0x6001dc00 <= endAddr && pa <= 0x6001dfff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//MC region.
|
||||
if (0x70019000 <= endAddr && pa <= 0x70019fff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//RTC and PMC region.
|
||||
if (0x7000e000 <= endAddr && pa <= 0x7000efff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
//MC0 and MC1 region.
|
||||
if (0x7001c000 <= endAddr && pa <= 0x7001dfff)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private static bool InsideRange(ulong start, ulong end, ulong rgStart, ulong rgEnd)
|
||||
{
|
||||
return start <= rgEnd && rgStart <= end;
|
||||
}
|
||||
|
||||
private bool ValidateRegionForState(ulong address, ulong size, MemoryState state)
|
||||
{
|
||||
ulong endAddr = address + size;
|
||||
|
@ -3038,7 +3200,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
ulong size = pagesCount * PageSize;
|
||||
|
||||
_cpuMemory.Map((long)dstVa, (long)(srcPa - DramMemoryMap.DramBase), (long)size);
|
||||
MapMemoryOrIo(dstVa, srcPa, size);
|
||||
|
||||
result = KernelResult.Success;
|
||||
|
||||
|
@ -3105,7 +3267,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
{
|
||||
ulong size = pageNode.PagesCount * PageSize;
|
||||
|
||||
_cpuMemory.Map((long)address, (long)(pageNode.Address - DramMemoryMap.DramBase), (long)size);
|
||||
MapMemoryOrIo(address, pageNode.Address, size);
|
||||
|
||||
address += size;
|
||||
}
|
||||
|
@ -3113,14 +3275,28 @@ namespace Ryujinx.HLE.HOS.Kernel.Memory
|
|||
return KernelResult.Success;
|
||||
}
|
||||
|
||||
private void MapMemoryOrIo(ulong va, ulong pa, ulong size)
|
||||
{
|
||||
if (pa >= DramMemoryMap.DramBase)
|
||||
{
|
||||
IntPtr ptr = _system.Device.Memory.GetRamPointer(pa - DramMemoryMap.DramBase, size);
|
||||
|
||||
_cpuMemory.Map((long)va, (long)pa, ptr, (long)size);
|
||||
}
|
||||
else
|
||||
{
|
||||
_cpuMemory.Map((long)va, (long)pa, IntPtr.Zero, (long)size);
|
||||
}
|
||||
}
|
||||
|
||||
public ulong GetDramAddressFromVa(ulong va)
|
||||
{
|
||||
return (ulong)_cpuMemory.GetPhysicalAddress((long)va);
|
||||
return (ulong)_cpuMemory.GetPhysicalAddress((long)va) - DramMemoryMap.DramBase;
|
||||
}
|
||||
|
||||
public bool ConvertVaToPa(ulong va, out ulong pa)
|
||||
{
|
||||
pa = DramMemoryMap.DramBase + (ulong)_cpuMemory.GetPhysicalAddress((long)va);
|
||||
pa = (ulong)_cpuMemory.GetPhysicalAddress((long)va);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
using ChocolArm64;
|
||||
using ChocolArm64.Events;
|
||||
using ChocolArm64.Memory;
|
||||
using Luea.Devices;
|
||||
using Ryujinx.Common;
|
||||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
|
@ -91,7 +92,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
_processLock = new object();
|
||||
_threadingLock = new object();
|
||||
|
||||
CpuMemory = new MemoryManager(system.Device.Memory.RamPointer);
|
||||
DummyDevice device = new DummyDevice();
|
||||
|
||||
CpuMemory = new MemoryManager(device);
|
||||
|
||||
CpuMemory.InvalidAccess += InvalidAccessHandler;
|
||||
|
||||
|
@ -1010,6 +1013,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
private void InvalidAccessHandler(object sender, MemoryAccessEventArgs e)
|
||||
{
|
||||
PrintCurrentThreadStackTrace();
|
||||
|
||||
throw new Exception($"Attempted to access unmapped address 0x{e.VirtualAddress:X16}.");
|
||||
}
|
||||
|
||||
public void PrintCurrentThreadStackTrace()
|
||||
|
|
|
@ -83,8 +83,8 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
long address = ((long)(uint)prevCap << 5) & 0xffffff000;
|
||||
long size = ((long)(uint)cap << 5) & 0xfffff000;
|
||||
ulong address = ((ulong)(uint)prevCap << 5) & 0xffffff000;
|
||||
ulong size = ((ulong)(uint)cap << 5) & 0xfffff000;
|
||||
|
||||
if (((ulong)(address + size - 1) >> 36) != 0)
|
||||
{
|
||||
|
@ -99,11 +99,11 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
if ((cap >> 31) != 0)
|
||||
{
|
||||
result = memoryManager.MapNormalMemory(address, size, perm);
|
||||
result = memoryManager.MapPhysical(address, size, perm);
|
||||
}
|
||||
else
|
||||
{
|
||||
result = memoryManager.MapIoMemory(address, size, perm);
|
||||
result = memoryManager.MapIo(address, size, perm);
|
||||
}
|
||||
|
||||
if (result != KernelResult.Success)
|
||||
|
@ -214,9 +214,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Process
|
|||
|
||||
case 0x80:
|
||||
{
|
||||
long address = ((long)(uint)cap << 4) & 0xffffff000;
|
||||
ulong address = ((ulong)(uint)cap << 4) & 0xffffff000;
|
||||
|
||||
memoryManager.MapIoMemory(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
||||
memoryManager.MapIo(address, KMemoryManager.PageSize, MemoryPermission.ReadAndWrite);
|
||||
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -386,6 +386,30 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return _process.MemoryManager.UnmapPhysicalMemory(address, size);
|
||||
}
|
||||
|
||||
public KernelResult QueryIoMapping64(ulong pa, ulong size, out ulong va)
|
||||
{
|
||||
return QueryIoMapping(pa, size, out va);
|
||||
}
|
||||
|
||||
private KernelResult QueryIoMapping(ulong pa, ulong size, out ulong va)
|
||||
{
|
||||
va = 0;
|
||||
|
||||
if (size == 0)
|
||||
{
|
||||
return KernelResult.InvalidSize;
|
||||
}
|
||||
|
||||
if (pa + size <= pa)
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
return currentProcess.MemoryManager.QueryIoMapping(pa, size, out va);
|
||||
}
|
||||
|
||||
public KernelResult CreateDeviceAddressSpace64(ulong address, ulong size, out int handle)
|
||||
{
|
||||
return CreateDeviceAddressSpace(address, size, out handle);
|
||||
|
@ -431,7 +455,7 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return deviceAs.Attach(deviceName);
|
||||
}
|
||||
|
||||
public KernelResult MapDeviceAddressSpace64(
|
||||
public KernelResult MapDeviceAddressSpaceByForce64(
|
||||
int dasHandle,
|
||||
int processHandle,
|
||||
ulong mapAddress,
|
||||
|
|
|
@ -3,6 +3,7 @@ using Ryujinx.Common;
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.Exceptions;
|
||||
using Ryujinx.HLE.HOS.Kernel.Common;
|
||||
using Ryujinx.HLE.HOS.Kernel.Interrupt;
|
||||
using Ryujinx.HLE.HOS.Kernel.Ipc;
|
||||
using Ryujinx.HLE.HOS.Kernel.Memory;
|
||||
using Ryujinx.HLE.HOS.Kernel.Process;
|
||||
|
@ -465,6 +466,37 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
return result;
|
||||
}
|
||||
|
||||
public KernelResult CreateInterruptEvent64(int irqId, uint flags, out int handle)
|
||||
{
|
||||
return CreateInterruptEvent(irqId, flags, out handle);
|
||||
}
|
||||
|
||||
private KernelResult CreateInterruptEvent(int irqId, uint flags, out int handle)
|
||||
{
|
||||
handle = 0;
|
||||
|
||||
if (flags > 1)
|
||||
{
|
||||
return KernelResult.InvalidEnumValue;
|
||||
}
|
||||
|
||||
if ((uint)irqId > 0x3ff)
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
|
||||
KProcess currentProcess = _system.Scheduler.GetCurrentProcess();
|
||||
|
||||
if ((currentProcess.Capabilities.IrqAccessMask[irqId / 8] & (1 << (irqId & 7))) == 0)
|
||||
{
|
||||
return KernelResult.NotFound;
|
||||
}
|
||||
|
||||
KInterruptEvent interruptEvent = new KInterruptEvent(_system);
|
||||
|
||||
return currentProcess.HandleTable.GenerateHandle(interruptEvent.Event, out handle);
|
||||
}
|
||||
|
||||
public KernelResult GetProcessList64(ulong address, int maxCount, out int count)
|
||||
{
|
||||
return GetProcessList(address, maxCount, out count);
|
||||
|
|
|
@ -67,9 +67,11 @@ namespace Ryujinx.HLE.HOS.Kernel.SupervisorCall
|
|||
{ 0x41, nameof(SvcHandler.AcceptSession64) },
|
||||
{ 0x43, nameof(SvcHandler.ReplyAndReceive64) },
|
||||
{ 0x45, nameof(SvcHandler.CreateEvent64) },
|
||||
{ 0x53, nameof(SvcHandler.CreateInterruptEvent64) },
|
||||
{ 0x55, nameof(SvcHandler.QueryIoMapping64) },
|
||||
{ 0x56, nameof(SvcHandler.CreateDeviceAddressSpace64) },
|
||||
{ 0x57, nameof(SvcHandler.AttachDeviceAddressSpace64) },
|
||||
{ 0x5b, nameof(SvcHandler.MapDeviceAddressSpace64) },
|
||||
{ 0x59, nameof(SvcHandler.MapDeviceAddressSpaceByForce64) },
|
||||
{ 0x65, nameof(SvcHandler.GetProcessList64) },
|
||||
{ 0x6f, nameof(SvcHandler.GetSystemInfo64) },
|
||||
{ 0x70, nameof(SvcHandler.CreatePort64) },
|
||||
|
|
|
@ -7,7 +7,7 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
|
||||
public KEvent(Horizon system)
|
||||
{
|
||||
ReadableEvent = new KReadableEvent(system, this);
|
||||
ReadableEvent = new KReadableEvent(system);
|
||||
WritableEvent = new KWritableEvent(system, this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,14 +4,9 @@ namespace Ryujinx.HLE.HOS.Kernel.Threading
|
|||
{
|
||||
class KReadableEvent : KSynchronizationObject
|
||||
{
|
||||
private KEvent _parent;
|
||||
|
||||
private bool _signaled;
|
||||
|
||||
public KReadableEvent(Horizon system, KEvent parent) : base(system)
|
||||
{
|
||||
_parent = parent;
|
||||
}
|
||||
public KReadableEvent(Horizon system) : base(system) { }
|
||||
|
||||
public override void Signal()
|
||||
{
|
||||
|
|
52
Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs
Normal file
52
Ryujinx.HLE/HOS/Services/Pcv/IPcvService.cs
Normal file
|
@ -0,0 +1,52 @@
|
|||
using Ryujinx.Common.Logging;
|
||||
using Ryujinx.HLE.HOS.Ipc;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Ryujinx.HLE.HOS.Services.Pcv
|
||||
{
|
||||
class IPcvService : IpcService
|
||||
{
|
||||
private Dictionary<int, ServiceProcessRequest> _commands;
|
||||
|
||||
public override IReadOnlyDictionary<int, ServiceProcessRequest> Commands => _commands;
|
||||
|
||||
public IPcvService(bool needInitialize = true)
|
||||
{
|
||||
_commands = new Dictionary<int, ServiceProcessRequest>
|
||||
{
|
||||
{ 0, SetPowerEnabled },
|
||||
{ 1, SetClockEnabled },
|
||||
{ 2, SetClockRate },
|
||||
{ 7, SetReset }
|
||||
};
|
||||
}
|
||||
|
||||
private long SetPowerEnabled(ServiceCtx context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServicePcv, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long SetClockEnabled(ServiceCtx context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServicePcv, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long SetClockRate(ServiceCtx context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServicePcv, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
private long SetReset(ServiceCtx context)
|
||||
{
|
||||
Logger.PrintStub(LogClass.ServicePcv, "Stubbed.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -16,6 +16,7 @@ using Ryujinx.HLE.HOS.Services.Nfp;
|
|||
using Ryujinx.HLE.HOS.Services.Ns;
|
||||
using Ryujinx.HLE.HOS.Services.Nv;
|
||||
using Ryujinx.HLE.HOS.Services.Pctl;
|
||||
using Ryujinx.HLE.HOS.Services.Pcv;
|
||||
using Ryujinx.HLE.HOS.Services.Pl;
|
||||
using Ryujinx.HLE.HOS.Services.Prepo;
|
||||
using Ryujinx.HLE.HOS.Services.Psm;
|
||||
|
@ -158,6 +159,9 @@ namespace Ryujinx.HLE.HOS.Services
|
|||
case "pctl":
|
||||
return new IParentalControlServiceFactory();
|
||||
|
||||
case "pcv":
|
||||
return new IPcvService();
|
||||
|
||||
case "pl:u":
|
||||
return new ISharedFontManager();
|
||||
|
||||
|
|
|
@ -25,6 +25,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.LLE\Luea.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Audio\Ryujinx.Audio.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Common\Ryujinx.Common.csproj" />
|
||||
<ProjectReference Include="..\Ryujinx.Graphics\Ryujinx.Graphics.csproj" />
|
||||
|
|
56
Ryujinx.LLE/Devices/Device.cs
Normal file
56
Ryujinx.LLE/Devices/Device.cs
Normal file
|
@ -0,0 +1,56 @@
|
|||
using ChocolArm64.Memory;
|
||||
using System;
|
||||
|
||||
namespace Luea.Devices
|
||||
{
|
||||
public class Device : IBus
|
||||
{
|
||||
public byte ReadByte(ulong address)
|
||||
{
|
||||
Console.WriteLine($"ReadByte to unimplemented device at 0x{address:X16}.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ushort ReadUInt16(ulong address)
|
||||
{
|
||||
Console.WriteLine($"ReadUInt16 to unimplemented device at 0x{address:X16}.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public uint ReadUInt32(ulong address)
|
||||
{
|
||||
Console.WriteLine($"ReadUInt32 to unimplemented device at 0x{address:X16}.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public ulong ReadUInt64(ulong address)
|
||||
{
|
||||
Console.WriteLine($"ReadUInt64 to unimplemented device at 0x{address:X16}.");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
public void WriteByte(ulong address, byte value)
|
||||
{
|
||||
Console.WriteLine($"WriteByte to unimplemented device at 0x{address:X16} = 0x{value:X2}.");
|
||||
}
|
||||
|
||||
public void WriteUInt16(ulong address, ushort value)
|
||||
{
|
||||
Console.WriteLine($"WriteUInt16 to unimplemented device at 0x{address:X16} = 0x{value:X4}.");
|
||||
}
|
||||
|
||||
public void WriteUInt32(ulong address, uint value)
|
||||
{
|
||||
Console.WriteLine($"WriteUInt32 to unimplemented device at 0x{address:X16} = 0x{value:X8}.");
|
||||
}
|
||||
|
||||
public void WriteUInt64(ulong address, ulong value)
|
||||
{
|
||||
Console.WriteLine($"WriteUInt64 to unimplemented device at 0x{address:X16} = 0x{value:X16}.");
|
||||
}
|
||||
}
|
||||
}
|
7
Ryujinx.LLE/Devices/DummyDevice.cs
Normal file
7
Ryujinx.LLE/Devices/DummyDevice.cs
Normal file
|
@ -0,0 +1,7 @@
|
|||
namespace Luea.Devices
|
||||
{
|
||||
public class DummyDevice : Device
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -6,4 +6,8 @@
|
|||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\ChocolArm64\ChocolArm64.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
@ -50,8 +50,8 @@ namespace Ryujinx.Tests.Cpu
|
|||
|
||||
Translator translator = new Translator();
|
||||
_ramPointer = Marshal.AllocHGlobal(new IntPtr(_size));
|
||||
_memory = new MemoryManager(_ramPointer);
|
||||
_memory.Map(Position, 0, _size);
|
||||
_memory = new MemoryManager();
|
||||
_memory.Map(Position, Position, _ramPointer, _size);
|
||||
_thread = new CpuThread(translator, _memory, _entryPoint);
|
||||
|
||||
if (_unicornAvailable)
|
||||
|
|
Loading…
Add table
Reference in a new issue