// Copyright (C) 2026 SharpEmu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later

using SharpEmu.HLE;
using SharpEmu.Libs.Ampr;
using System.Buffers;
using System.Buffers.Binary;
using System.Text;
using System.Threading;
using System.Reflection;
using System.Runtime.InteropServices;
using System.Linq;
using System.Globalization;

namespace SharpEmu.Libs.Kernel;

public static class KernelMemoryCompatExports
{
    private const int MaxGuestStringLength = 4096;
    private const int WideCharSize = sizeof(ushort);
    private const int MemsetChunkSize = 16 * 1024;
    private const int TlsModuleBlockSize = 0x10000;
    private const int O_WRONLY = 0x1;
    private const int O_RDWR = 0x2;
    private const int O_APPEND = 0x8;
    private const int O_CREAT = 0x0200;
    private const int O_TRUNC = 0x0400;
    private const int O_DIRECTORY = 0x00020000;
    private const int OrbisKernelMapFixed = 0x0010;
    private const int OrbisKernelMapOpMapDirect = 0;
    private const int OrbisKernelMapOpUnmap = 1;
    private const int OrbisKernelMapOpProtect = 2;
    private const int OrbisKernelMapOpMapFlexible = 3;
    private const int OrbisKernelMapOpTypeProtect = 4;
    private const int OrbisKernelBatchMapEntrySize = 32;
    private const int OrbisKernelBatchMapEntryStartOffset = 0;
    private const int OrbisKernelBatchMapEntryOffsetOffset = 8;
    private const int OrbisKernelBatchMapEntryLengthOffset = 16;
    private const int OrbisKernelBatchMapEntryProtectionOffset = 24;
    private const int OrbisKernelBatchMapEntryTypeOffset = 25;
    private const int OrbisKernelBatchMapEntryOperationOffset = 28;
    private const ulong OrbisPageSize = 0x4000;
    private const int OrbisProtCpuRead = 0x01;
    private const int OrbisProtCpuWrite = 0x02;
    private const int OrbisProtCpuExec = 0x04;
    private const int OrbisProtGpuRead = 0x10;
    private const int OrbisProtGpuWrite = 0x20;
    private const int OrbisProtCpuReadWrite = OrbisProtCpuRead | OrbisProtCpuWrite;
    private const int SeekSet = 0;
    private const int SeekCur = 1;
    private const int SeekEnd = 2;
    private const ulong DirectMemorySizeBytes = 16384UL * 1024 * 1024;
    private const ulong UnsetMainDirectMemoryPoolBase = ulong.MaxValue;
    private const ulong FlexibleMemorySizeBytes = 448UL * 1024 * 1024;
    private const int OrbisVirtualQueryInfoSize = 72;
    private const int OrbisKernelMaximumNameLength = 32;
    private const uint MemCommit = 0x1000;
    private const uint HostPageNoAccess = 0x01;
    private const uint HostPageReadOnly = 0x02;
    private const uint HostPageReadWrite = 0x04;
    private const uint HostPageWriteCopy = 0x08;
    private const uint HostPageExecute = 0x10;
    private const uint HostPageExecuteRead = 0x20;
    private const uint HostPageExecuteReadWrite = 0x40;
    private const uint HostPageExecuteWriteCopy = 0x80;
    private const uint HostPageGuard = 0x100;
    private const int Enomem = 12;
    private const int Efault = 14;
    private const int Einval = 22;
    private const int Erange = 34;
    private const int Struncate = 80;
    private const nuint DefaultLibcHeapAlignment = 16;
    private const ushort KernelStatModeDirectory = 0x41FF;
    private const ushort KernelStatModeRegular = 0x81FF;
    private const int KernelStatSize = 120;
    private const int KernelStatStDevOffset = 0;
    private const int KernelStatStInoOffset = 4;
    private const int KernelStatStModeOffset = 8;
    private const int KernelStatStNlinkOffset = 10;
    private const int KernelStatStUidOffset = 12;
    private const int KernelStatStGidOffset = 16;
    private const int KernelStatStRdevOffset = 20;
    private const int KernelStatStAtimOffset = 24;
    private const int KernelStatStMtimOffset = 40;
    private const int KernelStatStCtimOffset = 56;
    private const int KernelStatStSizeOffset = 72;
    private const int KernelStatStBlocksOffset = 80;
    private const int KernelStatStBlksizeOffset = 88;
    private const int KernelStatStFlagsOffset = 92;
    private const int KernelStatStGenOffset = 96;
    private const int KernelStatStLspareOffset = 100;
    private const int KernelStatStBirthtimOffset = 104;

    private static readonly object _fdGate = new();
    private static readonly Dictionary<int, FileStream> _openFiles = new();
    private static readonly Dictionary<int, OpenDirectory> _openDirectories = new();
    private static readonly object _libcAllocGate = new();
    private static readonly object _memoryGate = new();
    private static readonly object _tlsGate = new();
    private static readonly object _ioTraceGate = new();
    private static readonly object _statCacheGate = new();
    private static readonly object _guestMountGate = new();
    private static readonly Dictionary<ulong, DirectAllocation> _directAllocations = new();
    private static readonly Dictionary<ulong, LibcHeapAllocation> _libcAllocations = new();
    private static readonly Dictionary<ulong, MappedRegion> _mappedRegions = new();
    private static readonly Dictionary<ulong, string> _mappedRegionNames = new();
    private static readonly Dictionary<ulong, ulong> _tlsModuleBlocks = new();
    private static readonly Dictionary<string, string> _guestMounts = new(StringComparer.OrdinalIgnoreCase);
    private static readonly HashSet<string> _tracedStatResults = new(StringComparer.Ordinal);
    private static readonly HashSet<string> _negativeStatCache = new(StringComparer.OrdinalIgnoreCase);
    private static long _nextFileDescriptor = 2;
    private static ulong _nextPhysicalAddress;
    private static ulong _nextVirtualAddress;
    private static ulong _mainDirectMemoryPoolBase = UnsetMainDirectMemoryPoolBase;
    private static ulong _allocatedFlexibleBytes;
    private static ulong _threadAtexitCountCallback;
    private static ulong _threadAtexitReportCallback;
    private static ulong _threadDtorsCallback;
    private static int _nullMemsetRecoveryCount;
    private static int _nonCanonicalMemsetRecoveryCount;
    private static int _inaccessibleMemsetRecoveryCount;
    private static int _hostMemoryWriteFallbackCount;
    private static int _hostMemoryReadFallbackCount;
    private static int _nullWcscpyRecoveryCount;
    private static string? _cachedApp0Root;
    private static string? _cachedDownload0Root;

    [StructLayout(LayoutKind.Sequential)]
    private struct MemoryBasicInformation
    {
        public nint BaseAddress;
        public nint AllocationBase;
        public uint AllocationProtect;
        public nuint RegionSize;
        public uint State;
        public uint Protect;
        public uint Type;
    }

    [DllImport("kernel32.dll", SetLastError = true)]
    private static extern nuint VirtualQuery(nint lpAddress, out MemoryBasicInformation lpBuffer, nuint dwLength);

    [DllImport("kernel32.dll", SetLastError = true)]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool VirtualProtect(nint lpAddress, nuint dwSize, uint flNewProtect, out uint lpflOldProtect);

    private sealed class OpenDirectory
    {
        public required string Path { get; init; }
        public required string[] Entries { get; init; }
        public int NextIndex { get; set; }
    }

    private readonly record struct DirectAllocation(ulong Start, ulong Length, int MemoryType);
    private readonly record struct LibcHeapAllocation(nint BaseAddress, nuint Size, nuint Alignment);
    private readonly record struct MappedRegion(ulong Address, ulong Length, int Protection, bool IsFlexible, bool IsDirect, ulong DirectStart);
    private readonly record struct BatchMapEntry(ulong Start, ulong Offset, ulong Length, byte Protection, byte Type, int Operation);

    public static void RegisterGuestPathMount(string guestMountPoint, string hostRoot)
    {
        ArgumentException.ThrowIfNullOrWhiteSpace(guestMountPoint);
        ArgumentException.ThrowIfNullOrWhiteSpace(hostRoot);

        var normalizedMountPoint = NormalizeGuestStatCachePath(guestMountPoint);
        if (normalizedMountPoint is null || normalizedMountPoint == "/")
        {
            throw new ArgumentException("Guest mount point must name a directory.", nameof(guestMountPoint));
        }

        var normalizedHostRoot = Path.GetFullPath(hostRoot);
        Directory.CreateDirectory(normalizedHostRoot);
        lock (_guestMountGate)
        {
            _guestMounts[normalizedMountPoint] = normalizedHostRoot;
        }

        lock (_statCacheGate)
        {
            _negativeStatCache.RemoveWhere(path =>
                string.Equals(path, normalizedMountPoint, StringComparison.OrdinalIgnoreCase) ||
                path.StartsWith(normalizedMountPoint + "/", StringComparison.OrdinalIgnoreCase));
        }
    }

    internal static bool TryAllocateHleData(
        CpuContext ctx,
        ulong length,
        ulong alignment,
        out ulong address)
    {
        address = 0;
        if (length == 0 || length > int.MaxValue)
        {
            return false;
        }

        var mappedLength = AlignUp(length, 0x1000UL);
        var effectiveAlignment = Math.Max(alignment, 0x1000UL);
        lock (_memoryGate)
        {
            var desiredAddress = AlignUp(
                _nextVirtualAddress == 0 ? 0x1_0000_0000UL : _nextVirtualAddress,
                effectiveAlignment);
            if (!TryReserveGuestVirtualRange(ctx, desiredAddress, mappedLength, OrbisProtCpuReadWrite, effectiveAlignment, out address) ||
                address == 0)
            {
                return false;
            }

            _nextVirtualAddress = Math.Max(_nextVirtualAddress, address + mappedLength);
            _mappedRegions[address] = new MappedRegion(
                address,
                mappedLength,
                OrbisProtCpuReadWrite,
                IsFlexible: false,
                IsDirect: false,
                DirectStart: 0);
        }

        var zeroes = new byte[(int)Math.Min(mappedLength, (ulong)MemsetChunkSize)];
        for (ulong offset = 0; offset < mappedLength;)
        {
            var chunkLength = (int)Math.Min((ulong)zeroes.Length, mappedLength - offset);
            if (!ctx.Memory.TryWrite(address + offset, zeroes.AsSpan(0, chunkLength)))
            {
                return false;
            }

            offset += (ulong)chunkLength;
        }

        return true;
    }

    internal static void RegisterReservedVirtualRange(ulong address, ulong length)
    {
        if (address == 0 || length == 0)
        {
            return;
        }

        lock (_memoryGate)
        {
            _mappedRegions[address] = new MappedRegion(
                address,
                length,
                Protection: 0,
                IsFlexible: false,
                IsDirect: false,
                DirectStart: 0);
        }
    }

