private ResultCode MapNro(KProcess process, NroInfo info, out ulong nroMappedAddress) { KPageTableBase memMgr = process.MemoryManager; int retryCount = 0; nroMappedAddress = 0; while (retryCount++ < MaxMapRetries) { ResultCode result = MapCodeMemoryInProcess(process, info.NroAddress, info.NroSize, out nroMappedAddress); if (result != ResultCode.Success) { return(result); } if (info.BssSize > 0) { KernelResult bssMappingResult = memMgr.MapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize); if (bssMappingResult == KernelResult.InvalidMemState) { memMgr.UnmapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize); memMgr.UnmapProcessCodeMemory(nroMappedAddress, info.NroAddress, info.NroSize); continue; } else if (bssMappingResult != KernelResult.Success) { memMgr.UnmapProcessCodeMemory(nroMappedAddress + info.NroSize, info.BssAddress, info.BssSize); memMgr.UnmapProcessCodeMemory(nroMappedAddress, info.NroAddress, info.NroSize); return((ResultCode)bssMappingResult); } } if (CanAddGuardRegionsInProcess(process, nroMappedAddress, info.TotalSize)) { return(ResultCode.Success); } } return(ResultCode.InsufficientAddressSpace); }
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)); }
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)); }
public KernelResult MapIntoProcess( KPageTableBase memoryManager, ulong address, ulong size, KProcess process, KMemoryPermission permission) { if (_storage == null) { throw new NotImplementedException(); } ulong pagesCountRounded = BitUtils.DivRoundUp(size, KPageTableBase.PageSize); var pageList = _storage.GetPageList(); if (pageList.GetPagesCount() != pagesCountRounded) { return(KernelResult.InvalidSize); } if (permission != Permission || _isMapped) { return(KernelResult.InvalidState); } MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory; KernelResult result = memoryManager.MapPages(address, pageList, state, KMemoryPermission.ReadAndWrite); if (result == KernelResult.Success) { _isMapped = true; if (!memoryManager.SupportsMemoryAliasing) { _storage.Borrow(process, address); } } return(result); }
public KernelResult UnmapFromProcess( KPageTableBase memoryManager, ulong address, ulong size, KProcess process) { ulong pagesCountRounded = BitUtils.DivRoundUp(size, KPageTableBase.PageSize); var pageList = _storage.GetPageList(); ulong pagesCount = pageList.GetPagesCount(); if (pagesCount != pagesCountRounded) { return(KernelResult.InvalidSize); } var ranges = _storage.GetRanges(); return(memoryManager.UnmapPages(address, pagesCount, ranges, MemoryState.SharedMemory)); }
public KernelResult UnmapFromProcess( KPageTableBase memoryManager, ulong address, ulong size, KProcess process) { if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize)) { return(KernelResult.InvalidSize); } MemoryState state = Permission == KMemoryPermission.None ? MemoryState.TransferMemoryIsolated : MemoryState.TransferMemory; KernelResult result = memoryManager.UnmapPages(address, _pageList, state); if (result == KernelResult.Success) { _isMapped = false; } return(result); }
public KernelResult MapIntoProcess( KPageTableBase memoryManager, ulong address, ulong size, KProcess process, KMemoryPermission permission) { if (_pageList.GetPagesCount() != BitUtils.DivRoundUp(size, KPageTableBase.PageSize)) { return(KernelResult.InvalidSize); } KMemoryPermission expectedPermission = process.Pid == _ownerPid ? _ownerPermission : _userPermission; if (permission != expectedPermission) { return(KernelResult.InvalidPermission); } return(memoryManager.MapPages(address, _pageList, MemoryState.SharedMemory, permission)); }
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); }
private KernelResult Parse(ReadOnlySpan <int> capabilities, KPageTableBase memoryManager) { int mask0 = 0; int mask1 = 0; for (int index = 0; index < capabilities.Length; index++) { int cap = capabilities[index]; if (((cap + 1) & ~cap) != 0x40) { KernelResult result = ParseCapability(cap, ref mask0, ref mask1, memoryManager); if (result != KernelResult.Success) { return(result); } } else { if ((uint)index + 1 >= capabilities.Length) { return(KernelResult.InvalidCombination); } int prevCap = cap; cap = capabilities[++index]; if (((cap + 1) & ~cap) != 0x40) { return(KernelResult.InvalidCombination); } if ((cap & 0x78000000) != 0) { return(KernelResult.MaximumExceeded); } if ((cap & 0x7ffff80) == 0) { return(KernelResult.InvalidSize); } long address = ((long)(uint)prevCap << 5) & 0xffffff000; long size = ((long)(uint)cap << 5) & 0xfffff000; if (((ulong)(address + size - 1) >> 36) != 0) { return(KernelResult.InvalidAddress); } KMemoryPermission perm = (prevCap >> 31) != 0 ? KMemoryPermission.Read : KMemoryPermission.ReadAndWrite; KernelResult result; if ((cap >> 31) != 0) { result = memoryManager.MapNormalMemory(address, size, perm); } else { result = memoryManager.MapIoMemory(address, size, perm); } if (result != KernelResult.Success) { return(result); } } } return(KernelResult.Success); }
public KernelResult InitializeForUser(ReadOnlySpan <int> capabilities, KPageTableBase memoryManager) { return(Parse(capabilities, memoryManager)); }
private KernelResult ParseCapability(int cap, ref int mask0, ref int mask1, KPageTableBase memoryManager) { int code = (cap + 1) & ~cap; if (code == 1) { return(KernelResult.InvalidCapability); } else if (code == 0) { return(KernelResult.Success); } int codeMask = 1 << (32 - BitUtils.CountLeadingZeros32(code + 1)); // Check if the property was already set. if (((mask0 & codeMask) & 0x1e008) != 0) { return(KernelResult.InvalidCombination); } mask0 |= codeMask; switch (code) { case 8: { if (AllowedCpuCoresMask != 0 || AllowedThreadPriosMask != 0) { return(KernelResult.InvalidCapability); } int lowestCpuCore = (cap >> 16) & 0xff; int highestCpuCore = (cap >> 24) & 0xff; if (lowestCpuCore > highestCpuCore) { return(KernelResult.InvalidCombination); } int highestThreadPrio = (cap >> 4) & 0x3f; int lowestThreadPrio = (cap >> 10) & 0x3f; if (lowestThreadPrio > highestThreadPrio) { return(KernelResult.InvalidCombination); } if (highestCpuCore >= KScheduler.CpuCoresCount) { return(KernelResult.InvalidCpuCore); } AllowedCpuCoresMask = GetMaskFromMinMax(lowestCpuCore, highestCpuCore); AllowedThreadPriosMask = GetMaskFromMinMax(lowestThreadPrio, highestThreadPrio); break; } case 0x10: { int slot = (cap >> 29) & 7; int svcSlotMask = 1 << slot; if ((mask1 & svcSlotMask) != 0) { return(KernelResult.InvalidCombination); } mask1 |= svcSlotMask; int svcMask = (cap >> 5) & 0xffffff; int baseSvc = slot * 24; for (int index = 0; index < 24; index++) { if (((svcMask >> index) & 1) == 0) { continue; } int svcId = baseSvc + index; if (svcId > 0x7f) { return(KernelResult.MaximumExceeded); } SvcAccessMask[svcId / 8] |= (byte)(1 << (svcId & 7)); } break; } case 0x80: { long address = ((long)(uint)cap << 4) & 0xffffff000; memoryManager.MapIoMemory(address, KPageTableBase.PageSize, KMemoryPermission.ReadAndWrite); break; } case 0x800: { // TODO: GIC distributor check. int irq0 = (cap >> 12) & 0x3ff; int irq1 = (cap >> 22) & 0x3ff; if (irq0 != 0x3ff) { IrqAccessMask[irq0 / 8] |= (byte)(1 << (irq0 & 7)); } if (irq1 != 0x3ff) { IrqAccessMask[irq1 / 8] |= (byte)(1 << (irq1 & 7)); } break; } case 0x2000: { int applicationType = cap >> 14; if ((uint)applicationType > 7) { return(KernelResult.ReservedValue); } ApplicationType = applicationType; break; } case 0x4000: { // Note: This check is bugged on kernel too, we are just replicating the bug here. if ((KernelReleaseVersion >> 17) != 0 || cap < 0x80000) { return(KernelResult.ReservedValue); } KernelReleaseVersion = cap; break; } case 0x8000: { int handleTableSize = cap >> 26; if ((uint)handleTableSize > 0x3ff) { return(KernelResult.ReservedValue); } HandleTableSize = handleTableSize; break; } case 0x10000: { int debuggingFlags = cap >> 19; if ((uint)debuggingFlags > 3) { return(KernelResult.ReservedValue); } DebuggingFlags &= ~3; DebuggingFlags |= debuggingFlags; break; } default: return(KernelResult.InvalidCapability); } return(KernelResult.Success); }