| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217 |
- using Ryujinx.Common;
- using Ryujinx.HLE.HOS.Kernel.Common;
- using Ryujinx.HLE.HOS.Kernel.Memory;
- using System.Collections.Generic;
- namespace Ryujinx.HLE.HOS.Kernel.Ipc
- {
- class KBufferDescriptorTable
- {
- private const int MaxInternalBuffersCount = 8;
- private List<KBufferDescriptor> _sendBufferDescriptors;
- private List<KBufferDescriptor> _receiveBufferDescriptors;
- private List<KBufferDescriptor> _exchangeBufferDescriptors;
- public KBufferDescriptorTable()
- {
- _sendBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
- _receiveBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
- _exchangeBufferDescriptors = new List<KBufferDescriptor>(MaxInternalBuffersCount);
- }
- public KernelResult AddSendBuffer(ulong src, ulong dst, ulong size, MemoryState state)
- {
- return Add(_sendBufferDescriptors, src, dst, size, state);
- }
- public KernelResult AddReceiveBuffer(ulong src, ulong dst, ulong size, MemoryState state)
- {
- return Add(_receiveBufferDescriptors, src, dst, size, state);
- }
- public KernelResult AddExchangeBuffer(ulong src, ulong dst, ulong size, MemoryState state)
- {
- return Add(_exchangeBufferDescriptors, src, dst, size, state);
- }
- private KernelResult Add(List<KBufferDescriptor> list, ulong src, ulong dst, ulong size, MemoryState state)
- {
- if (list.Count < MaxInternalBuffersCount)
- {
- list.Add(new KBufferDescriptor(src, dst, size, state));
- return KernelResult.Success;
- }
- return KernelResult.OutOfMemory;
- }
- public KernelResult CopyBuffersToClient(KPageTableBase memoryManager)
- {
- KernelResult result = CopyToClient(memoryManager, _receiveBufferDescriptors);
- if (result != KernelResult.Success)
- {
- return result;
- }
- return CopyToClient(memoryManager, _exchangeBufferDescriptors);
- }
- private KernelResult CopyToClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
- {
- foreach (KBufferDescriptor desc in list)
- {
- MemoryState stateMask;
- switch (desc.State)
- {
- case MemoryState.IpcBuffer0: stateMask = MemoryState.IpcSendAllowedType0; break;
- case MemoryState.IpcBuffer1: stateMask = MemoryState.IpcSendAllowedType1; break;
- case MemoryState.IpcBuffer3: stateMask = MemoryState.IpcSendAllowedType3; break;
- default: return KernelResult.InvalidCombination;
- }
- MemoryAttribute attributeMask = MemoryAttribute.Borrowed | MemoryAttribute.Uncached;
- if (desc.State == MemoryState.IpcBuffer0)
- {
- attributeMask |= MemoryAttribute.DeviceMapped;
- }
- ulong clientAddrTruncated = BitUtils.AlignDown(desc.ClientAddress, KPageTableBase.PageSize);
- ulong clientAddrRounded = BitUtils.AlignUp (desc.ClientAddress, KPageTableBase.PageSize);
- // Check if address is not aligned, in this case we need to perform 2 copies.
- if (clientAddrTruncated != clientAddrRounded)
- {
- ulong copySize = clientAddrRounded - desc.ClientAddress;
- if (copySize > desc.Size)
- {
- copySize = desc.Size;
- }
- KernelResult result = memoryManager.CopyDataFromCurrentProcess(
- desc.ClientAddress,
- copySize,
- stateMask,
- stateMask,
- KMemoryPermission.ReadAndWrite,
- attributeMask,
- MemoryAttribute.None,
- desc.ServerAddress);
- if (result != KernelResult.Success)
- {
- return result;
- }
- }
- ulong clientEndAddr = desc.ClientAddress + desc.Size;
- ulong serverEndAddr = desc.ServerAddress + desc.Size;
- ulong clientEndAddrTruncated = BitUtils.AlignDown(clientEndAddr, KPageTableBase.PageSize);
- ulong clientEndAddrRounded = BitUtils.AlignUp (clientEndAddr, KPageTableBase.PageSize);
- ulong serverEndAddrTruncated = BitUtils.AlignDown(serverEndAddr, KPageTableBase.PageSize);
- if (clientEndAddrTruncated < clientEndAddrRounded &&
- (clientAddrTruncated == clientAddrRounded || clientAddrTruncated < clientEndAddrTruncated))
- {
- KernelResult result = memoryManager.CopyDataFromCurrentProcess(
- clientEndAddrTruncated,
- clientEndAddr - clientEndAddrTruncated,
- stateMask,
- stateMask,
- KMemoryPermission.ReadAndWrite,
- attributeMask,
- MemoryAttribute.None,
- serverEndAddrTruncated);
- if (result != KernelResult.Success)
- {
- return result;
- }
- }
- }
- return KernelResult.Success;
- }
- public KernelResult UnmapServerBuffers(KPageTableBase memoryManager)
- {
- KernelResult result = UnmapServer(memoryManager, _sendBufferDescriptors);
- if (result != KernelResult.Success)
- {
- return result;
- }
- result = UnmapServer(memoryManager, _receiveBufferDescriptors);
- if (result != KernelResult.Success)
- {
- return result;
- }
- return UnmapServer(memoryManager, _exchangeBufferDescriptors);
- }
- private KernelResult UnmapServer(KPageTableBase memoryManager, List<KBufferDescriptor> list)
- {
- foreach (KBufferDescriptor descriptor in list)
- {
- KernelResult result = memoryManager.UnmapNoAttributeIfStateEquals(
- descriptor.ServerAddress,
- descriptor.Size,
- descriptor.State);
- if (result != KernelResult.Success)
- {
- return result;
- }
- }
- return KernelResult.Success;
- }
- public KernelResult RestoreClientBuffers(KPageTableBase memoryManager)
- {
- KernelResult result = RestoreClient(memoryManager, _sendBufferDescriptors);
- if (result != KernelResult.Success)
- {
- return result;
- }
- result = RestoreClient(memoryManager, _receiveBufferDescriptors);
- if (result != KernelResult.Success)
- {
- return result;
- }
- return RestoreClient(memoryManager, _exchangeBufferDescriptors);
- }
- private KernelResult RestoreClient(KPageTableBase memoryManager, List<KBufferDescriptor> list)
- {
- foreach (KBufferDescriptor descriptor in list)
- {
- KernelResult result = memoryManager.UnmapIpcRestorePermission(
- descriptor.ClientAddress,
- descriptor.Size,
- descriptor.State);
- if (result != KernelResult.Success)
- {
- return result;
- }
- }
- return KernelResult.Success;
- }
- }
- }
|