    [SysAbiExport(
        Nid = "8zTFvBIAIN8",
        ExportName = "memset",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Memset(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var value = (byte)(ctx[CpuRegister.Rsi] & 0xFF);
        var length = ctx[CpuRegister.Rdx];
        if (length == 0)
        {
            ctx[CpuRegister.Rax] = destination;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (destination == 0)
        {
            if (length <= 0x20)
            {
                var recoveryIndex = Interlocked.Increment(ref _nullMemsetRecoveryCount);
                if (recoveryIndex <= 8)
                {
                    Console.Error.WriteLine(
                        $"[LOADER][WARNING] memset null-dst recovery#{recoveryIndex}: rip=0x{ctx.Rip:X16} len=0x{length:X} val=0x{value:X2}");
                }

                ctx[CpuRegister.Rax] = 0;
                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }

            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        const ulong CanonicalUserUpper = 0x0000800000000000UL;
        if (destination >= CanonicalUserUpper && length <= 0x40)
        {
            var recoveryIndex = Interlocked.Increment(ref _nonCanonicalMemsetRecoveryCount);
            if (recoveryIndex <= 8)
            {
                Console.Error.WriteLine(
                    $"[LOADER][WARNING] memset non-canonical-dst recovery#{recoveryIndex}: rip=0x{ctx.Rip:X16} dst=0x{destination:X16} len=0x{length:X} val=0x{value:X2}");
            }

            ctx[CpuRegister.Rax] = destination;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        const ulong MaxSane = 512UL * 1024 * 1024;
        if (destination < 0x1000 || destination >= CanonicalUserUpper || length > MaxSane)
        {
            Console.WriteLine("!!! CRITICAL: Bad Memset Call !!!");
            Console.WriteLine($"Called from RIP: 0x{ctx.Rip:X}");
            Console.WriteLine($"dst=0x{destination:X} val=0x{value:X2} len=0x{length:X}");
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var chunk = new byte[MemsetChunkSize];
        Array.Fill(chunk, value);
        var remaining = length;
        var cursor = destination;
        while (remaining > 0)
        {
            var take = (int)Math.Min((ulong)chunk.Length, remaining);
            if (!TryWriteCompat(ctx, cursor, chunk.AsSpan(0, take)))
            {
                if (length <= 0x40)
                {
                    var recoveryIndex = Interlocked.Increment(ref _inaccessibleMemsetRecoveryCount);
                    if (recoveryIndex <= 8)
                    {
                        Console.Error.WriteLine(
                            $"[LOADER][WARNING] memset inaccessible-dst recovery#{recoveryIndex}: rip=0x{ctx.Rip:X16} dst=0x{destination:X16} len=0x{length:X} val=0x{value:X2}");
                    }

                    ctx[CpuRegister.Rax] = destination;
                    return (int)OrbisGen2Result.ORBIS_GEN2_OK;
                }

                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            cursor += (ulong)take;
            remaining -= (ulong)take;
        }

        ctx[CpuRegister.Rax] = destination;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "j4ViWNHEgww",
        ExportName = "strlen",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Strlen(CpuContext ctx)
    {
        if (!TryReadCString(ctx, ctx[CpuRegister.Rdi], 1_048_576, out var bytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)bytes.Length);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "5jNubw4vlAA",
        ExportName = "strnlen",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Strnlen(CpuContext ctx)
    {
        var maxLength = ctx[CpuRegister.Rsi];
        if (!TryReadCString(ctx, ctx[CpuRegister.Rdi], maxLength, out var bytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)bytes.Length);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "LHMrG7e8G78",
        ExportName = "wcslen",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Wcslen(CpuContext ctx)
    {
        return WcslenCore(ctx, ctx[CpuRegister.Rdi]);
    }

    [SysAbiExport(
        Nid = "WkkeywLJcgU",
        ExportName = "wcslen",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int WcslenWkkey(CpuContext ctx)
    {
        return WcslenCore(ctx, ctx[CpuRegister.Rdi]);
    }

    private static int WcslenCore(CpuContext ctx, ulong address)
    {
        if (string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_WIDE"), "1", StringComparison.Ordinal))
        {
            Span<byte> probe = stackalloc byte[32];
            if (TryReadCompat(ctx, address, probe))
            {
                Console.Error.WriteLine(
                    $"[LOADER][TRACE] wcslen probe @0x{address:X16}: {Convert.ToHexString(probe).ToLowerInvariant()}");
            }
            else
            {
                Console.Error.WriteLine($"[LOADER][TRACE] wcslen probe @0x{address:X16}: <unreadable>");
            }
        }

        if (!TryReadWideCString(ctx, address, 1_048_576, out var units))
        {
            Console.Error.WriteLine($"[LOADER][WARN] wcslen: unreadable string at 0x{address:X16}");
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)units.Length);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Ovb2dSJOAuE",
        ExportName = "strcmp",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Strcmp(CpuContext ctx)
    {
        var left = ctx[CpuRegister.Rdi];
        var right = ctx[CpuRegister.Rsi];
        if (!TryCompareStrings(ctx, left, right, limit: ulong.MaxValue, out var compare))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)compare);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "fV2xHER+bKE",
        ExportName = "wcscoll",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Wcscoll(CpuContext ctx)
    {
        return WcscollCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi]);
    }

    [SysAbiExport(
        Nid = "pNtJdE3x49E",
        ExportName = "wcscmp",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Wcscmp(CpuContext ctx)
    {
        return WcscmpCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi]);
    }

    private static int WcscollCore(CpuContext ctx, ulong left, ulong right)
    {
        return WcscmpCore(ctx, left, right);
    }

    private static int WcscmpCore(CpuContext ctx, ulong left, ulong right)
    {
        if (!TryCompareWideStrings(ctx, left, right, limit: ulong.MaxValue, out var compare))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)compare);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "FM5NPnLqBc8",
        ExportName = "wcscpy",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int WcscpyFm5(CpuContext ctx)
    {
        return WcscpyCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi]);
    }

    private static int WcscpyCore(CpuContext ctx, ulong destination, ulong source)
    {
        if (source == 0)
        {
            var recoveryIndex = Interlocked.Increment(ref _nullWcscpyRecoveryCount);
            if (recoveryIndex <= 8)
            {
                Console.Error.WriteLine(
                    $"[LOADER][WARNING] wcscpy null-src recovery#{recoveryIndex}: rip=0x{ctx.Rip:X16} dst=0x{destination:X16}");
            }

            if (!TryWriteWideTerminator(ctx, destination))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = destination;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (!TryReadWideCString(ctx, source, 1_048_576, out var units))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        if (!TryWriteCompat(ctx, destination, EncodeWideUnitsWithTerminator(units)))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = destination;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "aesyjrHVWy4",
        ExportName = "strncmp",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Strncmp(CpuContext ctx)
    {
        var left = ctx[CpuRegister.Rdi];
        var right = ctx[CpuRegister.Rsi];
        var limit = ctx[CpuRegister.Rdx];
        if (!TryCompareStrings(ctx, left, right, limit, out var compare))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)compare);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "0nV21JjYCH8",
        ExportName = "wcsncpy",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Wcsncpy(CpuContext ctx)
    {
        return WcsncpyCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], ctx[CpuRegister.Rdx]);
    }

    [SysAbiExport(
        Nid = "E8wCoUEbfzk",
        ExportName = "wcsncmp",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Wcsncmp(CpuContext ctx)
    {
        return WcsncmpCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], ctx[CpuRegister.Rdx]);
    }

    private static int WcsncmpCore(CpuContext ctx, ulong left, ulong right, ulong limit)
    {
        if (!TryCompareWideStrings(ctx, left, right, limit, out var compare))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)compare);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "eLdDw6l0-bU",
        ExportName = "snprintf",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Snprintf(CpuContext ctx)
    {
        return SnprintfCore(ctx);
    }

    [SysAbiExport(
        Nid = "Q2V+iqvjgC0",
        ExportName = "vsnprintf",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Vsnprintf(CpuContext ctx)
    {
        return VsnprintfCore(ctx);
    }

    [SysAbiExport(
        Nid = "nJz16JE1txM",
        ExportName = "swprintf",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Swprintf(CpuContext ctx)
    {
        return SwprintfCore(ctx);
    }

    [SysAbiExport(
        Nid = "u0XOsuOmOzc",
        ExportName = "vswprintf",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Vswprintf(CpuContext ctx)
    {
        return VswprintfCore(ctx);
    }

    [SysAbiExport(
        Nid = "Im55VJ-Bekc",
        ExportName = "swprintf_s",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int SwprintfS(CpuContext ctx)
    {
        return SwprintfCore(ctx);
    }

    [SysAbiExport(
        Nid = "oDoV9tyHTbA",
        ExportName = "vswprintf_s",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int VswprintfS(CpuContext ctx)
    {
        return VswprintfCore(ctx);
    }

    [SysAbiExport(
        Nid = "GMpvxPFW924",
        ExportName = "vprintf",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Vprintf(CpuContext ctx)
    {
        var formatAddress = ctx[CpuRegister.Rdi];
        var vaListAddress = ctx[CpuRegister.Rsi];
        if (!TryReadCString(ctx, formatAddress, 1_048_576, out var formatBytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var format = Encoding.UTF8.GetString(formatBytes);
        string rendered;
        if (!TryCreateVaListCursor(ctx, vaListAddress, out var vaCursor))
        {
            rendered = format;
        }
        else
        {
            rendered = FormatString(ctx, format, ref vaCursor);
        }

        Console.Write(rendered);
        ctx[CpuRegister.Rax] = unchecked((ulong)Encoding.UTF8.GetByteCount(rendered));
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "kiZSXIWd9vg",
        ExportName = "strcpy",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Strcpy(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var source = ctx[CpuRegister.Rsi];
        if (!TryReadCString(ctx, source, 1_048_576, out var bytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var payload = new byte[bytes.Length + 1];
        bytes.CopyTo(payload.AsSpan());
        if (!TryWriteCompat(ctx, destination, payload))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = destination;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "6f5f-qx4ucA",
        ExportName = "wcscpy_s",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int WcscpyS(CpuContext ctx)
    {
        return WcscpySCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], ctx[CpuRegister.Rdx]);
    }

    [SysAbiExport(
        Nid = "6sJWiWSRuqk",
        ExportName = "strncpy",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Strncpy(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var source = ctx[CpuRegister.Rsi];
        var count = (int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue);
        if (count < 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var payload = new byte[count];
        Span<byte> one = stackalloc byte[1];
        var copied = 0;
        while (copied < count)
        {
            if (!TryReadCompat(ctx, source + (ulong)copied, one))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            payload[copied] = one[0];
            copied++;
            if (one[0] == 0)
            {
                break;
            }
        }

        if (!TryWriteCompat(ctx, destination, payload))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = destination;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Slmz4HMpNGs",
        ExportName = "wcsncpy_s",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int WcsncpyS(CpuContext ctx)
    {
        return WcsncpySCore(ctx, ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], ctx[CpuRegister.Rdx], ctx[CpuRegister.Rcx]);
    }

    private static int WcsncpyCore(CpuContext ctx, ulong destination, ulong source, ulong countValue)
    {
        var count = (int)Math.Min(countValue, int.MaxValue);
        if (count < 0 || count > (int.MaxValue / WideCharSize))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var payload = new byte[count * WideCharSize];
        for (var copied = 0; copied < count; copied++)
        {
            if (!TryReadUInt16Compat(ctx, source + ((ulong)copied * WideCharSize), out var unit))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            BinaryPrimitives.WriteUInt16LittleEndian(
                payload.AsSpan(copied * WideCharSize, WideCharSize),
                unit);

            if (unit == 0)
            {
                break;
            }
        }

        if (!TryWriteCompat(ctx, destination, payload))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = destination;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Ezzq78ZgHPs",
        ExportName = "wcschr",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Wcschr(CpuContext ctx)
    {
        return WcschrCore(ctx, ctx[CpuRegister.Rdi], unchecked((ushort)ctx[CpuRegister.Rsi]));
    }

    private static int WcschrCore(CpuContext ctx, ulong address, ushort needle)
    {
        for (ulong index = 0; index < 1_048_576; index++)
        {
            if (!TryReadUInt16Compat(ctx, address + (index * WideCharSize), out var unit))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            if (unit == needle)
            {
                ctx[CpuRegister.Rax] = address + (index * WideCharSize);
                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }

            if (unit == 0)
            {
                break;
            }
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static int WcscpySCore(CpuContext ctx, ulong destination, ulong destinationCount, ulong source)
    {
        if (destination == 0 || destinationCount == 0)
        {
            ctx[CpuRegister.Rax] = Einval;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (source == 0)
        {
            if (!TryZeroWideDestination(ctx, destination, destinationCount))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = Einval;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        var probeLimit = Math.Min(destinationCount, 1_048_576UL);
        if (!TryReadWideCStringBounded(ctx, source, probeLimit, out var units, out var terminated))
        {
            _ = TryZeroWideDestination(ctx, destination, destinationCount);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        if (!terminated || (ulong)units.Length + 1 > destinationCount)
        {
            if (!TryZeroWideDestination(ctx, destination, destinationCount))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = Erange;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (!TryWriteCompat(ctx, destination, EncodeWideUnitsWithTerminator(units)))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static int WcsncpySCore(CpuContext ctx, ulong destination, ulong destinationCount, ulong source, ulong count)
    {
        if (destination == 0 || destinationCount == 0)
        {
            ctx[CpuRegister.Rax] = Einval;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (source == 0)
        {
            if (!TryZeroWideDestination(ctx, destination, destinationCount))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = Einval;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (count == 0)
        {
            if (!TryWriteWideTerminator(ctx, destination))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (count == ulong.MaxValue)
        {
            var copyLimit = Math.Min(destinationCount - 1, 1_048_576UL);
            if (!TryReadWideCStringBounded(ctx, source, copyLimit, out var truncatedUnits, out var terminated))
            {
                _ = TryZeroWideDestination(ctx, destination, destinationCount);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            if (!TryWriteCompat(ctx, destination, EncodeWideUnitsWithTerminator(truncatedUnits)))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = terminated ? 0UL : Struncate;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        var boundedCount = Math.Min(count, 1_048_576UL);
        if (!TryReadWideCStringBounded(ctx, source, boundedCount, out var units, out var sourceTerminated))
        {
            _ = TryZeroWideDestination(ctx, destination, destinationCount);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var requiredUnits = sourceTerminated ? (ulong)units.Length + 1 : boundedCount + 1;
        if (requiredUnits > destinationCount)
        {
            if (!TryZeroWideDestination(ctx, destination, destinationCount))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            ctx[CpuRegister.Rax] = Erange;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (!TryWriteCompat(ctx, destination, EncodeWideUnitsWithTerminator(units)))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Q3VBxCXhUHs",
        ExportName = "memcpy",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Memcpy(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var source = ctx[CpuRegister.Rsi];
        var count = (int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue);
        if (count < 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var payload = GC.AllocateUninitializedArray<byte>(count);
        if (count > 0 && (!TryReadCompat(ctx, source, payload) || !TryWriteCompat(ctx, destination, payload)))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = destination;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "+P6FRGH4LfA",
        ExportName = "memmove",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Memmove(CpuContext ctx)
    {
        return Memcpy(ctx);
    }

    [SysAbiExport(
        Nid = "gQX+4GDQjpM",
        ExportName = "malloc",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Malloc(CpuContext ctx)
    {
        ctx[CpuRegister.Rax] =
            TryAllocateLibcHeap(ctx[CpuRegister.Rdi], DefaultLibcHeapAlignment, zeroFill: false, out var address)
                ? address
                : 0;
        TraceLibcAllocation(
            ctx,
            "malloc",
            size: ctx[CpuRegister.Rdi],
            alignment: DefaultLibcHeapAlignment,
            resultAddress: ctx[CpuRegister.Rax]);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "tIhsqj0qsFE",
        ExportName = "free",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Free(CpuContext ctx)
    {
        FreeLibcHeap(ctx[CpuRegister.Rdi]);
        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "2X5agFjKxMc",
        ExportName = "calloc",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Calloc(CpuContext ctx)
    {
        ctx[CpuRegister.Rax] =
            TryMultiplyAllocationSize(ctx[CpuRegister.Rdi], ctx[CpuRegister.Rsi], out var totalSize) &&
            TryAllocateLibcHeapCore(totalSize, DefaultLibcHeapAlignment, zeroFill: true, out var address)
                ? address
                : 0;
        TraceLibcAllocation(
            ctx,
            "calloc",
            size: ctx[CpuRegister.Rdi],
            count: ctx[CpuRegister.Rsi],
            alignment: DefaultLibcHeapAlignment,
            resultAddress: ctx[CpuRegister.Rax]);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Y7aJ1uydPMo",
        ExportName = "realloc",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Realloc(CpuContext ctx)
    {
        var existingAddress = ctx[CpuRegister.Rdi];
        var requestedSize = ctx[CpuRegister.Rsi];

        if (existingAddress == 0)
        {
            ctx[CpuRegister.Rax] =
                TryAllocateLibcHeap(requestedSize, DefaultLibcHeapAlignment, zeroFill: false, out var freshAddress)
                    ? freshAddress
                    : 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (requestedSize == 0)
        {
            FreeLibcHeap(existingAddress);
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        ctx[CpuRegister.Rax] =
            TryReallocateLibcHeap(existingAddress, requestedSize, out var resizedAddress)
                ? resizedAddress
                : 0;
        TraceLibcAllocation(
            ctx,
            "realloc",
            size: requestedSize,
            existingAddress: existingAddress,
            resultAddress: ctx[CpuRegister.Rax]);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Ujf3KzMvRmI",
        ExportName = "memalign",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Memalign(CpuContext ctx)
    {
        ctx[CpuRegister.Rax] =
            TryAllocateAlignedLibcHeap(
                alignmentValue: ctx[CpuRegister.Rdi],
                requestedSize: ctx[CpuRegister.Rsi],
                requireSizeMultiple: false,
                out var address)
                ? address
                : 0;
        TraceLibcAllocation(
            ctx,
            "memalign",
            size: ctx[CpuRegister.Rsi],
            alignment: ctx[CpuRegister.Rdi],
            resultAddress: ctx[CpuRegister.Rax]);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "2Btkg8k24Zg",
        ExportName = "aligned_alloc",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int AlignedAlloc(CpuContext ctx)
    {
        ctx[CpuRegister.Rax] =
            TryAllocateAlignedLibcHeap(
                alignmentValue: ctx[CpuRegister.Rdi],
                requestedSize: ctx[CpuRegister.Rsi],
                requireSizeMultiple: true,
                out var address)
                ? address
                : 0;
        TraceLibcAllocation(
            ctx,
            "aligned_alloc",
            size: ctx[CpuRegister.Rsi],
            alignment: ctx[CpuRegister.Rdi],
            resultAddress: ctx[CpuRegister.Rax]);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "cVSk9y8URbc",
        ExportName = "posix_memalign",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int PosixMemalign(CpuContext ctx)
    {
        var outPointerAddress = ctx[CpuRegister.Rdi];
        if (outPointerAddress == 0)
        {
            ctx[CpuRegister.Rax] = Einval;
            TraceLibcAllocation(
                ctx,
                "posix_memalign",
                size: ctx[CpuRegister.Rdx],
                alignment: ctx[CpuRegister.Rsi],
                existingAddress: outPointerAddress,
                resultAddress: 0,
                errorCode: Einval);
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (!TryValidateAlignedAllocation(
                ctx[CpuRegister.Rsi],
                ctx[CpuRegister.Rdx],
                requireSizeMultiple: false,
                requirePointerSizedAlignment: true,
                out var alignment,
                out var requestedSize))
        {
            _ = TryWriteUInt64Compat(ctx, outPointerAddress, 0);
            ctx[CpuRegister.Rax] = Einval;
            TraceLibcAllocation(
                ctx,
                "posix_memalign",
                size: ctx[CpuRegister.Rdx],
                alignment: ctx[CpuRegister.Rsi],
                existingAddress: outPointerAddress,
                resultAddress: 0,
                errorCode: Einval);
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (!TryAllocateLibcHeapCore(requestedSize, alignment, zeroFill: false, out var address))
        {
            _ = TryWriteUInt64Compat(ctx, outPointerAddress, 0);
            ctx[CpuRegister.Rax] = Enomem;
            TraceLibcAllocation(
                ctx,
                "posix_memalign",
                size: requestedSize,
                alignment: alignment,
                existingAddress: outPointerAddress,
                resultAddress: 0,
                errorCode: Enomem);
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        if (!TryWriteUInt64Compat(ctx, outPointerAddress, address))
        {
            FreeLibcHeap(address);
            ctx[CpuRegister.Rax] = Einval;
            TraceLibcAllocation(
                ctx,
                "posix_memalign",
                size: requestedSize,
                alignment: alignment,
                existingAddress: outPointerAddress,
                resultAddress: 0,
                errorCode: Einval);
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        ctx[CpuRegister.Rax] = 0;
        TraceLibcAllocation(
            ctx,
            "posix_memalign",
            size: requestedSize,
            alignment: alignment,
            existingAddress: outPointerAddress,
            resultAddress: address);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "DfivPArhucg",
        ExportName = "memcmp",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Memcmp(CpuContext ctx)
    {
        var left = ctx[CpuRegister.Rdi];
        var right = ctx[CpuRegister.Rsi];
        var count = (int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue);
        if (count < 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        Span<byte> leftByte = stackalloc byte[1];
        Span<byte> rightByte = stackalloc byte[1];
        for (var i = 0; i < count; i++)
        {
            if (!TryReadCompat(ctx, left + (ulong)i, leftByte) ||
                !TryReadCompat(ctx, right + (ulong)i, rightByte))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            var diff = leftByte[0] - rightByte[0];
            if (diff != 0)
            {
                ctx[CpuRegister.Rax] = unchecked((ulong)diff);
                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "QrZZdJ8XsX0",
        ExportName = "fputs",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libc")]
    public static int Fputs(CpuContext ctx)
    {
        var textAddress = ctx[CpuRegister.Rdi];
        var stream = ctx[CpuRegister.Rsi];
        if (textAddress == 0)
        {
            ctx[CpuRegister.Rax] = unchecked((ulong)(-1L));
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryReadNullTerminatedUtf8(ctx, textAddress, MaxGuestStringLength, out var text))
        {
            ctx[CpuRegister.Rax] = unchecked((ulong)(-1L));
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        if (stream == 0)
        {
            Console.Error.Write(text);
            Console.Error.Flush();
        }
        else
        {
            Console.Out.Write(text);
            Console.Out.Flush();
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)text.Length);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "6c3rCVE-fTU",
        ExportName = "_open",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelOpenUnderscore(CpuContext ctx)
    {
        var pathAddress = ctx[CpuRegister.Rdi];
        var flags = unchecked((int)ctx[CpuRegister.Rsi]);
        if (!TryReadNullTerminatedUtf8(ctx, pathAddress, MaxGuestStringLength, out var guestPath))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var hostPath = ResolveGuestPath(guestPath);
        var access = ResolveOpenAccess(flags);
        var mode = ResolveOpenMode(flags, access);
        try
        {
            if (IsMutatingOpen(flags) && IsReadOnlyGuestMutationPath(guestPath))
            {
                LogOpenTrace($"_open readonly path='{guestPath}' host='{hostPath}' flags=0x{flags:X8}");
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
            }

            var wantsDirectory = (flags & O_DIRECTORY) != 0;
            if (wantsDirectory || Directory.Exists(hostPath))
            {
                if (!Directory.Exists(hostPath))
                {
                    LogOpenTrace($"_open miss path='{guestPath}' host='{hostPath}' flags=0x{flags:X8} directory=1");
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
                }

                if (access != FileAccess.Read || (flags & (O_CREAT | O_TRUNC | O_APPEND)) != 0)
                {
                    LogOpenTrace($"_open invalid-dir path='{guestPath}' host='{hostPath}' flags=0x{flags:X8}");
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
                }

                var directoryFd = (int)Interlocked.Increment(ref _nextFileDescriptor);
                lock (_fdGate)
                {
                    _openDirectories[directoryFd] = new OpenDirectory
                    {
                        Path = hostPath,
                        Entries = EnumerateDirectoryEntries(hostPath),
                        NextIndex = 0
                    };
                }

                LogOpenTrace($"_open dir path='{guestPath}' host='{hostPath}' flags=0x{flags:X8} fd={directoryFd}");
                ctx[CpuRegister.Rax] = unchecked((ulong)directoryFd);
                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }

            EnsureOpenParentDirectoryExists(guestPath, hostPath, flags);
            var stream = new FileStream(hostPath, mode, access, FileShare.ReadWrite);
            if ((flags & O_APPEND) != 0)
            {
                stream.Seek(0, SeekOrigin.End);
            }

            var fd = (int)Interlocked.Increment(ref _nextFileDescriptor);
            lock (_fdGate)
            {
                _openFiles[fd] = stream;
            }

            if (IsMutatingOpen(flags))
            {
                InvalidateNegativeStatCacheForPathAndAncestors(guestPath);
            }

            LogOpenTrace($"_open file path='{guestPath}' host='{hostPath}' flags=0x{flags:X8} fd={fd}");
            ctx[CpuRegister.Rax] = unchecked((ulong)fd);
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }
        catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
        {
            LogOpenTrace($"_open fail path='{guestPath}' host='{hostPath}' flags=0x{flags:X8} ex={ex.GetType().Name}: {ex.Message}");
            return ex is UnauthorizedAccessException
                ? (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT
                : (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }
    }

    [SysAbiExport(
        Nid = "NNtFaKJbPt0",
        ExportName = "_close",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelCloseUnderscore(CpuContext ctx) => KernelCloseCore(ctx, unchecked((int)ctx[CpuRegister.Rdi]));

    [SysAbiExport(
        Nid = "bY-PO6JhzhQ",
        ExportName = "close",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int PosixClose(CpuContext ctx) => KernelCloseCore(ctx, unchecked((int)ctx[CpuRegister.Rdi]));

    [SysAbiExport(
        Nid = "UK2Tl2DWUns",
        ExportName = "sceKernelClose",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelClose(CpuContext ctx) => KernelCloseCore(ctx, unchecked((int)ctx[CpuRegister.Rdi]));

    [SysAbiExport(
        Nid = "eV9wAD2riIA",
        ExportName = "sceKernelStat",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelStat(CpuContext ctx)
    {
        var pathAddress = ctx[CpuRegister.Rdi];
        var statAddress = ctx[CpuRegister.Rsi];
        if (pathAddress == 0 || statAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryReadNullTerminatedUtf8(ctx, pathAddress, MaxGuestStringLength, out var guestPath))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var hostPath = ResolveGuestPath(guestPath);
        var statCacheKey = GetNegativeStatCacheKey(guestPath);
        if (statCacheKey is not null && IsNegativeStatCached(statCacheKey))
        {
            LogUniqueStatTrace(guestPath, hostPath, found: false);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        if (!TryWriteHostPathStat(ctx, statAddress, hostPath))
        {
            if (statCacheKey is not null)
            {
                AddNegativeStatCache(statCacheKey);
            }

            LogUniqueStatTrace(guestPath, hostPath, found: false);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        if (statCacheKey is not null)
        {
            RemoveNegativeStatCache(statCacheKey);
        }

        LogUniqueStatTrace(guestPath, hostPath, found: true);
        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "gEpBkcwxUjw",
        ExportName = "sceKernelAprResolveFilepathsToIdsAndFileSizes",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelAprResolveFilepathsToIdsAndFileSizes(CpuContext ctx)
    {
        var pathListAddress = ctx[CpuRegister.Rdi];
        var count = ctx[CpuRegister.Rsi];
        var idsAddress = ctx[CpuRegister.Rdx];
        var sizesAddress = ctx[CpuRegister.Rcx];
        if (pathListAddress == 0 || count == 0 || sizesAddress == 0 || count > 1024)
        {
            KernelRuntimeCompatExports.TrySetErrno(ctx, Einval);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        for (ulong i = 0; i < count; i++)
        {
            if (idsAddress != 0 &&
                !TryWriteUInt32Compat(ctx, idsAddress + (i * sizeof(uint)), uint.MaxValue))
            {
                KernelRuntimeCompatExports.TrySetErrno(ctx, Efault);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            if (!TryResolveAprFilepath(ctx, pathListAddress, i, out var guestPath))
            {
                KernelRuntimeCompatExports.TrySetErrno(ctx, Efault);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            var hostPath = ResolveGuestPath(guestPath);
            if (!TryGetAprFileSize(hostPath, out var fileSize))
            {
                LogIoTrace("apr_resolve", guestPath, $"host='{hostPath}' index={i} count={count} result=not_found");
                KernelRuntimeCompatExports.TrySetErrno(ctx, 2);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            var fileId = AmprFileRegistry.Register(guestPath, hostPath);
            LogIoTrace("apr_resolve", guestPath, $"host='{hostPath}' index={i} count={count} id=0x{fileId:X8} size={fileSize}");

            if (idsAddress != 0 &&
                !TryWriteUInt32Compat(ctx, idsAddress + (i * sizeof(uint)), fileId))
            {
                KernelRuntimeCompatExports.TrySetErrno(ctx, Efault);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            if (!TryWriteUInt64Compat(ctx, sizesAddress + (i * sizeof(ulong)), fileSize))
            {
                KernelRuntimeCompatExports.TrySetErrno(ctx, Efault);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "kBwCPsYX-m4",
        ExportName = "sceKernelFstat",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelFstat(CpuContext ctx)
    {
        var fd = unchecked((int)ctx[CpuRegister.Rdi]);
        var statAddress = ctx[CpuRegister.Rsi];
        if (statAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryWriteOpenDescriptorStat(ctx, fd, statAddress))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "AUXVxWeJU-A",
        ExportName = "sceKernelUnlink",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelUnlink(CpuContext ctx)
    {
        var pathAddress = ctx[CpuRegister.Rdi];
        if (pathAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryReadNullTerminatedUtf8(ctx, pathAddress, MaxGuestStringLength, out var guestPath))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var hostPath = ResolveGuestPath(guestPath);
        if (IsReadOnlyGuestMutationPath(guestPath))
        {
            LogOpenTrace($"unlink readonly path='{guestPath}' host='{hostPath}'");
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
        }

        try
        {
            if (Directory.Exists(hostPath))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
            }

            if (!File.Exists(hostPath))
            {
                AddNegativeStatCacheForGuestPath(guestPath);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            File.Delete(hostPath);
            InvalidateNegativeStatCacheForPathAndAncestors(guestPath);
            AddNegativeStatCacheForGuestPath(guestPath);
            LogOpenTrace($"unlink path='{guestPath}' host='{hostPath}'");
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }
        catch (UnauthorizedAccessException)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
        }
        catch (IOException)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_BUSY;
        }
    }

    [SysAbiExport(
        Nid = "1-LFLmRFxxM",
        ExportName = "sceKernelMkdir",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMkdir(CpuContext ctx)
    {
        var pathAddress = ctx[CpuRegister.Rdi];
        if (pathAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryReadNullTerminatedUtf8(ctx, pathAddress, MaxGuestStringLength, out var guestPath))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var hostPath = ResolveGuestPath(guestPath);
        if (IsReadOnlyGuestMutationPath(guestPath))
        {
            LogOpenTrace($"mkdir readonly path='{guestPath}' host='{hostPath}'");
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
        }

        try
        {
            if (File.Exists(hostPath) || Directory.Exists(hostPath))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_ALREADY_EXISTS;
            }

            var parentDirectory = Path.GetDirectoryName(hostPath);
            if (string.IsNullOrWhiteSpace(parentDirectory) || !Directory.Exists(parentDirectory))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            Directory.CreateDirectory(hostPath);
            if (!Directory.Exists(hostPath))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            InvalidateNegativeStatCacheForPathAndAncestors(guestPath);
            LogOpenTrace($"mkdir path='{guestPath}' host='{hostPath}'");
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }
        catch (UnauthorizedAccessException)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
        }
        catch (IOException)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }
    }

    [SysAbiExport(
        Nid = "naInUjYt3so",
        ExportName = "sceKernelRmdir",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelRmdir(CpuContext ctx)
    {
        var pathAddress = ctx[CpuRegister.Rdi];
        if (pathAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryReadNullTerminatedUtf8(ctx, pathAddress, MaxGuestStringLength, out var guestPath))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var hostPath = ResolveGuestPath(guestPath);
        if (IsReadOnlyGuestMutationPath(guestPath))
        {
            LogOpenTrace($"rmdir readonly path='{guestPath}' host='{hostPath}'");
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
        }

        try
        {
            if (!Directory.Exists(hostPath))
            {
                AddNegativeStatCacheForGuestPath(guestPath);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            Directory.Delete(hostPath, recursive: false);
            InvalidateNegativeStatCacheForPathAndAncestors(guestPath);
            AddNegativeStatCacheForGuestPath(guestPath);
            LogOpenTrace($"rmdir path='{guestPath}' host='{hostPath}'");
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }
        catch (UnauthorizedAccessException)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_PERMISSION_DENIED;
        }
        catch (IOException)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_BUSY;
        }
    }

    private static int KernelCloseCore(CpuContext ctx, int fd)
    {
        if (fd is 0 or 1 or 2)
        {
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        FileStream? stream;
        lock (_fdGate)
        {
            if (_openFiles.Remove(fd, out stream))
            {
            }
            else if (_openDirectories.Remove(fd))
            {
                ctx[CpuRegister.Rax] = 0;
                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }
            else
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }
        }

        stream.Dispose();
        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "DRuBt2pvICk",
        ExportName = "_read",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelReadUnderscore(CpuContext ctx)
    {
        var fd = unchecked((int)ctx[CpuRegister.Rdi]);
        var bufferAddress = ctx[CpuRegister.Rsi];
        var requested = (int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue);
        if (requested < 0 || (requested > 0 && bufferAddress == 0))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (requested == 0 || fd == 0)
        {
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        FileStream? stream;
        lock (_fdGate)
        {
            _openFiles.TryGetValue(fd, out stream);
        }

        if (stream is null)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        long positionBefore;
        try
        {
            positionBefore = stream.Position;
        }
        catch (IOException)
        {
            positionBefore = -1;
        }

        var buffer = GC.AllocateUninitializedArray<byte>(requested);
        var read = stream.Read(buffer, 0, requested);
        if (read > 0 && !ctx.Memory.TryWrite(bufferAddress, buffer.AsSpan(0, read)))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        long positionAfter;
        try
        {
            positionAfter = stream.Position;
        }
        catch (IOException)
        {
            positionAfter = -1;
        }

        LogIoTrace(
            "read",
            stream.Name,
            $"fd={fd} req={requested} read={read} pos={positionBefore}->{positionAfter} preview='{PreviewIoBytes(buffer, read, 64)}' hex={PreviewIoHex(buffer, read, 32)} guest_tail={PreviewGuestHex(ctx, bufferAddress + (ulong)Math.Max(read, 0), 32)}");

        ctx[CpuRegister.Rax] = unchecked((ulong)read);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "AqBioC2vF3I",
        ExportName = "read",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int PosixRead(CpuContext ctx) => KernelReadUnderscore(ctx);

    [SysAbiExport(
        Nid = "Cg4srZ6TKbU",
        ExportName = "sceKernelRead",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelRead(CpuContext ctx) => KernelReadUnderscore(ctx);

    [SysAbiExport(
        Nid = "Oy6IpwgtYOk",
        ExportName = "lseek",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int PosixLseek(CpuContext ctx)
    {
        var result = KernelLseekCore(
            unchecked((int)ctx[CpuRegister.Rdi]),
            unchecked((long)ctx[CpuRegister.Rsi]),
            unchecked((int)ctx[CpuRegister.Rdx]),
            out var position);

        if (result != OrbisGen2Result.ORBIS_GEN2_OK)
        {
            ctx[CpuRegister.Rax] = ulong.MaxValue;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)position);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "oib76F-12fk",
        ExportName = "sceKernelLseek",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelLseek(CpuContext ctx)
    {
        var result = KernelLseekCore(
            unchecked((int)ctx[CpuRegister.Rdi]),
            unchecked((long)ctx[CpuRegister.Rsi]),
            unchecked((int)ctx[CpuRegister.Rdx]),
            out var position);

        if (result != OrbisGen2Result.ORBIS_GEN2_OK)
        {
            return (int)result;
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)position);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "taRWhTJFTgE",
        ExportName = "sceKernelGetdirentries",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelGetdirentries(CpuContext ctx)
    {
        return KernelGetdirentriesCore(
            ctx,
            unchecked((int)ctx[CpuRegister.Rdi]),
            ctx[CpuRegister.Rsi],
            unchecked((int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue)),
            ctx[CpuRegister.Rcx]);
    }

    [SysAbiExport(
        Nid = "j2AIqSqJP0w",
        ExportName = "sceKernelGetdents",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelGetdents(CpuContext ctx)
    {
        return KernelGetdirentriesCore(
            ctx,
            unchecked((int)ctx[CpuRegister.Rdi]),
            ctx[CpuRegister.Rsi],
            unchecked((int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue)),
            0);
    }

    private static OrbisGen2Result KernelLseekCore(int fd, long offset, int whence, out long position)
    {
        position = -1;

        FileStream? stream;
        lock (_fdGate)
        {
            _openFiles.TryGetValue(fd, out stream);
        }

        if (stream is null)
        {
            LogIoTrace("lseek", $"fd:{fd}", $"offset={offset} whence={whence} result=badfd");
            return OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        SeekOrigin origin;
        switch (whence)
        {
            case SeekSet:
                origin = SeekOrigin.Begin;
                break;
            case SeekCur:
                origin = SeekOrigin.Current;
                break;
            case SeekEnd:
                origin = SeekOrigin.End;
                break;
            default:
                LogIoTrace("lseek", stream.Name, $"fd={fd} offset={offset} whence={whence} result=invalid_whence");
                return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        try
        {
            position = stream.Seek(offset, origin);
        }
        catch (IOException ex)
        {
            LogIoTrace("lseek", stream.Name, $"fd={fd} offset={offset} whence={whence} result=io_error ex={ex.Message}");
            return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }
        catch (ArgumentException ex)
        {
            LogIoTrace("lseek", stream.Name, $"fd={fd} offset={offset} whence={whence} result=invalid ex={ex.Message}");
            return OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        LogIoTrace("lseek", stream.Name, $"fd={fd} offset={offset} whence={whence} pos={position}");
        return OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "FxVZqBAA7ks",
        ExportName = "_write",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelWriteUnderscore(CpuContext ctx)
    {
        var fd = unchecked((int)ctx[CpuRegister.Rdi]);
        var bufferAddress = ctx[CpuRegister.Rsi];
        var requested = (int)Math.Min(ctx[CpuRegister.Rdx], int.MaxValue);
        if (requested < 0 || (requested > 0 && bufferAddress == 0))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var payload = requested == 0
            ? Array.Empty<byte>()
            : GC.AllocateUninitializedArray<byte>(requested);
        if (requested > 0 && !ctx.Memory.TryRead(bufferAddress, payload))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        if (fd == 1 || fd == 2)
        {
            var text = Encoding.UTF8.GetString(payload);
            if (fd == 1)
            {
                Console.Out.Write(text);
                Console.Out.Flush();
            }
            else
            {
                Console.Error.Write(text);
                Console.Error.Flush();
            }

            ctx[CpuRegister.Rax] = unchecked((ulong)requested);
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        FileStream? stream;
        lock (_fdGate)
        {
            _openFiles.TryGetValue(fd, out stream);
        }

        if (stream is null)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        stream.Write(payload, 0, requested);
        stream.Flush();
        ctx[CpuRegister.Rax] = unchecked((ulong)requested);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "FN4gaPmuFV8",
        ExportName = "write",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int PosixWrite(CpuContext ctx) => KernelWriteUnderscore(ctx);

    [SysAbiExport(
        Nid = "4wSze92BhLI",
        ExportName = "sceKernelWrite",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelWrite(CpuContext ctx) => KernelWriteUnderscore(ctx);

    [SysAbiExport(
        Nid = "lLMT9vJAck0",
        ExportName = "clock_gettime",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int ClockGettime(CpuContext ctx)
    {
        var timespecAddress = ctx[CpuRegister.Rsi];
        if (timespecAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var now = DateTimeOffset.UtcNow;
        var seconds = now.ToUnixTimeSeconds();
        var nanoseconds = (now.Ticks % TimeSpan.TicksPerSecond) * 100;
        if (!ctx.TryWriteUInt64(timespecAddress, unchecked((ulong)seconds)) ||
            !ctx.TryWriteUInt64(timespecAddress + sizeof(long), unchecked((ulong)nanoseconds)))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "vNe1w4diLCs",
        ExportName = "__tls_get_addr",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int TlsGetAddr(CpuContext ctx)
    {
        var tlsInfoAddress = ctx[CpuRegister.Rdi];
        if (tlsInfoAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!ctx.TryReadUInt64(tlsInfoAddress, out var moduleId) ||
            !ctx.TryReadUInt64(tlsInfoAddress + sizeof(ulong), out var offset))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = ResolveTlsAddress(ctx, moduleId, offset);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static ulong ResolveTlsAddress(CpuContext ctx, ulong moduleId, ulong offset)
    {
        if (ctx.FsBase == 0)
        {
            return 0;
        }

        if (moduleId <= 1)
        {
            return unchecked(ctx.FsBase + offset);
        }

        var key = (ctx.FsBase << 16) ^ (moduleId & 0xFFFFUL);
        ulong moduleBase;
        lock (_tlsGate)
        {
            if (!_tlsModuleBlocks.TryGetValue(key, out moduleBase))
            {
                var block = Marshal.AllocHGlobal(TlsModuleBlockSize);
                Marshal.Copy(new byte[TlsModuleBlockSize], 0, block, TlsModuleBlockSize);

                moduleBase = unchecked((ulong)block);
                _tlsModuleBlocks[key] = moduleBase;
            }
        }

        return unchecked(moduleBase + offset);
    }

    [SysAbiExport(
        Nid = "pB-yGZ2nQ9o",
        ExportName = "_sceKernelSetThreadAtexitCount",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelSetThreadAtexitCount(CpuContext ctx)
    {
        _threadAtexitCountCallback = ctx[CpuRegister.Rdi];
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "WhCc1w3EhSI",
        ExportName = "_sceKernelSetThreadAtexitReport",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelSetThreadAtexitReport(CpuContext ctx)
    {
        _threadAtexitReportCallback = ctx[CpuRegister.Rdi];
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "rNhWz+lvOMU",
        ExportName = "_sceKernelSetThreadDtors",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelSetThreadDtors(CpuContext ctx)
    {
        _threadDtorsCallback = ctx[CpuRegister.Rdi];
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "Tz4RNUCBbGI",
        ExportName = "_sceKernelRtldThreadAtexitIncrement",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelRtldThreadAtexitIncrement(CpuContext ctx)
    {
        return KernelRtldThreadAtexitAdjust(ctx, delta: +1);
    }

    [SysAbiExport(
        Nid = "8OnWXlgQlvo",
        ExportName = "_sceKernelRtldThreadAtexitDecrement",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelRtldThreadAtexitDecrement(CpuContext ctx)
    {
        return KernelRtldThreadAtexitAdjust(ctx, delta: -1);
    }

    [SysAbiExport(
        Nid = "pO96TwzOm5E",
        ExportName = "sceKernelGetDirectMemorySize",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelGetDirectMemorySize(CpuContext ctx)
    {
        ctx[CpuRegister.Rax] = DirectMemorySizeBytes;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "C0f7TJcbfac",
        ExportName = "sceKernelAvailableDirectMemorySize",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelAvailableDirectMemorySize(CpuContext ctx)
    {
        var arg0 = ctx[CpuRegister.Rdi];
        var arg1 = ctx[CpuRegister.Rsi];
        var arg2 = ctx[CpuRegister.Rdx];
        var arg3 = ctx[CpuRegister.Rcx];
        var arg4 = ctx[CpuRegister.R8];

        ulong used = 0;
        lock (_memoryGate)
        {
            foreach (var allocation in _directAllocations.Values)
            {
                used = Math.Min(DirectMemorySizeBytes, used + allocation.Length);
            }
        }

        var totalAvailable = used >= DirectMemorySizeBytes
            ? 0UL
            : DirectMemorySizeBytes - used;

        if (arg1 != 0 || arg2 != 0 || arg3 != 0 || arg4 != 0)
        {
            var searchStartRaw = unchecked((long)arg0);
            var searchEndRaw = unchecked((long)arg1);
            var alignment = arg2 == 0 ? 0x1000UL : arg2;
            var outAddress = arg3;
            var outSize = arg4;
            if (outAddress == 0 || outSize == 0)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
            }

            var searchStart = searchStartRaw < 0 ? 0UL : (ulong)searchStartRaw;
            var searchEnd = searchEndRaw <= 0
                ? DirectMemorySizeBytes
                : Math.Min((ulong)searchEndRaw, DirectMemorySizeBytes);
            if (searchStart >= searchEnd)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
            }

            if (!TryFindAvailableDirectMemorySpanLocked(searchStart, searchEnd, alignment, out var candidate, out var rangeAvailable))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            if (!ctx.TryWriteUInt64(outAddress, candidate) || !ctx.TryWriteUInt64(outSize, rangeAvailable))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        var outSizeAddress = arg0;
        if (outSizeAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!ctx.TryWriteUInt64(outSizeAddress, totalAvailable))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "aNz11fnnzi4",
        ExportName = "sceKernelAvailableFlexibleMemorySize",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelAvailableFlexibleMemorySize(CpuContext ctx)
    {
        var outSizeAddress = ctx[CpuRegister.Rdi];
        if (outSizeAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        ulong available;
        lock (_memoryGate)
        {
            available = _allocatedFlexibleBytes >= FlexibleMemorySizeBytes
                ? 0
                : FlexibleMemorySizeBytes - _allocatedFlexibleBytes;
        }

        if (!ctx.TryWriteUInt64(outSizeAddress, available))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "rTXw65xmLIA",
        ExportName = "sceKernelAllocateDirectMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelAllocateDirectMemory(CpuContext ctx)
    {
        var searchStartRaw = unchecked((long)ctx[CpuRegister.Rdi]);
        var searchEndRaw = unchecked((long)ctx[CpuRegister.Rsi]);
        var length = ctx[CpuRegister.Rdx];
        var alignment = ctx[CpuRegister.Rcx];
        var memoryType = unchecked((int)ctx[CpuRegister.R8]);
        var outAddress = ctx[CpuRegister.R9];

        if (length == 0 || outAddress == 0)
        {
            TraceDirectMemoryCall(
                ctx,
                "allocate_direct",
                length,
                alignment,
                memoryType,
                outAddress,
                result: OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var limit = DirectMemorySizeBytes;
        ulong searchStart;
        ulong searchEnd;

        if (searchEndRaw <= 0)
        {
            searchEnd = limit;
        }
        else
        {
            searchEnd = (ulong)searchEndRaw;
            if (searchEnd > limit)
            {
                searchEnd = limit;
            }
        }

        if (searchStartRaw < 0)
        {
            searchStart = 0;
        }
        else
        {
            searchStart = (ulong)searchStartRaw;
        }

        if (searchStart >= searchEnd)
        {
            searchStart = 0;
        }

        var align = alignment == 0 ? 0x1000UL : alignment;
        ulong selectedAddress;
        lock (_memoryGate)
        {
            if (!TryAllocateDirectMemoryLocked(searchStart, searchEnd, length, align, memoryType, DirectMemorySizeBytes, out selectedAddress))
            {
                TraceDirectMemoryCall(
                    ctx,
                    "allocate_direct",
                    length,
                    align,
                    memoryType,
                    outAddress,
                    result: OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN);
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN;
            }
        }

        if (!ctx.TryWriteUInt64(outAddress, selectedAddress))
        {
            TraceDirectMemoryCall(
                ctx,
                "allocate_direct",
                length,
                align,
                memoryType,
                outAddress,
                selectedAddress,
                OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        TraceDirectMemoryCall(
            ctx,
            "allocate_direct",
            length,
            align,
            memoryType,
            outAddress,
            selectedAddress,
            OrbisGen2Result.ORBIS_GEN2_OK);

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "B+vc2AO2Zrc",
        ExportName = "sceKernelAllocateMainDirectMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelAllocateMainDirectMemory(CpuContext ctx)
    {
        var length = ctx[CpuRegister.Rdi];
        var alignment = ctx[CpuRegister.Rsi];
        var memoryType = unchecked((int)ctx[CpuRegister.Rdx]);
        var outAddress = ctx[CpuRegister.Rcx];
        if (outAddress == 0 || length == 0)
        {
            TraceDirectMemoryCall(
                ctx,
                "allocate_main_direct",
                length,
                alignment,
                memoryType,
                outAddress,
                result: OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var effectiveAlignment = alignment == 0 ? 0x1000UL : alignment;
        ulong aligned;
        lock (_memoryGate)
        {
            var allocationLimit = DirectMemorySizeBytes;
            if (_mainDirectMemoryPoolBase != UnsetMainDirectMemoryPoolBase &&
                !TryAddU64(_mainDirectMemoryPoolBase, DirectMemorySizeBytes, out allocationLimit))
            {
                allocationLimit = ulong.MaxValue;
            }

            if (!TryAllocateDirectMemoryLocked(0, allocationLimit, length, effectiveAlignment, memoryType, allocationLimit, out aligned))
            {
                var poolBase = _mainDirectMemoryPoolBase == UnsetMainDirectMemoryPoolBase
                    ? AlignUp(GetDirectMemoryHighWaterMarkLocked(), effectiveAlignment)
                    : _mainDirectMemoryPoolBase;

                if (_mainDirectMemoryPoolBase == UnsetMainDirectMemoryPoolBase &&
                    TryAddU64(poolBase, DirectMemorySizeBytes, out var shiftedLimit) &&
                    TryAllocateDirectMemoryLocked(0, shiftedLimit, length, effectiveAlignment, memoryType, shiftedLimit, out aligned))
                {
                    _mainDirectMemoryPoolBase = poolBase;
                    if (ShouldTraceDirectMemory())
                    {
                        Console.Error.WriteLine(
                            $"[LOADER][TRACE] main_direct_pool: base=0x{poolBase:X16} limit=0x{shiftedLimit:X16}");
                    }
                }
                else
                {
                    TraceDirectMemoryCall(
                        ctx,
                        "allocate_main_direct",
                        length,
                        effectiveAlignment,
                        memoryType,
                        outAddress,
                        result: OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN);
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_TRY_AGAIN;
                }
            }
        }

        if (!ctx.TryWriteUInt64(outAddress, aligned))
        {
            TraceDirectMemoryCall(
                ctx,
                "allocate_main_direct",
                length,
                effectiveAlignment,
                memoryType,
                outAddress,
                aligned,
                OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT);
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        TraceDirectMemoryCall(
            ctx,
            "allocate_main_direct",
            length,
            effectiveAlignment,
            memoryType,
            outAddress,
            aligned,
            OrbisGen2Result.ORBIS_GEN2_OK);

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "MBuItvba6z8",
        ExportName = "sceKernelReleaseDirectMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelReleaseDirectMemory(CpuContext ctx)
    {
        var start = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        if (length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        lock (_memoryGate)
        {
            if (!_directAllocations.TryGetValue(start, out var allocation) || allocation.Length != length)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            _directAllocations.Remove(start);
            _nextPhysicalAddress = GetDirectMemoryHighWaterMarkLocked();
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
    Nid = "hwVSPCmp5tM",
    ExportName = "sceKernelCheckedReleaseDirectMemory",
    Target = Generation.Gen4 | Generation.Gen5,
    LibraryName = "libKernel")]
    public static int KernelCheckedReleaseDirectMemory(CpuContext ctx)
    {
        var start = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];

        if (length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        lock (_memoryGate)
        {
            if (!_directAllocations.TryGetValue(start, out var allocation) ||
                allocation.Length != length)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            _directAllocations.Remove(start);
            _nextPhysicalAddress = GetDirectMemoryHighWaterMarkLocked();
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "L-Q3LEjIbgA",
        ExportName = "sceKernelMapDirectMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMapDirectMemory(CpuContext ctx)
    {
        var inOutAddressPointer = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        var protection = unchecked((int)ctx[CpuRegister.Rdx]);
        var flags = ctx[CpuRegister.Rcx];
        var directMemoryStart = ctx[CpuRegister.R8];
        var alignment = ctx[CpuRegister.R9];
        if (ShouldTraceDirectMemory())
        {
            Console.Error.WriteLine(
                $"[LOADER][TRACE] map_direct: inout=0x{inOutAddressPointer:X16} len=0x{length:X16} prot=0x{protection:X8} flags=0x{flags:X16} direct=0x{directMemoryStart:X16} align=0x{alignment:X16}");
        }
        if (inOutAddressPointer == 0 || length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!ctx.TryReadUInt64(inOutAddressPointer, out var requestedAddress))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ulong mappedAddress;
        lock (_memoryGate)
        {
            var effectiveAlignment = alignment == 0 ? 0x1000UL : alignment;
            var fixedMapping = (flags & 0x10UL) != 0;
            var desiredAddress = requestedAddress != 0
                ? requestedAddress
                : directMemoryStart != 0
                    ? AlignUp(directMemoryStart, effectiveAlignment)
                    : AlignUp(_nextVirtualAddress == 0 ? 0x1_0000_0000UL : _nextVirtualAddress, effectiveAlignment);

            var reserved = false;
            if (fixedMapping && requestedAddress != 0)
            {
                mappedAddress = requestedAddress;
            }
            else
            {
                reserved = TryReserveGuestVirtualRange(ctx, desiredAddress, length, protection, effectiveAlignment, out mappedAddress);
            }
            if (ShouldTraceDirectMemory())
            {
                Console.Error.WriteLine(
                    $"[LOADER][TRACE] map_direct reserve: requested=0x{requestedAddress:X16} desired=0x{desiredAddress:X16} reserved={reserved} mapped=0x{mappedAddress:X16}");
            }
            if (!reserved)
            {
                if (mappedAddress == 0)
                {
                    mappedAddress = requestedAddress != 0
                        ? requestedAddress
                        : AllocateMappedGuestAddress(ctx, length, effectiveAlignment);
                    if (ShouldTraceDirectMemory())
                    {
                        Console.Error.WriteLine($"[LOADER][TRACE] map_direct fallback mapped=0x{mappedAddress:X16}");
                    }
                }
            }

            if (mappedAddress == 0)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            _nextVirtualAddress = Math.Max(_nextVirtualAddress, mappedAddress + length);
            _mappedRegions[mappedAddress] = new MappedRegion(
                mappedAddress,
                length,
                protection,
                IsFlexible: false,
                IsDirect: true,
                DirectStart: directMemoryStart);
        }

        if (!ctx.TryWriteUInt64(inOutAddressPointer, mappedAddress))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "NcaWUxfMNIQ",
        ExportName = "sceKernelMapNamedDirectMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMapNamedDirectMemory(CpuContext ctx)
    {
        return KernelMapDirectMemory(ctx);
    }

    [SysAbiExport(
        Nid = "mL8NDH86iQI",
        ExportName = "sceKernelMapNamedFlexibleMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMapNamedFlexibleMemory(CpuContext ctx)
    {
        var inOutAddressPointer = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        var protection = unchecked((int)ctx[CpuRegister.Rdx]);
        var flags = ctx[CpuRegister.Rcx];
        Console.Error.WriteLine(
            $"[LOADER][TRACE] map_flexible: inout=0x{inOutAddressPointer:X16} len=0x{length:X16} prot=0x{protection:X8} flags=0x{flags:X16}");
        if (inOutAddressPointer == 0 || length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!ctx.TryReadUInt64(inOutAddressPointer, out var requestedAddress))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ulong mappedAddress;
        lock (_memoryGate)
        {
            var fixedMapping = (flags & 0x10UL) != 0;
            var desiredAddress = requestedAddress != 0
                ? requestedAddress
                : AlignUp(_nextVirtualAddress == 0 ? 0x1_0000_0000UL : _nextVirtualAddress, 0x1000UL);

            if (fixedMapping && requestedAddress != 0)
            {
                mappedAddress = requestedAddress;
            }
            else if (!TryReserveGuestVirtualRange(ctx, desiredAddress, length, protection, OrbisPageSize, out mappedAddress))
            {
                mappedAddress = requestedAddress != 0 && fixedMapping
                    ? requestedAddress
                    : AllocateMappedGuestAddress(ctx, length, 0x1000UL);
            }

            Console.Error.WriteLine(
                $"[LOADER][TRACE] map_flexible reserve: requested=0x{requestedAddress:X16} desired=0x{desiredAddress:X16} mapped=0x{mappedAddress:X16}");

            if (mappedAddress == 0)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            _nextVirtualAddress = Math.Max(_nextVirtualAddress, mappedAddress + length);
            _allocatedFlexibleBytes = Math.Min(FlexibleMemorySizeBytes, _allocatedFlexibleBytes + length);
            _mappedRegions[mappedAddress] = new MappedRegion(
                mappedAddress,
                length,
                protection,
                IsFlexible: true,
                IsDirect: false,
                DirectStart: 0);
        }

        if (!ctx.TryWriteUInt64(inOutAddressPointer, mappedAddress))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "IWIBBdTHit4",
        ExportName = "sceKernelMapFlexibleMemory",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMapFlexibleMemory(CpuContext ctx)
    {
        return KernelMapNamedFlexibleMemory(ctx);
    }

    [SysAbiExport(
        Nid = "4h6F1LLbTiw",
        ExportName = "sceKernelMapFlexibleMemoryInternal",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMapFlexibleMemoryInternal(CpuContext ctx)
    {
        return KernelMapNamedFlexibleMemory(ctx);
    }

    [SysAbiExport(
        Nid = "2SKEx6bSq-4",
        ExportName = "sceKernelBatchMap",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelBatchMap(CpuContext ctx)
    {
        return KernelBatchMapCore(ctx, OrbisKernelMapFixed);
    }

    [SysAbiExport(
        Nid = "kBJzF8x4SyE",
        ExportName = "sceKernelBatchMap2",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelBatchMap2(CpuContext ctx)
    {
        return KernelBatchMapCore(ctx, unchecked((int)ctx[CpuRegister.Rcx]));
    }

    [SysAbiExport(
        Nid = "cQke9UuBQOk",
        ExportName = "sceKernelMunmap",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMunmap(CpuContext ctx)
    {
        var address = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        if (address == 0 || length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        lock (_memoryGate)
        {
            if (!_mappedRegions.TryGetValue(address, out var mappedRegion) || mappedRegion.Length != length)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            _mappedRegions.Remove(address);
            if (mappedRegion.IsFlexible)
            {
                _allocatedFlexibleBytes = mappedRegion.Length >= _allocatedFlexibleBytes
                    ? 0
                    : _allocatedFlexibleBytes - mappedRegion.Length;
            }
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "DGMG3JshrZU",
        ExportName = "sceKernelSetVirtualRangeName",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelSetVirtualRangeName(CpuContext ctx)
    {
        var address = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        var nameAddress = ctx[CpuRegister.Rdx];
        if (nameAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        if (!TryReadCString(ctx, nameAddress, OrbisKernelMaximumNameLength, out var nameBytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        var name = Encoding.UTF8.GetString(nameBytes);
        lock (_memoryGate)
        {
            if (!TryFindVirtualQueryRegionLocked(address, findNext: false, out var region) ||
                length > region.Length ||
                address < region.Address ||
                length > region.Address + region.Length - address)
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            _mappedRegionNames[region.Address] = name;
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "rVjRvHJ0X6c",
        ExportName = "sceKernelVirtualQuery",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelVirtualQuery(CpuContext ctx)
    {
        var queryAddress = ctx[CpuRegister.Rdi];
        var flags = unchecked((int)ctx[CpuRegister.Rsi]);
        var infoAddress = ctx[CpuRegister.Rdx];
        var infoSize = ctx[CpuRegister.Rcx];
        if (infoAddress == 0 || infoSize < OrbisVirtualQueryInfoSize)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        MappedRegion region;
        var memoryType = 0;
        lock (_memoryGate)
        {
            if (!TryFindVirtualQueryRegionLocked(queryAddress, findNext: (flags & 0x1) != 0, out region))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
            }

            if (region.IsDirect && TryFindDirectAllocationLocked(region.DirectStart, out var allocation))
            {
                memoryType = allocation.MemoryType;
            }
        }

        Span<byte> payload = stackalloc byte[OrbisVirtualQueryInfoSize];
        payload.Clear();

        var regionEnd = TryAddU64(region.Address, region.Length, out var exclusiveEnd)
            ? exclusiveEnd
            : ulong.MaxValue;
        var stateFlags = 0u;
        if (region.IsFlexible)
        {
            stateFlags |= 0x01u;
        }

        if (region.IsDirect)
        {
            stateFlags |= 0x02u;
        }

        stateFlags |= 0x10u;

        BinaryPrimitives.WriteUInt64LittleEndian(payload[0..8], region.Address);
        BinaryPrimitives.WriteUInt64LittleEndian(payload[8..16], regionEnd);
        BinaryPrimitives.WriteUInt64LittleEndian(payload[16..24], region.DirectStart);
        BinaryPrimitives.WriteInt32LittleEndian(payload[24..28], region.Protection);
        BinaryPrimitives.WriteInt32LittleEndian(payload[28..32], memoryType);
        payload[32] = unchecked((byte)stateFlags);

        string name;
        lock (_memoryGate)
        {
            name = _mappedRegionNames.GetValueOrDefault(region.Address)
                ?? (region.IsDirect
                    ? "direct"
                    : region.IsFlexible
                        ? "flexible"
                        : string.Empty);
        }
        if (!string.IsNullOrEmpty(name))
        {
            var nameBytes = Encoding.ASCII.GetBytes(name);
            nameBytes.AsSpan(0, Math.Min(nameBytes.Length, OrbisKernelMaximumNameLength))
                .CopyTo(payload.Slice(33, OrbisKernelMaximumNameLength));
        }

        if (!TryWriteCompat(ctx, infoAddress, payload))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = 0;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "WFcfL2lzido",
        ExportName = "sceKernelQueryMemoryProtection",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelQueryMemoryProtection(CpuContext ctx)
    {
        var queryAddress = ctx[CpuRegister.Rdi];
        var startOut = ctx[CpuRegister.Rsi];
        var endOut = ctx[CpuRegister.Rdx];
        var protectionOut = ctx[CpuRegister.Rcx];

        lock (_memoryGate)
        {
            foreach (var region in _mappedRegions.Values)
            {
                if (queryAddress < region.Address || queryAddress >= region.Address + region.Length)
                {
                    continue;
                }

                if (startOut != 0 && !ctx.TryWriteUInt64(startOut, region.Address))
                {
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
                }

                if (endOut != 0 && !ctx.TryWriteUInt64(endOut, region.Address + region.Length - 1))
                {
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
                }

                if (protectionOut != 0 && !TryWriteInt32(ctx, protectionOut, region.Protection))
                {
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
                }

                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
    }

    [SysAbiExport(
        Nid = "BHouLQzh0X0",
        ExportName = "sceKernelDirectMemoryQuery",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelDirectMemoryQuery(CpuContext ctx)
    {
        var offset = ctx[CpuRegister.Rdi];
        _ = ctx[CpuRegister.Rsi]; // flags
        var infoAddress = ctx[CpuRegister.Rdx];
        var infoSize = ctx[CpuRegister.Rcx];
        if (infoAddress == 0 || infoSize < 24)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        lock (_memoryGate)
        {
            foreach (var block in _directAllocations.Values)
            {
                if (offset < block.Start || offset >= block.Start + block.Length)
                {
                    continue;
                }

                if (!ctx.TryWriteUInt64(infoAddress, block.Start) ||
                    !ctx.TryWriteUInt64(infoAddress + sizeof(ulong), block.Start + block.Length) ||
                    !TryWriteInt32(ctx, infoAddress + (sizeof(ulong) * 2), block.MemoryType))
                {
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
                }

                return (int)OrbisGen2Result.ORBIS_GEN2_OK;
            }
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
    }

    [SysAbiExport(
        Nid = "vSMAm3cxYTY",
        ExportName = "sceKernelMprotect",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMprotect(CpuContext ctx)
    {
        var address = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        var protection = unchecked((int)ctx[CpuRegister.Rdx]);
        if (address == 0 || length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryNormalizeProtectRange(address, length, out var alignedAddress, out var alignedLength))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryProtectHostRange(alignedAddress, alignedLength, protection))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        lock (_memoryGate)
        {
            _ = TryApplyMappedRegionProtectionLocked(alignedAddress, alignedLength, protection);
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    [SysAbiExport(
        Nid = "9bfdLIyuwCY",
        ExportName = "sceKernelMtypeprotect",
        Target = Generation.Gen4 | Generation.Gen5,
        LibraryName = "libKernel")]
    public static int KernelMtypeprotect(CpuContext ctx)
    {
        var address = ctx[CpuRegister.Rdi];
        var length = ctx[CpuRegister.Rsi];
        var memoryType = unchecked((int)ctx[CpuRegister.Rdx]);
        var protection = unchecked((int)ctx[CpuRegister.Rcx]);
        if (address == 0 || length == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryNormalizeProtectRange(address, length, out var alignedAddress, out var alignedLength))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!TryProtectHostRange(alignedAddress, alignedLength, protection))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        lock (_memoryGate)
        {
            _ = TryApplyMappedRegionProtectionLocked(alignedAddress, alignedLength, protection, memoryType);
        }

        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static int KernelRtldThreadAtexitAdjust(CpuContext ctx, int delta)
    {
        var counterAddress = ctx[CpuRegister.Rdi];
        if (counterAddress == 0)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        if (!ctx.TryReadUInt64(counterAddress, out var value))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var adjusted = delta >= 0
            ? unchecked(value + (ulong)delta)
            : value >= (ulong)(-delta)
                ? unchecked(value - (ulong)(-delta))
                : 0UL;
        if (!ctx.TryWriteUInt64(counterAddress, adjusted))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = adjusted;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static int SnprintfCore(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var bufferSize = ctx[CpuRegister.Rsi];
        var formatAddress = ctx[CpuRegister.Rdx];

        if (!TryReadCString(ctx, formatAddress, 1_048_576, out var formatBytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var format = Encoding.UTF8.GetString(formatBytes);
        var result = FormatString(ctx, format);

        return WriteSnprintfOutput(ctx, destination, bufferSize, result);
    }

    private static int VsnprintfCore(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var bufferSize = ctx[CpuRegister.Rsi];
        var formatAddress = ctx[CpuRegister.Rdx];
        var vaListAddress = ctx[CpuRegister.Rcx];

        if (!TryReadCString(ctx, formatAddress, 1_048_576, out var formatBytes))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var format = Encoding.UTF8.GetString(formatBytes);
        if (!TryCreateVaListCursor(ctx, vaListAddress, out var vaCursor))
        {
            return WriteSnprintfOutput(ctx, destination, bufferSize, formatBytes);
        }

        var rendered = FormatString(ctx, format, ref vaCursor);

        return WriteSnprintfOutput(ctx, destination, bufferSize, rendered);
    }

    private static int SwprintfCore(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var bufferSize = ctx[CpuRegister.Rsi];
        var formatAddress = ctx[CpuRegister.Rdx];

        if (!TryReadWideCString(ctx, formatAddress, 1_048_576, out var formatUnits))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var format = DecodeWideUnits(formatUnits);
        var rendered = FormatString(ctx, format);
        TraceWidePrintf(ctx, "swprintf", destination, bufferSize, format, rendered);
        return WriteSwprintfOutput(ctx, destination, bufferSize, rendered);
    }

    private static int VswprintfCore(CpuContext ctx)
    {
        var destination = ctx[CpuRegister.Rdi];
        var bufferSize = ctx[CpuRegister.Rsi];
        var formatAddress = ctx[CpuRegister.Rdx];
        var vaListAddress = ctx[CpuRegister.Rcx];

        if (!TryReadWideCString(ctx, formatAddress, 1_048_576, out var formatUnits))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        var format = DecodeWideUnits(formatUnits);
        string rendered;
        if (!TryCreateVaListCursor(ctx, vaListAddress, out var vaCursor))
        {
            rendered = format;
        }
        else
        {
            TraceWidePrintfVaList(ctx, "vswprintf", format, vaListAddress, vaCursor);
            rendered = FormatString(ctx, format, ref vaCursor);
        }

        TraceWidePrintf(ctx, "vswprintf", destination, bufferSize, format, rendered);
        return WriteSwprintfOutput(ctx, destination, bufferSize, rendered);
    }

    private static bool TryCreateVaListCursor(CpuContext ctx, ulong vaListAddress, out SysVAmd64VaListCursor cursor)
    {
        cursor = default;
        if (vaListAddress == 0)
        {
            return false;
        }

        Span<byte> vaList = stackalloc byte[24];
        if (!TryReadCompat(ctx, vaListAddress, vaList))
        {
            return false;
        }

        cursor = new SysVAmd64VaListCursor(
            ctx,
            vaListAddress,
            BinaryPrimitives.ReadUInt32LittleEndian(vaList),
            BinaryPrimitives.ReadUInt32LittleEndian(vaList[4..]),
            BinaryPrimitives.ReadUInt64LittleEndian(vaList[8..]),
            BinaryPrimitives.ReadUInt64LittleEndian(vaList[16..]));
        return true;
    }

    private static int WriteSnprintfOutput(
        CpuContext ctx,
        ulong destination,
        ulong bufferSize,
        ReadOnlySpan<byte> outputBytes)
    {
        if (bufferSize != 0 && destination != 0)
        {
            var maxWritable = (int)Math.Min((ulong)int.MaxValue, bufferSize - 1);
            var copyLength = Math.Min(maxWritable, outputBytes.Length);
            if (copyLength > 0 && !ctx.Memory.TryWrite(destination, outputBytes[..copyLength]))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }

            Span<byte> nullTerminator = stackalloc byte[1];
            if (!ctx.Memory.TryWrite(destination + (ulong)copyLength, nullTerminator))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)outputBytes.Length);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static int WriteSnprintfOutput(
        CpuContext ctx,
        ulong destination,
        ulong bufferSize,
        string output)
    {
        if (bufferSize == 0 || destination == 0)
        {
            ctx[CpuRegister.Rax] = unchecked((ulong)Encoding.UTF8.GetByteCount(output));
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        return WriteSnprintfOutput(ctx, destination, bufferSize, Encoding.UTF8.GetBytes(output));
    }

    private static int WriteSwprintfOutput(
        CpuContext ctx,
        ulong destination,
        ulong bufferSize,
        string rendered)
    {
        if (bufferSize != 0 && destination != 0)
        {
            var maxWritableChars = (int)Math.Min((ulong)int.MaxValue, bufferSize - 1);
            var copyLength = Math.Min(maxWritableChars, rendered.Length);
            if (copyLength > 0)
            {
                var outputBytes = Encoding.Unicode.GetBytes(rendered[..copyLength]);
                if (!TryWriteCompat(ctx, destination, outputBytes))
                {
                    return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
                }
            }

            Span<byte> nullTerminator = stackalloc byte[WideCharSize];
            if (!TryWriteCompat(ctx, destination + ((ulong)copyLength * WideCharSize), nullTerminator))
            {
                return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
            }
        }

        ctx[CpuRegister.Rax] = unchecked((ulong)rendered.Length);
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static void TraceWidePrintf(CpuContext ctx, string exportName, ulong destination, ulong bufferSize, string format, string rendered)
    {
        if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_WIDE_PRINTF"), "1", StringComparison.Ordinal))
        {
            return;
        }

        var formatPreview = format.Length > 160 ? format[..160] + "..." : format;
        var renderedPreview = rendered.Length > 160 ? rendered[..160] + "..." : rendered;
        Console.Error.WriteLine(
            $"[LOADER][TRACE] {exportName}: dst=0x{destination:X16} count=0x{bufferSize:X} len={rendered.Length} fmt='{formatPreview}' rendered='{renderedPreview}'");
    }

    private static void TraceWidePrintfVaList(
        CpuContext ctx,
        string exportName,
        string format,
        ulong vaListAddress,
        SysVAmd64VaListCursor cursor)
    {
        if (!ShouldTraceWidePrintfArgs(format))
        {
            return;
        }

        Console.Error.WriteLine(
            $"[LOADER][TRACE] {exportName}: va_list=0x{vaListAddress:X16} gp_offset={cursor.GpOffset} fp_offset={cursor.FpOffset} overflow=0x{cursor.OverflowArgArea:X16} reg_save=0x{cursor.RegSaveArea:X16}");

        if (cursor.RegSaveArea != 0)
        {
            for (var i = 0; i < 6; i++)
            {
                var slotAddress = cursor.RegSaveArea + ((ulong)i * 8);
                var valueText = TryReadUInt64Compat(ctx, slotAddress, out var value)
                    ? $"0x{value:X16}"
                    : "<unreadable>";
                Console.Error.WriteLine(
                    $"[LOADER][TRACE] {exportName}: reg_save.gp[{i}] @0x{slotAddress:X16} = {valueText}");
            }
        }

        if (cursor.OverflowArgArea != 0)
        {
            for (var i = 0; i < 4; i++)
            {
                var slotAddress = cursor.OverflowArgArea + ((ulong)i * 8);
                var valueText = TryReadUInt64Compat(ctx, slotAddress, out var value)
                    ? $"0x{value:X16}"
                    : "<unreadable>";
                Console.Error.WriteLine(
                    $"[LOADER][TRACE] {exportName}: overflow[{i}] @0x{slotAddress:X16} = {valueText}");
            }
        }
    }

    private static bool ShouldTraceWidePrintfArgs(string format)
    {
        if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_WIDE_PRINTF_ARGS"), "1", StringComparison.Ordinal))
        {
            return false;
        }

        var filter = Environment.GetEnvironmentVariable("SHARPEMU_LOG_WIDE_PRINTF_FILTER");
        return string.IsNullOrEmpty(filter) || format.Contains(filter, StringComparison.Ordinal);
    }

    private static void TracePrintfStringArgument(CpuContext ctx, string lengthMod, ulong address)
    {
        if (!ShouldTraceWidePrintfArgs(lengthMod == "l" ? "%ls" : "%s"))
        {
            return;
        }

        var widePreview = "<not-wide>";
        if (address != 0 && TryReadWideCString(ctx, address, 64, out var wideUnits))
        {
            widePreview = SanitizeTracePreview(DecodeWideUnits(wideUnits), 64);
        }
        else if (address == 0)
        {
            widePreview = "<null>";
        }
        else
        {
            widePreview = "<unreadable>";
        }

        var utf8Preview = "<null>";
        if (address != 0 && TryReadCString(ctx, address, 128, out var utf8Bytes))
        {
            utf8Preview = SanitizeTracePreview(Encoding.UTF8.GetString(utf8Bytes), 64);
        }
        else if (address != 0)
        {
            utf8Preview = "<unreadable>";
        }

        var rawPreview = "<null>";
        if (address != 0)
        {
            Span<byte> raw = stackalloc byte[32];
            rawPreview = TryReadCompat(ctx, address, raw)
                ? Convert.ToHexString(raw).ToLowerInvariant()
                : "<unreadable>";
        }

        Console.Error.WriteLine(
            $"[LOADER][TRACE] printf-arg %{lengthMod}s addr=0x{address:X16} wide='{widePreview}' utf8='{utf8Preview}' raw={rawPreview}");
    }

    private static string SanitizeTracePreview(string value, int maxLength)
    {
        if (string.IsNullOrEmpty(value))
        {
            return value;
        }

        var sanitized = value
            .Replace("\r", "\\r", StringComparison.Ordinal)
            .Replace("\n", "\\n", StringComparison.Ordinal)
            .Replace("\t", "\\t", StringComparison.Ordinal);
        return sanitized.Length > maxLength
            ? sanitized[..maxLength] + "..."
            : sanitized;
    }

    private readonly record struct PosixTm(
        int Second,
        int Minute,
        int Hour,
        int Day,
        int Month,
        int Year,
        int WeekDay,
        int YearDay,
        int IsDst)
    {
        public DateTime ToDateTime()
        {
            var year = Math.Clamp(1900 + Year, 1, 9999);
            var month = Math.Clamp(Month + 1, 1, 12);
            var day = Math.Clamp(Day, 1, DateTime.DaysInMonth(year, month));
            var hour = Math.Clamp(Hour, 0, 23);
            var minute = Math.Clamp(Minute, 0, 59);
            var second = Math.Clamp(Second, 0, 60);
            if (second == 60)
            {
                second = 59;
            }

            return new DateTime(year, month, day, hour, minute, second, DateTimeKind.Unspecified);
        }
    }

    private static bool TryReadPosixTm(CpuContext ctx, ulong address, out PosixTm tm)
    {
        tm = default;
        if (address == 0)
        {
            return false;
        }

        Span<byte> bytes = stackalloc byte[9 * sizeof(int)];
        if (!TryReadCompat(ctx, address, bytes))
        {
            return false;
        }

        tm = new PosixTm(
            BinaryPrimitives.ReadInt32LittleEndian(bytes[0..4]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[4..8]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[8..12]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[12..16]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[16..20]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[20..24]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[24..28]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[28..32]),
            BinaryPrimitives.ReadInt32LittleEndian(bytes[32..36]));
        return true;
    }

    private static string FormatWcsftime(string format, PosixTm tm)
    {
        var timestamp = tm.ToDateTime();
        var culture = CultureInfo.InvariantCulture;
        var builder = new StringBuilder(format.Length + 16);
        for (var i = 0; i < format.Length; i++)
        {
            var ch = format[i];
            if (ch != '%' || i + 1 >= format.Length)
            {
                builder.Append(ch);
                continue;
            }

            i++;
            builder.Append(format[i] switch
            {
                '%' => "%",
                'a' => timestamp.ToString("ddd", culture),
                'A' => timestamp.ToString("dddd", culture),
                'b' or 'h' => timestamp.ToString("MMM", culture),
                'B' => timestamp.ToString("MMMM", culture),
                'c' => timestamp.ToString("ddd MMM dd HH:mm:ss yyyy", culture),
                'd' => timestamp.ToString("dd", culture),
                'e' => timestamp.Day.ToString().PadLeft(2, ' '),
                'F' => timestamp.ToString("yyyy-MM-dd", culture),
                'H' => timestamp.ToString("HH", culture),
                'I' => timestamp.ToString("hh", culture),
                'j' => timestamp.DayOfYear.ToString("D3", culture),
                'm' => timestamp.ToString("MM", culture),
                'M' => timestamp.ToString("mm", culture),
                'n' => "\n",
                'p' => timestamp.ToString("tt", culture),
                'R' => timestamp.ToString("HH:mm", culture),
                'S' => timestamp.ToString("ss", culture),
                't' => "\t",
                'T' => timestamp.ToString("HH:mm:ss", culture),
                'u' => (((int)timestamp.DayOfWeek + 6) % 7 + 1).ToString(culture),
                'w' => ((int)timestamp.DayOfWeek).ToString(culture),
                'x' => timestamp.ToString("MM/dd/yy", culture),
                'X' => timestamp.ToString("HH:mm:ss", culture),
                'y' => timestamp.ToString("yy", culture),
                'Y' => timestamp.ToString("yyyy", culture),
                'Z' => tm.IsDst == 0 ? "UTC" : "DST",
                'z' => "+0000",
                _ => "%" + format[i]
            });
        }

        return builder.ToString();
    }

    private static void TraceLibcAllocation(
        CpuContext ctx,
        string operation,
        ulong size,
        ulong alignment = 0,
        ulong count = 0,
        ulong existingAddress = 0,
        ulong resultAddress = 0,
        int? errorCode = null)
    {
        if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_LIBC_ALLOC"), "1", StringComparison.Ordinal))
        {
            return;
        }

        var returnRip = 0UL;
        var stackPointer = ctx[CpuRegister.Rsp];
        if (stackPointer != 0)
        {
            _ = ctx.TryReadUInt64(stackPointer, out returnRip);
        }

        Console.Error.WriteLine(
            $"[LOADER][TRACE] {operation}: ret=0x{returnRip:X16} size=0x{size:X16} count=0x{count:X16} align=0x{alignment:X16} in=0x{existingAddress:X16} result=0x{resultAddress:X16} errno={(errorCode.HasValue ? errorCode.Value : 0)}");
    }

    internal static string FormatStringFromVarArgs(CpuContext ctx, string format, int firstGpArgIndex)
    {
        var argumentSource = new RegisterPrintfArgumentSource(ctx, Math.Max(0, firstGpArgIndex));
        return FormatString(ctx, format, ref argumentSource);
    }

    private static string FormatString(CpuContext ctx, string format)
    {
        return FormatStringFromVarArgs(ctx, format, firstGpArgIndex: 3);
    }

    private static string FormatString<TArgumentSource>(
        CpuContext ctx,
        string format,
        ref TArgumentSource argumentSource)
        where TArgumentSource : struct, IPrintfArgumentSource
    {
        var sb = new StringBuilder(format.Length + 32);

        for (var i = 0; i < format.Length; i++)
        {
            if (format[i] != '%')
            {
                sb.Append(format[i]);
                continue;
            }

            i++;
            if (i >= format.Length)
            {
                sb.Append('%');
                break;
            }

            var leftAlign = false;
            var showSign = false;
            var spaceForSign = false;
            var padWithZero = false;
            var alternateForm = false;

            while (i < format.Length)
            {
                switch (format[i])
                {
                    case '-': leftAlign = true; i++; continue;
                    case '+': showSign = true; i++; continue;
                    case ' ': spaceForSign = true; i++; continue;
                    case '0': padWithZero = true; i++; continue;
                    case '#': alternateForm = true; i++; continue;
                }
                break;
            }

            var width = 0;
            if (i < format.Length && format[i] == '*')
            {
                width = unchecked((int)argumentSource.NextGpArg());
                i++;
                if (width < 0)
                {
                    leftAlign = true;
                    width = -width;
                }
            }
            else if (i < format.Length && char.IsDigit(format[i]))
            {
                while (i < format.Length && char.IsDigit(format[i]))
                {
                    width = width * 10 + (format[i] - '0');
                    i++;
                }
            }

            var precision = -1;
            if (i < format.Length && format[i] == '.')
            {
                i++;
                if (i < format.Length && format[i] == '*')
                {
                    precision = unchecked((int)argumentSource.NextGpArg());
                    i++;
                }
                else if (i < format.Length && char.IsDigit(format[i]))
                {
                    precision = 0;
                    while (i < format.Length && char.IsDigit(format[i]))
                    {
                        precision = precision * 10 + (format[i] - '0');
                        i++;
                    }
                }
                else
                {
                    precision = 0;
                }
            }

            var lengthMod = "";
            if (i < format.Length)
            {
                if (i + 1 < format.Length &&
                    ((format[i] == 'h' && format[i + 1] == 'h') ||
                     (format[i] == 'l' && format[i + 1] == 'l')))
                {
                    lengthMod = format.Substring(i, 2);
                    i += 2;
                }
                else if (format[i] is 'h' or 'l' or 'j' or 'z' or 't' or 'L')
                {
                    lengthMod = format[i].ToString();
                    i++;
                }
            }

            if (i >= format.Length)
            {
                sb.Append('%');
                break;
            }

            var specifier = format[i];

            switch (specifier)
            {
                case '%':
                    sb.Append('%');
                    break;

                case 'd':
                case 'i':
                    {
                        long value = lengthMod switch
                        {
                            "hh" => unchecked((sbyte)argumentSource.NextGpArg()),
                            "h" => unchecked((short)argumentSource.NextGpArg()),
                            "l" => unchecked((long)argumentSource.NextGpArg()),
                            "ll" => unchecked((long)argumentSource.NextGpArg()),
                            "j" => unchecked((long)argumentSource.NextGpArg()),
                            "z" => unchecked((long)argumentSource.NextGpArg()),
                            "t" => unchecked((long)argumentSource.NextGpArg()),
                            _ => unchecked((int)argumentSource.NextGpArg())
                        };

                        var formatted = value.ToString();
                        if (showSign && value >= 0)
                            formatted = "+" + formatted;
                        else if (spaceForSign && value >= 0)
                            formatted = " " + formatted;

                        sb.Append(PadString(formatted, width, leftAlign, padWithZero && !leftAlign));
                    }
                    break;

                case 'u':
                    {
                        ulong value = lengthMod switch
                        {
                            "hh" => (byte)argumentSource.NextGpArg(),
                            "h" => (ushort)argumentSource.NextGpArg(),
                            "l" => argumentSource.NextGpArg(),
                            "ll" => argumentSource.NextGpArg(),
                            "j" => argumentSource.NextGpArg(),
                            "z" => argumentSource.NextGpArg(),
                            "t" => argumentSource.NextGpArg(),
                            _ => (uint)argumentSource.NextGpArg()
                        };

                        var formatted = value.ToString();
                        sb.Append(PadString(formatted, width, leftAlign, padWithZero && !leftAlign));
                    }
                    break;

                case 'x':
                case 'X':
                    {
                        ulong value = lengthMod switch
                        {
                            "hh" => (byte)argumentSource.NextGpArg(),
                            "h" => (ushort)argumentSource.NextGpArg(),
                            "l" => argumentSource.NextGpArg(),
                            "ll" => argumentSource.NextGpArg(),
                            "j" => argumentSource.NextGpArg(),
                            "z" => argumentSource.NextGpArg(),
                            "t" => argumentSource.NextGpArg(),
                            _ => (uint)argumentSource.NextGpArg()
                        };

                        var formatted = specifier == 'x'
                            ? value.ToString("x")
                            : value.ToString("X");

                        if (alternateForm && value != 0)
                            formatted = specifier == 'x' ? "0x" + formatted : "0X" + formatted;

                        sb.Append(PadString(formatted, width, leftAlign, padWithZero && !leftAlign));
                    }
                    break;

                case 'o':
                    {
                        ulong value = lengthMod switch
                        {
                            "hh" => (byte)argumentSource.NextGpArg(),
                            "h" => (ushort)argumentSource.NextGpArg(),
                            "l" => argumentSource.NextGpArg(),
                            "ll" => argumentSource.NextGpArg(),
                            "j" => argumentSource.NextGpArg(),
                            "z" => argumentSource.NextGpArg(),
                            "t" => argumentSource.NextGpArg(),
                            _ => (uint)argumentSource.NextGpArg()
                        };

                        var formatted = Convert.ToString((long)value, 8);
                        if (alternateForm && value != 0)
                            formatted = "0" + formatted;

                        sb.Append(PadString(formatted, width, leftAlign, padWithZero && !leftAlign));
                    }
                    break;

                case 'p':
                    {
                        var value = argumentSource.NextGpArg();
                        var formatted = value == 0
                            ? "(nil)"
                            : $"0x{value:X}";
                        sb.Append(formatted);
                    }
                    break;

                case 's':
                    {
                        var strAddr = argumentSource.NextGpArg();
                        TracePrintfStringArgument(ctx, lengthMod, strAddr);
                        if (strAddr == 0)
                        {
                            sb.Append("(null)");
                        }
                        else if (lengthMod == "l")
                        {
                            if (TryReadWideCString(ctx, strAddr, 1_048_576, out var wideUnits))
                            {
                                var str = DecodeWideUnits(wideUnits);
                                if (precision >= 0 && str.Length > precision)
                                    str = str.Substring(0, precision);
                                sb.Append(PadString(str, width, leftAlign, false));
                            }
                            else
                            {
                                sb.Append("(null)");
                            }
                        }
                        else if (TryReadCString(ctx, strAddr, 1_048_576, out var strBytes))
                        {
                            var str = Encoding.UTF8.GetString(strBytes);
                            if (precision >= 0 && str.Length > precision)
                                str = str.Substring(0, precision);
                            sb.Append(PadString(str, width, leftAlign, false));
                        }
                        else
                        {
                            sb.Append("(null)");
                        }
                    }
                    break;

                case 'c':
                    {
                        string renderedChar;
                        if (lengthMod == "l")
                        {
                            var scalar = unchecked((ushort)argumentSource.NextGpArg());
                            renderedChar = TryConvertWideScalarToString(scalar, out var wideCharText)
                                ? wideCharText
                                : "?";
                        }
                        else
                        {
                            renderedChar = ((char)(byte)argumentSource.NextGpArg()).ToString();
                        }

                        sb.Append(PadString(renderedChar, width, leftAlign, false));
                    }
                    break;

                case 'f':
                case 'F':
                case 'e':
                case 'E':
                case 'g':
                case 'G':
                    {
                        var value = argumentSource.NextFloatArg();

                        var formatStr = precision >= 0
                            ? $"{{0:{specifier}{precision}}}"
                            : $"{{0:{specifier}}}";
                        var formatted = string.Format(formatStr, value);

                        if (showSign && value >= 0)
                            formatted = "+" + formatted;
                        else if (spaceForSign && value >= 0)
                            formatted = " " + formatted;

                        sb.Append(PadString(formatted, width, leftAlign, padWithZero && !leftAlign));
                    }
                    break;

                case 'n':
                    {
                        var addr = argumentSource.NextGpArg();
                        if (addr != 0)
                        {
                            _ = TryWriteInt32(ctx, addr, sb.Length);
                        }
                    }
                    break;

                default:
                    sb.Append('%');
                    sb.Append(specifier);
                    break;
            }
        }

        return sb.ToString();
    }

    private static ulong ReadStackArg(CpuContext ctx, ulong offset)
    {
        var rsp = ctx[CpuRegister.Rsp];
        if (!ctx.TryReadUInt64(rsp + offset + 8, out var value)) // +8 to skip return address
        {
            return 0;
        }
        return value;
    }

    private static string PadString(string str, int width, bool leftAlign, bool padWithZero)
    {
        if (width <= str.Length)
            return str;

        var padChar = padWithZero ? '0' : ' ';
        var padLength = width - str.Length;
        var padding = new string(padChar, padLength);

        return leftAlign ? str + padding : padding + str;
    }

    private interface IPrintfArgumentSource
    {
        ulong NextGpArg();

        double NextFloatArg();
    }

    private struct RegisterPrintfArgumentSource : IPrintfArgumentSource
    {
        private readonly CpuContext _ctx;
        private int _gpIndex;

        public RegisterPrintfArgumentSource(CpuContext ctx, int gpIndex)
        {
            _ctx = ctx;
            _gpIndex = gpIndex;
        }

        public ulong NextGpArg()
        {
            var index = _gpIndex++;
            return index switch
            {
                0 => _ctx[CpuRegister.Rdi],
                1 => _ctx[CpuRegister.Rsi],
                2 => _ctx[CpuRegister.Rdx],
                3 => _ctx[CpuRegister.Rcx],
                4 => _ctx[CpuRegister.R8],
                5 => _ctx[CpuRegister.R9],
                _ => ReadStackArg(_ctx, (ulong)(index - 6) * 8)
            };
        }

        public double NextFloatArg()
        {
            return BitConverter.Int64BitsToDouble(unchecked((long)NextGpArg()));
        }
    }

    private struct SysVAmd64VaListCursor : IPrintfArgumentSource
    {
        private const uint GpSaveAreaLimit = 48;
        private const uint FpSaveAreaLimit = 176;

        private readonly CpuContext _ctx;
        private readonly ulong _vaListAddress;
        private uint _gpOffset;
        private uint _fpOffset;
        private ulong _overflowArgArea;
        private readonly ulong _regSaveArea;

        public SysVAmd64VaListCursor(
            CpuContext ctx,
            ulong vaListAddress,
            uint gpOffset,
            uint fpOffset,
            ulong overflowArgArea,
            ulong regSaveArea)
        {
            _ctx = ctx;
            _vaListAddress = vaListAddress;
            _gpOffset = gpOffset;
            _fpOffset = fpOffset;
            _overflowArgArea = overflowArgArea;
            _regSaveArea = regSaveArea;
        }

        public ulong NextGpArg()
        {
            ulong readAddress;
            if (_regSaveArea != 0 && _gpOffset <= GpSaveAreaLimit - 8)
            {
                readAddress = _regSaveArea + _gpOffset;
                _gpOffset += 8;
            }
            else
            {
                readAddress = _overflowArgArea;
                _overflowArgArea += 8;
            }

            return TryReadUInt64Compat(_ctx, readAddress, out var value) ? value : 0;
        }

        public double NextFloatArg()
        {
            ulong readAddress;
            if (_regSaveArea != 0 && _fpOffset <= FpSaveAreaLimit - 16)
            {
                readAddress = _regSaveArea + _fpOffset;
                _fpOffset += 16;
            }
            else
            {
                readAddress = _overflowArgArea;
                _overflowArgArea += 8;
            }

            return TryReadUInt64Compat(_ctx, readAddress, out var rawBits)
                ? BitConverter.Int64BitsToDouble(unchecked((long)rawBits))
                : 0.0;
        }

        public uint GpOffset => _gpOffset;

        public uint FpOffset => _fpOffset;

        public ulong OverflowArgArea => _overflowArgArea;

        public ulong RegSaveArea => _regSaveArea;
    }

    private static ulong AllocateMappedGuestAddress(CpuContext ctx, ulong length, ulong alignment)
    {
        if (length == 0)
        {
            return 0;
        }

        var effectiveAlignment = alignment == 0 ? 0x1000UL : alignment;
        if (_nextVirtualAddress == 0)
        {
            _nextVirtualAddress = 0x0100_0000UL;
        }

        var probeCandidates = new[]
        {
            8UL * 1024 * 1024,
            2UL * 1024 * 1024,
            512UL * 1024,
            128UL * 1024,
            0x1000UL,
        };

        foreach (var probeCandidate in probeCandidates)
        {
            var cursor = AlignUp(_nextVirtualAddress, effectiveAlignment);
            for (var i = 0; i < 0x4000; i++)
            {
                if (IsMappedGuestRangeAvailable(ctx, cursor, length, probeCandidate))
                {
                    _nextVirtualAddress = cursor + length;
                    return cursor;
                }

                cursor = AlignUp(cursor + 0x1000UL, effectiveAlignment);
            }
        }

        return 0;
    }

    private static bool TryReserveGuestVirtualRange(
        CpuContext ctx,
        ulong desiredAddress,
        ulong length,
        int protection,
        ulong alignment,
        out ulong mappedAddress)
    {
        mappedAddress = 0;
        if (length == 0)
        {
            return false;
        }

        try
        {
            object memoryObject = ctx.Memory;
            MethodInfo? allocateAt = null;
            MethodInfo? allocateAtOrAbove = null;
            var allocateAtHasAllowAlternativeArg = false;
            for (var depth = 0; depth < 4; depth++)
            {
                foreach (var candidate in memoryObject.GetType().GetMethods(BindingFlags.Public | BindingFlags.Instance))
                {
                    var parameters = candidate.GetParameters();
                    if (string.Equals(candidate.Name, "TryAllocateAtOrAbove", StringComparison.Ordinal) &&
                        parameters.Length == 5 &&
                        parameters[0].ParameterType == typeof(ulong) &&
                        parameters[1].ParameterType == typeof(ulong) &&
                        parameters[2].ParameterType == typeof(bool) &&
                        parameters[3].ParameterType == typeof(ulong) &&
                        parameters[4].ParameterType == typeof(ulong).MakeByRefType())
                    {
                        allocateAtOrAbove = candidate;
                    }
                    else if (string.Equals(candidate.Name, "AllocateAt", StringComparison.Ordinal))
                    {
                        if (parameters.Length == 3 &&
                            parameters[0].ParameterType == typeof(ulong) &&
                            parameters[1].ParameterType == typeof(ulong) &&
                            parameters[2].ParameterType == typeof(bool))
                        {
                            allocateAt = candidate;
                            allocateAtHasAllowAlternativeArg = false;
                        }
                        else if (parameters.Length == 4 &&
                            parameters[0].ParameterType == typeof(ulong) &&
                            parameters[1].ParameterType == typeof(ulong) &&
                            parameters[2].ParameterType == typeof(bool) &&
                            parameters[3].ParameterType == typeof(bool))
                        {
                            allocateAt = candidate;
                            allocateAtHasAllowAlternativeArg = true;
                        }
                    }

                    if (allocateAtOrAbove is not null && allocateAt is not null)
                    {
                        break;
                    }
                }

                if (allocateAtOrAbove is not null || allocateAt is not null)
                {
                    break;
                }

                var innerProperty = memoryObject.GetType().GetProperty("Inner", BindingFlags.Public | BindingFlags.Instance);
                if (innerProperty is null)
                {
                    break;
                }

                var innerValue = innerProperty.GetValue(memoryObject);
                if (innerValue is null || ReferenceEquals(innerValue, memoryObject))
                {
                    break;
                }

                memoryObject = innerValue;
            }

            var executable = (protection & OrbisProtCpuExec) != 0;
            if (allocateAtOrAbove is not null)
            {
                var searchArgs = new object[] { desiredAddress, length, executable, alignment, 0UL };
                var searchResult = allocateAtOrAbove.Invoke(memoryObject, searchArgs);
                if (searchResult is bool trueValue && trueValue &&
                    searchArgs[4] is ulong searchedAddress && searchedAddress != 0)
                {
                    mappedAddress = searchedAddress;
                    return true;
                }
            }

            if (allocateAt is null)
            {
                Console.Error.WriteLine($"[LOADER][TRACE] reserve range: AllocateAt missing on {ctx.Memory.GetType().FullName}");
                return false;
            }

            var invokeArgs = allocateAtHasAllowAlternativeArg
                ? new object[] { desiredAddress, length, executable, false }
                : new object[] { desiredAddress, length, executable };
            var result = allocateAt.Invoke(memoryObject, invokeArgs);
            if (result is not ulong allocated || allocated == 0)
            {
                var resultType = result?.GetType().FullName ?? "null";
                Console.Error.WriteLine($"[LOADER][TRACE] reserve range: AllocateAt returned {resultType} value={result ?? "null"}");
                return false;
            }

            mappedAddress = allocated;
            return true;
        }
        catch
        {
            Console.Error.WriteLine("[LOADER][TRACE] reserve range threw while invoking AllocateAt");
            return false;
        }
    }

    private static bool IsMappedGuestRangeAvailable(
        CpuContext ctx,
        ulong address,
        ulong length,
        ulong minimumReadableSpan)
    {
        if (length == 0)
        {
            return false;
        }

        if (ulong.MaxValue - address < length - 1)
        {
            return false;
        }

        var end = address + length - 1;
        foreach (var region in _mappedRegions.Values)
        {
            var regionEnd = region.Address + region.Length - 1;
            if (address <= regionEnd && end >= region.Address)
            {
                return false;
            }
        }

        var probeLength = Math.Min(length, Math.Max(0x1000UL, minimumReadableSpan));
        var probeEnd = address + probeLength - 1;
        Span<byte> probe = stackalloc byte[1];
        return ctx.Memory.TryRead(address, probe) &&
               ctx.Memory.TryRead(probeEnd, probe);
    }

    private static FileAccess ResolveOpenAccess(int flags)
    {
        if ((flags & O_RDWR) == O_RDWR)
        {
            return FileAccess.ReadWrite;
        }

        if ((flags & O_WRONLY) == O_WRONLY)
        {
            return FileAccess.Write;
        }

        return FileAccess.Read;
    }

    private static FileMode ResolveOpenMode(int flags, FileAccess access)
    {
        var create = (flags & O_CREAT) != 0;
        var truncate = (flags & O_TRUNC) != 0;
        if (create && truncate)
        {
            return FileMode.Create;
        }

        if (create)
        {
            return FileMode.OpenOrCreate;
        }

        if (truncate)
        {
            return access == FileAccess.Read ? FileMode.Open : FileMode.Truncate;
        }

        return FileMode.Open;
    }

    private static string ResolveGuestPath(string guestPath)
    {
        if (string.IsNullOrWhiteSpace(guestPath))
        {
            return guestPath;
        }

        if (TryResolveRegisteredGuestMount(guestPath, out var mountedPath))
        {
            return mountedPath;
        }

        if (guestPath.StartsWith("/devlog/app/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["/devlog/app/".Length..]);
            return Path.Combine(ResolveDevlogAppRoot(), relative);
        }

        if (guestPath.StartsWith("devlog/app/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["devlog/app/".Length..]);
            return Path.Combine(ResolveDevlogAppRoot(), relative);
        }

        if (string.Equals(guestPath, "/devlog/app", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(guestPath, "devlog/app", StringComparison.OrdinalIgnoreCase))
        {
            return ResolveDevlogAppRoot();
        }

        if (guestPath.StartsWith("/temp0/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["/temp0/".Length..]);
            return Path.Combine(ResolveTemp0Root(), relative);
        }

        if (string.Equals(guestPath, "/temp0", StringComparison.OrdinalIgnoreCase))
        {
            return ResolveTemp0Root();
        }

        if (guestPath.StartsWith("/download0/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["/download0/".Length..]);
            return Path.Combine(ResolveDownload0Root(), relative);
        }

        if (guestPath.StartsWith("download0/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["download0/".Length..]);
            return Path.Combine(ResolveDownload0Root(), relative);
        }

        if (string.Equals(guestPath, "/download0", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(guestPath, "download0", StringComparison.OrdinalIgnoreCase))
        {
            return ResolveDownload0Root();
        }

        if (guestPath.StartsWith("/hostapp/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["/hostapp/".Length..]);
            return Path.Combine(ResolveHostappRoot(), relative);
        }

        if (guestPath.StartsWith("hostapp/", StringComparison.OrdinalIgnoreCase))
        {
            var relative = NormalizeMountRelativePath(guestPath["hostapp/".Length..]);
            return Path.Combine(ResolveHostappRoot(), relative);
        }

        if (string.Equals(guestPath, "/hostapp", StringComparison.OrdinalIgnoreCase) ||
            string.Equals(guestPath, "hostapp", StringComparison.OrdinalIgnoreCase))
        {
            return ResolveHostappRoot();
        }

        var app0Root = ResolveApp0Root();
        if (!string.IsNullOrWhiteSpace(app0Root))
        {
            if (string.Equals(guestPath, "/app0", StringComparison.OrdinalIgnoreCase) ||
                string.Equals(guestPath, "app0", StringComparison.OrdinalIgnoreCase))
            {
                return app0Root;
            }

            if (guestPath.StartsWith("/app0/", StringComparison.OrdinalIgnoreCase))
            {
                var relative = NormalizeMountRelativePath(guestPath["/app0/".Length..]);
                return Path.Combine(app0Root, relative);
            }

            if (guestPath.StartsWith("app0/", StringComparison.OrdinalIgnoreCase))
            {
                var relative = NormalizeMountRelativePath(guestPath["app0/".Length..]);
                return Path.Combine(app0Root, relative);
            }

            if (!Path.IsPathFullyQualified(guestPath) &&
                !guestPath.StartsWith("/", StringComparison.Ordinal) &&
                !guestPath.StartsWith("\\", StringComparison.Ordinal))
            {
                var relative = guestPath.Replace('/', Path.DirectorySeparatorChar);
                return Path.Combine(app0Root, relative);
            }
        }

        return guestPath;
    }

    private static bool TryResolveRegisteredGuestMount(string guestPath, out string hostPath)
    {
        hostPath = string.Empty;
        var normalizedGuestPath = NormalizeGuestStatCachePath(guestPath);
        if (normalizedGuestPath is null)
        {
            return false;
        }

        string? matchedMountPoint = null;
        string? matchedHostRoot = null;
        lock (_guestMountGate)
        {
            foreach (var (mountPoint, hostRoot) in _guestMounts)
            {
                if ((string.Equals(normalizedGuestPath, mountPoint, StringComparison.OrdinalIgnoreCase) ||
                     normalizedGuestPath.StartsWith(mountPoint + "/", StringComparison.OrdinalIgnoreCase)) &&
                    (matchedMountPoint is null || mountPoint.Length > matchedMountPoint.Length))
                {
                    matchedMountPoint = mountPoint;
                    matchedHostRoot = hostRoot;
                }
            }
        }

        if (matchedMountPoint is null || matchedHostRoot is null)
        {
            return false;
        }

        var relativePath = normalizedGuestPath[matchedMountPoint.Length..].TrimStart('/');
        var candidate = Path.GetFullPath(Path.Combine(
            matchedHostRoot,
            NormalizeMountRelativePath(relativePath)));
        var rootWithSeparator = Path.TrimEndingDirectorySeparator(matchedHostRoot) + Path.DirectorySeparatorChar;
        if (!string.Equals(candidate, matchedHostRoot, StringComparison.OrdinalIgnoreCase) &&
            !candidate.StartsWith(rootWithSeparator, StringComparison.OrdinalIgnoreCase))
        {
            return false;
        }

        hostPath = candidate;
        return true;
    }

    private static string? ResolveApp0Root()
    {
        var cached = Volatile.Read(ref _cachedApp0Root);
        if (!string.IsNullOrWhiteSpace(cached))
        {
            return cached;
        }

        var configured = Environment.GetEnvironmentVariable("SHARPEMU_APP0_DIR");
        if (string.IsNullOrWhiteSpace(configured))
        {
            return null;
        }

        Interlocked.CompareExchange(ref _cachedApp0Root, configured, null);
        return _cachedApp0Root;
    }

    private static string NormalizeMountRelativePath(string relativePath)
    {
        return relativePath
            .TrimStart('/', '\\')
            .Replace('/', Path.DirectorySeparatorChar)
            .Replace('\\', Path.DirectorySeparatorChar);
    }

    private static string ResolveDevlogAppRoot()
    {
        var configuredRoot = Environment.GetEnvironmentVariable("SHARPEMU_DEVLOG_APP_DIR");
        string root;
        if (!string.IsNullOrWhiteSpace(configuredRoot))
        {
            root = Path.GetFullPath(configuredRoot);
        }
        else
        {
            root = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "logs", "devlog", "app"));
        }

        Directory.CreateDirectory(root);
        return root;
    }

    private static string ResolveTemp0Root()
    {
        const string temp0VariableName = "SHARPEMU_TEMP0_DIR";
        var configuredRoot = Environment.GetEnvironmentVariable(temp0VariableName);
        if (!string.IsNullOrWhiteSpace(configuredRoot))
        {
            return Path.GetFullPath(configuredRoot);
        }

        var app0Root = Environment.GetEnvironmentVariable("SHARPEMU_APP0_DIR");
        var appName = string.IsNullOrWhiteSpace(app0Root)
            ? "default"
            : Path.GetFileName(Path.TrimEndingDirectorySeparator(app0Root));
        if (string.IsNullOrWhiteSpace(appName))
        {
            appName = "default";
        }

        var invalidChars = Path.GetInvalidFileNameChars();
        appName = new string(appName.Select(ch => invalidChars.Contains(ch) ? '_' : ch).ToArray());
        var root = Path.Combine(Path.GetTempPath(), "SharpEmu", appName, "temp0");
        Environment.SetEnvironmentVariable(temp0VariableName, root);
        return root;
    }

    private static string ResolveDownload0Root()
    {
        var cached = Volatile.Read(ref _cachedDownload0Root);
        if (!string.IsNullOrWhiteSpace(cached))
        {
            return cached;
        }

        const string download0VariableName = "SHARPEMU_DOWNLOAD0_DIR";
        var configuredRoot = Environment.GetEnvironmentVariable(download0VariableName);
        string root;
        if (!string.IsNullOrWhiteSpace(configuredRoot))
        {
            root = Path.GetFullPath(configuredRoot);
        }
        else
        {
            root = Path.Combine(GetPerAppWritableRoot(), "download0");
            Environment.SetEnvironmentVariable(download0VariableName, root);
        }

        Directory.CreateDirectory(root);
        Interlocked.CompareExchange(ref _cachedDownload0Root, root, null);
        return _cachedDownload0Root;
    }

    private static string ResolveHostappRoot()
    {
        const string hostappVariableName = "SHARPEMU_HOSTAPP_DIR";
        var configuredRoot = Environment.GetEnvironmentVariable(hostappVariableName);
        string root;
        if (!string.IsNullOrWhiteSpace(configuredRoot))
        {
            root = Path.GetFullPath(configuredRoot);
        }
        else
        {
            root = Path.GetFullPath(Path.Combine(Environment.CurrentDirectory, "logs", "hostapp"));
            Environment.SetEnvironmentVariable(hostappVariableName, root);
        }

        Directory.CreateDirectory(root);
        return root;
    }

    private static string GetPerAppWritableRoot()
    {
        var app0Root = Environment.GetEnvironmentVariable("SHARPEMU_APP0_DIR");
        var appName = string.IsNullOrWhiteSpace(app0Root)
            ? "default"
            : Path.GetFileName(Path.TrimEndingDirectorySeparator(app0Root));
        if (string.IsNullOrWhiteSpace(appName))
        {
            appName = "default";
        }

        var invalidChars = Path.GetInvalidFileNameChars();
        appName = new string(appName.Select(ch => invalidChars.Contains(ch) ? '_' : ch).ToArray());
        return Path.Combine(Path.GetTempPath(), "SharpEmu", appName);
    }

    private static void EnsureOpenParentDirectoryExists(string guestPath, string hostPath, int flags)
    {
        if (string.IsNullOrWhiteSpace(hostPath))
        {
            return;
        }

        var shouldCreateParent =
            (flags & O_CREAT) != 0 ||
            guestPath.StartsWith("/devlog/app/", StringComparison.OrdinalIgnoreCase) ||
            guestPath.StartsWith("devlog/app/", StringComparison.OrdinalIgnoreCase);
        if (!shouldCreateParent)
        {
            return;
        }

        var parentDirectory = Path.GetDirectoryName(hostPath);
        if (!string.IsNullOrWhiteSpace(parentDirectory))
        {
            Directory.CreateDirectory(parentDirectory);
        }
    }

    private static bool IsMutatingOpen(int flags) =>
        (flags & (O_WRONLY | O_RDWR | O_CREAT | O_TRUNC | O_APPEND)) != 0;

    private static bool IsReadOnlyGuestMutationPath(string guestPath)
    {
        var normalized = NormalizeGuestStatCachePath(guestPath);
        return normalized is not null &&
               (string.Equals(normalized, "/app0", StringComparison.OrdinalIgnoreCase) ||
                normalized.StartsWith("/app0/", StringComparison.OrdinalIgnoreCase));
    }

    private static bool TryReadCString(CpuContext ctx, ulong address, ulong maxLength, out byte[] bytes)
    {
        return TryReadBytesUntilNull(ctx, address, maxLength, 1_048_576, out bytes);
    }

    private static bool TryReadBytesUntilNull(
        CpuContext ctx,
        ulong address,
        ulong maxLength,
        int hardLimit,
        out byte[] bytes)
    {
        bytes = Array.Empty<byte>();
        if (address == 0)
        {
            return false;
        }

        var limit = (int)Math.Min(maxLength, (ulong)Math.Max(0, hardLimit));
        if (limit == 0)
        {
            return true;
        }

        const int maxChunkSize = 4096;
        const int inlineChunkSize = 256;
        Span<byte> inlineChunk = stackalloc byte[inlineChunkSize];
        var firstPageRemaining = maxChunkSize - (int)(address & (maxChunkSize - 1));
        var firstReadLength = Math.Min(limit, Math.Min(inlineChunkSize, firstPageRemaining));
        var firstSpan = inlineChunk[..firstReadLength];
        ulong offset = 0;
        if (TryReadCompat(ctx, address, firstSpan))
        {
            var nulIndex = firstSpan.IndexOf((byte)0);
            if (nulIndex >= 0)
            {
                bytes = firstSpan[..nulIndex].ToArray();
                return true;
            }

            offset = unchecked((ulong)firstReadLength);
        }

        var chunk = GC.AllocateUninitializedArray<byte>(Math.Min(maxChunkSize, limit));
        var writer = new ArrayBufferWriter<byte>(Math.Min(limit, 256));
        if (offset != 0)
        {
            firstSpan.CopyTo(writer.GetSpan(firstReadLength));
            writer.Advance(firstReadLength);
        }

        while (offset < (ulong)limit)
        {
            var current = address + offset;
            if (current < address)
            {
                return false;
            }

            var pageRemaining = maxChunkSize - (int)(current & (maxChunkSize - 1));
            var remaining = (int)Math.Min((ulong)limit - offset, (ulong)Math.Min(chunk.Length, pageRemaining));
            var span = chunk.AsSpan(0, remaining);
            if (TryReadCompat(ctx, current, span))
            {
                var nulIndex = span.IndexOf((byte)0);
                var copyLength = nulIndex >= 0 ? nulIndex : remaining;
                if (copyLength > 0)
                {
                    span[..copyLength].CopyTo(writer.GetSpan(copyLength));
                    writer.Advance(copyLength);
                }

                if (nulIndex >= 0)
                {
                    bytes = writer.WrittenSpan.ToArray();
                    return true;
                }

                offset += (ulong)remaining;
                continue;
            }

            Span<byte> one = stackalloc byte[1];
            if (!TryReadCompat(ctx, current, one))
            {
                return false;
            }

            if (one[0] == 0)
            {
                bytes = writer.WrittenSpan.ToArray();
                return true;
            }

            one.CopyTo(writer.GetSpan(1));
            writer.Advance(1);
            offset++;
        }

        bytes = writer.WrittenSpan.ToArray();
        return true;
    }

    private static bool TryCompareStrings(CpuContext ctx, ulong left, ulong right, ulong limit, out int compare)
    {
        compare = 0;
        if (left == 0 || right == 0)
        {
            return false;
        }

        var max = limit == ulong.MaxValue ? 1_048_576UL : Math.Min(limit, 1_048_576UL);
        Span<byte> leftByte = stackalloc byte[1];
        Span<byte> rightByte = stackalloc byte[1];
        for (ulong i = 0; i < max; i++)
        {
            if (!TryReadCompat(ctx, left + i, leftByte) ||
                !TryReadCompat(ctx, right + i, rightByte))
            {
                return false;
            }

            compare = leftByte[0] - rightByte[0];
            if (compare != 0 || leftByte[0] == 0 || rightByte[0] == 0)
            {
                return true;
            }
        }

        compare = 0;
        return true;
    }

    private static bool TryReadWideCString(CpuContext ctx, ulong address, ulong maxLength, out ushort[] units)
    {
        units = Array.Empty<ushort>();
        if (address == 0)
        {
            return false;
        }

        var limit = (int)Math.Min(maxLength, 1_048_576UL);
        var buffer = new List<ushort>(Math.Min(limit, 256));
        for (var i = 0; i < limit; i++)
        {
            if (!TryReadUInt16Compat(ctx, address + ((ulong)i * WideCharSize), out var unit))
            {
                return false;
            }

            if (unit == 0)
            {
                units = buffer.ToArray();
                return true;
            }

            buffer.Add(unit);
        }

        units = buffer.ToArray();
        return true;
    }

    private static bool TryReadWideCStringBounded(CpuContext ctx, ulong address, ulong maxLength, out ushort[] units, out bool terminated)
    {
        units = Array.Empty<ushort>();
        terminated = false;
        if (address == 0)
        {
            return false;
        }

        var limit = (int)Math.Min(maxLength, 1_048_576UL);
        var buffer = new List<ushort>(Math.Min(limit, 256));
        for (var i = 0; i < limit; i++)
        {
            if (!TryReadUInt16Compat(ctx, address + ((ulong)i * WideCharSize), out var unit))
            {
                return false;
            }

            if (unit == 0)
            {
                terminated = true;
                units = buffer.ToArray();
                return true;
            }

            buffer.Add(unit);
        }

        units = buffer.ToArray();
        return true;
    }

    private static bool TryCompareWideStrings(CpuContext ctx, ulong left, ulong right, ulong limit, out int compare)
    {
        compare = 0;
        if (left == 0 || right == 0)
        {
            return false;
        }

        var max = limit == ulong.MaxValue ? 1_048_576UL : Math.Min(limit, 1_048_576UL);
        for (ulong i = 0; i < max; i++)
        {
            if (!TryReadUInt16Compat(ctx, left + (i * WideCharSize), out var leftUnit) ||
                !TryReadUInt16Compat(ctx, right + (i * WideCharSize), out var rightUnit))
            {
                return false;
            }

            compare = leftUnit == rightUnit ? 0 : leftUnit < rightUnit ? -1 : 1;
            if (compare != 0 || leftUnit == 0 || rightUnit == 0)
            {
                return true;
            }
        }

        compare = 0;
        return true;
    }

    private static byte[] EncodeWideUnits(ReadOnlySpan<ushort> units)
    {
        var bytes = new byte[units.Length * WideCharSize];
        for (var i = 0; i < units.Length; i++)
        {
            BinaryPrimitives.WriteUInt16LittleEndian(
                bytes.AsSpan(i * WideCharSize, WideCharSize),
                units[i]);
        }

        return bytes;
    }

    private static string DecodeWideUnits(ReadOnlySpan<ushort> units)
    {
        if (units.IsEmpty)
        {
            return string.Empty;
        }

        return new string(MemoryMarshal.Cast<ushort, char>(units));
    }

    private static bool TryConvertWideScalarToString(ushort scalar, out string text)
    {
        text = ((char)scalar).ToString();
        return true;
    }

    private static byte[] EncodeWideUnitsWithTerminator(ReadOnlySpan<ushort> units)
    {
        var bytes = new byte[(units.Length + 1) * WideCharSize];
        EncodeWideUnits(units).CopyTo(bytes, 0);
        return bytes;
    }

    private static bool TryWriteWideTerminator(CpuContext ctx, ulong address)
    {
        Span<byte> terminator = stackalloc byte[WideCharSize];
        terminator.Clear();
        return TryWriteCompat(ctx, address, terminator);
    }

    private static bool TryZeroWideDestination(CpuContext ctx, ulong destination, ulong destinationCount)
    {
        return destination == 0 || destinationCount == 0 || TryWriteWideTerminator(ctx, destination);
    }

    private static bool TryReadNullTerminatedUtf8(CpuContext ctx, ulong address, int maxLength, out string value)
    {
        value = string.Empty;
        if (address == 0 || maxLength <= 0)
        {
            return false;
        }

        if (!TryReadBytesUntilNull(ctx, address, (ulong)maxLength, maxLength, out var bytes))
        {
            return false;
        }

        value = Encoding.UTF8.GetString(bytes);
        return true;
    }

    private static bool TryResolveAprFilepath(CpuContext ctx, ulong pathListAddress, ulong index, out string guestPath)
    {
        guestPath = string.Empty;
        if (TryReadAprPathPointer(ctx, pathListAddress + (index * sizeof(ulong)), out guestPath))
        {
            return true;
        }

        if (index != 0)
        {
            return false;
        }

        if (TryReadAprPathText(ctx, pathListAddress, out guestPath))
        {
            return true;
        }

        const ulong scanLimit = 0x40;
        for (ulong offset = 0; offset < scanLimit; offset += sizeof(ulong))
        {
            if (TryReadAprPathPointer(ctx, pathListAddress + offset, out guestPath))
            {
                return true;
            }
        }

        return false;
    }

    private static bool TryReadAprPathPointer(CpuContext ctx, ulong pointerAddress, out string guestPath)
    {
        guestPath = string.Empty;
        if (!ctx.TryReadUInt64(pointerAddress, out var candidatePath) || candidatePath == 0)
        {
            return false;
        }

        return TryReadAprPathText(ctx, candidatePath, out guestPath);
    }

    private static bool TryReadAprPathText(CpuContext ctx, ulong address, out string guestPath)
    {
        guestPath = string.Empty;
        if (TryReadNullTerminatedUtf8(ctx, address, MaxGuestStringLength, out guestPath) &&
            !string.IsNullOrWhiteSpace(guestPath))
        {
            return true;
        }

        if (!TryReadWideCString(ctx, address, MaxGuestStringLength, out var wideUnits))
        {
            return false;
        }

        guestPath = DecodeWideUnits(wideUnits);
        return !string.IsNullOrWhiteSpace(guestPath);
    }

    private static bool TryReadCompat(CpuContext ctx, ulong address, Span<byte> destination)
    {
        if (destination.IsEmpty)
        {
            return true;
        }

        if (ctx.Memory.TryRead(address, destination))
        {
            return true;
        }

        if (!TryReadHostMemory(address, destination))
        {
            return false;
        }

        var recoveryIndex = Interlocked.Increment(ref _hostMemoryReadFallbackCount);
        if (recoveryIndex <= 8)
        {
            Console.Error.WriteLine(
                $"[LOADER][WARNING] host-read fallback#{recoveryIndex}: addr=0x{address:X16} len=0x{destination.Length:X}");
        }

        return true;
    }

    private static bool TryReadUInt32Compat(CpuContext ctx, ulong address, out uint value)
    {
        Span<byte> bytes = stackalloc byte[sizeof(uint)];
        if (!TryReadCompat(ctx, address, bytes))
        {
            value = 0;
            return false;
        }

        value = BinaryPrimitives.ReadUInt32LittleEndian(bytes);
        return true;
    }

    private static bool TryReadUInt16Compat(CpuContext ctx, ulong address, out ushort value)
    {
        Span<byte> bytes = stackalloc byte[sizeof(ushort)];
        if (!TryReadCompat(ctx, address, bytes))
        {
            value = 0;
            return false;
        }

        value = BinaryPrimitives.ReadUInt16LittleEndian(bytes);
        return true;
    }

    internal static bool TryReadUInt64Compat(CpuContext ctx, ulong address, out ulong value)
    {
        Span<byte> bytes = stackalloc byte[sizeof(ulong)];
        if (!TryReadCompat(ctx, address, bytes))
        {
            value = 0;
            return false;
        }

        value = BinaryPrimitives.ReadUInt64LittleEndian(bytes);
        return true;
    }

    private static bool TryWriteCompat(CpuContext ctx, ulong address, ReadOnlySpan<byte> source)
    {
        if (source.IsEmpty)
        {
            return true;
        }

        if (ctx.Memory.TryWrite(address, source))
        {
            return true;
        }

        if (!TryWriteHostMemory(address, source))
        {
            return false;
        }

        var recoveryIndex = Interlocked.Increment(ref _hostMemoryWriteFallbackCount);
        if (recoveryIndex <= 8)
        {
            Console.Error.WriteLine(
                $"[LOADER][WARNING] host-write fallback#{recoveryIndex}: addr=0x{address:X16} len=0x{source.Length:X}");
        }

        return true;
    }

    private static bool TryWriteUInt32Compat(CpuContext ctx, ulong address, uint value)
    {
        Span<byte> bytes = stackalloc byte[sizeof(uint)];
        BinaryPrimitives.WriteUInt32LittleEndian(bytes, value);
        return TryWriteCompat(ctx, address, bytes);
    }

    internal static bool TryWriteUInt64Compat(CpuContext ctx, ulong address, ulong value)
    {
        Span<byte> bytes = stackalloc byte[sizeof(ulong)];
        BinaryPrimitives.WriteUInt64LittleEndian(bytes, value);
        return TryWriteCompat(ctx, address, bytes);
    }

    private static int KernelBatchMapCore(CpuContext ctx, int flags)
    {
        var entriesAddress = ctx[CpuRegister.Rdi];
        var entryCount = unchecked((int)ctx[CpuRegister.Rsi]);
        var processedOutAddress = ctx[CpuRegister.Rdx];
        var processedCount = 0;
        var result = (int)OrbisGen2Result.ORBIS_GEN2_OK;

        for (var index = 0; index < entryCount; index++)
        {
            var entryAddress = entriesAddress + (ulong)(index * OrbisKernelBatchMapEntrySize);
            if (!TryReadBatchMapEntry(ctx, entryAddress, out var entry) ||
                entry.Length == 0 ||
                entry.Operation < OrbisKernelMapOpMapDirect ||
                entry.Operation > OrbisKernelMapOpTypeProtect)
            {
                result = (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
                break;
            }

            result = entry.Operation switch
            {
                OrbisKernelMapOpMapDirect => InvokeKernelMemoryOperation(
                    ctx,
                    KernelMapDirectMemory,
                    entryAddress + OrbisKernelBatchMapEntryStartOffset,
                    entry.Length,
                    entry.Protection,
                    unchecked((ulong)(uint)flags),
                    entry.Offset,
                    0),
                OrbisKernelMapOpUnmap => InvokeKernelMemoryOperation(
                    ctx,
                    KernelMunmap,
                    entry.Start,
                    entry.Length),
                OrbisKernelMapOpProtect => InvokeKernelMemoryOperation(
                    ctx,
                    KernelMprotect,
                    entry.Start,
                    entry.Length,
                    entry.Protection),
                OrbisKernelMapOpMapFlexible => InvokeKernelMemoryOperation(
                    ctx,
                    KernelMapNamedFlexibleMemory,
                    entryAddress + OrbisKernelBatchMapEntryStartOffset,
                    entry.Length,
                    entry.Protection,
                    unchecked((ulong)(uint)flags)),
                OrbisKernelMapOpTypeProtect => InvokeKernelMemoryOperation(
                    ctx,
                    KernelMtypeprotect,
                    entry.Start,
                    entry.Length,
                    entry.Type,
                    entry.Protection),
                _ => (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT,
            };

            if (result != (int)OrbisGen2Result.ORBIS_GEN2_OK)
            {
                break;
            }

            processedCount++;
        }

        if (processedOutAddress != 0 && !TryWriteInt32(ctx, processedOutAddress, processedCount))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        return result;
    }

    private static int InvokeKernelMemoryOperation(
        CpuContext ctx,
        Func<CpuContext, int> operation,
        ulong rdi = 0,
        ulong rsi = 0,
        ulong rdx = 0,
        ulong rcx = 0,
        ulong r8 = 0,
        ulong r9 = 0)
    {
        var savedRdi = ctx[CpuRegister.Rdi];
        var savedRsi = ctx[CpuRegister.Rsi];
        var savedRdx = ctx[CpuRegister.Rdx];
        var savedRcx = ctx[CpuRegister.Rcx];
        var savedR8 = ctx[CpuRegister.R8];
        var savedR9 = ctx[CpuRegister.R9];

        ctx[CpuRegister.Rdi] = rdi;
        ctx[CpuRegister.Rsi] = rsi;
        ctx[CpuRegister.Rdx] = rdx;
        ctx[CpuRegister.Rcx] = rcx;
        ctx[CpuRegister.R8] = r8;
        ctx[CpuRegister.R9] = r9;

        try
        {
            return operation(ctx);
        }
        finally
        {
            ctx[CpuRegister.Rdi] = savedRdi;
            ctx[CpuRegister.Rsi] = savedRsi;
            ctx[CpuRegister.Rdx] = savedRdx;
            ctx[CpuRegister.Rcx] = savedRcx;
            ctx[CpuRegister.R8] = savedR8;
            ctx[CpuRegister.R9] = savedR9;
        }
    }

    private static bool TryReadBatchMapEntry(CpuContext ctx, ulong entryAddress, out BatchMapEntry entry)
    {
        entry = default;
        if (!ctx.TryReadUInt64(entryAddress + OrbisKernelBatchMapEntryStartOffset, out var start) ||
            !ctx.TryReadUInt64(entryAddress + OrbisKernelBatchMapEntryOffsetOffset, out var offset) ||
            !ctx.TryReadUInt64(entryAddress + OrbisKernelBatchMapEntryLengthOffset, out var length))
        {
            return false;
        }

        Span<byte> protection = stackalloc byte[1];
        Span<byte> memoryType = stackalloc byte[1];
        if (!TryReadCompat(ctx, entryAddress + OrbisKernelBatchMapEntryProtectionOffset, protection) ||
            !TryReadCompat(ctx, entryAddress + OrbisKernelBatchMapEntryTypeOffset, memoryType) ||
            !TryReadUInt32Compat(ctx, entryAddress + OrbisKernelBatchMapEntryOperationOffset, out var operation))
        {
            return false;
        }

        entry = new BatchMapEntry(start, offset, length, protection[0], memoryType[0], unchecked((int)operation));
        return true;
    }

    private static bool TryApplyMappedRegionProtectionLocked(
        ulong address,
        ulong length,
        int protection,
        int? memoryType = null)
    {
        if (length == 0 || !TryAddU64(address, length, out var endAddress))
        {
            return false;
        }

        var affected = new List<MappedRegion>();
        var cursor = address;
        foreach (var region in _mappedRegions.Values.OrderBy(static region => region.Address))
        {
            if (!TryAddU64(region.Address, region.Length, out var regionEnd) || regionEnd <= cursor)
            {
                continue;
            }

            if (region.Address > cursor)
            {
                return false;
            }

            affected.Add(region);
            cursor = regionEnd >= endAddress ? endAddress : regionEnd;
            if (cursor == endAddress)
            {
                break;
            }
        }

        if (cursor != endAddress)
        {
            return false;
        }

        foreach (var region in affected)
        {
            _mappedRegions.Remove(region.Address);
        }

        foreach (var region in affected)
        {
            var regionEnd = region.Address + region.Length;
            var protectStart = Math.Max(region.Address, address);
            var protectEnd = Math.Min(regionEnd, endAddress);

            if (region.Address < protectStart)
            {
                AddMappedRegionSliceLocked(region, region.Address, protectStart, region.Protection);
            }

            AddMappedRegionSliceLocked(region, protectStart, protectEnd, protection);

            if (protectEnd < regionEnd)
            {
                AddMappedRegionSliceLocked(region, protectEnd, regionEnd, region.Protection);
            }

            if (memoryType.HasValue && region.IsDirect && TryFindDirectAllocationLocked(region.DirectStart, out var allocation))
            {
                _directAllocations[allocation.Start] = allocation with { MemoryType = memoryType.Value };
            }
        }

        return true;
    }

    private static void AddMappedRegionSliceLocked(
        MappedRegion source,
        ulong start,
        ulong end,
        int protection)
    {
        if (end <= start)
        {
            return;
        }

        var directStart = source.IsDirect
            ? unchecked(source.DirectStart + (start - source.Address))
            : 0UL;

        _mappedRegions[start] = source with
        {
            Address = start,
            Length = end - start,
            Protection = protection,
            DirectStart = directStart,
        };
    }

    private static bool TryFindDirectAllocationLocked(ulong directStart, out DirectAllocation allocation)
    {
        foreach (var candidate in _directAllocations.Values)
        {
            if (!TryAddU64(candidate.Start, candidate.Length, out var candidateEnd))
            {
                continue;
            }

            if (directStart >= candidate.Start && directStart < candidateEnd)
            {
                allocation = candidate;
                return true;
            }
        }

        allocation = default;
        return false;
    }

    private static bool TryNormalizeProtectRange(
        ulong address,
        ulong length,
        out ulong alignedAddress,
        out ulong alignedLength)
    {
        alignedAddress = 0;
        alignedLength = 0;
        if (length == 0 || !TryAddU64(address, length, out var endAddress))
        {
            return false;
        }

        alignedAddress = AlignDown(address, OrbisPageSize);
        var alignedEnd = AlignUp(endAddress, OrbisPageSize);
        alignedLength = alignedEnd - alignedAddress;
        return alignedLength != 0;
    }

    private static bool TryProtectHostRange(ulong address, ulong length, int orbisProtection)
    {
        if (length == 0 || length > nuint.MaxValue)
        {
            return false;
        }

        var hostProtection = ResolveHostProtection(orbisProtection);
        if (!VirtualProtect((nint)address, (nuint)length, hostProtection, out _))
        {
            return false;
        }

        return true;
    }

    private static uint ResolveHostProtection(int orbisProtection)
    {
        var read = (orbisProtection & (OrbisProtCpuRead | OrbisProtGpuRead)) != 0;
        var write = (orbisProtection & (OrbisProtCpuWrite | OrbisProtGpuWrite)) != 0;
        var execute = (orbisProtection & OrbisProtCpuExec) != 0;

        if (execute)
        {
            return write
                ? HostPageExecuteReadWrite
                : read
                    ? HostPageExecuteRead
                    : HostPageExecute;
        }

        return write
            ? HostPageReadWrite
            : read
                ? HostPageReadOnly
                : HostPageNoAccess;
    }

    private static bool TryFindVirtualQueryRegionLocked(ulong queryAddress, bool findNext, out MappedRegion region)
    {
        region = default;
        var foundNext = false;
        foreach (var candidate in _mappedRegions.Values)
        {
            if (TryAddU64(candidate.Address, candidate.Length, out var candidateEnd) &&
                queryAddress >= candidate.Address &&
                queryAddress < candidateEnd)
            {
                region = candidate;
                return true;
            }

            if (!findNext || candidate.Address < queryAddress)
            {
                continue;
            }

            if (!foundNext || candidate.Address < region.Address)
            {
                region = candidate;
                foundNext = true;
            }
        }

        return foundNext;
    }

    private static void TraceDirectMemoryCall(
        CpuContext ctx,
        string operation,
        ulong length,
        ulong alignment,
        int memoryType,
        ulong outAddress,
        ulong selectedAddress = 0,
        OrbisGen2Result? result = null)
    {
        if (!ShouldTraceDirectMemory())
        {
            return;
        }

        var returnRip = 0UL;
        var stackPointer = ctx[CpuRegister.Rsp];
        if (stackPointer != 0)
        {
            _ = ctx.TryReadUInt64(stackPointer, out returnRip);
        }

        Console.Error.WriteLine(
            $"[LOADER][TRACE] {operation}: ret=0x{returnRip:X16} len=0x{length:X16} align=0x{alignment:X16} type=0x{memoryType:X8} out=0x{outAddress:X16} selected=0x{selectedAddress:X16} result={result?.ToString() ?? "<pending>"}");
    }

    private static bool ShouldTraceDirectMemory()
    {
        return string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_DIRECT_MEMORY"), "1", StringComparison.Ordinal);
    }

    private static bool TryAllocateDirectMemoryLocked(
        ulong searchStart,
        ulong searchEnd,
        ulong length,
        ulong alignment,
        int memoryType,
        ulong allocationLimit,
        out ulong selectedAddress)
    {
        selectedAddress = 0;
        if (length == 0 || searchStart >= searchEnd)
        {
            return false;
        }

        var effectiveAlignment = alignment == 0 ? 0x1000UL : alignment;
        if (!TryFindAllocatableDirectMemoryRangeLocked(searchStart, searchEnd, length, effectiveAlignment, allocationLimit, out var freePosition) ||
            !TryAddU64(freePosition, length, out var endAddress))
        {
            return false;
        }

        _directAllocations[freePosition] = new DirectAllocation(freePosition, length, memoryType);
        _nextPhysicalAddress = endAddress;
        selectedAddress = freePosition;
        return true;
    }

    private static bool TryFindAllocatableDirectMemoryRangeLocked(
        ulong searchStart,
        ulong searchEnd,
        ulong length,
        ulong alignment,
        ulong allocationLimit,
        out ulong selectedAddress)
    {
        selectedAddress = 0;
        if (length == 0 || searchStart >= searchEnd)
        {
            return false;
        }

        var effectiveEnd = Math.Min(searchEnd, allocationLimit);
        var candidate = AlignUp(searchStart, alignment);
        if (candidate >= effectiveEnd)
        {
            return false;
        }

        var allocations = new List<DirectAllocation>(_directAllocations.Values);
        allocations.Sort(static (left, right) => left.Start.CompareTo(right.Start));

        foreach (var allocation in allocations)
        {
            if (!TryAddU64(allocation.Start, allocation.Length, out var allocationEnd))
            {
                return false;
            }

            if (allocationEnd <= candidate)
            {
                continue;
            }

            var gapEnd = Math.Min(allocation.Start, effectiveEnd);
            if (candidate < gapEnd &&
                TryAddU64(candidate, length, out var candidateEnd) &&
                candidateEnd <= gapEnd)
            {
                selectedAddress = candidate;
                return true;
            }

            if (allocation.Start >= effectiveEnd)
            {
                break;
            }

            candidate = AlignUp(Math.Max(candidate, allocationEnd), alignment);
            if (candidate >= effectiveEnd)
            {
                return false;
            }
        }

        if (!TryAddU64(candidate, length, out var endAddress) || endAddress > effectiveEnd)
        {
            return false;
        }

        selectedAddress = candidate;
        return true;
    }

    private static bool TryFindAvailableDirectMemorySpanLocked(
        ulong searchStart,
        ulong searchEnd,
        ulong alignment,
        out ulong spanStart,
        out ulong spanLength)
    {
        spanStart = 0;
        spanLength = 0;
        if (searchStart >= searchEnd)
        {
            return false;
        }

        var effectiveEnd = Math.Min(searchEnd, DirectMemorySizeBytes);
        var candidate = AlignUp(searchStart, alignment);
        if (candidate >= effectiveEnd)
        {
            return false;
        }

        var allocations = new List<DirectAllocation>(_directAllocations.Values);
        allocations.Sort(static (left, right) => left.Start.CompareTo(right.Start));

        foreach (var allocation in allocations)
        {
            if (!TryAddU64(allocation.Start, allocation.Length, out var allocationEnd))
            {
                return false;
            }

            if (allocationEnd <= candidate)
            {
                continue;
            }

            var gapEnd = Math.Min(allocation.Start, effectiveEnd);
            if (candidate < gapEnd)
            {
                spanStart = candidate;
                spanLength = gapEnd - candidate;
                return true;
            }

            if (allocation.Start >= effectiveEnd)
            {
                break;
            }

            candidate = AlignUp(Math.Max(candidate, allocationEnd), alignment);
            if (candidate >= effectiveEnd)
            {
                return false;
            }
        }

        spanStart = candidate;
        spanLength = effectiveEnd - candidate;
        return spanLength != 0;
    }

    private static ulong GetDirectMemoryHighWaterMarkLocked()
    {
        ulong highWaterMark = 0;
        foreach (var allocation in _directAllocations.Values)
        {
            if (!TryAddU64(allocation.Start, allocation.Length, out var endAddress))
            {
                return ulong.MaxValue;
            }

            if (endAddress > highWaterMark)
            {
                highWaterMark = endAddress;
            }
        }

        return highWaterMark;
    }

    private static bool TryReadHostMemory(ulong address, Span<byte> destination)
    {
        if (destination.IsEmpty || !IsHostRangeAccessible(address, (ulong)destination.Length, writeAccess: false))
        {
            return false;
        }

        try
        {
            var temporary = new byte[destination.Length];
            Marshal.Copy((nint)address, temporary, 0, temporary.Length);
            temporary.AsSpan().CopyTo(destination);
            return true;
        }
        catch
        {
            return false;
        }
    }

    internal static bool TryReadTrackedLibcHeap(
        ulong address,
        Span<byte> destination)
    {
        if (destination.IsEmpty)
        {
            return true;
        }

        var length = (ulong)destination.Length;
        lock (_libcAllocGate)
        {
            foreach (var (allocationAddress, allocation) in _libcAllocations)
            {
                var allocationSize = (ulong)allocation.Size;
                var offset = address >= allocationAddress
                    ? address - allocationAddress
                    : ulong.MaxValue;
                if (offset > allocationSize ||
                    length > allocationSize - offset)
                {
                    continue;
                }

                return TryReadHostMemory(address, destination);
            }
        }

        return false;
    }

    private static bool TryAllocateLibcHeap(ulong requestedSize, nuint alignment, bool zeroFill, out ulong address)
    {
        address = 0;
        return TryConvertAllocationSize(requestedSize, out var size) &&
               TryAllocateLibcHeapCore(size, alignment, zeroFill, out address);
    }

    private static unsafe bool TryAllocateLibcHeapCore(nuint requestedSize, nuint alignment, bool zeroFill, out ulong address)
    {
        address = 0;
        alignment = NormalizeLibcAlignment(alignment);
        var actualSize = requestedSize == 0 ? 1u : requestedSize;

        nuint totalSize;
        try
        {
            checked
            {
                totalSize = actualSize + alignment - 1 + (nuint)IntPtr.Size;
            }
        }
        catch (OverflowException)
        {
            return false;
        }

        nint baseAddress;
        try
        {
            baseAddress = Marshal.AllocHGlobal(checked((nint)totalSize));
        }
        catch (OutOfMemoryException)
        {
            return false;
        }
        catch (OverflowException)
        {
            return false;
        }

        if (baseAddress == 0)
        {
            return false;
        }

        var alignedAddress = AlignUp(unchecked((ulong)baseAddress) + (ulong)IntPtr.Size, (ulong)alignment);
        lock (_libcAllocGate)
        {
            _libcAllocations[alignedAddress] = new LibcHeapAllocation(baseAddress, actualSize, alignment);
        }

        try
        {
            if (zeroFill)
            {
                NativeMemory.Clear((void*)alignedAddress, actualSize);
            }
        }
        catch
        {
            FreeLibcHeap(alignedAddress);
            return false;
        }

        address = alignedAddress;
        return true;
    }

    private static unsafe bool TryReallocateLibcHeap(ulong existingAddress, ulong requestedSize, out ulong resizedAddress)
    {
        resizedAddress = 0;
        if (existingAddress == 0)
        {
            return TryAllocateLibcHeap(requestedSize, DefaultLibcHeapAlignment, zeroFill: false, out resizedAddress);
        }

        if (requestedSize == 0)
        {
            FreeLibcHeap(existingAddress);
            return true;
        }

        LibcHeapAllocation allocation;
        lock (_libcAllocGate)
        {
            if (!_libcAllocations.TryGetValue(existingAddress, out allocation))
            {
                return false;
            }
        }

        if (!TryAllocateLibcHeap(requestedSize, allocation.Alignment, zeroFill: false, out resizedAddress))
        {
            return false;
        }

        var bytesToCopy = Math.Min(allocation.Size, (nuint)requestedSize);
        Buffer.MemoryCopy(
            source: (void*)existingAddress,
            destination: (void*)resizedAddress,
            destinationSizeInBytes: checked((long)Math.Max(bytesToCopy, 1u)),
            sourceBytesToCopy: checked((long)bytesToCopy));
        FreeLibcHeap(existingAddress);
        return true;
    }

    private static bool TryAllocateAlignedLibcHeap(ulong alignmentValue, ulong requestedSize, bool requireSizeMultiple, out ulong address)
    {
        address = 0;
        return TryValidateAlignedAllocation(
                   alignmentValue,
                   requestedSize,
                   requireSizeMultiple,
                   requirePointerSizedAlignment: false,
                   out var alignment,
                   out var size) &&
               TryAllocateLibcHeapCore(size, alignment, zeroFill: false, out address);
    }

    private static bool TryValidateAlignedAllocation(
        ulong alignmentValue,
        ulong requestedSize,
        bool requireSizeMultiple,
        bool requirePointerSizedAlignment,
        out nuint alignment,
        out nuint size)
    {
        alignment = 0;
        size = 0;
        if (!TryConvertAllocationSize(requestedSize, out size) ||
            alignmentValue == 0 ||
            alignmentValue > (ulong)nint.MaxValue)
        {
            return false;
        }

        alignment = (nuint)alignmentValue;
        if (!IsPowerOfTwo(alignment))
        {
            return false;
        }

        if (requirePointerSizedAlignment && alignment % (nuint)IntPtr.Size != 0)
        {
            return false;
        }

        if (alignment < (nuint)IntPtr.Size)
        {
            alignment = (nuint)IntPtr.Size;
        }

        if (requireSizeMultiple && size % alignment != 0)
        {
            return false;
        }

        return true;
    }

    private static void FreeLibcHeap(ulong address)
    {
        if (address == 0)
        {
            return;
        }

        LibcHeapAllocation allocation;
        lock (_libcAllocGate)
        {
            if (!_libcAllocations.Remove(address, out allocation))
            {
                return;
            }
        }

        Marshal.FreeHGlobal(allocation.BaseAddress);
    }

    private static bool TryMultiplyAllocationSize(ulong left, ulong right, out nuint size)
    {
        size = 0;
        if (!TryConvertAllocationSize(left, out var leftSize) ||
            !TryConvertAllocationSize(right, out var rightSize))
        {
            return false;
        }

        try
        {
            checked
            {
                size = leftSize * rightSize;
            }
        }
        catch (OverflowException)
        {
            return false;
        }

        return true;
    }

    private static bool TryConvertAllocationSize(ulong requestedSize, out nuint size)
    {
        size = 0;
        if (requestedSize > (ulong)nint.MaxValue)
        {
            return false;
        }

        size = (nuint)requestedSize;
        return true;
    }

    private static nuint NormalizeLibcAlignment(nuint alignment)
    {
        if (alignment < DefaultLibcHeapAlignment)
        {
            return DefaultLibcHeapAlignment;
        }

        return alignment;
    }

    private static bool IsPowerOfTwo(nuint value)
    {
        return value != 0 && (value & (value - 1)) == 0;
    }

    private static bool TryWriteHostMemory(ulong address, ReadOnlySpan<byte> source)
    {
        if (source.IsEmpty || !IsHostRangeAccessible(address, (ulong)source.Length, writeAccess: true))
        {
            return false;
        }

        try
        {
            var temporary = source.ToArray();
            Marshal.Copy(temporary, 0, (nint)address, temporary.Length);
            return true;
        }
        catch
        {
            return false;
        }
    }

    private static bool IsHostRangeAccessible(ulong address, ulong length, bool writeAccess)
    {
        if (address == 0 || length == 0)
        {
            return false;
        }

        const ulong canonicalUpper = 0x0000800000000000UL;
        if (address >= canonicalUpper)
        {
            return false;
        }

        if (ulong.MaxValue - address < length - 1)
        {
            return false;
        }

        if (!TryQueryHostPage(address, out var startInfo) || !HasRequiredProtection(startInfo.Protect, writeAccess))
        {
            return false;
        }

        var endAddress = address + length - 1;
        if (endAddress == address)
        {
            return true;
        }

        if (!TryQueryHostPage(endAddress, out var endInfo) || !HasRequiredProtection(endInfo.Protect, writeAccess))
        {
            return false;
        }

        return true;
    }

    private static bool TryQueryHostPage(ulong address, out MemoryBasicInformation info)
    {
        info = default;
        var size = (nuint)Marshal.SizeOf<MemoryBasicInformation>();
        if (VirtualQuery((nint)address, out info, size) == 0)
        {
            return false;
        }

        return info.State == MemCommit;
    }

    private static bool HasRequiredProtection(uint protect, bool writeAccess)
    {
        if ((protect & (HostPageNoAccess | HostPageGuard)) != 0)
        {
            return false;
        }

        const uint readableMask = HostPageReadOnly | HostPageReadWrite | HostPageWriteCopy | HostPageExecuteRead | HostPageExecuteReadWrite | HostPageExecuteWriteCopy;
        const uint writableMask = HostPageReadWrite | HostPageWriteCopy | HostPageExecuteReadWrite | HostPageExecuteWriteCopy;
        var expected = writeAccess ? writableMask : readableMask;
        return (protect & expected) != 0;
    }

    private static bool TryWriteInt32(CpuContext ctx, ulong address, int value)
    {
        Span<byte> bytes = stackalloc byte[sizeof(int)];
        BitConverter.TryWriteBytes(bytes, value);
        return ctx.Memory.TryWrite(address, bytes);
    }

    private static bool TryWriteOpenDescriptorStat(CpuContext ctx, int fd, ulong statAddress)
    {
        if (fd is 0 or 1 or 2)
        {
            var now = DateTime.UtcNow;
            LogIoTrace("fstat", $"stdio:{fd}", $"fd={fd} size=0 dir=0");
            return TryWriteKernelStat(ctx, statAddress, isDirectory: false, size: 0, now, now, now, $"stdio:{fd}");
        }

        string? hostPath = null;
        bool isDirectory = false;
        lock (_fdGate)
        {
            if (_openDirectories.TryGetValue(fd, out var directory))
            {
                hostPath = directory.Path;
                isDirectory = true;
            }
            else if (_openFiles.TryGetValue(fd, out var stream))
            {
                hostPath = stream.Name;
            }
        }

        if (!string.IsNullOrWhiteSpace(hostPath))
        {
            long size = 0;
            if (!isDirectory)
            {
                try
                {
                    size = new FileInfo(hostPath!).Length;
                }
                catch (IOException)
                {
                    size = -1;
                }
            }

            LogIoTrace("fstat", hostPath!, $"fd={fd} size={size} dir={(isDirectory ? 1 : 0)}");
        }

        return !string.IsNullOrWhiteSpace(hostPath) && TryWriteHostPathStat(ctx, statAddress, hostPath!, isDirectory);
    }

    private static bool TryWriteHostPathStat(CpuContext ctx, ulong statAddress, string hostPath)
    {
        var isDirectory = Directory.Exists(hostPath);
        if (!isDirectory && !File.Exists(hostPath))
        {
            return false;
        }

        return TryWriteHostPathStat(ctx, statAddress, hostPath, isDirectory);
    }

    private static bool TryGetAprFileSize(string hostPath, out ulong size)
    {
        size = 0;
        try
        {
            var fileInfo = new FileInfo(hostPath);
            if (fileInfo.Exists)
            {
                var length = fileInfo.Length;
                size = length < 0 ? 0UL : unchecked((ulong)length);
                return true;
            }

            if (!new DirectoryInfo(hostPath).Exists)
            {
                return false;
            }

            size = 65536;
            return true;
        }
        catch
        {
            return false;
        }
    }

    private static bool TryWriteHostPathStat(CpuContext ctx, ulong statAddress, string hostPath, bool isDirectory)
    {
        if (isDirectory)
        {
            if (!Directory.Exists(hostPath))
            {
                return false;
            }
        }
        else if (!File.Exists(hostPath))
        {
            return false;
        }

        try
        {
            var lastAccessUtc = File.GetLastAccessTimeUtc(hostPath);
            var lastWriteUtc = File.GetLastWriteTimeUtc(hostPath);
            var creationUtc = File.GetCreationTimeUtc(hostPath);
            var size = isDirectory ? 65536L : new FileInfo(hostPath).Length;
            return TryWriteKernelStat(ctx, statAddress, isDirectory, size, lastAccessUtc, lastWriteUtc, creationUtc, hostPath);
        }
        catch
        {
            return false;
        }
    }

    private static bool TryWriteKernelStat(
        CpuContext ctx,
        ulong statAddress,
        bool isDirectory,
        long size,
        DateTime lastAccessUtc,
        DateTime lastWriteUtc,
        DateTime creationUtc,
        string inodeSeed)
    {
        Span<byte> payload = stackalloc byte[KernelStatSize];
        payload.Clear();

        var seedBytes = Encoding.UTF8.GetBytes(inodeSeed);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStDevOffset..], 0);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStInoOffset..], ComputeDirectoryEntryHash(seedBytes));
        BinaryPrimitives.WriteUInt16LittleEndian(payload[KernelStatStModeOffset..], isDirectory ? KernelStatModeDirectory : KernelStatModeRegular);
        BinaryPrimitives.WriteUInt16LittleEndian(payload[KernelStatStNlinkOffset..], 1);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStUidOffset..], 0);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStGidOffset..], 0);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStRdevOffset..], 0);
        WriteKernelTimespec(payload[KernelStatStAtimOffset..], lastAccessUtc);
        WriteKernelTimespec(payload[KernelStatStMtimOffset..], lastWriteUtc);
        WriteKernelTimespec(payload[KernelStatStCtimOffset..], lastWriteUtc);
        BinaryPrimitives.WriteInt64LittleEndian(payload[KernelStatStSizeOffset..], size);
        BinaryPrimitives.WriteInt64LittleEndian(payload[KernelStatStBlocksOffset..], isDirectory ? 128 : (size + 511) / 512);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStBlksizeOffset..], isDirectory ? 65536U : 512U);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStFlagsOffset..], 0);
        BinaryPrimitives.WriteUInt32LittleEndian(payload[KernelStatStGenOffset..], 0);
        BinaryPrimitives.WriteInt32LittleEndian(payload[KernelStatStLspareOffset..], 0);
        WriteKernelTimespec(payload[KernelStatStBirthtimOffset..], creationUtc);
        return TryWriteCompat(ctx, statAddress, payload);
    }

    private static void WriteKernelTimespec(Span<byte> destination, DateTime utcTime)
    {
        var timestamp = utcTime.Kind == DateTimeKind.Utc ? utcTime : utcTime.ToUniversalTime();
        var dto = new DateTimeOffset(timestamp);
        BinaryPrimitives.WriteInt64LittleEndian(destination, dto.ToUnixTimeSeconds());
        var ticksWithinSecond = timestamp.Ticks % TimeSpan.TicksPerSecond;
        BinaryPrimitives.WriteInt64LittleEndian(destination[sizeof(long)..], ticksWithinSecond * 100);
    }

    private static int KernelGetdirentriesCore(CpuContext ctx, int fd, ulong bufferAddress, int requested, ulong basePointerAddress)
    {
        if (fd < 0 || bufferAddress == 0 || requested < 512)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT;
        }

        OpenDirectory? directory;
        lock (_fdGate)
        {
            _openDirectories.TryGetValue(fd, out directory);
        }

        if (directory is null)
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND;
        }

        var currentIndex = directory.NextIndex;
        if (basePointerAddress != 0 && !TryWriteUInt64Compat(ctx, basePointerAddress, (ulong)currentIndex))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        if (currentIndex >= directory.Entries.Length)
        {
            ctx[CpuRegister.Rax] = 0;
            return (int)OrbisGen2Result.ORBIS_GEN2_OK;
        }

        var entryName = directory.Entries[currentIndex];
        directory.NextIndex = currentIndex + 1;

        var entryBytes = Encoding.UTF8.GetBytes(entryName);
        var nameLength = Math.Min(entryBytes.Length, 255);
        var entryPath = Path.Combine(directory.Path, entryName);
        var entryType = Directory.Exists(entryPath) ? (byte)4 : (byte)8;

        var payload = new byte[512];
        BinaryPrimitives.WriteUInt32LittleEndian(payload.AsSpan(0, sizeof(uint)), ComputeDirectoryEntryHash(entryBytes.AsSpan(0, nameLength)));
        BinaryPrimitives.WriteUInt16LittleEndian(payload.AsSpan(4, sizeof(ushort)), 512);
        payload[6] = entryType;
        payload[7] = unchecked((byte)nameLength);
        entryBytes.AsSpan(0, nameLength).CopyTo(payload.AsSpan(8));

        if (!TryWriteCompat(ctx, bufferAddress, payload))
        {
            return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT;
        }

        ctx[CpuRegister.Rax] = 512;
        return (int)OrbisGen2Result.ORBIS_GEN2_OK;
    }

    private static string[] EnumerateDirectoryEntries(string hostPath)
    {
        return Directory.EnumerateFileSystemEntries(hostPath)
            .Select(Path.GetFileName)
            .Where(static name => !string.IsNullOrEmpty(name))
            .OrderBy(static name => name, StringComparer.OrdinalIgnoreCase)
            .ToArray()!;
    }

    private static uint ComputeDirectoryEntryHash(ReadOnlySpan<byte> utf8Name)
    {
        const uint offsetBasis = 2166136261;
        const uint prime = 16777619;

        var hash = offsetBasis;
        for (var i = 0; i < utf8Name.Length; i++)
        {
            hash ^= utf8Name[i];
            hash *= prime;
        }

        return hash;
    }

    private static void LogOpenTrace(string message)
    {
        if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_OPEN"), "1", StringComparison.Ordinal))
        {
            return;
        }

        Console.Error.WriteLine($"[LOADER][TRACE] {message}");
    }

    private static void LogIoTrace(string operation, string path, string detail)
    {
        if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_IO"), "1", StringComparison.Ordinal))
        {
            return;
        }

        var filter = Environment.GetEnvironmentVariable("SHARPEMU_LOG_IO_FILTER");
        if (!string.IsNullOrWhiteSpace(filter) &&
            path.IndexOf(filter, StringComparison.OrdinalIgnoreCase) < 0)
        {
            return;
        }

        Console.Error.WriteLine($"[LOADER][TRACE] {operation} path='{path}' {detail}");
    }

    private static void LogUniqueStatTrace(string guestPath, string hostPath, bool found)
    {
        if (!string.Equals(Environment.GetEnvironmentVariable("SHARPEMU_LOG_IO"), "1", StringComparison.Ordinal))
        {
            return;
        }

        var result = found ? "found" : "not_found";
        lock (_ioTraceGate)
        {
            if (!_tracedStatResults.Add($"{result}\0{guestPath}"))
            {
                return;
            }
        }

        LogIoTrace("stat", guestPath, $"host='{hostPath}' result={result}");
    }

    private static string? GetNegativeStatCacheKey(string guestPath)
    {
        var normalized = NormalizeGuestStatCachePath(guestPath);
        return IsReadOnlyGuestStatPath(normalized) ? normalized : null;
    }

    private static string? NormalizeGuestStatCachePath(string guestPath)
    {
        var normalized = guestPath.Replace('\\', '/').TrimEnd('/');
        if (normalized.Length == 0)
        {
            return null;
        }

        if (normalized[0] != '/')
        {
            normalized = "/" + normalized;
        }

        return normalized;
    }

    private static bool IsReadOnlyGuestStatPath(string? normalizedGuestPath) =>
        normalizedGuestPath is not null &&
        (string.Equals(normalizedGuestPath, "/app0", StringComparison.OrdinalIgnoreCase) ||
         normalizedGuestPath.StartsWith("/app0/", StringComparison.OrdinalIgnoreCase) ||
         string.Equals(normalizedGuestPath, "/hostapp", StringComparison.OrdinalIgnoreCase) ||
         normalizedGuestPath.StartsWith("/hostapp/", StringComparison.OrdinalIgnoreCase) ||
         string.Equals(normalizedGuestPath, "/devlog/app", StringComparison.OrdinalIgnoreCase) ||
         normalizedGuestPath.StartsWith("/devlog/app/", StringComparison.OrdinalIgnoreCase) ||
         string.Equals(normalizedGuestPath, "/temp0", StringComparison.OrdinalIgnoreCase) ||
         normalizedGuestPath.StartsWith("/temp0/", StringComparison.OrdinalIgnoreCase) ||
         string.Equals(normalizedGuestPath, "/download0", StringComparison.OrdinalIgnoreCase) ||
         normalizedGuestPath.StartsWith("/download0/", StringComparison.OrdinalIgnoreCase));

    private static bool IsNegativeStatCached(string cacheKey)
    {
        lock (_statCacheGate)
        {
            return _negativeStatCache.Contains(cacheKey);
        }
    }

    private static void AddNegativeStatCache(string cacheKey)
    {
        lock (_statCacheGate)
        {
            _negativeStatCache.Add(cacheKey);
        }
    }

    private static void RemoveNegativeStatCache(string cacheKey)
    {
        lock (_statCacheGate)
        {
            _negativeStatCache.Remove(cacheKey);
        }
    }

    private static void AddNegativeStatCacheForGuestPath(string guestPath)
    {
        var cacheKey = GetNegativeStatCacheKey(guestPath);
        if (cacheKey is not null)
        {
            AddNegativeStatCache(cacheKey);
        }
    }

    private static void InvalidateNegativeStatCacheForPathAndAncestors(string guestPath)
    {
        var normalized = NormalizeGuestStatCachePath(guestPath);
        if (normalized is null)
        {
            return;
        }

        lock (_statCacheGate)
        {
            var current = normalized;
            while (true)
            {
                _negativeStatCache.Remove(current);
                var slash = current.LastIndexOf('/');
                if (slash <= 0)
                {
                    break;
                }

                current = current[..slash];
            }

            _negativeStatCache.Remove("/");
        }
    }

    private static string PreviewIoBytes(byte[] buffer, int count, int maxBytes)
    {
        if (count <= 0)
        {
            return string.Empty;
        }

        var previewLength = Math.Min(count, maxBytes);
        var text = Encoding.UTF8.GetString(buffer, 0, previewLength);
        return SanitizeTracePreview(text, maxBytes);
    }

    private static string PreviewIoHex(byte[] buffer, int count, int maxBytes)
    {
        if (count <= 0)
        {
            return string.Empty;
        }

        var previewLength = Math.Min(count, maxBytes);
        return Convert.ToHexString(buffer, 0, previewLength);
    }

    private static string PreviewGuestHex(CpuContext ctx, ulong address, int maxBytes)
    {
        if (address == 0 || maxBytes <= 0)
        {
            return string.Empty;
        }

        var bytes = GC.AllocateUninitializedArray<byte>(maxBytes);
        if (!ctx.Memory.TryRead(address, bytes))
        {
            return "<unreadable>";
        }

        return Convert.ToHexString(bytes);
    }

    private static ulong AlignUp(ulong value, ulong alignment)
    {
        if (alignment <= 1)
        {
            return value;
        }

        var mask = alignment - 1;
        return (value + mask) & ~mask;
    }

    private static ulong AlignDown(ulong value, ulong alignment)
    {
        if (alignment <= 1)
        {
            return value;
        }

        var mask = alignment - 1;
        return value & ~mask;
    }

    private static bool TryAddU64(ulong left, ulong right, out ulong sum)
    {
        sum = left + right;
        return sum >= left;
    }
}
