mirror of
https://github.com/mitch030504/Wiicompiled_VR_Frame.git
synced 2026-10-06 05:00:27 +02:00
Merge upstream main into openxr-work
This commit is contained in:
commit
60316f0115
69 files changed
+5581
-315
No files matched your search
@@ -172,6 +172,7 @@ return command switch
|
||||
"emit-build-shards" => RunEmitBuildShards(tail),
|
||||
"emit-base-manifest" => RunEmitBaseManifest(tail),
|
||||
"check-base-mod-awareness" => RunCheckBaseModAwareness(tail),
|
||||
"validate-retro-wfc-payload" => RunValidateRetroWfcPayload(tail),
|
||||
_ => ShowHelp(command)
|
||||
};
|
||||
|
||||
@@ -360,6 +361,33 @@ int RunInfo()
|
||||
return 0;
|
||||
}
|
||||
|
||||
int RunValidateRetroWfcPayload(string[] argsTail)
|
||||
{
|
||||
var directory = OptionValue(argsTail, "--directory");
|
||||
if (string.IsNullOrWhiteSpace(directory))
|
||||
{
|
||||
Console.Error.WriteLine("--directory is required.");
|
||||
return 1;
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
WiiCompiled.Setup.Common.RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(directory);
|
||||
Console.WriteLine("[translator] Retro WFC payload signature validated.");
|
||||
return 0;
|
||||
}
|
||||
catch (InvalidDataException ex)
|
||||
{
|
||||
Console.Error.WriteLine($"[translator] Retro WFC payload validation failed: {ex.Message}");
|
||||
return 2;
|
||||
}
|
||||
catch (Exception ex) when (ex is IOException or UnauthorizedAccessException)
|
||||
{
|
||||
Console.Error.WriteLine($"[translator] Could not read Retro WFC payload: {ex.Message}");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
int RunTranslateRecursive(string[] argsTail)
|
||||
{
|
||||
if (argsTail.Length == 0 || argsTail[0].StartsWith("--", StringComparison.Ordinal))
|
||||
@@ -3671,7 +3699,8 @@ static string[] KnownCommands() => new[]
|
||||
"translate-mod",
|
||||
"emit-base-manifest",
|
||||
"emit-build-shards",
|
||||
"check-base-mod-awareness"
|
||||
"check-base-mod-awareness",
|
||||
"validate-retro-wfc-payload"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
@@ -3714,6 +3743,10 @@ static (string? Positional, CommandOption[] Options)? CommandSpec(string command
|
||||
new("--translation-output-metadata", "path"),
|
||||
new("--code-pul", "path")
|
||||
}),
|
||||
"validate-retro-wfc-payload" => (null, new CommandOption[]
|
||||
{
|
||||
new("--directory", "directory", Required: true)
|
||||
}),
|
||||
"emit-base-manifest" => (null, new CommandOption[]
|
||||
{
|
||||
new("--out", "path"),
|
||||
@@ -4110,4 +4143,3 @@ sealed record ResolvedDispatchEntry(
|
||||
bool MustRemainDynamicallyDispatchable,
|
||||
string SourceFile);
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Translator.Core\Translator.Core.csproj" />
|
||||
<ProjectReference Include="..\..\..\Launcher\WiiCompiled.Setup.Common\WiiCompiled.Setup.Common.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
||||
@@ -22,14 +22,15 @@ internal static class AssemblyBlobWriter
|
||||
var expectedFiles = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
|
||||
var assembly = new StringBuilder();
|
||||
foreach (var header in headerLines) assembly.AppendLine(header);
|
||||
// PE/COFF (Windows) and ELF (Linux) spell a read-only data section differently in GNU-as
|
||||
// syntax - COFF section flags ("dr" = data, read-only) versus an ELF section needing an
|
||||
// allocatable-only flag plus an explicit @progbits type. The build always targets
|
||||
// PE/COFF (Windows), Mach-O (macOS), and ELF (Linux) spell a read-only data section
|
||||
// differently in GNU-as syntax. The build always targets
|
||||
// whichever platform the translator itself runs on (there is no cross-compilation
|
||||
// support), so that's what this picks the section syntax from.
|
||||
assembly.AppendLine(OperatingSystem.IsWindows()
|
||||
? ".section .rdata,\"dr\""
|
||||
: ".section .rodata,\"a\",@progbits");
|
||||
: OperatingSystem.IsMacOS()
|
||||
? ".section __TEXT,__const"
|
||||
: ".section .rodata,\"a\",@progbits");
|
||||
assembly.AppendLine();
|
||||
|
||||
foreach (var blob in blobs)
|
||||
@@ -40,8 +41,12 @@ internal static class AssemblyBlobWriter
|
||||
var hash = ChecksumUtilities.Sha256Hex(blob.Data.Span);
|
||||
assembly.AppendLine($"// {blob.Comment}; sha256={hash}");
|
||||
assembly.AppendLine(".p2align 4");
|
||||
assembly.AppendLine($".globl {blob.Symbol}");
|
||||
assembly.AppendLine($"{blob.Symbol}:");
|
||||
// C/C++ external symbols carry a leading underscore in Mach-O,
|
||||
// unlike ELF and COFF. The generated C++ still names the symbol
|
||||
// without that ABI decoration, so emit the platform spelling here.
|
||||
var assemblySymbol = OperatingSystem.IsMacOS() ? $"_{blob.Symbol}" : blob.Symbol;
|
||||
assembly.AppendLine($".globl {assemblySymbol}");
|
||||
assembly.AppendLine($"{assemblySymbol}:");
|
||||
var referencePath = Path.Combine(blobReferenceDirectory, blob.FileName);
|
||||
assembly.AppendLine($".incbin \"{SanitizeAssemblyPath(referencePath)}\"");
|
||||
assembly.AppendLine();
|
||||
@@ -51,7 +56,7 @@ internal static class AssemblyBlobWriter
|
||||
{
|
||||
if (!expectedFiles.Contains(Path.GetFullPath(stalePath))) File.Delete(stalePath);
|
||||
}
|
||||
if (!OperatingSystem.IsWindows())
|
||||
if (!OperatingSystem.IsWindows() && !OperatingSystem.IsMacOS())
|
||||
{
|
||||
// Absence of a .note.GNU-stack section makes the linker assume the oldest, most
|
||||
// conservative default for this object (an executable stack) and warn about it; this
|
||||
|
||||
@@ -6,6 +6,12 @@ namespace Translator.Core.Parsing.Kamek;
|
||||
public sealed class KamekChunk
|
||||
{
|
||||
public const uint Magic0 = 0x4B616D65;
|
||||
/// <summary>
|
||||
/// Kamek v2 is still emitted by current Retro Rewind releases. Its command
|
||||
/// stream matches v3, but combined v2 files carry each chunk length only in
|
||||
/// the outer size table.
|
||||
/// </summary>
|
||||
public const uint Magic1V2 = 0x6B000002;
|
||||
public const uint Magic1 = 0x6B000003;
|
||||
public const int HeaderSize = 0x20;
|
||||
|
||||
@@ -58,7 +64,7 @@ public sealed class KamekChunk
|
||||
}
|
||||
|
||||
return BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset, 4)) == Magic0 &&
|
||||
BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset + 4, 4)) == Magic1;
|
||||
IsSupportedFormatVersion(BinaryPrimitives.ReadUInt32BigEndian(data.Slice(offset + 4, 4)));
|
||||
}
|
||||
|
||||
public static KamekChunk Parse(byte[] data, int offset, int expectedSize, int index)
|
||||
@@ -74,7 +80,7 @@ public sealed class KamekChunk
|
||||
|
||||
var magic0 = reader.ReadUInt32();
|
||||
var magic1 = reader.ReadUInt32();
|
||||
if (magic0 != Magic0 || magic1 != Magic1)
|
||||
if (magic0 != Magic0 || !IsSupportedFormatVersion(magic1))
|
||||
{
|
||||
throw new InvalidDataException($"Kamek chunk {index} at 0x{offset:X} has invalid magic 0x{magic0:X8}/0x{magic1:X8}.");
|
||||
}
|
||||
@@ -83,9 +89,15 @@ public sealed class KamekChunk
|
||||
var codeSize = reader.ReadUInt32();
|
||||
var ctorStart = reader.ReadUInt32();
|
||||
var ctorEnd = reader.ReadUInt32();
|
||||
var chunkSize = reader.ReadUInt32();
|
||||
var declaredChunkSize = reader.ReadUInt32();
|
||||
_ = reader.ReadUInt32(); // reserved
|
||||
|
||||
// v3 writes each chunk's length in its header. v2 leaves that field at
|
||||
// zero and relies on the combined-file table (or the raw file length).
|
||||
var chunkSize = magic1 == Magic1V2
|
||||
? checked((uint)(expectedSize != 0 ? expectedSize : data.Length - offset))
|
||||
: declaredChunkSize;
|
||||
|
||||
if (chunkSize < HeaderSize + codeSize)
|
||||
{
|
||||
throw new InvalidDataException($"Kamek chunk {index} chunkSize 0x{chunkSize:X} is smaller than header+code.");
|
||||
@@ -171,4 +183,7 @@ public sealed class KamekChunk
|
||||
KamekCommandId.BranchLink => 1,
|
||||
_ => throw new ArgumentOutOfRangeException(nameof(id), id, "Unsupported Kamek command id")
|
||||
};
|
||||
|
||||
private static bool IsSupportedFormatVersion(uint magic1) =>
|
||||
magic1 is Magic1V2 or Magic1;
|
||||
}
|
||||
@@ -33,7 +33,7 @@ public sealed class KamekPulFile
|
||||
|
||||
if (!KamekChunk.HasMagic(data, 0))
|
||||
{
|
||||
throw new InvalidDataException("File is neither a combined Code.pul nor a raw Kamek v3 chunk.");
|
||||
throw new InvalidDataException("File is neither a combined Code.pul nor a raw supported Kamek chunk.");
|
||||
}
|
||||
|
||||
var rawChunk = KamekChunk.Parse(data, 0, expectedSize: 0, index: 0);
|
||||
|
||||
@@ -49,6 +49,27 @@ public class KamekPulFileTests
|
||||
Assert.Equal(0x20u, pul.SelectRegion("E").BssSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void ParsesKamekV2CombinedChunks()
|
||||
{
|
||||
var p = BuildChunk(0x10, [0x4E, 0x80, 0x00, 0x20],
|
||||
[BuildCommand(KamekCommandId.Branch, true, 0x8053369C, [0x100])], KamekChunk.Magic1V2);
|
||||
var combined = new byte[0x10 + p.Length];
|
||||
WriteU32(combined, 0, (uint)p.Length);
|
||||
p.CopyTo(combined, 0x10);
|
||||
|
||||
var pul = KamekPulFile.Parse(combined);
|
||||
|
||||
Assert.True(pul.IsCombined);
|
||||
Assert.Equal(0x10u, pul.SelectRegion("P").BssSize);
|
||||
Assert.Equal(KamekCommandId.Branch, pul.SelectRegion("P").Commands.Single().Id);
|
||||
|
||||
var raw = KamekPulFile.Parse(p);
|
||||
|
||||
Assert.False(raw.IsCombined);
|
||||
Assert.Equal((uint)p.Length, raw.Chunks.Single().ChunkSize);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void EncodesPpcBranchLikeKamek()
|
||||
{
|
||||
@@ -83,18 +104,19 @@ public class KamekPulFileTests
|
||||
Assert.Equal(chunk.Commands.Count, chunk.CommandCounts.Values.Sum());
|
||||
}
|
||||
|
||||
private static byte[] BuildChunk(uint bssSize, byte[] code, byte[][] commands)
|
||||
private static byte[] BuildChunk(uint bssSize, byte[] code, byte[][] commands,
|
||||
uint magic1 = KamekChunk.Magic1)
|
||||
{
|
||||
var commandSize = commands.Sum(c => c.Length);
|
||||
var chunkSize = KamekChunk.HeaderSize + code.Length + commandSize;
|
||||
var data = new byte[chunkSize];
|
||||
WriteU32(data, 0x00, KamekChunk.Magic0);
|
||||
WriteU32(data, 0x04, KamekChunk.Magic1);
|
||||
WriteU32(data, 0x04, magic1);
|
||||
WriteU32(data, 0x08, bssSize);
|
||||
WriteU32(data, 0x0C, (uint)code.Length);
|
||||
WriteU32(data, 0x10, 0);
|
||||
WriteU32(data, 0x14, 0);
|
||||
WriteU32(data, 0x18, (uint)chunkSize);
|
||||
WriteU32(data, 0x18, magic1 == KamekChunk.Magic1V2 ? 0u : (uint)chunkSize);
|
||||
code.CopyTo(data, KamekChunk.HeaderSize);
|
||||
|
||||
var offset = KamekChunk.HeaderSize + code.Length;
|
||||
|
||||
@@ -28,8 +28,10 @@ public sealed class ModDataPatchWriterTests
|
||||
|
||||
var assemblyPath = Path.Combine(root, "cpp", "mod_data_patches_blobs.S");
|
||||
var assembly = File.ReadAllText(assemblyPath);
|
||||
Assert.Contains(".globl kModuleImage", assembly, StringComparison.Ordinal);
|
||||
Assert.Contains(".globl kKamekCodeSha1Digest", assembly, StringComparison.Ordinal);
|
||||
var symbolPrefix = OperatingSystem.IsMacOS() ? "_" : "";
|
||||
Assert.Contains($".globl {symbolPrefix}kModuleImage", assembly, StringComparison.Ordinal);
|
||||
Assert.Contains($".globl {symbolPrefix}kKamekCodeSha1Digest", assembly, StringComparison.Ordinal);
|
||||
Assert.DoesNotContain("__APPLE__", assembly, StringComparison.Ordinal);
|
||||
Assert.Contains(".incbin", assembly, StringComparison.Ordinal);
|
||||
|
||||
var timestamps = new[] { cppPath, assemblyPath }
|
||||
|
||||
Reference in new issue
Block a user