Example #1
0
        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);
        }
Example #2
0
        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));
        }
Example #3
0
        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));
        }
Example #4
0
        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);
        }
Example #5
0
        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));
        }
Example #6
0
        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);
        }
Example #7
0
        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));
        }
Example #8
0
        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);
        }
Example #9
0
        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);
        }
Example #10
0
 public KernelResult InitializeForUser(ReadOnlySpan <int> capabilities, KPageTableBase memoryManager)
 {
     return(Parse(capabilities, memoryManager));
 }
Example #11
0
        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);
        }