Exemple #1
0
        private void FreePages(ulong Address, ulong PagesCount)
        {
            ulong EndAddr = Address + PagesCount * KMemoryManager.PageSize;

            int BlockIndex = BlockOrdersCount - 1;

            ulong AddressRounded   = 0;
            ulong EndAddrTruncated = 0;

            for (; BlockIndex >= 0; BlockIndex--)
            {
                KMemoryRegionBlock AllocInfo = Blocks[BlockIndex];

                int BlockSize = 1 << AllocInfo.Order;

                AddressRounded   = BitUtils.AlignUp(Address, BlockSize);
                EndAddrTruncated = BitUtils.AlignDown(EndAddr, BlockSize);

                if (AddressRounded < EndAddrTruncated)
                {
                    break;
                }
            }

            void FreeRegion(ulong CurrAddress)
            {
                for (int CurrBlockIndex = BlockIndex;
                     CurrBlockIndex < BlockOrdersCount && CurrAddress != 0;
                     CurrBlockIndex++)
                {
                    KMemoryRegionBlock Block = Blocks[CurrBlockIndex];

                    Block.FreeCount++;

                    ulong FreedBlocks = (CurrAddress - Block.StartAligned) >> Block.Order;

                    int Index = (int)FreedBlocks;

                    for (int Level = Block.MaxLevel - 1; Level >= 0; Level--, Index /= 64)
                    {
                        long Mask = Block.Masks[Level][Index / 64];

                        Block.Masks[Level][Index / 64] = Mask | (1L << (Index & 63));

                        if (Mask != 0)
                        {
                            break;
                        }
                    }

                    int BlockSizeDelta = 1 << (Block.NextOrder - Block.Order);

                    int FreedBlocksTruncated = BitUtils.AlignDown((int)FreedBlocks, BlockSizeDelta);

                    if (!Block.TryCoalesce(FreedBlocksTruncated, BlockSizeDelta))
                    {
                        break;
                    }

                    CurrAddress = Block.StartAligned + ((ulong)FreedBlocksTruncated << Block.Order);
                }
            }

            //Free inside aligned region.
            ulong BaseAddress = AddressRounded;

            while (BaseAddress < EndAddrTruncated)
            {
                ulong BlockSize = 1UL << Blocks[BlockIndex].Order;

                FreeRegion(BaseAddress);

                BaseAddress += BlockSize;
            }

            int NextBlockIndex = BlockIndex - 1;

            //Free region between Address and aligned region start.
            BaseAddress = AddressRounded;

            for (BlockIndex = NextBlockIndex; BlockIndex >= 0; BlockIndex--)
            {
                ulong BlockSize = 1UL << Blocks[BlockIndex].Order;

                while (BaseAddress - BlockSize >= Address)
                {
                    BaseAddress -= BlockSize;

                    FreeRegion(BaseAddress);
                }
            }

            //Free region between aligned region end and End Address.
            BaseAddress = EndAddrTruncated;

            for (BlockIndex = NextBlockIndex; BlockIndex >= 0; BlockIndex--)
            {
                ulong BlockSize = 1UL << Blocks[BlockIndex].Order;

                while (BaseAddress + BlockSize <= EndAddr)
                {
                    FreeRegion(BaseAddress);

                    BaseAddress += BlockSize;
                }
            }
        }
Exemple #2
0
        private void FreePages(ulong address, ulong pagesCount)
        {
            ulong endAddr = address + pagesCount * KMemoryManager.PageSize;

            int blockIndex = _blockOrdersCount - 1;

            ulong addressRounded   = 0;
            ulong endAddrTruncated = 0;

            for (; blockIndex >= 0; blockIndex--)
            {
                KMemoryRegionBlock allocInfo = _blocks[blockIndex];

                int blockSize = 1 << allocInfo.Order;

                addressRounded   = BitUtils.AlignUp(address, blockSize);
                endAddrTruncated = BitUtils.AlignDown(endAddr, blockSize);

                if (addressRounded < endAddrTruncated)
                {
                    break;
                }
            }

            void FreeRegion(ulong currAddress)
            {
                for (int currBlockIndex = blockIndex;
                     currBlockIndex < _blockOrdersCount && currAddress != 0;
                     currBlockIndex++)
                {
                    KMemoryRegionBlock block = _blocks[currBlockIndex];

                    block.FreeCount++;

                    ulong freedBlocks = (currAddress - block.StartAligned) >> block.Order;

                    int index = (int)freedBlocks;

                    for (int level = block.MaxLevel - 1; level >= 0; level--, index /= 64)
                    {
                        long mask = block.Masks[level][index / 64];

                        block.Masks[level][index / 64] = mask | (1L << (index & 63));

                        if (mask != 0)
                        {
                            break;
                        }
                    }

                    int blockSizeDelta = 1 << (block.NextOrder - block.Order);

                    int freedBlocksTruncated = BitUtils.AlignDown((int)freedBlocks, blockSizeDelta);

                    if (!block.TryCoalesce(freedBlocksTruncated, blockSizeDelta))
                    {
                        break;
                    }

                    currAddress = block.StartAligned + ((ulong)freedBlocksTruncated << block.Order);
                }
            }

            //Free inside aligned region.
            ulong baseAddress = addressRounded;

            while (baseAddress < endAddrTruncated)
            {
                ulong blockSize = 1UL << _blocks[blockIndex].Order;

                FreeRegion(baseAddress);

                baseAddress += blockSize;
            }

            int nextBlockIndex = blockIndex - 1;

            //Free region between Address and aligned region start.
            baseAddress = addressRounded;

            for (blockIndex = nextBlockIndex; blockIndex >= 0; blockIndex--)
            {
                ulong blockSize = 1UL << _blocks[blockIndex].Order;

                while (baseAddress - blockSize >= address)
                {
                    baseAddress -= blockSize;

                    FreeRegion(baseAddress);
                }
            }

            //Free region between aligned region end and End Address.
            baseAddress = endAddrTruncated;

            for (blockIndex = nextBlockIndex; blockIndex >= 0; blockIndex--)
            {
                ulong blockSize = 1UL << _blocks[blockIndex].Order;

                while (baseAddress + blockSize <= endAddr)
                {
                    FreeRegion(baseAddress);

                    baseAddress += blockSize;
                }
            }
        }
