diff --git a/src/SharpEmu.Libs/Ampr/AmprFileRegistry.cs b/src/SharpEmu.Libs/Ampr/AmprFileRegistry.cs index 084c8e64..d808b9a8 100644 --- a/src/SharpEmu.Libs/Ampr/AmprFileRegistry.cs +++ b/src/SharpEmu.Libs/Ampr/AmprFileRegistry.cs @@ -21,7 +21,7 @@ public static bool TryGetHostPath(uint id, out string hostPath) return _hostPathsById.TryGetValue(id, out hostPath!); } - private static uint ComputeFileId(string guestPath) + internal static uint ComputeFileId(string guestPath) { var bytes = System.Text.Encoding.UTF8.GetBytes(guestPath); diff --git a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs index 379b884e..5f0e2ced 100644 --- a/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs +++ b/src/SharpEmu.Libs/Kernel/KernelMemoryCompatExports.cs @@ -1689,15 +1689,15 @@ public static int KernelAprResolveFilepathsToIdsAndFileSizes(CpuContext ctx) return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_INVALID_ARGUMENT; } + var entryCount = (int)count; + Span localIds = count <= 256 ? stackalloc uint[entryCount] : new uint[entryCount]; + Span localSizes = count <= 128 ? stackalloc ulong[entryCount] : new ulong[entryCount]; + var resolvedGuestPaths = new string[entryCount]; + var resolvedHostPaths = new string[entryCount]; + 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; - } - + var index = (int)i; if (!TryResolveAprFilepath(ctx, pathListAddress, i, out var guestPath)) { KernelRuntimeCompatExports.TrySetErrno(ctx, Efault); @@ -1712,23 +1712,47 @@ public static int KernelAprResolveFilepathsToIdsAndFileSizes(CpuContext ctx) return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND; } - var fileId = AmprFileRegistry.Register(guestPath, hostPath); + var fileId = AmprFileRegistry.ComputeFileId(guestPath); 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)) + localIds[index] = fileId; + localSizes[index] = fileSize; + resolvedGuestPaths[index] = guestPath; + resolvedHostPaths[index] = hostPath; + } + + Span sizePayload = count <= 64 ? stackalloc byte[entryCount * sizeof(ulong)] : new byte[entryCount * sizeof(ulong)]; + for (ulong i = 0; i < count; i++) + { + BinaryPrimitives.WriteUInt64LittleEndian(sizePayload[(int)(i * sizeof(ulong))..], localSizes[(int)i]); + } + + if (!TryWriteCompat(ctx, sizesAddress, sizePayload)) + { + KernelRuntimeCompatExports.TrySetErrno(ctx, Efault); + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + } + + if (idsAddress != 0) + { + Span idPayload = count <= 128 ? stackalloc byte[entryCount * sizeof(uint)] : new byte[entryCount * sizeof(uint)]; + for (ulong i = 0; i < count; i++) { - KernelRuntimeCompatExports.TrySetErrno(ctx, Efault); - return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + BinaryPrimitives.WriteUInt32LittleEndian(idPayload[(int)(i * sizeof(uint))..], localIds[(int)i]); } - if (!TryWriteUInt64Compat(ctx, sizesAddress + (i * sizeof(ulong)), fileSize)) + if (!TryWriteCompat(ctx, idsAddress, idPayload)) { KernelRuntimeCompatExports.TrySetErrno(ctx, Efault); return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; } } + for (var i = 0; i < entryCount; i++) + { + AmprFileRegistry.Register(resolvedGuestPaths[i], resolvedHostPaths[i]); + } + ctx[CpuRegister.Rax] = 0; return (int)OrbisGen2Result.ORBIS_GEN2_OK; } @@ -6350,19 +6374,19 @@ private static int KernelGetdirentriesCore(CpuContext ctx, int fd, ulong bufferA } 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) { + if (basePointerAddress != 0 && + !TryWriteUInt64Compat(ctx, basePointerAddress, (ulong)currentIndex)) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + } + 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); @@ -6381,6 +6405,13 @@ private static int KernelGetdirentriesCore(CpuContext ctx, int fd, ulong bufferA return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; } + if (basePointerAddress != 0 && + !TryWriteUInt64Compat(ctx, basePointerAddress, (ulong)currentIndex)) + { + return (int)OrbisGen2Result.ORBIS_GEN2_ERROR_MEMORY_FAULT; + } + + directory.NextIndex = currentIndex + 1; ctx[CpuRegister.Rax] = 512; return (int)OrbisGen2Result.ORBIS_GEN2_OK; }