| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191 |
- using ChocolArm64.Memory;
- using Ryujinx.HLE.Memory;
- using System;
- using System.Collections.Generic;
- using static Ryujinx.HLE.HOS.ErrorCode;
- namespace Ryujinx.HLE.HOS.Kernel
- {
- class KMemoryManager
- {
- public const int PageSize = 0x1000;
- private LinkedList<KMemoryBlock> Blocks;
- private MemoryManager CpuMemory;
- private ArenaAllocator Allocator;
- public long AddrSpaceStart { get; private set; }
- public long AddrSpaceEnd { get; private set; }
- public long CodeRegionStart { get; private set; }
- public long CodeRegionEnd { get; private set; }
- public long MapRegionStart { get; private set; }
- public long MapRegionEnd { get; private set; }
- public long HeapRegionStart { get; private set; }
- public long HeapRegionEnd { get; private set; }
- public long NewMapRegionStart { get; private set; }
- public long NewMapRegionEnd { get; private set; }
- public long TlsIoRegionStart { get; private set; }
- public long TlsIoRegionEnd { get; private set; }
- public long PersonalMmHeapUsage { get; private set; }
- private long CurrentHeapAddr;
- public KMemoryManager(Process Process)
- {
- CpuMemory = Process.Memory;
- Allocator = Process.Device.Memory.Allocator;
- long CodeRegionSize;
- long MapRegionSize;
- long HeapRegionSize;
- long NewMapRegionSize;
- long TlsIoRegionSize;
- int AddrSpaceWidth;
- AddressSpaceType AddrType = AddressSpaceType.Addr39Bits;
- if (Process.MetaData != null)
- {
- AddrType = (AddressSpaceType)Process.MetaData.AddressSpaceWidth;
- }
- switch (AddrType)
- {
- case AddressSpaceType.Addr32Bits:
- CodeRegionStart = 0x200000;
- CodeRegionSize = 0x3fe00000;
- MapRegionSize = 0x40000000;
- HeapRegionSize = 0x40000000;
- NewMapRegionSize = 0;
- TlsIoRegionSize = 0;
- AddrSpaceWidth = 32;
- break;
- case AddressSpaceType.Addr36Bits:
- CodeRegionStart = 0x8000000;
- CodeRegionSize = 0x78000000;
- MapRegionSize = 0x180000000;
- HeapRegionSize = 0x180000000;
- NewMapRegionSize = 0;
- TlsIoRegionSize = 0;
- AddrSpaceWidth = 36;
- break;
- case AddressSpaceType.Addr36BitsNoMap:
- CodeRegionStart = 0x200000;
- CodeRegionSize = 0x3fe00000;
- MapRegionSize = 0;
- HeapRegionSize = 0x80000000;
- NewMapRegionSize = 0;
- TlsIoRegionSize = 0;
- AddrSpaceWidth = 36;
- break;
- case AddressSpaceType.Addr39Bits:
- CodeRegionStart = 0x8000000;
- CodeRegionSize = 0x80000000;
- MapRegionSize = 0x1000000000;
- HeapRegionSize = 0x180000000;
- NewMapRegionSize = 0x80000000;
- TlsIoRegionSize = 0x1000000000;
- AddrSpaceWidth = 39;
- break;
- default: throw new InvalidOperationException();
- }
- AddrSpaceStart = 0;
- AddrSpaceEnd = 1L << AddrSpaceWidth;
- CodeRegionEnd = CodeRegionStart + CodeRegionSize;
- MapRegionStart = CodeRegionEnd;
- MapRegionEnd = CodeRegionEnd + MapRegionSize;
- HeapRegionStart = MapRegionEnd;
- HeapRegionEnd = MapRegionEnd + HeapRegionSize;
- NewMapRegionStart = HeapRegionEnd;
- NewMapRegionEnd = HeapRegionEnd + NewMapRegionSize;
- TlsIoRegionStart = NewMapRegionEnd;
- TlsIoRegionEnd = NewMapRegionEnd + TlsIoRegionSize;
- CurrentHeapAddr = HeapRegionStart;
- if (NewMapRegionSize == 0)
- {
- NewMapRegionStart = AddrSpaceStart;
- NewMapRegionEnd = AddrSpaceEnd;
- }
- Blocks = new LinkedList<KMemoryBlock>();
- long AddrSpacePagesCount = (AddrSpaceEnd - AddrSpaceStart) / PageSize;
- InsertBlock(AddrSpaceStart, AddrSpacePagesCount, MemoryState.Unmapped);
- }
- public void HleMapProcessCode(long Position, long Size)
- {
- long PagesCount = Size / PageSize;
- if (!Allocator.TryAllocate(Size, out long PA))
- {
- throw new InvalidOperationException();
- }
- lock (Blocks)
- {
- InsertBlock(Position, PagesCount, MemoryState.CodeStatic, MemoryPermission.ReadAndExecute);
- CpuMemory.Map(Position, PA, Size);
- }
- }
- public long MapProcessCodeMemory(long Dst, long Src, long Size)
- {
- lock (Blocks)
- {
- long PagesCount = Size / PageSize;
- bool Success = IsUnmapped(Dst, Size);
- Success &= CheckRange(
- Src,
- Size,
- MemoryState.Mask,
- MemoryState.Heap,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out _,
- out _,
- out _);
- if (Success)
- {
- long PA = CpuMemory.GetPhysicalAddress(Src);
- InsertBlock(Dst, PagesCount, MemoryState.CodeStatic, MemoryPermission.ReadAndExecute);
- InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.None);
- CpuMemory.Map(Dst, PA, Size);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long UnmapProcessCodeMemory(long Dst, long Src, long Size)
- {
- lock (Blocks)
- {
- long PagesCount = Size / PageSize;
- bool Success = CheckRange(
- Dst,
- Size,
- MemoryState.Mask,
- MemoryState.CodeStatic,
- MemoryPermission.None,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out _,
- out _,
- out _);
- Success &= CheckRange(
- Src,
- Size,
- MemoryState.Mask,
- MemoryState.Heap,
- MemoryPermission.Mask,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out _,
- out _,
- out _);
- if (Success)
- {
- InsertBlock(Dst, PagesCount, MemoryState.Unmapped);
- InsertBlock(Src, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
- CpuMemory.Unmap(Dst, Size);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public void HleMapCustom(long Position, long Size, MemoryState State, MemoryPermission Permission)
- {
- long PagesCount = Size / PageSize;
- if (!Allocator.TryAllocate(Size, out long PA))
- {
- throw new InvalidOperationException();
- }
- lock (Blocks)
- {
- InsertBlock(Position, PagesCount, State, Permission);
- CpuMemory.Map(Position, PA, Size);
- }
- }
- public long HleMapTlsPage()
- {
- bool HasTlsIoRegion = TlsIoRegionStart != TlsIoRegionEnd;
- long Position = HasTlsIoRegion ? TlsIoRegionStart : CodeRegionStart;
- lock (Blocks)
- {
- while (Position < (HasTlsIoRegion ? TlsIoRegionEnd : CodeRegionEnd))
- {
- if (FindBlock(Position).State == MemoryState.Unmapped)
- {
- InsertBlock(Position, 1, MemoryState.ThreadLocal, MemoryPermission.ReadAndWrite);
- if (!Allocator.TryAllocate(PageSize, out long PA))
- {
- throw new InvalidOperationException();
- }
- CpuMemory.Map(Position, PA, PageSize);
- return Position;
- }
- Position += PageSize;
- }
- throw new InvalidOperationException();
- }
- }
- public long TrySetHeapSize(long Size, out long Position)
- {
- Position = 0;
- if ((ulong)Size > (ulong)(HeapRegionEnd - HeapRegionStart))
- {
- return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory);
- }
- bool Success = false;
- long CurrentHeapSize = GetHeapSize();
- if ((ulong)CurrentHeapSize <= (ulong)Size)
- {
- //Expand.
- long DiffSize = Size - CurrentHeapSize;
- lock (Blocks)
- {
- if (Success = IsUnmapped(CurrentHeapAddr, DiffSize))
- {
- if (!Allocator.TryAllocate(DiffSize, out long PA))
- {
- return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory);
- }
- long PagesCount = DiffSize / PageSize;
- InsertBlock(CurrentHeapAddr, PagesCount, MemoryState.Heap, MemoryPermission.ReadAndWrite);
- CpuMemory.Map(CurrentHeapAddr, PA, DiffSize);
- }
- }
- }
- else
- {
- //Shrink.
- long FreeAddr = HeapRegionStart + Size;
- long DiffSize = CurrentHeapSize - Size;
- lock (Blocks)
- {
- Success = CheckRange(
- FreeAddr,
- DiffSize,
- MemoryState.Mask,
- MemoryState.Heap,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out _,
- out _,
- out _);
- if (Success)
- {
- long PagesCount = DiffSize / PageSize;
- InsertBlock(FreeAddr, PagesCount, MemoryState.Unmapped);
- FreePages(FreeAddr, PagesCount);
- CpuMemory.Unmap(FreeAddr, DiffSize);
- }
- }
- }
- CurrentHeapAddr = HeapRegionStart + Size;
- if (Success)
- {
- Position = HeapRegionStart;
- return 0;
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long GetHeapSize()
- {
- return CurrentHeapAddr - HeapRegionStart;
- }
- public long SetMemoryAttribute(
- long Position,
- long Size,
- MemoryAttribute AttributeMask,
- MemoryAttribute AttributeValue)
- {
- lock (Blocks)
- {
- if (CheckRange(
- Position,
- Size,
- MemoryState.AttributeChangeAllowed,
- MemoryState.AttributeChangeAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
- MemoryAttribute.BorrowedAndIpcMapped,
- MemoryAttribute.None,
- MemoryAttribute.DeviceMappedAndUncached,
- out MemoryState State,
- out MemoryPermission Permission,
- out MemoryAttribute Attribute))
- {
- long PagesCount = Size / PageSize;
- Attribute &= ~AttributeMask;
- Attribute |= AttributeMask & AttributeValue;
- InsertBlock(Position, PagesCount, State, Permission, Attribute);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public KMemoryInfo QueryMemory(long Position)
- {
- if ((ulong)Position >= (ulong)AddrSpaceStart &&
- (ulong)Position < (ulong)AddrSpaceEnd)
- {
- lock (Blocks)
- {
- return FindBlock(Position).GetInfo();
- }
- }
- else
- {
- return new KMemoryInfo(
- AddrSpaceEnd,
- -AddrSpaceEnd,
- MemoryState.Reserved,
- MemoryPermission.None,
- MemoryAttribute.None,
- 0,
- 0);
- }
- }
- public long Map(long Src, long Dst, long Size)
- {
- bool Success;
- lock (Blocks)
- {
- Success = CheckRange(
- Src,
- Size,
- MemoryState.MapAllowed,
- MemoryState.MapAllowed,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out MemoryState SrcState,
- out _,
- out _);
- Success &= IsUnmapped(Dst, Size);
- if (Success)
- {
- long PagesCount = Size / PageSize;
- InsertBlock(Src, PagesCount, SrcState, MemoryPermission.None, MemoryAttribute.Borrowed);
- InsertBlock(Dst, PagesCount, MemoryState.MappedMemory, MemoryPermission.ReadAndWrite);
- long PA = CpuMemory.GetPhysicalAddress(Src);
- CpuMemory.Map(Dst, PA, Size);
- }
- }
- return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long Unmap(long Src, long Dst, long Size)
- {
- bool Success;
- lock (Blocks)
- {
- Success = CheckRange(
- Src,
- Size,
- MemoryState.MapAllowed,
- MemoryState.MapAllowed,
- MemoryPermission.Mask,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.Borrowed,
- MemoryAttribute.IpcAndDeviceMapped,
- out MemoryState SrcState,
- out _,
- out _);
- Success &= CheckRange(
- Dst,
- Size,
- MemoryState.Mask,
- MemoryState.MappedMemory,
- MemoryPermission.None,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out _,
- out _,
- out _);
- if (Success)
- {
- long PagesCount = Size / PageSize;
- InsertBlock(Src, PagesCount, SrcState, MemoryPermission.ReadAndWrite);
- InsertBlock(Dst, PagesCount, MemoryState.Unmapped);
- CpuMemory.Unmap(Dst, Size);
- }
- }
- return Success ? 0 : MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long MapSharedMemory(KSharedMemory SharedMemory, MemoryPermission Permission, long Position)
- {
- lock (Blocks)
- {
- if (IsUnmapped(Position, SharedMemory.Size))
- {
- long PagesCount = SharedMemory.Size / PageSize;
- InsertBlock(Position, PagesCount, MemoryState.SharedMemory, Permission);
- CpuMemory.Map(Position, SharedMemory.PA, SharedMemory.Size);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long UnmapSharedMemory(long Position, long Size)
- {
- lock (Blocks)
- {
- if (CheckRange(
- Position,
- Size,
- MemoryState.Mask,
- MemoryState.SharedMemory,
- MemoryPermission.None,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out MemoryState State,
- out _,
- out _))
- {
- long PagesCount = Size / PageSize;
- InsertBlock(Position, PagesCount, MemoryState.Unmapped);
- CpuMemory.Unmap(Position, Size);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long ReserveTransferMemory(long Position, long Size, MemoryPermission Permission)
- {
- lock (Blocks)
- {
- if (CheckRange(
- Position,
- Size,
- MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
- MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
- MemoryPermission.Mask,
- MemoryPermission.ReadAndWrite,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out MemoryState State,
- out _,
- out MemoryAttribute Attribute))
- {
- long PagesCount = Size / PageSize;
- Attribute |= MemoryAttribute.Borrowed;
- InsertBlock(Position, PagesCount, State, Permission, Attribute);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long ResetTransferMemory(long Position, long Size)
- {
- lock (Blocks)
- {
- if (CheckRange(
- Position,
- Size,
- MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
- MemoryState.TransferMemoryAllowed | MemoryState.IsPoolAllocated,
- MemoryPermission.None,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.Borrowed,
- MemoryAttribute.IpcAndDeviceMapped,
- out MemoryState State,
- out _,
- out _))
- {
- long PagesCount = Size / PageSize;
- InsertBlock(Position, PagesCount, State, MemoryPermission.ReadAndWrite);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long SetProcessMemoryPermission(long Position, long Size, MemoryPermission Permission)
- {
- lock (Blocks)
- {
- if (CheckRange(
- Position,
- Size,
- MemoryState.ProcessPermissionChangeAllowed,
- MemoryState.ProcessPermissionChangeAllowed,
- MemoryPermission.None,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out MemoryState State,
- out _,
- out _))
- {
- if (State == MemoryState.CodeStatic)
- {
- State = MemoryState.CodeMutable;
- }
- else if (State == MemoryState.ModCodeStatic)
- {
- State = MemoryState.ModCodeMutable;
- }
- else
- {
- throw new InvalidOperationException();
- }
- long PagesCount = Size / PageSize;
- InsertBlock(Position, PagesCount, State, Permission);
- return 0;
- }
- }
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- public long MapPhysicalMemory(long Position, long Size)
- {
- long End = Position + Size;
- lock (Blocks)
- {
- long MappedSize = 0;
- KMemoryInfo Info;
- LinkedListNode<KMemoryBlock> BaseNode = FindBlockNode(Position);
- LinkedListNode<KMemoryBlock> Node = BaseNode;
- do
- {
- Info = Node.Value.GetInfo();
- if (Info.State != MemoryState.Unmapped)
- {
- MappedSize += GetSizeInRange(Info, Position, End);
- }
- Node = Node.Next;
- }
- while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null);
- if (MappedSize == Size)
- {
- return 0;
- }
- long RemainingSize = Size - MappedSize;
- if (!Allocator.TryAllocate(RemainingSize, out long PA))
- {
- return MakeError(ErrorModule.Kernel, KernelErr.OutOfMemory);
- }
- Node = BaseNode;
- do
- {
- Info = Node.Value.GetInfo();
- if (Info.State == MemoryState.Unmapped)
- {
- long CurrSize = GetSizeInRange(Info, Position, End);
- long MapPosition = Info.Position;
- if ((ulong)MapPosition < (ulong)Position)
- {
- MapPosition = Position;
- }
- CpuMemory.Map(MapPosition, PA, CurrSize);
- PA += CurrSize;
- }
- Node = Node.Next;
- }
- while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null);
- PersonalMmHeapUsage += RemainingSize;
- long PagesCount = Size / PageSize;
- InsertBlock(
- Position,
- PagesCount,
- MemoryState.Unmapped,
- MemoryPermission.None,
- MemoryAttribute.None,
- MemoryState.Heap,
- MemoryPermission.ReadAndWrite,
- MemoryAttribute.None);
- }
- return 0;
- }
- public long UnmapPhysicalMemory(long Position, long Size)
- {
- long End = Position + Size;
- lock (Blocks)
- {
- long HeapMappedSize = 0;
- long CurrPosition = Position;
- KMemoryInfo Info;
- LinkedListNode<KMemoryBlock> Node = FindBlockNode(CurrPosition);
- do
- {
- Info = Node.Value.GetInfo();
- if (Info.State == MemoryState.Heap)
- {
- if (Info.Attribute != MemoryAttribute.None)
- {
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- HeapMappedSize += GetSizeInRange(Info, Position, End);
- }
- else if (Info.State != MemoryState.Unmapped)
- {
- return MakeError(ErrorModule.Kernel, KernelErr.NoAccessPerm);
- }
- Node = Node.Next;
- }
- while ((ulong)(Info.Position + Info.Size) < (ulong)End && Node != null);
- if (HeapMappedSize == 0)
- {
- return 0;
- }
- PersonalMmHeapUsage -= HeapMappedSize;
- long PagesCount = Size / PageSize;
- InsertBlock(Position, PagesCount, MemoryState.Unmapped);
- FreePages(Position, PagesCount);
- CpuMemory.Unmap(Position, Size);
- return 0;
- }
- }
- private long GetSizeInRange(KMemoryInfo Info, long Start, long End)
- {
- long CurrEnd = Info.Size + Info.Position;
- long CurrSize = Info.Size;
- if ((ulong)Info.Position < (ulong)Start)
- {
- CurrSize -= Start - Info.Position;
- }
- if ((ulong)CurrEnd > (ulong)End)
- {
- CurrSize -= CurrEnd - End;
- }
- return CurrSize;
- }
- private void FreePages(long Position, long PagesCount)
- {
- for (long Page = 0; Page < PagesCount; Page++)
- {
- long VA = Position + Page * PageSize;
- if (!CpuMemory.IsMapped(VA))
- {
- continue;
- }
- long PA = CpuMemory.GetPhysicalAddress(VA);
- Allocator.Free(PA, PageSize);
- }
- }
- public bool HleIsUnmapped(long Position, long Size)
- {
- bool Result = false;
- lock (Blocks)
- {
- Result = IsUnmapped(Position, Size);
- }
- return Result;
- }
- private bool IsUnmapped(long Position, long Size)
- {
- return CheckRange(
- Position,
- Size,
- MemoryState.Mask,
- MemoryState.Unmapped,
- MemoryPermission.Mask,
- MemoryPermission.None,
- MemoryAttribute.Mask,
- MemoryAttribute.None,
- MemoryAttribute.IpcAndDeviceMapped,
- out _,
- out _,
- out _);
- }
- private bool CheckRange(
- long Position,
- long Size,
- MemoryState StateMask,
- MemoryState StateExpected,
- MemoryPermission PermissionMask,
- MemoryPermission PermissionExpected,
- MemoryAttribute AttributeMask,
- MemoryAttribute AttributeExpected,
- MemoryAttribute AttributeIgnoreMask,
- out MemoryState OutState,
- out MemoryPermission OutPermission,
- out MemoryAttribute OutAttribute)
- {
- KMemoryInfo BlkInfo = FindBlock(Position).GetInfo();
- ulong Start = (ulong)Position;
- ulong End = (ulong)Size + Start;
- if (End <= (ulong)(BlkInfo.Position + BlkInfo.Size))
- {
- if ((BlkInfo.Attribute & AttributeMask) == AttributeExpected &&
- (BlkInfo.State & StateMask) == StateExpected &&
- (BlkInfo.Permission & PermissionMask) == PermissionExpected)
- {
- OutState = BlkInfo.State;
- OutPermission = BlkInfo.Permission;
- OutAttribute = BlkInfo.Attribute & ~AttributeIgnoreMask;
- return true;
- }
- }
- OutState = MemoryState.Unmapped;
- OutPermission = MemoryPermission.None;
- OutAttribute = MemoryAttribute.None;
- return false;
- }
- private void InsertBlock(
- long BasePosition,
- long PagesCount,
- MemoryState OldState,
- MemoryPermission OldPermission,
- MemoryAttribute OldAttribute,
- MemoryState NewState,
- MemoryPermission NewPermission,
- MemoryAttribute NewAttribute)
- {
- //Insert new block on the list only on areas where the state
- //of the block matches the state specified on the Old* state
- //arguments, otherwise leave it as is.
- OldAttribute |= MemoryAttribute.IpcAndDeviceMapped;
- ulong Start = (ulong)BasePosition;
- ulong End = (ulong)PagesCount * PageSize + Start;
- LinkedListNode<KMemoryBlock> Node = Blocks.First;
- while (Node != null)
- {
- LinkedListNode<KMemoryBlock> NewNode = Node;
- LinkedListNode<KMemoryBlock> NextNode = Node.Next;
- KMemoryBlock CurrBlock = Node.Value;
- ulong CurrStart = (ulong)CurrBlock.BasePosition;
- ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart;
- if (Start < CurrEnd && CurrStart < End)
- {
- MemoryAttribute CurrBlockAttr = CurrBlock.Attribute | MemoryAttribute.IpcAndDeviceMapped;
- if (CurrBlock.State != OldState ||
- CurrBlock.Permission != OldPermission ||
- CurrBlockAttr != OldAttribute)
- {
- Node = NextNode;
- continue;
- }
- if (CurrStart >= Start && CurrEnd <= End)
- {
- CurrBlock.State = NewState;
- CurrBlock.Permission = NewPermission;
- CurrBlock.Attribute &= ~MemoryAttribute.IpcAndDeviceMapped;
- CurrBlock.Attribute |= NewAttribute;
- }
- else if (CurrStart >= Start)
- {
- CurrBlock.BasePosition = (long)End;
- CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize);
- long NewPagesCount = (long)((End - CurrStart) / PageSize);
- NewNode = Blocks.AddBefore(Node, new KMemoryBlock(
- (long)CurrStart,
- NewPagesCount,
- NewState,
- NewPermission,
- NewAttribute));
- }
- else if (CurrEnd <= End)
- {
- CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize);
- long NewPagesCount = (long)((CurrEnd - Start) / PageSize);
- NewNode = Blocks.AddAfter(Node, new KMemoryBlock(
- BasePosition,
- NewPagesCount,
- NewState,
- NewPermission,
- NewAttribute));
- }
- else
- {
- CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize);
- long NextPagesCount = (long)((CurrEnd - End) / PageSize);
- NewNode = Blocks.AddAfter(Node, new KMemoryBlock(
- BasePosition,
- PagesCount,
- NewState,
- NewPermission,
- NewAttribute));
- Blocks.AddAfter(NewNode, new KMemoryBlock(
- (long)End,
- NextPagesCount,
- CurrBlock.State,
- CurrBlock.Permission,
- CurrBlock.Attribute));
- NextNode = null;
- }
- MergeEqualStateNeighbours(NewNode);
- }
- Node = NextNode;
- }
- }
- private void InsertBlock(
- long BasePosition,
- long PagesCount,
- MemoryState State,
- MemoryPermission Permission = MemoryPermission.None,
- MemoryAttribute Attribute = MemoryAttribute.None)
- {
- //Inserts new block at the list, replacing and spliting
- //existing blocks as needed.
- KMemoryBlock Block = new KMemoryBlock(BasePosition, PagesCount, State, Permission, Attribute);
- ulong Start = (ulong)BasePosition;
- ulong End = (ulong)PagesCount * PageSize + Start;
- LinkedListNode<KMemoryBlock> NewNode = null;
- LinkedListNode<KMemoryBlock> Node = Blocks.First;
- while (Node != null)
- {
- KMemoryBlock CurrBlock = Node.Value;
- LinkedListNode<KMemoryBlock> NextNode = Node.Next;
- ulong CurrStart = (ulong)CurrBlock.BasePosition;
- ulong CurrEnd = (ulong)CurrBlock.PagesCount * PageSize + CurrStart;
- if (Start < CurrEnd && CurrStart < End)
- {
- if (Start >= CurrStart && End <= CurrEnd)
- {
- Block.Attribute |= CurrBlock.Attribute & MemoryAttribute.IpcAndDeviceMapped;
- }
- if (Start > CurrStart && End < CurrEnd)
- {
- CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize);
- long NextPagesCount = (long)((CurrEnd - End) / PageSize);
- NewNode = Blocks.AddAfter(Node, Block);
- Blocks.AddAfter(NewNode, new KMemoryBlock(
- (long)End,
- NextPagesCount,
- CurrBlock.State,
- CurrBlock.Permission,
- CurrBlock.Attribute));
- break;
- }
- else if (Start <= CurrStart && End < CurrEnd)
- {
- CurrBlock.BasePosition = (long)End;
- CurrBlock.PagesCount = (long)((CurrEnd - End) / PageSize);
- if (NewNode == null)
- {
- NewNode = Blocks.AddBefore(Node, Block);
- }
- }
- else if (Start > CurrStart && End >= CurrEnd)
- {
- CurrBlock.PagesCount = (long)((Start - CurrStart) / PageSize);
- if (NewNode == null)
- {
- NewNode = Blocks.AddAfter(Node, Block);
- }
- }
- else
- {
- if (NewNode == null)
- {
- NewNode = Blocks.AddBefore(Node, Block);
- }
- Blocks.Remove(Node);
- }
- }
- Node = NextNode;
- }
- if (NewNode == null)
- {
- NewNode = Blocks.AddFirst(Block);
- }
- MergeEqualStateNeighbours(NewNode);
- }
- private void MergeEqualStateNeighbours(LinkedListNode<KMemoryBlock> Node)
- {
- KMemoryBlock Block = Node.Value;
- ulong Start = (ulong)Block.BasePosition;
- ulong End = (ulong)Block.PagesCount * PageSize + Start;
- if (Node.Previous != null)
- {
- KMemoryBlock Previous = Node.Previous.Value;
- if (BlockStateEquals(Block, Previous))
- {
- Blocks.Remove(Node.Previous);
- Block.BasePosition = Previous.BasePosition;
- Start = (ulong)Block.BasePosition;
- }
- }
- if (Node.Next != null)
- {
- KMemoryBlock Next = Node.Next.Value;
- if (BlockStateEquals(Block, Next))
- {
- Blocks.Remove(Node.Next);
- End = (ulong)(Next.BasePosition + Next.PagesCount * PageSize);
- }
- }
- Block.PagesCount = (long)((End - Start) / PageSize);
- }
- private static bool BlockStateEquals(KMemoryBlock LHS, KMemoryBlock RHS)
- {
- return LHS.State == RHS.State &&
- LHS.Permission == RHS.Permission &&
- LHS.Attribute == RHS.Attribute &&
- LHS.DeviceRefCount == RHS.DeviceRefCount &&
- LHS.IpcRefCount == RHS.IpcRefCount;
- }
- private KMemoryBlock FindBlock(long Position)
- {
- return FindBlockNode(Position)?.Value;
- }
- private LinkedListNode<KMemoryBlock> FindBlockNode(long Position)
- {
- ulong Addr = (ulong)Position;
- lock (Blocks)
- {
- LinkedListNode<KMemoryBlock> Node = Blocks.First;
- while (Node != null)
- {
- KMemoryBlock Block = Node.Value;
- ulong Start = (ulong)Block.BasePosition;
- ulong End = (ulong)Block.PagesCount * PageSize + Start;
- if (Start <= Addr && End - 1 >= Addr)
- {
- return Node;
- }
- Node = Node.Next;
- }
- }
- return null;
- }
- }
- }
|