Exemple #3
0
        public ResultCode Initialize(ref AudioRendererConfiguration parameter, uint processHandle, CpuAddress workBuffer, ulong workBufferSize, int sessionId, ulong appletResourceId, IVirtualMemoryManager memoryManager)
        {
            if (!BehaviourContext.CheckValidRevision(parameter.Revision))
            {
                return(ResultCode.OperationFailed);
            }

            if (GetWorkBufferSize(ref parameter) > workBufferSize)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            Debug.Assert(parameter.RenderingDevice == AudioRendererRenderingDevice.Dsp && parameter.ExecutionMode == AudioRendererExecutionMode.Auto);

            Logger.Info?.Print(LogClass.AudioRenderer, $"Initializing with REV{BehaviourContext.GetRevisionNumber(parameter.Revision)}");

            _behaviourContext.SetUserRevision(parameter.Revision);

            _sampleRate           = parameter.SampleRate;
            _sampleCount          = parameter.SampleCount;
            _mixBufferCount       = parameter.MixBufferCount;
            _voiceChannelCountMax = Constants.VoiceChannelCountMax;
            _upsamplerCount       = parameter.SinkCount + parameter.SubMixBufferCount;
            _appletResourceId     = appletResourceId;
            _memoryPoolCount      = parameter.EffectCount + parameter.VoiceCount * Constants.VoiceWaveBufferCount;
            _executionMode        = parameter.ExecutionMode;
            _sessionId            = sessionId;
            MemoryManager         = memoryManager;

            if (memoryManager is IRefCounted rc)
            {
                rc.IncrementReferenceCount();
            }

            WorkBufferAllocator workBufferAllocator;

            _workBufferRegion = MemoryManager.GetWritableRegion(workBuffer, (int)workBufferSize);
            _workBufferRegion.Memory.Span.Fill(0);
            _workBufferMemoryPin = _workBufferRegion.Memory.Pin();

            workBufferAllocator = new WorkBufferAllocator(_workBufferRegion.Memory);

            PoolMapper poolMapper = new PoolMapper(processHandle, false);

            poolMapper.InitializeSystemPool(ref _dspMemoryPoolState, workBuffer, workBufferSize);

            _mixBuffer = workBufferAllocator.Allocate <float>(_sampleCount * (_voiceChannelCountMax + _mixBufferCount), 0x10);

            if (_mixBuffer.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            Memory <float> upSamplerWorkBuffer = workBufferAllocator.Allocate <float>(Constants.TargetSampleCount * (_voiceChannelCountMax + _mixBufferCount) * _upsamplerCount, 0x10);

            if (upSamplerWorkBuffer.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            _depopBuffer = workBufferAllocator.Allocate <float>((ulong)BitUtils.AlignUp(parameter.MixBufferCount, Constants.BufferAlignment), Constants.BufferAlignment);

            if (_depopBuffer.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            // Invalidate DSP cache on what was currently allocated with workBuffer.
            AudioProcessorMemoryManager.InvalidateDspCache(_dspMemoryPoolState.Translate(workBuffer, workBufferAllocator.Offset), workBufferAllocator.Offset);

            Debug.Assert((workBufferAllocator.Offset % Constants.BufferAlignment) == 0);

            Memory <VoiceState> voices = workBufferAllocator.Allocate <VoiceState>(parameter.VoiceCount, VoiceState.Alignment);

            if (voices.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            foreach (ref VoiceState voice in voices.Span)
            {
                voice.Initialize();
            }

            // A pain to handle as we can't have VoiceState*, use indices to be a bit more safe
            Memory <int> sortedVoices = workBufferAllocator.Allocate <int>(parameter.VoiceCount, 0x10);

            if (sortedVoices.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            // Clear memory (use -1 as it's an invalid index)
            sortedVoices.Span.Fill(-1);

            Memory <VoiceChannelResource> voiceChannelResources = workBufferAllocator.Allocate <VoiceChannelResource>(parameter.VoiceCount, VoiceChannelResource.Alignment);

            if (voiceChannelResources.IsEmpty)
            {
                return(ResultCode.WorkBufferTooSmall);
            }

            for (uint id = 0; id < voiceChannelResources.Length; id++)
            {
                ref VoiceChannelResource voiceChannelResource = ref voiceChannelResources.Span[(int)id];

                voiceChannelResource.Id     = id;
                voiceChannelResource.IsUsed = false;
            }
Exemple #4
0
        public static bool LoadNsos(KernelContext context, Npdm metaData, byte[] arguments = null, params IExecutable[] executables)
        {
            ulong argsStart = 0;
            uint  argsSize  = 0;
            ulong codeStart = metaData.Is64Bit ? 0x8000000UL : 0x200000UL;
            uint  codeSize  = 0;

            ulong[] nsoBase = new ulong[executables.Length];

            for (int index = 0; index < executables.Length; index++)
            {
                IExecutable nso = executables[index];

                uint textEnd = nso.TextOffset + (uint)nso.Text.Length;
                uint roEnd   = nso.RoOffset + (uint)nso.Ro.Length;
                uint dataEnd = nso.DataOffset + (uint)nso.Data.Length + nso.BssSize;

                uint nsoSize = textEnd;

                if (nsoSize < roEnd)
                {
                    nsoSize = roEnd;
                }

                if (nsoSize < dataEnd)
                {
                    nsoSize = dataEnd;
                }

                nsoSize = BitUtils.AlignUp(nsoSize, KMemoryManager.PageSize);

                nsoBase[index] = codeStart + (ulong)codeSize;

                codeSize += nsoSize;

                if (arguments != null && argsSize == 0)
                {
                    argsStart = (ulong)codeSize;

                    argsSize = (uint)BitUtils.AlignDown(arguments.Length * 2 + ArgsTotalSize - 1, KMemoryManager.PageSize);

                    codeSize += argsSize;
                }
            }

            PtcProfiler.StaticCodeStart = codeStart;
            PtcProfiler.StaticCodeSize  = (ulong)codeSize;

            int codePagesCount = (int)(codeSize / KMemoryManager.PageSize);

            int personalMmHeapPagesCount = metaData.PersonalMmHeapSize / KMemoryManager.PageSize;

            ProcessCreationInfo creationInfo = new ProcessCreationInfo(
                metaData.TitleName,
                metaData.Version,
                metaData.Aci0.TitleId,
                codeStart,
                codePagesCount,
                (ProcessCreationFlags)metaData.ProcessFlags | ProcessCreationFlags.IsApplication,
                0,
                personalMmHeapPagesCount);

            KernelResult result;

            KResourceLimit resourceLimit = new KResourceLimit(context);

            long applicationRgSize = (long)context.MemoryRegions[(int)MemoryRegion.Application].Size;

            result  = resourceLimit.SetLimitValue(LimitableResource.Memory, applicationRgSize);
            result |= resourceLimit.SetLimitValue(LimitableResource.Thread, 608);
            result |= resourceLimit.SetLimitValue(LimitableResource.Event, 700);
            result |= resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
            result |= resourceLimit.SetLimitValue(LimitableResource.Session, 894);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process initialization failed setting resource limit values.");

                return(false);
            }

            KProcess process = new KProcess(context);

            MemoryRegion memoryRegion = (MemoryRegion)((metaData.Acid.Flags >> 2) & 0xf);

            if (memoryRegion > MemoryRegion.NvServices)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process initialization failed due to invalid ACID flags.");

                return(false);
            }

            var processContextFactory = new ArmProcessContextFactory();

            result = process.Initialize(
                creationInfo,
                metaData.Aci0.KernelAccessControl.Capabilities,
                resourceLimit,
                memoryRegion,
                processContextFactory);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            for (int index = 0; index < executables.Length; index++)
            {
                Logger.Info?.Print(LogClass.Loader, $"Loading image {index} at 0x{nsoBase[index]:x16}...");

                result = LoadIntoMemory(process, executables[index], nsoBase[index]);

                if (result != KernelResult.Success)
                {
                    Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                    return(false);
                }
            }

            process.DefaultCpuCore = metaData.DefaultCpuId;

            result = process.Start(metaData.MainThreadPriority, (ulong)metaData.MainThreadStackSize);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");

                return(false);
            }

            context.Processes.TryAdd(process.Pid, process);

            return(true);
        }
Exemple #5
0
        public void PrepareForReturn()
        {
            if (Config.Stage == ShaderStage.Fragment)
            {
                if (Config.OmapDepth)
                {
                    Operand dest = Attribute(AttributeConsts.FragmentOutputDepth);

                    Operand src = Register(Config.GetDepthRegister(), RegisterType.Gpr);

                    this.Copy(dest, src);
                }

                int regIndex = 0;

                for (int rtIndex = 0; rtIndex < 8; rtIndex++)
                {
                    OmapTarget target = Config.OmapTargets[rtIndex];

                    for (int component = 0; component < 4; component++)
                    {
                        if (!target.ComponentEnabled(component))
                        {
                            continue;
                        }

                        int fragmentOutputColorAttr = AttributeConsts.FragmentOutputColorBase + rtIndex * 16;

                        Operand src = Register(regIndex, RegisterType.Gpr);

                        // Perform B <-> R swap if needed, for BGRA formats (not supported on OpenGL).
                        if (component == 0 || component == 2)
                        {
                            Operand isBgra = Attribute(AttributeConsts.FragmentOutputIsBgraBase + rtIndex * 4);

                            Operand lblIsBgra = Label();
                            Operand lblEnd    = Label();

                            this.BranchIfTrue(lblIsBgra, isBgra);

                            this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
                            this.Branch(lblEnd);

                            MarkLabel(lblIsBgra);

                            this.Copy(Attribute(fragmentOutputColorAttr + (2 - component) * 4), src);

                            MarkLabel(lblEnd);
                        }
                        else
                        {
                            this.Copy(Attribute(fragmentOutputColorAttr + component * 4), src);
                        }

                        regIndex++;
                    }

                    regIndex = BitUtils.AlignUp(regIndex, 4);
                }
            }
        }
Exemple #6
0
        public static SizeInfo GetBlockLinearTextureSize(
            int width,
            int height,
            int depth,
            int levels,
            int layers,
            int blockWidth,
            int blockHeight,
            int bytesPerPixel,
            int gobBlocksInY,
            int gobBlocksInZ,
            int gobBlocksInTileX,
            int gpuLayerSize = 0)
        {
            bool is3D = depth > 1;

            int layerSize = 0;

            int[] allOffsets = new int[is3D ? Calculate3DOffsetCount(levels, depth) : levels * layers * depth];
            int[] mipOffsets = new int[levels];
            int[] sliceSizes = new int[levels];
            int[] levelSizes = new int[levels];

            int mipGobBlocksInY = gobBlocksInY;
            int mipGobBlocksInZ = gobBlocksInZ;

            int gobWidth  = (GobStride / bytesPerPixel) * gobBlocksInTileX;
            int gobHeight = gobBlocksInY * GobHeight;

            int depthLevelOffset = 0;

            for (int level = 0; level < levels; level++)
            {
                int w = Math.Max(1, width >> level);
                int h = Math.Max(1, height >> level);
                int d = Math.Max(1, depth >> level);

                w = BitUtils.DivRoundUp(w, blockWidth);
                h = BitUtils.DivRoundUp(h, blockHeight);

                while (h <= (mipGobBlocksInY >> 1) * GobHeight && mipGobBlocksInY != 1)
                {
                    mipGobBlocksInY >>= 1;
                }

                while (d <= (mipGobBlocksInZ >> 1) && mipGobBlocksInZ != 1)
                {
                    mipGobBlocksInZ >>= 1;
                }

                int widthInGobs = BitUtils.DivRoundUp(w * bytesPerPixel, GobStride);

                int alignment = gobBlocksInTileX;

                if (d < gobBlocksInZ || w <= gobWidth || h <= gobHeight)
                {
                    alignment = 1;
                }

                widthInGobs = BitUtils.AlignUp(widthInGobs, alignment);

                int totalBlocksOfGobsInZ = BitUtils.DivRoundUp(d, mipGobBlocksInZ);
                int totalBlocksOfGobsInY = BitUtils.DivRoundUp(BitUtils.DivRoundUp(h, GobHeight), mipGobBlocksInY);

                int robSize = widthInGobs * mipGobBlocksInY * mipGobBlocksInZ * GobSize;

                if (is3D)
                {
                    int gobSize = mipGobBlocksInY * GobSize;

                    int sliceSize = totalBlocksOfGobsInY * widthInGobs * gobSize;

                    int baseOffset = layerSize;

                    int mask = gobBlocksInZ - 1;

                    for (int z = 0; z < d; z++)
                    {
                        int zLow  = z & mask;
                        int zHigh = z & ~mask;

                        allOffsets[z + depthLevelOffset] = baseOffset + zLow * gobSize + zHigh * sliceSize;
                    }
                }

                mipOffsets[level] = layerSize;
                sliceSizes[level] = totalBlocksOfGobsInY * robSize;
                levelSizes[level] = totalBlocksOfGobsInZ * sliceSizes[level];

                layerSize += levelSizes[level];

                depthLevelOffset += d;
            }

            if (layers > 1)
            {
                layerSize = AlignLayerSize(
                    layerSize,
                    height,
                    depth,
                    blockHeight,
                    gobBlocksInY,
                    gobBlocksInZ,
                    gobBlocksInTileX);
            }

            int totalSize;

            if (layerSize < gpuLayerSize)
            {
                totalSize = (layers - 1) * gpuLayerSize + layerSize;
                layerSize = gpuLayerSize;
            }
            else
            {
                totalSize = layerSize * layers;
            }

            if (!is3D)
            {
                for (int layer = 0; layer < layers; layer++)
                {
                    int baseIndex  = layer * levels;
                    int baseOffset = layer * layerSize;

                    for (int level = 0; level < levels; level++)
                    {
                        allOffsets[baseIndex + level] = baseOffset + mipOffsets[level];
                    }
                }
            }

            return(new SizeInfo(mipOffsets, allOffsets, sliceSizes, levelSizes, depth, levels, layerSize, totalSize, is3D));
        }
 public readonly int GetMipStride(int level)
 {
     return(BitUtils.AlignUp(GetLevelWidth(level) * BytesPerPixel, 4));
 }
Exemple #8
0
        public static void ConvertLinearToBlockLinear(
            Span <byte> dst,
            int width,
            int height,
            int stride,
            int bytesPerPixel,
            int gobBlocksInY,
            ReadOnlySpan <byte> data)
        {
            int gobHeight = gobBlocksInY * GobHeight;

            int strideTrunc   = BitUtils.AlignDown(width * bytesPerPixel, 16);
            int strideTrunc64 = BitUtils.AlignDown(width * bytesPerPixel, 64);

            int xStart = strideTrunc / bytesPerPixel;

            int inStrideGap = stride - width * bytesPerPixel;

            int alignment = GobStride / bytesPerPixel;

            int wAligned = BitUtils.AlignUp(width, alignment);

            BlockLinearLayout layoutConverter = new BlockLinearLayout(wAligned, height, gobBlocksInY, 1, bytesPerPixel);

            unsafe bool Convert <T>(Span <byte> output, ReadOnlySpan <byte> data) where T : unmanaged
            {
                fixed(byte *outputPtr = output, dataPtr = data)
                {
                    byte *inPtr = dataPtr;

                    for (int y = 0; y < height; y++)
                    {
                        layoutConverter.SetY(y);

                        for (int x = 0; x < strideTrunc64; x += 64, inPtr += 64)
                        {
                            byte *offset  = outputPtr + layoutConverter.GetOffsetWithLineOffset64(x);
                            byte *offset2 = offset + 0x20;
                            byte *offset3 = offset + 0x100;
                            byte *offset4 = offset + 0x120;

                            Vector128 <byte> value  = *(Vector128 <byte> *)inPtr;
                            Vector128 <byte> value2 = *(Vector128 <byte> *)(inPtr + 16);
                            Vector128 <byte> value3 = *(Vector128 <byte> *)(inPtr + 32);
                            Vector128 <byte> value4 = *(Vector128 <byte> *)(inPtr + 48);

                            *(Vector128 <byte> *)offset  = value;
                            *(Vector128 <byte> *)offset2 = value2;
                            *(Vector128 <byte> *)offset3 = value3;
                            *(Vector128 <byte> *)offset4 = value4;
                        }

                        for (int x = strideTrunc64; x < strideTrunc; x += 16, inPtr += 16)
                        {
                            byte *offset = outputPtr + layoutConverter.GetOffsetWithLineOffset16(x);

                            *(Vector128 <byte> *)offset = *(Vector128 <byte> *)inPtr;
                        }

                        for (int x = xStart; x < width; x++, inPtr += bytesPerPixel)
                        {
                            byte *offset = outputPtr + layoutConverter.GetOffset(x);

                            *(T *)offset = *(T *)inPtr;
                        }

                        inPtr += inStrideGap;
                    }
                }

                return(true);
            }

            bool _ = bytesPerPixel switch
            {
                1 => Convert <byte>(dst, data),
                2 => Convert <ushort>(dst, data),
                4 => Convert <uint>(dst, data),
                8 => Convert <ulong>(dst, data),
                12 => Convert <Bpp12Pixel>(dst, data),
                16 => Convert <Vector128 <byte> >(dst, data),
                _ => throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format.")
            };
        }
Exemple #9
0
        public static Span <byte> ConvertBlockLinearToLinear(
            int width,
            int height,
            int depth,
            int sliceDepth,
            int levels,
            int layers,
            int blockWidth,
            int blockHeight,
            int bytesPerPixel,
            int gobBlocksInY,
            int gobBlocksInZ,
            int gobBlocksInTileX,
            SizeInfo sizeInfo,
            ReadOnlySpan <byte> data)
        {
            int outSize = GetTextureSize(
                width,
                height,
                depth,
                levels,
                layers,
                blockWidth,
                blockHeight,
                bytesPerPixel);

            Span <byte> output = new byte[outSize];

            int outOffs = 0;

            int mipGobBlocksInY = gobBlocksInY;
            int mipGobBlocksInZ = gobBlocksInZ;

            int gobWidth  = (GobStride / bytesPerPixel) * gobBlocksInTileX;
            int gobHeight = gobBlocksInY * GobHeight;

            for (int level = 0; level < levels; level++)
            {
                int w = Math.Max(1, width >> level);
                int h = Math.Max(1, height >> level);
                int d = Math.Max(1, depth >> level);

                w = BitUtils.DivRoundUp(w, blockWidth);
                h = BitUtils.DivRoundUp(h, blockHeight);

                while (h <= (mipGobBlocksInY >> 1) * GobHeight && mipGobBlocksInY != 1)
                {
                    mipGobBlocksInY >>= 1;
                }

                while (d <= (mipGobBlocksInZ >> 1) && mipGobBlocksInZ != 1)
                {
                    mipGobBlocksInZ >>= 1;
                }

                int strideTrunc   = BitUtils.AlignDown(w * bytesPerPixel, 16);
                int strideTrunc64 = BitUtils.AlignDown(w * bytesPerPixel, 64);

                int xStart = strideTrunc / bytesPerPixel;

                int stride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);

                int outStrideGap = stride - w * bytesPerPixel;

                int alignment = gobWidth;

                if (d < gobBlocksInZ || w <= gobWidth || h <= gobHeight)
                {
                    alignment = GobStride / bytesPerPixel;
                }

                int wAligned = BitUtils.AlignUp(w, alignment);

                BlockLinearLayout layoutConverter = new BlockLinearLayout(
                    wAligned,
                    h,
                    mipGobBlocksInY,
                    mipGobBlocksInZ,
                    bytesPerPixel);

                int sd = Math.Max(1, sliceDepth >> level);

                unsafe bool Convert <T>(Span <byte> output, ReadOnlySpan <byte> data) where T : unmanaged
                {
                    fixed(byte *outputPtr = output, dataPtr = data)
                    {
                        byte *outPtr = outputPtr + outOffs;

                        for (int layer = 0; layer < layers; layer++)
                        {
                            byte *inBaseOffset = dataPtr + (layer * sizeInfo.LayerSize + sizeInfo.GetMipOffset(level));

                            for (int z = 0; z < sd; z++)
                            {
                                layoutConverter.SetZ(z);
                                for (int y = 0; y < h; y++)
                                {
                                    layoutConverter.SetY(y);

                                    for (int x = 0; x < strideTrunc64; x += 64, outPtr += 64)
                                    {
                                        byte *offset  = inBaseOffset + layoutConverter.GetOffsetWithLineOffset64(x);
                                        byte *offset2 = offset + 0x20;
                                        byte *offset3 = offset + 0x100;
                                        byte *offset4 = offset + 0x120;

                                        Vector128 <byte> value  = *(Vector128 <byte> *)offset;
                                        Vector128 <byte> value2 = *(Vector128 <byte> *)offset2;
                                        Vector128 <byte> value3 = *(Vector128 <byte> *)offset3;
                                        Vector128 <byte> value4 = *(Vector128 <byte> *)offset4;

                                        *(Vector128 <byte> *)outPtr        = value;
                                        *(Vector128 <byte> *)(outPtr + 16) = value2;
                                        *(Vector128 <byte> *)(outPtr + 32) = value3;
                                        *(Vector128 <byte> *)(outPtr + 48) = value4;
                                    }

                                    for (int x = strideTrunc64; x < strideTrunc; x += 16, outPtr += 16)
                                    {
                                        byte *offset = inBaseOffset + layoutConverter.GetOffsetWithLineOffset16(x);

                                        *(Vector128 <byte> *)outPtr = *(Vector128 <byte> *)offset;
                                    }

                                    for (int x = xStart; x < w; x++, outPtr += bytesPerPixel)
                                    {
                                        byte *offset = inBaseOffset + layoutConverter.GetOffset(x);

                                        *(T *)outPtr = *(T *)offset;
                                    }

                                    outPtr += outStrideGap;
                                }
                            }
                        }
                        outOffs += stride * h * d * layers;
                    }

                    return(true);
                }

                bool _ = bytesPerPixel switch
                {
                    1 => Convert <byte>(output, data),
                    2 => Convert <ushort>(output, data),
                    4 => Convert <uint>(output, data),
                    8 => Convert <ulong>(output, data),
                    12 => Convert <Bpp12Pixel>(output, data),
                    16 => Convert <Vector128 <byte> >(output, data),
                    _ => throw new NotSupportedException($"Unable to convert ${bytesPerPixel} bpp pixel format.")
                };
            }
            return(output);
        }
Exemple #10
0
        /// <summary>
        /// Determines if a given texture is "safe" for upscaling from its info.
        /// Note that this is different from being compatible - this elilinates targets that would have detrimental effects when scaled.
        /// </summary>
        /// <param name="info">The texture info to check</param>
        /// <returns>True if safe</returns>
        private static bool UpscaleSafeMode(TextureInfo info)
        {
            // While upscaling works for all targets defined by IsUpscaleCompatible, we additionally blacklist targets here that
            // may have undesirable results (upscaling blur textures) or simply waste GPU resources (upscaling texture atlas).

            if (info.Levels > 3)
            {
                // Textures with more than 3 levels are likely to be game textures, rather than render textures.
                // Small textures with full mips are likely to be removed by the next check.
                return(false);
            }

            if (info.Width < 8 || info.Height < 8)
            {
                // Discount textures with small dimensions.
                return(false);
            }

            int widthAlignment = (info.IsLinear ? Constants.StrideAlignment : Constants.GobAlignment) / info.FormatInfo.BytesPerPixel;

            if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1))
            {
                // Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas)
                // Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height.

                bool possiblySquare = BitUtils.AlignUp(info.Width, widthAlignment) == BitUtils.AlignUp(info.Height, widthAlignment);

                if (possiblySquare)
                {
                    return(false);
                }
            }

            if (info.Height < 360)
            {
                int aspectWidth    = (int)MathF.Ceiling((info.Height / 9f) * 16f);
                int aspectMaxWidth = BitUtils.AlignUp(aspectWidth, widthAlignment);
                int aspectMinWidth = BitUtils.AlignDown(aspectWidth, widthAlignment);

                if (info.Width >= aspectMinWidth && info.Width <= aspectMaxWidth && info.Height < 360)
                {
                    // Targets that are roughly 16:9 can only be rescaled if they're equal to or above 360p. (excludes blur and bloom textures)
                    return(false);
                }
            }

            return(true);
        }
 private static int Align4(int value)
 {
     return(BitUtils.AlignUp(value, 4));
 }
Exemple #12
0
        public static bool LoadKernelInitalProcess(Horizon system, KernelInitialProcess kip)
        {
            int endOffset = kip.DataOffset + kip.Data.Length;

            if (kip.BssSize != 0)
            {
                endOffset = kip.BssOffset + kip.BssSize;
            }

            int codeSize = BitUtils.AlignUp(kip.TextOffset + endOffset, KMemoryManager.PageSize);

            int codePagesCount = codeSize / KMemoryManager.PageSize;

            ulong codeBaseAddress = kip.Addr39Bits ? 0x8000000UL : 0x200000UL;

            ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;

            int mmuFlags = 0;

            if (AslrEnabled)
            {
                //TODO: Randomization.

                mmuFlags |= 0x20;
            }

            if (kip.Addr39Bits)
            {
                mmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
            }

            if (kip.Is64Bits)
            {
                mmuFlags |= 1;
            }

            ProcessCreationInfo creationInfo = new ProcessCreationInfo(
                kip.Name,
                kip.ProcessCategory,
                kip.TitleId,
                codeAddress,
                codePagesCount,
                mmuFlags,
                0,
                0);

            MemoryRegion memRegion = kip.IsService
                ? MemoryRegion.Service
                : MemoryRegion.Application;

            KMemoryRegionManager region = system.MemoryRegions[(int)memRegion];

            KernelResult result = region.AllocatePages((ulong)codePagesCount, false, out KPageList pageList);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            KProcess process = new KProcess(system);

            result = process.InitializeKip(
                creationInfo,
                kip.Capabilities,
                pageList,
                system.ResourceLimit,
                memRegion);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            result = LoadIntoMemory(process, kip, codeBaseAddress);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            result = process.Start(kip.MainThreadPriority, (ulong)kip.MainThreadStackSize);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process start returned error \"{result}\".");

                return(false);
            }

            system.Processes.Add(process.Pid, process);

            return(true);
        }
Exemple #13
0
        public static SizeInfo GetBlockLinearTextureSize(
            int width,
            int height,
            int depth,
            int levels,
            int layers,
            int blockWidth,
            int blockHeight,
            int bytesPerPixel,
            int gobBlocksInY,
            int gobBlocksInZ,
            int gobBlocksInTileX)
        {
            bool is3D = depth > 1;

            int layerSize = 0;

            int[] allOffsets = new int[levels * layers * depth];
            int[] mipOffsets = new int[levels];

            int mipGobBlocksInY = gobBlocksInY;
            int mipGobBlocksInZ = gobBlocksInZ;

            for (int level = 0; level < levels; level++)
            {
                int w = Math.Max(1, width >> level);
                int h = Math.Max(1, height >> level);
                int d = Math.Max(1, depth >> level);

                w = BitUtils.DivRoundUp(w, blockWidth);
                h = BitUtils.DivRoundUp(h, blockHeight);

                while (h <= (mipGobBlocksInY >> 1) * GobHeight && mipGobBlocksInY != 1)
                {
                    mipGobBlocksInY >>= 1;
                }

                while (d <= (mipGobBlocksInZ >> 1) && mipGobBlocksInZ != 1)
                {
                    mipGobBlocksInZ >>= 1;
                }

                int widthInGobs = BitUtils.AlignUp(BitUtils.DivRoundUp(w * bytesPerPixel, GobStride), gobBlocksInTileX);

                int totalBlocksOfGobsInZ = BitUtils.DivRoundUp(d, mipGobBlocksInZ);
                int totalBlocksOfGobsInY = BitUtils.DivRoundUp(BitUtils.DivRoundUp(h, GobHeight), mipGobBlocksInY);

                int robSize = widthInGobs * mipGobBlocksInY * mipGobBlocksInZ * GobSize;

                if (is3D)
                {
                    int gobSize = mipGobBlocksInY * GobSize;

                    int sliceSize = totalBlocksOfGobsInY * widthInGobs * gobSize;

                    int baseOffset = layerSize;

                    int mask = gobBlocksInZ - 1;

                    for (int z = 0; z < d; z++)
                    {
                        int zLow  = z & mask;
                        int zHigh = z & ~mask;

                        allOffsets[z * levels + level] = baseOffset + zLow * gobSize + zHigh * sliceSize;
                    }
                }

                mipOffsets[level] = layerSize;

                layerSize += totalBlocksOfGobsInZ * totalBlocksOfGobsInY * robSize;
            }

            layerSize = AlignLayerSize(
                layerSize,
                height,
                depth,
                blockHeight,
                gobBlocksInY,
                gobBlocksInZ);

            if (!is3D)
            {
                for (int layer = 0; layer < layers; layer++)
                {
                    int baseIndex  = layer * levels;
                    int baseOffset = layer * layerSize;

                    for (int level = 0; level < levels; level++)
                    {
                        allOffsets[baseIndex + level] = baseOffset + mipOffsets[level];
                    }
                }
            }

            int totalSize = layerSize * layers;

            return(new SizeInfo(mipOffsets, allOffsets, levels, layerSize, totalSize));
        }
Exemple #14
0
        /// <summary>
        /// Performs actual copy of the inline data after the transfer is finished.
        /// </summary>
        private void FinishTransfer()
        {
            var memoryManager = _channel.MemoryManager;

            var data = MemoryMarshal.Cast <int, byte>(_buffer).Slice(0, _size);

            if (_isLinear && _lineCount == 1)
            {
                memoryManager.Write(_dstGpuVa, data);
            }
            else
            {
                var dstCalculator = new OffsetCalculator(
                    _dstWidth,
                    _dstHeight,
                    _dstStride,
                    _isLinear,
                    _dstGobBlocksInY,
                    1);

                int srcOffset = 0;

                for (int y = _dstY; y < _dstY + _lineCount; y++)
                {
                    int x1      = _dstX;
                    int x2      = _dstX + _lineLengthIn;
                    int x1Round = BitUtils.AlignUp(_dstX, 16);
                    int x2Trunc = BitUtils.AlignDown(x2, 16);

                    int x = x1;

                    if (x1Round <= x2)
                    {
                        for (; x < x1Round; x++, srcOffset++)
                        {
                            int dstOffset = dstCalculator.GetOffset(x, y);

                            ulong dstAddress = _dstGpuVa + (uint)dstOffset;

                            memoryManager.Write(dstAddress, data[srcOffset]);
                        }
                    }

                    for (; x < x2Trunc; x += 16, srcOffset += 16)
                    {
                        int dstOffset = dstCalculator.GetOffset(x, y);

                        ulong dstAddress = _dstGpuVa + (uint)dstOffset;

                        memoryManager.Write(dstAddress, MemoryMarshal.Cast <byte, Vector128 <byte> >(data.Slice(srcOffset, 16))[0]);
                    }

                    for (; x < x2; x++, srcOffset++)
                    {
                        int dstOffset = dstCalculator.GetOffset(x, y);

                        ulong dstAddress = _dstGpuVa + (uint)dstOffset;

                        memoryManager.Write(dstAddress, data[srcOffset]);
                    }
                }
            }

            _finished = true;

            _context.AdvanceSequence();
        }
Exemple #15
0
        public static bool LoadKip(KernelContext context, KipExecutable kip)
        {
            int endOffset = kip.DataOffset + kip.Data.Length;

            if (kip.BssSize != 0)
            {
                endOffset = kip.BssOffset + kip.BssSize;
            }

            int codeSize = BitUtils.AlignUp(kip.TextOffset + endOffset, KMemoryManager.PageSize);

            int codePagesCount = codeSize / KMemoryManager.PageSize;

            ulong codeBaseAddress = (kip.Header.Flags & 0x10) != 0 ? 0x8000000UL : 0x200000UL;

            ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;

            int mmuFlags = 0;

            if (AslrEnabled)
            {
                // TODO: Randomization.

                mmuFlags |= 0x20;
            }

            if ((kip.Header.Flags & 0x10) != 0)
            {
                mmuFlags |= (int)AddressSpaceType.Addr39Bits << 1;
            }

            if ((kip.Header.Flags & 0x08) != 0)
            {
                mmuFlags |= 1;
            }

            ProcessCreationInfo creationInfo = new ProcessCreationInfo(
                kip.Header.Name,
                kip.Header.ProcessCategory,
                kip.Header.TitleId,
                codeAddress,
                codePagesCount,
                mmuFlags,
                0,
                0);

            MemoryRegion memoryRegion = (kip.Header.Flags & 0x20) != 0
                ? MemoryRegion.Service
                : MemoryRegion.Application;

            KMemoryRegionManager region = context.MemoryRegions[(int)memoryRegion];

            KernelResult result = region.AllocatePages((ulong)codePagesCount, false, out KPageList pageList);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            KProcess process = new KProcess(context);

            result = process.InitializeKip(
                creationInfo,
                kip.Capabilities,
                pageList,
                context.ResourceLimit,
                memoryRegion);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            result = LoadIntoMemory(process, kip, codeBaseAddress);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            process.DefaultCpuCore = kip.Header.DefaultCore;

            result = process.Start(kip.Header.MainThreadPriority, (ulong)kip.Header.Sections[1].Attribute);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process start returned error \"{result}\".");

                return(false);
            }

            context.Processes.TryAdd(process.Pid, process);

            return(true);
        }
Exemple #16
0
        private KernelResult CopyToClient(KMemoryManager 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, KMemoryManager.PageSize);
                ulong clientAddrRounded   = BitUtils.AlignUp(desc.ClientAddress, KMemoryManager.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,
                        MemoryPermission.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, KMemoryManager.PageSize);
                ulong clientEndAddrRounded   = BitUtils.AlignUp(clientEndAddr, KMemoryManager.PageSize);
                ulong serverEndAddrTruncated = BitUtils.AlignDown(serverEndAddr, KMemoryManager.PageSize);

                if (clientEndAddrTruncated < clientEndAddrRounded &&
                    (clientAddrTruncated == clientAddrRounded || clientAddrTruncated < clientEndAddrTruncated))
                {
                    KernelResult result = memoryManager.CopyDataFromCurrentProcess(
                        clientEndAddrTruncated,
                        clientEndAddr - clientEndAddrTruncated,
                        stateMask,
                        stateMask,
                        MemoryPermission.ReadAndWrite,
                        attributeMask,
                        MemoryAttribute.None,
                        serverEndAddrTruncated);

                    if (result != KernelResult.Success)
                    {
                        return(result);
                    }
                }
            }

            return(KernelResult.Success);
        }
Exemple #17
0
        public KernelResult Start(int mainThreadPriority, ulong stackSize)
        {
            lock (_processLock)
            {
                if (_state > ProcessState.CreatedAttached)
                {
                    return(KernelResult.InvalidState);
                }

                if (ResourceLimit != null && !ResourceLimit.Reserve(LimitableResource.Thread, 1))
                {
                    return(KernelResult.ResLimitExceeded);
                }

                KResourceLimit threadResourceLimit = ResourceLimit;
                KResourceLimit memoryResourceLimit = null;

                if (_mainThreadStackSize != 0)
                {
                    throw new InvalidOperationException("Trying to start a process with a invalid state!");
                }

                ulong stackSizeRounded = BitUtils.AlignUp(stackSize, KMemoryManager.PageSize);

                ulong neededSize = stackSizeRounded + _imageSize;

                //Check if the needed size for the code and the stack will fit on the
                //memory usage capacity of this Process. Also check for possible overflow
                //on the above addition.
                if (neededSize > _memoryUsageCapacity ||
                    neededSize < stackSizeRounded)
                {
                    threadResourceLimit?.Release(LimitableResource.Thread, 1);

                    return(KernelResult.OutOfMemory);
                }

                if (stackSizeRounded != 0 && ResourceLimit != null)
                {
                    memoryResourceLimit = ResourceLimit;

                    if (!memoryResourceLimit.Reserve(LimitableResource.Memory, stackSizeRounded))
                    {
                        threadResourceLimit?.Release(LimitableResource.Thread, 1);

                        return(KernelResult.ResLimitExceeded);
                    }
                }

                KernelResult result;

                KThread mainThread = null;

                ulong stackTop = 0;

                void CleanUpForError()
                {
                    HandleTable.Destroy();

                    mainThread?.DecrementReferenceCount();

                    if (_mainThreadStackSize != 0)
                    {
                        ulong stackBottom = stackTop - _mainThreadStackSize;

                        ulong stackPagesCount = _mainThreadStackSize / KMemoryManager.PageSize;

                        MemoryManager.UnmapForKernel(stackBottom, stackPagesCount, MemoryState.Stack);

                        _mainThreadStackSize = 0;
                    }

                    memoryResourceLimit?.Release(LimitableResource.Memory, stackSizeRounded);
                    threadResourceLimit?.Release(LimitableResource.Thread, 1);
                }

                if (stackSizeRounded != 0)
                {
                    ulong stackPagesCount = stackSizeRounded / KMemoryManager.PageSize;

                    ulong regionStart = MemoryManager.StackRegionStart;
                    ulong regionSize  = MemoryManager.StackRegionEnd - regionStart;

                    ulong regionPagesCount = regionSize / KMemoryManager.PageSize;

                    result = MemoryManager.AllocateOrMapPa(
                        stackPagesCount,
                        KMemoryManager.PageSize,
                        0,
                        false,
                        regionStart,
                        regionPagesCount,
                        MemoryState.Stack,
                        MemoryPermission.ReadAndWrite,
                        out ulong stackBottom);

                    if (result != KernelResult.Success)
                    {
                        CleanUpForError();

                        return(result);
                    }

                    _mainThreadStackSize += stackSizeRounded;

                    stackTop = stackBottom + stackSizeRounded;
                }

                ulong heapCapacity = _memoryUsageCapacity - _mainThreadStackSize - _imageSize;

                result = MemoryManager.SetHeapCapacity(heapCapacity);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                HandleTable = new KHandleTable(System);

                result = HandleTable.Initialize(Capabilities.HandleTableSize);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                mainThread = new KThread(System);

                result = mainThread.Initialize(
                    _entrypoint,
                    0,
                    stackTop,
                    mainThreadPriority,
                    DefaultCpuCore,
                    this);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                mainThread.SetEntryArguments(0, mainThreadHandle);

                ProcessState oldState = _state;
                ProcessState newState = _state != ProcessState.Created
                    ? ProcessState.Attached
                    : ProcessState.Started;

                SetState(newState);

                //TODO: We can't call KThread.Start from a non-guest thread.
                //We will need to make some changes to allow the creation of
                //dummy threads that will be used to initialize the current
                //thread on KCoreContext so that GetCurrentThread doesn't fail.

                /* Result = MainThread.Start();
                 *
                 * if (Result != KernelResult.Success)
                 * {
                 *  SetState(OldState);
                 *
                 *  CleanUpForError();
                 * } */

                mainThread.Reschedule(ThreadSchedState.Running);

                if (result == KernelResult.Success)
                {
                    mainThread.IncrementReferenceCount();
                }

                mainThread.DecrementReferenceCount();

                return(result);
            }
        }
Exemple #18
0
        public static byte[] DecodeBC4(ReadOnlySpan <byte> data, int width, int height, int depth, int levels, int layers, bool signed)
        {
            int size = 0;

            for (int l = 0; l < levels; l++)
            {
                size += BitUtils.AlignUp(Math.Max(1, width >> l), 4) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers;
            }

            // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
            int alignedWidth = BitUtils.AlignUp(width, 4);

            byte[]      output     = new byte[size];
            Span <byte> outputSpan = new Span <byte>(output);

            ReadOnlySpan <ulong> data64 = MemoryMarshal.Cast <byte, ulong>(data);

            Span <byte> tile = stackalloc byte[BlockWidth * BlockHeight];
            Span <byte> rPal = stackalloc byte[8];

            Span <uint> tileAsUint = MemoryMarshal.Cast <byte, uint>(tile);

            Span <uint> outputLine0 = default;
            Span <uint> outputLine1 = default;
            Span <uint> outputLine2 = default;
            Span <uint> outputLine3 = default;

            int imageBaseOOffs = 0;

            for (int l = 0; l < levels; l++)
            {
                int w = BitUtils.DivRoundUp(width, BlockWidth);
                int h = BitUtils.DivRoundUp(height, BlockHeight);

                for (int l2 = 0; l2 < layers; l2++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        for (int y = 0; y < h; y++)
                        {
                            int baseY         = y * BlockHeight;
                            int copyHeight    = Math.Min(BlockHeight, height - baseY);
                            int lineBaseOOffs = imageBaseOOffs + baseY * alignedWidth;

                            if (copyHeight == 4)
                            {
                                outputLine0 = MemoryMarshal.Cast <byte, uint>(outputSpan.Slice(lineBaseOOffs));
                                outputLine1 = MemoryMarshal.Cast <byte, uint>(outputSpan.Slice(lineBaseOOffs + alignedWidth));
                                outputLine2 = MemoryMarshal.Cast <byte, uint>(outputSpan.Slice(lineBaseOOffs + alignedWidth * 2));
                                outputLine3 = MemoryMarshal.Cast <byte, uint>(outputSpan.Slice(lineBaseOOffs + alignedWidth * 3));
                            }

                            for (int x = 0; x < w; x++)
                            {
                                int baseX     = x * BlockWidth;
                                int copyWidth = Math.Min(BlockWidth, width - baseX);

                                ulong block = data64[0];

                                rPal[0] = (byte)block;
                                rPal[1] = (byte)(block >> 8);

                                if (signed)
                                {
                                    BCnLerpAlphaSnorm(rPal);
                                }
                                else
                                {
                                    BCnLerpAlphaUnorm(rPal);
                                }

                                BCnDecodeTileAlpha(tile, rPal, block >> 16);

                                if ((copyWidth | copyHeight) == 4)
                                {
                                    outputLine0[x] = tileAsUint[0];
                                    outputLine1[x] = tileAsUint[1];
                                    outputLine2[x] = tileAsUint[2];
                                    outputLine3[x] = tileAsUint[3];
                                }
                                else
                                {
                                    int pixelBaseOOffs = lineBaseOOffs + baseX;

                                    for (int tY = 0; tY < copyHeight; tY++)
                                    {
                                        tile.Slice(tY * 4, copyWidth).CopyTo(outputSpan.Slice(pixelBaseOOffs + alignedWidth * tY, copyWidth));
                                    }
                                }

                                data64 = data64.Slice(1);
                            }
                        }

                        imageBaseOOffs += alignedWidth * height;
                    }
                }

                width  = Math.Max(1, width >> 1);
                height = Math.Max(1, height >> 1);
                depth  = Math.Max(1, depth >> 1);

                alignedWidth = BitUtils.AlignUp(width, 4);
            }

            return(output);
        }
Exemple #19
0
 public static ulong GetTargetSize <T>(ulong currentSize, ulong count, int align) where T : unmanaged
 {
     return(BitUtils.AlignUp(currentSize, align) + (ulong)Unsafe.SizeOf <T>() * count);
 }
Exemple #20
0
        public static byte[] DecodeBC5(ReadOnlySpan <byte> data, int width, int height, int depth, int levels, int layers, bool signed)
        {
            int size = 0;

            for (int l = 0; l < levels; l++)
            {
                size += BitUtils.AlignUp(Math.Max(1, width >> l), 2) * Math.Max(1, height >> l) * Math.Max(1, depth >> l) * layers * 2;
            }

            // Backends currently expect a stride alignment of 4 bytes, so output width must be aligned.
            int alignedWidth = BitUtils.AlignUp(width, 2);

            byte[] output = new byte[size];

            ReadOnlySpan <ulong> data64 = MemoryMarshal.Cast <byte, ulong>(data);

            Span <byte> rTile = stackalloc byte[BlockWidth * BlockHeight * 2];
            Span <byte> gTile = stackalloc byte[BlockWidth * BlockHeight * 2];
            Span <byte> rPal  = stackalloc byte[8];
            Span <byte> gPal  = stackalloc byte[8];

            Span <ushort> outputAsUshort = MemoryMarshal.Cast <byte, ushort>(output);

            Span <uint> rTileAsUint = MemoryMarshal.Cast <byte, uint>(rTile);
            Span <uint> gTileAsUint = MemoryMarshal.Cast <byte, uint>(gTile);

            Span <ulong> outputLine0 = default;
            Span <ulong> outputLine1 = default;
            Span <ulong> outputLine2 = default;
            Span <ulong> outputLine3 = default;

            int imageBaseOOffs = 0;

            for (int l = 0; l < levels; l++)
            {
                int w = BitUtils.DivRoundUp(width, BlockWidth);
                int h = BitUtils.DivRoundUp(height, BlockHeight);

                for (int l2 = 0; l2 < layers; l2++)
                {
                    for (int z = 0; z < depth; z++)
                    {
                        for (int y = 0; y < h; y++)
                        {
                            int baseY         = y * BlockHeight;
                            int copyHeight    = Math.Min(BlockHeight, height - baseY);
                            int lineBaseOOffs = imageBaseOOffs + baseY * alignedWidth;

                            if (copyHeight == 4)
                            {
                                outputLine0 = MemoryMarshal.Cast <ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs));
                                outputLine1 = MemoryMarshal.Cast <ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + alignedWidth));
                                outputLine2 = MemoryMarshal.Cast <ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + alignedWidth * 2));
                                outputLine3 = MemoryMarshal.Cast <ushort, ulong>(outputAsUshort.Slice(lineBaseOOffs + alignedWidth * 3));
                            }

                            for (int x = 0; x < w; x++)
                            {
                                int baseX     = x * BlockWidth;
                                int copyWidth = Math.Min(BlockWidth, width - baseX);

                                ulong blockL = data64[0];
                                ulong blockH = data64[1];

                                rPal[0] = (byte)blockL;
                                rPal[1] = (byte)(blockL >> 8);
                                gPal[0] = (byte)blockH;
                                gPal[1] = (byte)(blockH >> 8);

                                if (signed)
                                {
                                    BCnLerpAlphaSnorm(rPal);
                                    BCnLerpAlphaSnorm(gPal);
                                }
                                else
                                {
                                    BCnLerpAlphaUnorm(rPal);
                                    BCnLerpAlphaUnorm(gPal);
                                }

                                BCnDecodeTileAlpha(rTile, rPal, blockL >> 16);
                                BCnDecodeTileAlpha(gTile, gPal, blockH >> 16);

                                if ((copyWidth | copyHeight) == 4)
                                {
                                    outputLine0[x] = InterleaveBytes(rTileAsUint[0], gTileAsUint[0]);
                                    outputLine1[x] = InterleaveBytes(rTileAsUint[1], gTileAsUint[1]);
                                    outputLine2[x] = InterleaveBytes(rTileAsUint[2], gTileAsUint[2]);
                                    outputLine3[x] = InterleaveBytes(rTileAsUint[3], gTileAsUint[3]);
                                }
                                else
                                {
                                    int pixelBaseOOffs = lineBaseOOffs + baseX;

                                    for (int tY = 0; tY < copyHeight; tY++)
                                    {
                                        int line = pixelBaseOOffs + alignedWidth * tY;

                                        for (int tX = 0; tX < copyWidth; tX++)
                                        {
                                            int texel = tY * BlockWidth + tX;

                                            outputAsUshort[line + tX] = (ushort)(rTile[texel] | (gTile[texel] << 8));
                                        }
                                    }
                                }

                                data64 = data64.Slice(2);
                            }
                        }

                        imageBaseOOffs += alignedWidth * height;
                    }
                }

                width  = Math.Max(1, width >> 1);
                height = Math.Max(1, height >> 1);
                depth  = Math.Max(1, depth >> 1);

                alignedWidth = BitUtils.AlignUp(width, 2);
            }

            return(output);
        }
Exemple #21
0
        public KernelResult Start(int mainThreadPriority, ulong stackSize)
        {
            lock (_processLock)
            {
                if (State > ProcessState.CreatedAttached)
                {
                    return(KernelResult.InvalidState);
                }

                if (ResourceLimit != null && !ResourceLimit.Reserve(LimitableResource.Thread, 1))
                {
                    return(KernelResult.ResLimitExceeded);
                }

                KResourceLimit threadResourceLimit = ResourceLimit;
                KResourceLimit memoryResourceLimit = null;

                if (_mainThreadStackSize != 0)
                {
                    throw new InvalidOperationException("Trying to start a process with a invalid state!");
                }

                ulong stackSizeRounded = BitUtils.AlignUp(stackSize, KPageTableBase.PageSize);

                ulong neededSize = stackSizeRounded + _imageSize;

                // Check if the needed size for the code and the stack will fit on the
                // memory usage capacity of this Process. Also check for possible overflow
                // on the above addition.
                if (neededSize > _memoryUsageCapacity || neededSize < stackSizeRounded)
                {
                    threadResourceLimit?.Release(LimitableResource.Thread, 1);

                    return(KernelResult.OutOfMemory);
                }

                if (stackSizeRounded != 0 && ResourceLimit != null)
                {
                    memoryResourceLimit = ResourceLimit;

                    if (!memoryResourceLimit.Reserve(LimitableResource.Memory, stackSizeRounded))
                    {
                        threadResourceLimit?.Release(LimitableResource.Thread, 1);

                        return(KernelResult.ResLimitExceeded);
                    }
                }

                KernelResult result;

                KThread mainThread = null;

                ulong stackTop = 0;

                void CleanUpForError()
                {
                    HandleTable.Destroy();

                    mainThread?.DecrementReferenceCount();

                    if (_mainThreadStackSize != 0)
                    {
                        ulong stackBottom = stackTop - _mainThreadStackSize;

                        ulong stackPagesCount = _mainThreadStackSize / KPageTableBase.PageSize;

                        MemoryManager.UnmapForKernel(stackBottom, stackPagesCount, MemoryState.Stack);

                        _mainThreadStackSize = 0;
                    }

                    memoryResourceLimit?.Release(LimitableResource.Memory, stackSizeRounded);
                    threadResourceLimit?.Release(LimitableResource.Thread, 1);
                }

                if (stackSizeRounded != 0)
                {
                    ulong stackPagesCount = stackSizeRounded / KPageTableBase.PageSize;

                    ulong regionStart = MemoryManager.StackRegionStart;
                    ulong regionSize  = MemoryManager.StackRegionEnd - regionStart;

                    ulong regionPagesCount = regionSize / KPageTableBase.PageSize;

                    result = MemoryManager.MapPages(
                        stackPagesCount,
                        KPageTableBase.PageSize,
                        0,
                        false,
                        regionStart,
                        regionPagesCount,
                        MemoryState.Stack,
                        KMemoryPermission.ReadAndWrite,
                        out ulong stackBottom);

                    if (result != KernelResult.Success)
                    {
                        CleanUpForError();

                        return(result);
                    }

                    _mainThreadStackSize += stackSizeRounded;

                    stackTop = stackBottom + stackSizeRounded;
                }

                ulong heapCapacity = _memoryUsageCapacity - _mainThreadStackSize - _imageSize;

                result = MemoryManager.SetHeapCapacity(heapCapacity);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                HandleTable = new KHandleTable(KernelContext);

                result = HandleTable.Initialize(Capabilities.HandleTableSize);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                mainThread = new KThread(KernelContext);

                result = mainThread.Initialize(
                    _entrypoint,
                    0,
                    stackTop,
                    mainThreadPriority,
                    DefaultCpuCore,
                    this,
                    ThreadType.User,
                    _customThreadStart);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                result = HandleTable.GenerateHandle(mainThread, out int mainThreadHandle);

                if (result != KernelResult.Success)
                {
                    CleanUpForError();

                    return(result);
                }

                mainThread.SetEntryArguments(0, mainThreadHandle);

                ProcessState oldState = State;
                ProcessState newState = State != ProcessState.Created
                    ? ProcessState.Attached
                    : ProcessState.Started;

                SetState(newState);

                result = mainThread.Start();

                if (result != KernelResult.Success)
                {
                    SetState(oldState);

                    CleanUpForError();
                }

                if (result == KernelResult.Success)
                {
                    mainThread.IncrementReferenceCount();
                }

                mainThread.DecrementReferenceCount();

                return(result);
            }
        }
Exemple #22
0
        // GetWorkBufferSize(nn::audio::detail::AudioRendererParameterInternal) -> u64
        public ResultCode GetAudioRendererWorkBufferSize(ServiceCtx context)
        {
            AudioRendererParameter parameters = GetAudioRendererParameter(context);

            if (AudioRendererCommon.CheckValidRevision(parameters))
            {
                BehaviorInfo behaviorInfo = new BehaviorInfo();

                behaviorInfo.SetUserLibRevision(parameters.Revision);

                long size;

                int totalMixCount = parameters.SubMixCount + 1;

                size = BitUtils.AlignUp(parameters.MixBufferCount * 4, AudioRendererConsts.BufferAlignment) +
                       parameters.SubMixCount * 0x400 +
                       totalMixCount * 0x940 +
                       parameters.VoiceCount * 0x3F0 +
                       BitUtils.AlignUp(totalMixCount * 8, 16) +
                       BitUtils.AlignUp(parameters.VoiceCount * 8, 16) +
                       BitUtils.AlignUp(((parameters.SinkCount + parameters.SubMixCount) * 0x3C0 + parameters.SampleCount * 4) *
                                        (parameters.MixBufferCount + 6), AudioRendererConsts.BufferAlignment) +
                       (parameters.SinkCount + parameters.SubMixCount) * 0x2C0 +
                       (parameters.EffectCount + parameters.VoiceCount * 4) * 0x30 +
                       0x50;

                if (behaviorInfo.IsSplitterSupported())
                {
                    size += BitUtils.AlignUp(NodeStates.GetWorkBufferSize(totalMixCount) + EdgeMatrix.GetWorkBufferSize(totalMixCount), 16);
                }

                size = parameters.SinkCount * 0x170 +
                       (parameters.SinkCount + parameters.SubMixCount) * 0x280 +
                       parameters.EffectCount * 0x4C0 +
                       ((size + SplitterContext.CalcWorkBufferSize(behaviorInfo, parameters) + 0x30 * parameters.EffectCount + (4 * parameters.VoiceCount) + 0x8F) & ~0x3FL) +
                       ((parameters.VoiceCount << 8) | 0x40);

                if (parameters.PerformanceManagerCount >= 1)
                {
                    size += (PerformanceManager.GetRequiredBufferSizeForPerformanceMetricsPerFrame(behaviorInfo, parameters) *
                             (parameters.PerformanceManagerCount + 1) + 0xFF) & ~0x3FL;
                }

                if (behaviorInfo.IsVariadicCommandBufferSizeSupported())
                {
                    size += CommandGenerator.CalculateCommandBufferSize(parameters) + 0x7E;
                }
                else
                {
                    size += 0x1807E;
                }

                size = BitUtils.AlignUp(size, 0x1000);

                context.ResponseData.Write(size);

                Logger.PrintDebug(LogClass.ServiceAudio, $"WorkBufferSize is 0x{size:x16}.");

                return(ResultCode.Success);
            }
            else
            {
                context.ResponseData.Write(0L);

                Logger.PrintWarning(LogClass.ServiceAudio, $"Library Revision REV{AudioRendererCommon.GetRevisionVersion(parameters.Revision)} is not supported!");

                return(ResultCode.UnsupportedRevision);
            }
        }
Exemple #23
0
        public static bool LoadKip(KernelContext context, KipExecutable kip)
        {
            uint endOffset = kip.DataOffset + (uint)kip.Data.Length;

            if (kip.BssSize != 0)
            {
                endOffset = kip.BssOffset + kip.BssSize;
            }

            uint codeSize = BitUtils.AlignUp(kip.TextOffset + endOffset, KMemoryManager.PageSize);

            int codePagesCount = (int)(codeSize / KMemoryManager.PageSize);

            ulong codeBaseAddress = kip.Is64BitAddressSpace ? 0x8000000UL : 0x200000UL;

            ulong codeAddress = codeBaseAddress + (ulong)kip.TextOffset;

            ProcessCreationFlags flags = 0;

            if (AslrEnabled)
            {
                // TODO: Randomization.

                flags |= ProcessCreationFlags.EnableAslr;
            }

            if (kip.Is64BitAddressSpace)
            {
                flags |= ProcessCreationFlags.AddressSpace64Bit;
            }

            if (kip.Is64Bit)
            {
                flags |= ProcessCreationFlags.Is64Bit;
            }

            ProcessCreationInfo creationInfo = new ProcessCreationInfo(
                kip.Name,
                kip.Version,
                kip.ProgramId,
                codeAddress,
                codePagesCount,
                flags,
                0,
                0);

            MemoryRegion memoryRegion = kip.UsesSecureMemory
                ? MemoryRegion.Service
                : MemoryRegion.Application;

            KMemoryRegionManager region = context.MemoryRegions[(int)memoryRegion];

            KernelResult result = region.AllocatePages((ulong)codePagesCount, false, out KPageList pageList);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            KProcess process = new KProcess(context);

            var processContextFactory = new ArmProcessContextFactory();

            result = process.InitializeKip(
                creationInfo,
                kip.Capabilities,
                pageList,
                context.ResourceLimit,
                memoryRegion,
                processContextFactory);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            result = LoadIntoMemory(process, kip, codeBaseAddress);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            process.DefaultCpuCore = kip.IdealCoreId;

            result = process.Start(kip.Priority, (ulong)kip.StackSize);

            if (result != KernelResult.Success)
            {
                Logger.Error?.Print(LogClass.Loader, $"Process start returned error \"{result}\".");

                return(false);
            }

            context.Processes.TryAdd(process.Pid, process);

            return(true);
        }
Exemple #24
0
        /// <summary>
        /// Get the required work buffer size memory needed for the <see cref="EdgeMatrix"/>.
        /// </summary>
        /// <param name="nodeCount">The count of nodes.</param>
        /// <returns>The size required for the given <paramref name="nodeCount"/>.</returns>
        public static int GetWorkBufferSize(int nodeCount)
        {
            int size = BitUtils.AlignUp(nodeCount * nodeCount, RendererConstants.BufferAlignment);

            return(size / Unsafe.SizeOf <byte>());
        }
Exemple #25
0
        public KMemoryRegionManager(ulong address, ulong size, ulong endAddr)
        {
            _blocks = new KMemoryRegionBlock[BlockOrders.Length];

            Address = address;
            Size    = size;
            EndAddr = endAddr;

            _blockOrdersCount = BlockOrders.Length;

            for (int blockIndex = 0; blockIndex < _blockOrdersCount; blockIndex++)
            {
                _blocks[blockIndex] = new KMemoryRegionBlock();

                _blocks[blockIndex].Order = BlockOrders[blockIndex];

                int nextOrder = blockIndex == _blockOrdersCount - 1 ? 0 : BlockOrders[blockIndex + 1];

                _blocks[blockIndex].NextOrder = nextOrder;

                int currBlockSize = 1 << BlockOrders[blockIndex];
                int nextBlockSize = currBlockSize;

                if (nextOrder != 0)
                {
                    nextBlockSize = 1 << nextOrder;
                }

                ulong startAligned   = BitUtils.AlignDown(address, nextBlockSize);
                ulong endAddrAligned = BitUtils.AlignDown(endAddr, currBlockSize);

                ulong sizeInBlocksTruncated = (endAddrAligned - startAligned) >> BlockOrders[blockIndex];

                ulong endAddrRounded = BitUtils.AlignUp(address + size, nextBlockSize);

                ulong sizeInBlocksRounded = (endAddrRounded - startAligned) >> BlockOrders[blockIndex];

                _blocks[blockIndex].StartAligned          = startAligned;
                _blocks[blockIndex].SizeInBlocksTruncated = sizeInBlocksTruncated;
                _blocks[blockIndex].SizeInBlocksRounded   = sizeInBlocksRounded;

                ulong currSizeInBlocks = sizeInBlocksRounded;

                int maxLevel = 0;

                do
                {
                    maxLevel++;
                }while ((currSizeInBlocks /= 64) != 0);

                _blocks[blockIndex].MaxLevel = maxLevel;

                _blocks[blockIndex].Masks = new long[maxLevel][];

                currSizeInBlocks = sizeInBlocksRounded;

                for (int level = maxLevel - 1; level >= 0; level--)
                {
                    currSizeInBlocks = (currSizeInBlocks + 63) / 64;

                    _blocks[blockIndex].Masks[level] = new long[currSizeInBlocks];
                }
            }

            if (size != 0)
            {
                FreePages(address, size / KMemoryManager.PageSize);
            }
        }
Exemple #26
0
        private KernelResult GetReceiveListAddress(
            PointerBufferDesc descriptor,
            Message message,
            uint recvListType,
            uint messageSizeInWords,
            ulong[]           receiveList,
            ref uint dstOffset,
            out ulong address)
        {
            ulong recvListBufferAddress = address = 0;

            if (recvListType == 0)
            {
                return(KernelResult.OutOfResource);
            }
            else if (recvListType == 1 || recvListType == 2)
            {
                ulong recvListBaseAddr;
                ulong recvListEndAddr;

                if (recvListType == 1)
                {
                    recvListBaseAddr = message.Address + messageSizeInWords * 4;
                    recvListEndAddr  = message.Address + message.Size;
                }
                else /* if (recvListType == 2) */
                {
                    ulong packed = receiveList[0];

                    recvListBaseAddr = packed & 0x7fffffffff;

                    uint size = (uint)(packed >> 48);

                    if (size == 0)
                    {
                        return(KernelResult.OutOfResource);
                    }

                    recvListEndAddr = recvListBaseAddr + size;
                }

                recvListBufferAddress = BitUtils.AlignUp(recvListBaseAddr + dstOffset, 0x10);

                ulong endAddress = recvListBufferAddress + descriptor.BufferSize;

                dstOffset = (uint)endAddress - (uint)recvListBaseAddr;

                if (recvListBufferAddress + descriptor.BufferSize <= recvListBufferAddress ||
                    recvListBufferAddress + descriptor.BufferSize > recvListEndAddr)
                {
                    return(KernelResult.OutOfResource);
                }
            }
            else /* if (recvListType > 2) */
            {
                if (descriptor.ReceiveIndex >= receiveList.Length)
                {
                    return(KernelResult.OutOfResource);
                }

                ulong packed = receiveList[descriptor.ReceiveIndex];

                recvListBufferAddress = packed & 0x7fffffffff;

                uint size = (uint)(packed >> 48);

                if (recvListBufferAddress == 0 || size == 0 || size < descriptor.BufferSize)
                {
                    return(KernelResult.OutOfResource);
                }
            }

            address = recvListBufferAddress;

            return(KernelResult.Success);
        }
Exemple #27
0
        public static Span <byte> ConvertLinearToBlockLinear(
            int width,
            int height,
            int depth,
            int levels,
            int layers,
            int blockWidth,
            int blockHeight,
            int bytesPerPixel,
            int gobBlocksInY,
            int gobBlocksInZ,
            int gobBlocksInTileX,
            SizeInfo sizeInfo,
            ReadOnlySpan <byte> data)
        {
            Span <byte> output = new byte[sizeInfo.TotalSize];

            int inOffs = 0;

            int mipGobBlocksInY = gobBlocksInY;
            int mipGobBlocksInZ = gobBlocksInZ;

            int gobWidth  = (GobStride / bytesPerPixel) * gobBlocksInTileX;
            int gobHeight = gobBlocksInY * GobHeight;

            for (int level = 0; level < levels; level++)
            {
                int w = Math.Max(1, width >> level);
                int h = Math.Max(1, height >> level);
                int d = Math.Max(1, depth >> level);

                w = BitUtils.DivRoundUp(w, blockWidth);
                h = BitUtils.DivRoundUp(h, blockHeight);

                while (h <= (mipGobBlocksInY >> 1) * GobHeight && mipGobBlocksInY != 1)
                {
                    mipGobBlocksInY >>= 1;
                }

                while (d <= (mipGobBlocksInZ >> 1) && mipGobBlocksInZ != 1)
                {
                    mipGobBlocksInZ >>= 1;
                }

                int stride = BitUtils.AlignUp(w * bytesPerPixel, HostStrideAlignment);

                int alignment = gobWidth;

                if (d < gobBlocksInZ || w <= gobWidth || h <= gobHeight)
                {
                    alignment = GobStride / bytesPerPixel;
                }

                int wAligned = BitUtils.AlignUp(w, alignment);

                BlockLinearLayout layoutConverter = new BlockLinearLayout(
                    wAligned,
                    h,
                    d,
                    mipGobBlocksInY,
                    mipGobBlocksInZ,
                    bytesPerPixel);

                for (int layer = 0; layer < layers; layer++)
                {
                    int outBaseOffset = layer * sizeInfo.LayerSize + sizeInfo.GetMipOffset(level);

                    for (int z = 0; z < d; z++)
                    {
                        for (int y = 0; y < h; y++)
                        {
                            for (int x = 0; x < w; x++)
                            {
                                int offset = outBaseOffset + layoutConverter.GetOffset(x, y, z);

                                Span <byte> dest = output.Slice(offset, bytesPerPixel);

                                data.Slice(inOffs + x * bytesPerPixel, bytesPerPixel).CopyTo(dest);
                            }

                            inOffs += stride;
                        }
                    }
                }
            }

            return(output);
        }
Exemple #28
0
        public static bool LoadStaticObjects(
            Horizon system,
            Npdm metaData,
            IExecutable[] staticObjects,
            byte[]        arguments = null)
        {
            if (!metaData.Is64Bits)
            {
                Logger.PrintWarning(LogClass.Loader, "32-bits application detected!");
            }

            ulong argsStart = 0;
            int   argsSize  = 0;
            ulong codeStart = metaData.Is64Bits ? 0x8000000UL : 0x200000UL;
            int   codeSize  = 0;

            ulong[] nsoBase = new ulong[staticObjects.Length];

            for (int index = 0; index < staticObjects.Length; index++)
            {
                IExecutable staticObject = staticObjects[index];

                int textEnd = staticObject.TextOffset + staticObject.Text.Length;
                int roEnd   = staticObject.RoOffset + staticObject.Ro.Length;
                int dataEnd = staticObject.DataOffset + staticObject.Data.Length + staticObject.BssSize;

                int nsoSize = textEnd;

                if ((uint)nsoSize < (uint)roEnd)
                {
                    nsoSize = roEnd;
                }

                if ((uint)nsoSize < (uint)dataEnd)
                {
                    nsoSize = dataEnd;
                }

                nsoSize = BitUtils.AlignUp(nsoSize, KMemoryManager.PageSize);

                nsoBase[index] = codeStart + (ulong)codeSize;

                codeSize += nsoSize;

                if (arguments != null && argsSize == 0)
                {
                    argsStart = (ulong)codeSize;

                    argsSize = BitUtils.AlignDown(arguments.Length * 2 + ArgsTotalSize - 1, KMemoryManager.PageSize);

                    codeSize += argsSize;
                }
            }

            int codePagesCount = codeSize / KMemoryManager.PageSize;

            int personalMmHeapPagesCount = metaData.PersonalMmHeapSize / KMemoryManager.PageSize;

            ProcessCreationInfo creationInfo = new ProcessCreationInfo(
                metaData.TitleName,
                metaData.ProcessCategory,
                metaData.Aci0.TitleId,
                codeStart,
                codePagesCount,
                metaData.MmuFlags,
                0,
                personalMmHeapPagesCount);

            KernelResult result;

            KResourceLimit resourceLimit = new KResourceLimit(system);

            long applicationRgSize = (long)system.MemoryRegions[(int)MemoryRegion.Application].Size;

            result  = resourceLimit.SetLimitValue(LimitableResource.Memory, applicationRgSize);
            result |= resourceLimit.SetLimitValue(LimitableResource.Thread, 608);
            result |= resourceLimit.SetLimitValue(LimitableResource.Event, 700);
            result |= resourceLimit.SetLimitValue(LimitableResource.TransferMemory, 128);
            result |= resourceLimit.SetLimitValue(LimitableResource.Session, 894);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization failed setting resource limit values.");

                return(false);
            }

            KProcess process = new KProcess(system);

            MemoryRegion memoryRegion = (MemoryRegion)((metaData.Acid.Flags >> 2) & 0xf);

            if (memoryRegion > MemoryRegion.NvServices)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization failed due to invalid ACID flags.");

                return(false);
            }

            result = process.Initialize(
                creationInfo,
                metaData.Aci0.KernelAccessControl.Capabilities,
                resourceLimit,
                memoryRegion);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                return(false);
            }

            for (int index = 0; index < staticObjects.Length; index++)
            {
                Logger.PrintInfo(LogClass.Loader, $"Loading image {index} at 0x{nsoBase[index]:x16}...");

                result = LoadIntoMemory(process, staticObjects[index], nsoBase[index]);

                if (result != KernelResult.Success)
                {
                    Logger.PrintError(LogClass.Loader, $"Process initialization returned error \"{result}\".");

                    return(false);
                }
            }

            process.DefaultCpuCore = metaData.DefaultCpuId;

            result = process.Start(metaData.MainThreadPriority, (ulong)metaData.MainThreadStackSize);

            if (result != KernelResult.Success)
            {
                Logger.PrintError(LogClass.Loader, $"Process start returned error \"{result}\".");

                return(false);
            }

            system.Processes.Add(process.Pid, process);

            return(true);
        }
Exemple #29
0
        /// <summary>
        /// Determines if a given texture is "safe" for upscaling from its info.
        /// Note that this is different from being compatible - this elilinates targets that would have detrimental effects when scaled.
        /// </summary>
        /// <param name="info">The texture info to check</param>
        /// <returns>True if safe</returns>
        public bool UpscaleSafeMode(TextureInfo info)
        {
            // While upscaling works for all targets defined by IsUpscaleCompatible, we additionally blacklist targets here that
            // may have undesirable results (upscaling blur textures) or simply waste GPU resources (upscaling texture atlas).

            if (!(info.FormatInfo.Format.IsDepthOrStencil() || info.FormatInfo.Components == 1))
            {
                // Discount square textures that aren't depth-stencil like. (excludes game textures, cubemap faces, most 3D texture LUT, texture atlas)
                // Detect if the texture is possibly square. Widths may be aligned, so to remove the uncertainty we align both the width and height.

                int widthAlignment = (info.IsLinear ? 32 : 64) / info.FormatInfo.BytesPerPixel;

                bool possiblySquare = BitUtils.AlignUp(info.Width, widthAlignment) == BitUtils.AlignUp(info.Height, widthAlignment);

                if (possiblySquare)
                {
                    return(false);
                }
            }

            int aspect = (int)Math.Round((info.Width / (float)info.Height) * 9);

            if (aspect == 16 && info.Height < 360)
            {
                // Targets that are roughly 16:9 can only be rescaled if they're equal to or above 360p. (excludes blur and bloom textures)
                return(false);
            }

            return(true);
        }
Exemple #30
0
        public KMemoryRegionManager(ulong Address, ulong Size, ulong EndAddr)
        {
            Blocks = new KMemoryRegionBlock[BlockOrders.Length];

            this.Address = Address;
            this.Size    = Size;
            this.EndAddr = EndAddr;

            BlockOrdersCount = BlockOrders.Length;

            for (int BlockIndex = 0; BlockIndex < BlockOrdersCount; BlockIndex++)
            {
                Blocks[BlockIndex] = new KMemoryRegionBlock();

                Blocks[BlockIndex].Order = BlockOrders[BlockIndex];

                int NextOrder = BlockIndex == BlockOrdersCount - 1 ? 0 : BlockOrders[BlockIndex + 1];

                Blocks[BlockIndex].NextOrder = NextOrder;

                int CurrBlockSize = 1 << BlockOrders[BlockIndex];
                int NextBlockSize = CurrBlockSize;

                if (NextOrder != 0)
                {
                    NextBlockSize = 1 << NextOrder;
                }

                ulong StartAligned   = BitUtils.AlignDown(Address, NextBlockSize);
                ulong EndAddrAligned = BitUtils.AlignDown(EndAddr, CurrBlockSize);

                ulong SizeInBlocksTruncated = (EndAddrAligned - StartAligned) >> BlockOrders[BlockIndex];

                ulong EndAddrRounded = BitUtils.AlignUp(Address + Size, NextBlockSize);

                ulong SizeInBlocksRounded = (EndAddrRounded - StartAligned) >> BlockOrders[BlockIndex];

                Blocks[BlockIndex].StartAligned          = StartAligned;
                Blocks[BlockIndex].SizeInBlocksTruncated = SizeInBlocksTruncated;
                Blocks[BlockIndex].SizeInBlocksRounded   = SizeInBlocksRounded;

                ulong CurrSizeInBlocks = SizeInBlocksRounded;

                int MaxLevel = 0;

                do
                {
                    MaxLevel++;
                }while ((CurrSizeInBlocks /= 64) != 0);

                Blocks[BlockIndex].MaxLevel = MaxLevel;

                Blocks[BlockIndex].Masks = new long[MaxLevel][];

                CurrSizeInBlocks = SizeInBlocksRounded;

                for (int Level = MaxLevel - 1; Level >= 0; Level--)
                {
                    CurrSizeInBlocks = (CurrSizeInBlocks + 63) / 64;

                    Blocks[BlockIndex].Masks[Level] = new long[CurrSizeInBlocks];
                }
            }

            if (Size != 0)
            {
                FreePages(Address, Size / KMemoryManager.PageSize);
            }
        }