Compare commits

..

1 Commits

Author SHA1 Message Date
patchzyy 7caee02c74 Harden build path handling 2026-09-27 16:34:41 +02:00
30 changed files with 220 additions and 764 deletions
+1 -2
View File
@@ -152,8 +152,7 @@ if ($Profile -ne 'both' -and -not [string]::IsNullOrWhiteSpace($BaseOutputDirect
}
$realWorkspace = $Workspace.TrimEnd('\')
$Workspace = Get-MkwBuildSafePath $realWorkspace 'workspace' 'runtime\CMakeLists.txt'
# A selected package inside the install may also name the same Code.pul through the real path.
# Give it the workspace spelling before comparing it with the staged copy.
# One spelling of the workspace, so the staged Code.pul check below can't copy a file onto itself.
if (-not [string]::IsNullOrWhiteSpace($RetroRewindPackageDirectory) -and
$RetroRewindPackageDirectory.StartsWith($realWorkspace + '\', [StringComparison]::OrdinalIgnoreCase)) {
$RetroRewindPackageDirectory = $Workspace + $RetroRewindPackageDirectory.Substring($realWorkspace.Length)
+13 -20
View File
@@ -42,9 +42,10 @@ function Get-MkwToolchainPath([string]$ToolchainRoot) {
function Get-MkwBuildSafePath([string]$Path, [string]$Kind, [string]$MarkerFile) {
<#
The Windows native build passes workspace paths through CMake, Ninja response files and
clang, which do not all interpret quotes the same way. Keep those paths plain even when the
user's install directory contains an apostrophe, ampersand or other punctuation.
$Path, or a junction to it whose path is plain ASCII. cmd.exe, Ninja response files and the
compiler each have their own quoting rules, so a path outside this allowlist ('&', '%', an
apostrophe, non-ASCII...) is never handed to the native build at all. $MarkerFile is a file
that must exist under a live junction.
#>
if ([string]::IsNullOrWhiteSpace($Path)) { throw "A $Kind path is required." }
$full = [IO.Path]::GetFullPath($Path)
@@ -52,8 +53,6 @@ function Get-MkwBuildSafePath([string]$Path, [string]$Kind, [string]$MarkerFile)
if ($full -ne [IO.Path]::GetPathRoot($full)) { $full = $full.TrimEnd('\') }
if ($full -cmatch '^[A-Za-z0-9 ._\\:-]+$') { return $full }
Assert-File (Join-Path $full $MarkerFile) "$Kind marker"
$sha = [Security.Cryptography.SHA256]::Create()
try {
$bytes = $sha.ComputeHash([Text.Encoding]::UTF8.GetBytes($full.ToLowerInvariant()))
@@ -66,29 +65,23 @@ function Get-MkwBuildSafePath([string]$Path, [string]$Kind, [string]$MarkerFile)
$link = Join-Path (Join-Path $base 'WiiCompiled') $linkName
try {
[IO.Directory]::CreateDirectory((Split-Path -Parent $link)) | Out-Null
$existing = Get-Item -LiteralPath $link -Force -ErrorAction SilentlyContinue
if ($null -ne $existing) {
# Never trust a directory just because it has the marker: it could point at a
# different installation. Nor may we remove a directory we did not create.
if ($existing.LinkType -ne 'Junction' -or
@($existing.Target).Count -ne 1 -or
-not [string]::Equals([IO.Path]::GetFullPath(@($existing.Target)[0]),
$full, [StringComparison]::OrdinalIgnoreCase)) {
throw "An existing path is not the expected junction: $link"
}
} else {
# The name already identifies the target, so an existing junction that still resolves is
# this one; only a broken leftover is replaced. Directory.Delete removes the reparse
# point itself, where Remove-Item -Recurse would delete the tree it points at.
if (-not (Test-Path -LiteralPath (Join-Path $link $MarkerFile) -PathType Leaf)) {
if (Test-Path -LiteralPath $link) { [IO.Directory]::Delete($link) }
New-Item -ItemType Junction -Path $link -Target $full -ErrorAction Stop | Out-Null
}
Assert-File (Join-Path $link $MarkerFile) "$Kind junction marker"
Write-Host "MKWCBUILD: Building the $Kind through $link, because $full contains characters the native build cannot quote reliably"
return $link
} catch {
$failures += "$link ($($_.Exception.Message))"
}
}
throw ("The $Kind path $full cannot be passed safely to the native build, and no junction " +
'to it could be created: ' + ($failures -join '; ') + '. Install to a path of plain ' +
'letters, digits and spaces, or make a safe junction location available.')
Write-Host ("MKWCBUILD: Warning: no junction to $full could be created (" + ($failures -join '; ') +
'); building from the original path, which may fail. Installing to a path of plain ' +
'letters, digits and spaces avoids this.')
return $full
}
function Get-MkwProjectPins([string]$ProjectFile) {
+3 -3
View File
@@ -82,9 +82,9 @@ $packages = @(
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz' })
},
[pscustomobject]@{
Name = 'xxhash'; File = 'xxHash-0.8.4.tar.gz'
Uris = @('https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz')
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz' })
Name = 'xxhash'; File = 'xxHash-0.8.3.tar.gz'
Uris = @('https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.3.tar.gz')
Pins = @(@{ File = $auroraExtern; Text = 'https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.3.tar.gz' })
},
[pscustomobject]@{
Name = 'zlib'; File = 'zlib-1.3.2.tar.gz'
+16 -86
View File
@@ -1,6 +1,6 @@
#!/usr/bin/env bash
# Builds the redistributable precompiled aurora + third-party package for native Linux: aurora
# (~43% of local build CPU time per Prepare-NativePrebuilt.ps1), Crypto++ and mbed TLS are identical
# (~43% of local build CPU time per Prepare-NativePrebuilt.ps1) and vendored Crypto++ are identical
# for every user under the pinned toolchain prepare-portable-tools.sh bundles, so this configures
# runtime/ against that toolchain, builds just that closure, and harvests the archives plus a
# generated CMake description into an output package - the Linux counterpart to
@@ -22,17 +22,11 @@ workspace=$(cd "$script_dir/.." && pwd)
arch=""
output_dir=""
toolchain_dir=""
ninja_bin=""
cmake_bin=""
llvm_dir=""
sysroot=""
stage_dir="$workspace/build/native-prebuilt-stage"
keep_stage=0
reuse_stage=0
parallel=0
print_fingerprint_only=0
disconnected=0
usage() {
cat <<'EOF'
@@ -45,7 +39,8 @@ Usage: Prepare-NativePrebuilt.sh --arch {x86_64|aarch64} [options]
--reuse-stage Reuse an existing staging build directory (maintainer iteration aid: a
re-harvest does not recompile aurora from scratch)
--parallel N Ninja build parallelism (default: nproc)
--print-fingerprint-only Print the provenance inputs as "key=value" lines and
--print-fingerprint-only Print the four provenance inputs (compiler_sha256, flag_fingerprint,
aurora_fingerprint, third_party_fingerprint) as "key=value" lines and
exit, without configuring/building/harvesting anything - lets a caller
(build-appimage.sh) decide whether an existing package is still current
without paying for a full aurora rebuild just to find out.
@@ -61,12 +56,6 @@ while [[ $# -gt 0 ]]; do
--reuse-stage) reuse_stage=1; shift ;;
--parallel) parallel=$2; shift 2 ;;
--print-fingerprint-only) print_fingerprint_only=1; shift ;;
--toolchain-dir) toolchain_dir=$2; shift 2 ;;
--ninja-bin) ninja_bin=$2; shift 2 ;;
--cmake-bin) cmake_bin=$2; shift 2 ;;
--llvm-dir) llvm_dir=$2; shift 2 ;;
--sysroot) sysroot=$2; shift 2 ;;
--disconnected) disconnected=1; shift ;;
-h|--help) usage; exit 0 ;;
*) echo "Prepare-NativePrebuilt.sh: unknown argument: $1" >&2; exit 1 ;;
esac
@@ -83,22 +72,14 @@ assert_dir() { [[ -d "$1" ]] || fail "$2 is missing: $1"; }
sha256_of() { sha256sum "$1" | awk '{print $1}'; }
normalize() { readlink -f "$1"; }
# Environment check: Ensure the `SOURCE_DATE_EPOCH` value is not invalid
# before trying to build anything (fail-fast)
if [[ -n "${SOURCE_DATE_EPOCH:-}" ]] && ! python3 -c \
'import datetime, os; datetime.datetime.fromtimestamp(int(os.environ.get("SOURCE_DATE_EPOCH")), datetime.timezone.utc)'
then
fail "SOURCE_DATE_EPOCH must be a valid UNIX timestamp"
fi
[[ -n "$output_dir" ]] || output_dir="$script_dir/artifacts/native-prebuilt-$arch"
[[ "$stage_dir" = /* ]] || stage_dir="$workspace/$stage_dir"
toolchain_dir="${toolchain_dir:-$script_dir/artifacts/portable-tools/toolchain-$arch}"
cc="${llvm_dir:-$toolchain_dir}/bin/clang"
cxx="${llvm_dir:-$toolchain_dir}/bin/clang++"
cmake_bin="${cmake_bin:-$toolchain_dir/bin/cmake}"
ninja_bin="${ninja_bin:-$toolchain_dir/bin/ninja}"
toolchain_dir="$script_dir/artifacts/portable-tools/toolchain-$arch"
cc="$toolchain_dir/bin/clang"
cxx="$toolchain_dir/bin/clang++"
cmake_bin="$toolchain_dir/bin/cmake"
ninja_bin="$toolchain_dir/bin/ninja"
runtime_source="$workspace/runtime"
aurora_source="$workspace/aurora-main"
@@ -107,7 +88,7 @@ assert_file "$ninja_bin" "Portable Ninja"
assert_file "$cc" "Portable C compiler"
assert_file "$cxx" "Portable C++ compiler"
assert_dir "$aurora_source" "aurora-main source tree"
clang_binary=$(normalize "${llvm_dir:-$toolchain_dir}/bin/clang-22")
clang_binary=$(normalize "$toolchain_dir/bin/clang-22")
assert_file "$clang_binary" "Portable clang driver binary"
(( parallel > 0 )) || parallel=$(nproc)
@@ -150,8 +131,6 @@ fixed_configure_flags=(
-DCMAKE_DISABLE_FIND_PACKAGE_absl=ON
-DCMAKE_DISABLE_FIND_PACKAGE_PNG=ON
-DCMAKE_DISABLE_FIND_PACKAGE_Freetype=ON
-DUSE_STATIC_MBEDTLS_LIBRARY=ON
-DUSE_SHARED_MBEDTLS_LIBRARY=OFF
# Freetype's own vendored CMakeLists.txt separately probes for system BZip2 (optional
# bzip2-compressed-font support aurora-main never asked for) regardless of the Freetype
# find_package disable above, since that only stops aurora's own outer find_package(Freetype)
@@ -162,16 +141,6 @@ fixed_configure_flags=(
-DFT_DISABLE_BZIP2=ON
-DCMAKE_POLICY_DEFAULT_CMP0168=NEW
)
if [[ "$disconnected" -eq 1 ]]; then
fixed_configure_flags+=(
-DFETCHCONTENT_FULLY_DISCONNECTED=ON
)
fi
if [[ -n "$sysroot" ]]; then
fixed_configure_flags+=(
-DCMAKE_SYSROOT="$sysroot"
)
fi
flag_fingerprint=$(printf '%s\n' "${fixed_configure_flags[@]}" | sha256sum | awk '{print $1}')
# extern/ is excluded because the payload ships that tree separately (aurora-main/extern is bundled
@@ -179,24 +148,19 @@ flag_fingerprint=$(printf '%s\n' "${fixed_configure_flags[@]}" | sha256sum | awk
aurora_fingerprint=$(fingerprint_tree "$aurora_source" extern build)
[[ -n "$aurora_fingerprint" ]] || fail "The aurora source tree could not be fingerprinted: $aurora_source"
# The harvested Crypto++ archive is consumed against this tree's headers, so it is fingerprinted.
# The harvested Crypto++ archive is consumed against this tree's headers, so it is fingerprinted
# for the same reason as aurora above. No exclusions: unlike aurora's extern/, nothing under
# runtime/third_party is shipped separately.
third_party_fingerprint=$(fingerprint_tree "$runtime_source/third_party")
[[ -n "$third_party_fingerprint" ]] || fail "The vendored third-party tree could not be fingerprinted: $runtime_source/third_party"
mbedtls_fingerprint=$(sha256_of "$runtime_source/cmake/MbedTLSPin.cmake")
compiler_sha256=$(sha256_of "$cc")
cxx_sha256=$(sha256_of "$cxx")
# Append the CXX SHA256 if it doesn't match the hash of CC
if [[ "${cxx_sha256}" != "${compiler_sha256}" ]]; then
compiler_sha256="${compiler_sha256}:${cxx_sha256}"
fi
compiler_sha256=$(sha256_of "$clang_binary")
if [[ "$print_fingerprint_only" -eq 1 ]]; then
printf 'compiler_sha256=%s\n' "$compiler_sha256"
printf 'flag_fingerprint=%s\n' "$flag_fingerprint"
printf 'aurora_fingerprint=%s\n' "$aurora_fingerprint"
printf 'third_party_fingerprint=%s\n' "$third_party_fingerprint"
printf 'mbedtls_fingerprint=%s\n' "$mbedtls_fingerprint"
exit 0
fi
@@ -397,21 +361,6 @@ while IFS='|' read -r name type file linkerfile; do
linker_file_to_reference["$linkerfile"]="@PKG@/$relative_linker"
fi
done < "$targets_txt"
mbedtls_refs=()
mbedtls_txt="$export_dir/mbedtls.txt"
assert_file "$mbedtls_txt" "Mbed TLS export targets list"
while IFS='|' read -r name linkerfile; do
[[ -n "$name" ]] || continue
linkerfile=$(normalize "$linkerfile")
ref=${linker_file_to_reference["$linkerfile"]:-}
[[ -n "$ref" ]] || fail "Mbed TLS archive was not harvested: $name ($linkerfile)"
mbedtls_refs+=("$ref")
done < "$mbedtls_txt"
[[ ${#mbedtls_refs[@]} -ge 3 ]] || fail "Expected at least three Mbed TLS archives, got ${#mbedtls_refs[@]}"
mbedtls_source_dir=$(get_meta mbedtls_source_dir)
assert_dir "$mbedtls_source_dir/include/mbedtls" "Mbed TLS headers"
mkdir -p "$output_dir/include/mbedtls"
cp -a "$mbedtls_source_dir/include/." "$output_dir/include/mbedtls/"
# Unlike Windows (SDL/zlib/libpng ship as DLLs by default), everything here was forced static above
# and Dawn's own Linux package (verified directly) ships libwebgpu_dawn.a, also static - so zero
# shared imports is the expected, normal outcome, not a failure.
@@ -477,9 +426,6 @@ for item in "${link_items[@]}"; do
if [[ "$item" = /* ]]; then item_abs=$(normalize "$item"); else item_abs=$(normalize "$stage_dir/$item"); fi
ref=${linker_file_to_reference["$item_abs"]:-}
if [[ -n "$ref" ]]; then
for mbedtls_ref in "${mbedtls_refs[@]}"; do
[[ "$ref" == "$mbedtls_ref" ]] && continue 2
done
package_link_items+=("$ref")
continue
fi
@@ -559,9 +505,6 @@ generated_cmake="$output_dir/native_prebuilt.cmake"
format_cmake_block MKW_NP_COMPILE_DEFINITIONS "${package_definitions[@]}"
format_cmake_block MKW_NP_COMPILE_OPTIONS "${package_compile_options[@]}"
format_cmake_block MKW_NP_LINK_LIBRARIES "${package_link_items[@]}"
format_cmake_block MKW_NP_MBEDTLS_LIBRARIES "${mbedtls_refs[@]}"
echo 'set(MKW_NP_MBEDTLS_INCLUDE_DIR "@PKG@/include/mbedtls")'
printf 'set(MKW_NP_MBEDTLS_FINGERPRINT "%s")\n' "$mbedtls_fingerprint"
format_cmake_block MKW_NP_AURORA_TARGETS "aurora::gx" "aurora::pad" "aurora::si" "aurora::vi" "aurora::mtx"
echo ""
printf 'set(MKW_NP_DAWN_CONFIG_DIR "%s")\n' "$dawn_config_token"
@@ -597,12 +540,12 @@ harvested_count=${#linker_file_to_reference[@]}
python3 - "$output_dir" "$compiler_sha256" "$compiler_version" "$flag_fingerprint" \
"$dawn_version" "$dawn_runtime_sha256" "$aurora_fingerprint" "$third_party_fingerprint" \
"$sdl3_target" "$harvested_count" "$mbedtls_fingerprint" <<'PY'
"$sdl3_target" "$harvested_count" <<'PY'
import hashlib, json, os, sys, datetime
(output_dir, compiler_sha256, compiler_version, flag_fingerprint, dawn_version,
dawn_runtime_sha256, aurora_fingerprint, third_party_fingerprint, sdl3_target,
harvested_count, mbedtls_fingerprint) = sys.argv[1:]
harvested_count) = sys.argv[1:]
contents = []
for root, dirs, files in os.walk(output_dir):
@@ -617,21 +560,9 @@ for root, dirs, files in os.walk(output_dir):
contents.append({"Path": rel, "Bytes": os.path.getsize(path), "Sha256": digest})
contents.sort(key=lambda c: c["Path"])
source_date_epoch = os.environ.get("SOURCE_DATE_EPOCH") or None
utc = datetime.timezone.utc
if source_date_epoch is not None:
built_utc = datetime.datetime.fromtimestamp(
int(source_date_epoch),
utc
)
else:
built_utc = datetime.datetime.now(utc)
built_utc = built_utc.strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z"
provenance = {
"SchemaVersion": 1,
"BuiltUtc": built_utc,
"BuiltUtc": datetime.datetime.now(datetime.timezone.utc).strftime("%Y-%m-%dT%H:%M:%S.%f")[:-3] + "Z",
"CompilerSha256": compiler_sha256,
"CompilerVersion": compiler_version,
"FlagFingerprint": flag_fingerprint,
@@ -639,7 +570,6 @@ provenance = {
"DawnRuntimeSha256": dawn_runtime_sha256,
"AuroraSourceFingerprint": aurora_fingerprint,
"ThirdPartySourceFingerprint": third_party_fingerprint,
"MbedTlsFingerprint": mbedtls_fingerprint,
"Sdl3Target": sdl3_target,
"HarvestedLibraryCount": int(harvested_count),
"Contents": contents,
+7 -28
View File
@@ -127,40 +127,19 @@ internal static class Program
string? retroWfcOfflineDir = null;
if (downloadPayload)
{
// Reused if a previous install already downloaded and it's still valid - matches
// Windows's own reuse-if-valid behavior instead of re-downloading on every install.
var cacheDir = Path.Combine(workspace, "generated", "retro-wfc-payload");
reporter.Progress(InstallStages.Validate,
"Downloading the current Retro-WFC payload", 1);
reporter.Progress(InstallStages.Validate, "Preparing the Retro-WFC payload", 1);
try
{
// A valid signature authenticates a payload, but does not prove it is the latest
// signed revision. Always ask the fixed endpoint for the current snapshot; the
// downloader verifies it before atomically replacing the cache.
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir);
}
catch (InvalidDataException)
{
await RetroWfcPayload.DownloadRetroWfcPayloadAsync(
RetroWfcPayload.CurrentRetroWfcPayloadUri, cacheDir, token);
}
catch (Exception downloadFailure) when (!token.IsCancellationRequested &&
downloadFailure is HttpRequestException or TimeoutException
or IOException)
{
// Offline installs may continue with a previously authenticated snapshot. Do not
// use this path for a newly downloaded payload that failed signature validation:
// that must remain a hard failure instead of hiding possible endpoint tampering.
try
{
RetroWfcPayload.ValidateStagedRetroWfcPayloadDirectory(cacheDir);
}
catch (Exception cacheFailure) when (cacheFailure is IOException or
UnauthorizedAccessException or InvalidDataException)
{
throw new InvalidOperationException(
"The current Retro-WFC payload could not be downloaded and no valid cached " +
$"payload is available ({cacheFailure.Message.TrimEnd('.')}).", downloadFailure);
}
reporter.Diagnostic(
"The current Retro-WFC payload could not be downloaded; using the previously " +
$"verified cached payload instead ({downloadFailure.Message.TrimEnd('.')}).");
}
retroWfcOfflineDir = cacheDir;
}
@@ -110,7 +110,8 @@ internal sealed class ProductRepairService
InputValidation.CurrentRetroWfcPayloadUri, payloadScratch, cancellationToken);
}
catch (Exception ex) when (!cancellationToken.IsCancellationRequested &&
ex is HttpRequestException or TimeoutException or IOException)
ex is HttpRequestException or IOException or InvalidDataException
or InvalidOperationException or OperationCanceledException)
{
payloadSnapshot = RecoverInstalledRetroWfcPayload(toolkitFingerprint,
Path.Combine(scratchRoot, "retro-wfc-payload-recovered"), ex, cancellationToken);
+2 -3
View File
@@ -128,9 +128,9 @@ cp -a "$workspace/Launcher/artifacts/portable-tools/toolchain-$appimagetool_arch
# Precompiled aurora + third-party package (see Prepare-NativePrebuilt.sh) so a user's own
# local-build.sh never has to compile aurora itself (~43% of local build CPU time). Re-harvesting
# recompiles the aurora/Crypto++/mbed TLS closure with the toolchain above, so this is skipped unless
# recompiles the whole aurora/Crypto++ closure with the toolchain above, so this is skipped unless
# --print-fingerprint-only (a fast, build-free check) says the existing package no longer matches
# the current compiler, flags, source trees or mbed TLS pin.
# the current compiler/flags/aurora/third_party sources.
native_prebuilt_dir="$workspace/Launcher/artifacts/native-prebuilt-$appimagetool_arch"
echo "Checking whether the precompiled aurora + third-party package ($appimagetool_arch) is current..."
current_fingerprint=$(bash "$script_dir/Prepare-NativePrebuilt.sh" --arch "$appimagetool_arch" --print-fingerprint-only)
@@ -148,7 +148,6 @@ fields = {
"flag_fingerprint": "FlagFingerprint",
"aurora_fingerprint": "AuroraSourceFingerprint",
"third_party_fingerprint": "ThirdPartySourceFingerprint",
"mbedtls_fingerprint": "MbedTlsFingerprint",
}
print(1 if all(provenance.get(v) == current.get(k) for k, v in fields.items()) else 0)
PY
+13 -27
View File
@@ -77,40 +77,26 @@ if [[ -n "$retro_dir" ]]; then
# verify its pinned signature before publishing it into the local cache.
retro_wfc_dir="$support_root/RetroWfcPayload"
retro_wfc_payload="$retro_wfc_dir/binary/payload.RMCPD00.bin"
cached_payload_valid=0
if [[ -f "$retro_wfc_payload" ]]; then
if "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir"; then
cached_payload_valid=1
else
printf 'Discarding an invalid cached Retro-WFC payload...\n' >&2
rm -f "$retro_wfc_payload"
fi
if [[ -f "$retro_wfc_payload" ]] && ! "$translator" validate-retro-wfc-payload --directory "$retro_wfc_dir"; then
printf 'Discarding an invalid cached Retro-WFC payload...\n' >&2
rm -f "$retro_wfc_payload"
fi
# A signed cache may still be an older vulnerable revision, so always attempt to replace it
# with the current signed snapshot. A transport failure may fall back to the verified cache;
# a downloaded snapshot with an invalid signature remains a hard failure.
printf 'Downloading the current Retro-WFC payload needed for online play...\n'
mkdir -p "$retro_wfc_dir"
payload_stage=$(mktemp -d "$retro_wfc_dir/.payload-download.XXXXXX")
temporary_payload="$payload_stage/binary/payload.RMCPD00.bin"
mkdir -p "$(dirname "$temporary_payload")"
trap 'rm -rf "$payload_stage"' EXIT
if /usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \
--retry 1 --output "$temporary_payload" \
'https://rwfc.net/api/wfc/payload?g=RMCPD00'; then
if [[ ! -f "$retro_wfc_payload" ]]; then
printf 'Downloading the Retro-WFC payload needed for online play...\n'
mkdir -p "$retro_wfc_dir"
payload_stage=$(mktemp -d "$retro_wfc_dir/.payload-download.XXXXXX")
temporary_payload="$payload_stage/binary/payload.RMCPD00.bin"
mkdir -p "$(dirname "$temporary_payload")"
trap 'rm -rf "$payload_stage"' EXIT
/usr/bin/curl --fail --silent --show-error --connect-timeout 10 --max-time 30 \
--retry 1 --output "$temporary_payload" \
'https://rwfc.net/api/wfc/payload?g=RMCPD00' || fail 'could not download the Retro-WFC payload needed for online play'
"$translator" validate-retro-wfc-payload --directory "$payload_stage" || \
fail 'downloaded Retro-WFC payload failed signature validation'
mkdir -p "$retro_wfc_dir/binary"
mv "$temporary_payload" "$retro_wfc_payload"
rmdir "$payload_stage/binary" "$payload_stage"
trap - EXIT
elif (( cached_payload_valid )); then
printf 'Could not download the current Retro-WFC payload; using the previously verified cached payload.\n' >&2
rm -rf "$payload_stage"
trap - EXIT
else
fail 'could not download the current Retro-WFC payload and no valid cached payload is available'
fi
build_args+=(--profile both --base-output-dir "$products" --retro-rewind-package-dir "$retro_dir" --retro-wfc-offline-dir "$retro_wfc_dir")
fi
+1 -1
View File
@@ -225,7 +225,7 @@ EOF
# clang++ invocation above would not catch a broken CMAKE_ROOT (Modules/Templates) or a Ninja that
# can't find the compiler.
cat > "$test_dir/CMakeLists.txt" <<'EOF'
cmake_minimum_required(VERSION 3.25)
cmake_minimum_required(VERSION 3.16)
project(test CXX)
add_executable(test t.cpp)
EOF
+1 -1
View File
@@ -132,7 +132,7 @@ trees themselves (fetched by `Launcher/Prepare-Dependencies.ps1`) so end-user bu
| Abseil | LTS 20240722.0 | Apache-2.0 | <https://github.com/abseil/abseil-cpp> |
| Dear ImGui | 1.91.9b-docking | MIT | <https://github.com/ocornut/imgui> |
| {fmt} | 11.1.4 | MIT | <https://github.com/fmtlib/fmt> |
| xxHash | 0.8.4 | BSD-2-Clause | <https://github.com/Cyan4973/xxHash> |
| xxHash | 0.8.3 | BSD-2-Clause | <https://github.com/Cyan4973/xxHash> |
| zlib | 1.3.2 | zlib | <https://github.com/madler/zlib> |
| libpng | 1.6.58 | PNG Reference Library License v2 | <https://github.com/pnggroup/libpng> |
| FreeType | 2.14.3 | **FreeType License (FTL)** - see below | <https://freetype.org/> |
+2 -2
View File
@@ -101,7 +101,7 @@ if (_aurora_dawn_provider STREQUAL "vendor")
include(FetchContent)
FetchContent_Declare(dawn
URL "https://github.com/google/dawn/archive/refs/tags/${AURORA_DAWN_VERSION}.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(dawn)
@@ -194,7 +194,7 @@ elseif (_aurora_dawn_provider STREQUAL "package")
FetchContent_Declare(dawn_prebuilt
URL "${AURORA_DAWN_PACKAGE_URL}"
${_dawn_prebuilt_hash_argument}
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_MakeAvailable(dawn_prebuilt)
+1 -1
View File
@@ -7,7 +7,7 @@
include(FetchContent)
FetchContent_Declare(libusb
URL "https://github.com/libusb/libusb/releases/download/v${AURORA_LIBUSB_VERSION}/libusb-${AURORA_LIBUSB_VERSION}.tar.bz2"
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
# Upstream ships no CMakeLists.txt, so this only populates the source tree.
FetchContent_MakeAvailable(libusb)
+1 -1
View File
@@ -120,7 +120,7 @@ elseif (_aurora_nod_provider STREQUAL "package")
include(FetchContent)
FetchContent_Declare(nod_prebuilt
URL "${AURORA_NOD_PACKAGE_URL}"
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(nod_prebuilt)
+2 -2
View File
@@ -92,7 +92,7 @@ elseif (_aurora_sdl3_provider STREQUAL "package")
include(FetchContent)
FetchContent_Declare(sdl3_prebuilt
URL "${AURORA_SDL3_PACKAGE_URL}"
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
)
FetchContent_MakeAvailable(sdl3_prebuilt)
@@ -145,7 +145,7 @@ elseif (_aurora_sdl3_provider STREQUAL "vendor")
endif ()
FetchContent_Declare(SDL
URL "https://github.com/libsdl-org/SDL/releases/download/release-${AURORA_SDL3_VERSION}/SDL3-${AURORA_SDL3_VERSION}.tar.gz"
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
PATCH_COMMAND "${CMAKE_COMMAND}" -DSDL_SOURCE_DIR=<SOURCE_DIR> -P "${_aurora_sdl3_patches}"
EXCLUDE_FROM_ALL
)
+13 -13
View File
@@ -38,7 +38,7 @@ else ()
set(ABSL_PROPAGATE_CXX_STD ON)
FetchContent_Declare(abseil-cpp
URL https://github.com/abseil/abseil-cpp/archive/refs/tags/20240722.0.tar.gz
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(abseil-cpp)
@@ -52,10 +52,10 @@ include(${CMAKE_CURRENT_SOURCE_DIR}/../cmake/AuroraSDL3Provider.cmake)
if (NOT TARGET xxhash)
message(STATUS "aurora: Fetching xxhash")
FetchContent_Declare(xxhash
URL https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.4.tar.gz
URL_HASH SHA256=5738270935e7c3d38a79b3adf7c9692566ce7895a25f67de43ad52ab504acd32
SOURCE_SUBDIR build/cmake
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
URL https://github.com/Cyan4973/xxHash/archive/refs/tags/v0.8.3.tar.gz
URL_HASH SHA256=aae608dfe8213dfd05d909a57718ef82f30722c392344583d3f39050c7f29a80
SOURCE_SUBDIR cmake_unofficial
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
set(XXHASH_BUILD_XXHSUM OFF CACHE INTERNAL "Build the xxhsum binary")
@@ -78,7 +78,7 @@ if (NOT TARGET fmt)
FetchContent_Declare(fmt
URL https://github.com/fmtlib/fmt/archive/refs/tags/11.1.4.tar.gz
URL_HASH SHA256=ac366b7b4c2e9f0dde63a59b3feb5ee59b67974b14ee5dc9ea8ad78aa2c1ee1e
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(fmt)
@@ -116,7 +116,7 @@ if (AURORA_ENABLE_GX)
ZLIB
URL https://github.com/madler/zlib/releases/download/v1.3.2/zlib-1.3.2.tar.gz
URL_HASH SHA256=bb329a0a2cd0274d05519d61c667c062e06990d72e125ee2dfa8de64f0119d16
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(ZLIB)
@@ -152,7 +152,7 @@ if (AURORA_ENABLE_GX)
PNG
URL https://github.com/pnggroup/libpng/archive/refs/tags/v1.6.58.tar.gz
URL_HASH SHA256=A9D4DF463D36A6E5F9C29BD6F4967312D17E996C1854F3511F833924EB1993CF
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(PNG)
@@ -176,7 +176,7 @@ if (AURORA_ENABLE_GX)
FetchContent_Declare(Freetype
URL https://files.twilitrealm.dev/freetype-2.14.3.tar.gz
URL_HASH SHA256=e61b31ab26358b946e767ed7eb7f4bb2e507da1cfefeb7a8861ace7fd5c899a1
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(Freetype)
@@ -190,7 +190,7 @@ if (AURORA_ENABLE_GX)
FetchContent_Declare(imgui
URL https://github.com/ocornut/imgui/archive/refs/tags/v1.91.9b-docking.tar.gz
URL_HASH SHA256=466fdef9b18de15f0bb6e288e3d00ffa3d82200ec458ce5e4f724a161d9528a5
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(imgui)
@@ -235,7 +235,7 @@ if (AURORA_ENABLE_GX)
FetchContent_Declare(sqlite3
URL https://sqlite.org/2026/sqlite-amalgamation-3510300.zip
URL_HASH SHA256=acb1e6f5d832484bf6d32b681e858c38add8b2acdfd42ac5df24b8afb46552b4
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(sqlite3)
@@ -278,7 +278,7 @@ if (AURORA_ENABLE_GX)
FetchContent_Declare(zstd
URL https://github.com/facebook/zstd/releases/download/v1.5.7/zstd-1.5.7.tar.gz
URL_HASH SHA256=eb33e51f49a15e023950cd7825ca74a4a2b43db8354825ac24fc1b7ee09e6fa3
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
SOURCE_SUBDIR build/cmake
EXCLUDE_FROM_ALL
)
@@ -299,7 +299,7 @@ if (NOT TARGET TracyClient)
tracy
URL https://github.com/wolfpld/tracy/archive/a64b9a20294d59421a2f57aeca3c6383d8c48169.tar.gz
URL_HASH SHA256=24d342b5127d7f659dc3cf94f24347b348cc736f25b17a691fd7f69541937658
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(tracy)
+1 -1
View File
@@ -5,7 +5,7 @@ if (NOT TARGET gtest)
FetchContent_Declare(googletest
URL https://github.com/google/googletest/archive/refs/tags/v1.17.0.tar.gz
URL_HASH SHA256=65fab701d9829d38cb77c14acdc431d2108bfdbf8979e40eb8ae567edf10b27c
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
DOWNLOAD_EXTRACT_TIMESTAMP TRUE
EXCLUDE_FROM_ALL
)
FetchContent_MakeAvailable(googletest)
+27 -55
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.25)
cmake_minimum_required(VERSION 3.16)
project(mkw_recompiled)
if(NOT CMAKE_CXX_COMPILER_ID MATCHES "^(Clang|AppleClang)$" OR NOT CMAKE_SIZEOF_VOID_P EQUAL 8)
@@ -21,8 +21,14 @@ if(NOT CMAKE_BUILD_TYPE STREQUAL "Release")
message(FATAL_ERROR "WiiCompiled only supports Release builds")
endif()
# Ninja writes Windows-quoted response files; the GNU clang driver otherwise reads them POSIX-style.
if(CMAKE_HOST_WIN32)
foreach(_mkw_lang C CXX)
set(CMAKE_${_mkw_lang}_RESPONSE_FILE_LINK_FLAG "--rsp-quoting=windows @")
endforeach()
endif()
option(MKW_BUILD_PRODUCTS "Build translated WiiCompiled product targets" ON)
option(MKW_BUILD_PSQ_TESTS "Build focused PSQ ISA tests" OFF)
# Preprocessor definitions that belong to this project's own code (the runtime,
# the translated shards and the product glue) and to nothing else. They are
@@ -114,10 +120,11 @@ endif()
# compiles cleanly for Android with nothing beyond a plain C toolchain (no perl/asm build-script
# dependency the way OpenSSL's build has), matching how this project already prefers toolchain-
# simple libraries (see Crypto++ above, similarly stripped of ASM/SIMD for portability).
# The from-source build fetches a pinned upstream tarball with a checked SHA-256.
# The Linux native prebuilt package instead ships its compiled archives and headers.
# Bump both values in cmake/MbedTLSPin.cmake when updating; the hash comes from
# upstream's signed `mbedtls-<version>-sha256sum.txt` release asset.
# Fetched at build time from a pinned upstream release tarball with a checked SHA-256, the same way
# aurora-main's own dependencies (SDL, zlib, etc.) are pulled in - not committed as a vendored
# source tree, so the repository ships the compiled dependency rather than ~280 tracked upstream
# files. Bump MKW_MBEDTLS_VERSION/MKW_MBEDTLS_SHA256 together when updating; the hash comes from
# upstream's own signed `mbedtls-<version>-sha256sum.txt` release asset.
#
# The alias exists on every platform so the link lines in cmake/PublicProducts.cmake stay
# platform-independent, but it is only populated where network_ssl.cpp actually compiles the mbed
@@ -128,22 +135,20 @@ endif()
add_library(mkw_mbedtls INTERFACE)
add_library(mkw::mbedtls ALIAS mkw_mbedtls)
if(NOT MKW_PLATFORM_WINDOWS)
include("${CMAKE_CURRENT_LIST_DIR}/cmake/MbedTLSPin.cmake")
if(NOT MKW_NATIVE_PREBUILT_DIR)
include(FetchContent)
FetchContent_Declare(mkw_mbedtls_upstream
URL "https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-${MKW_MBEDTLS_VERSION}/mbedtls-${MKW_MBEDTLS_VERSION}.tar.bz2"
URL_HASH SHA256=${MKW_MBEDTLS_SHA256}
DOWNLOAD_EXTRACT_TIMESTAMP FALSE
)
# Subproject mode already disables testing and codegen; it still enables programs.
set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE)
set(ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(MBEDTLS_FATAL_WARNINGS OFF CACHE BOOL "" FORCE)
set(DISABLE_PACKAGE_CONFIG_AND_INSTALL ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(mkw_mbedtls_upstream)
target_link_libraries(mkw_mbedtls INTERFACE MbedTLS::mbedtls MbedTLS::mbedx509 MbedTLS::mbedcrypto)
endif()
include(FetchContent)
set(MKW_MBEDTLS_VERSION "3.6.7")
set(MKW_MBEDTLS_SHA256 "a7e8bcbec0e6f761b4af24f25677626b35f762f68eef79c08677a363212d11f6")
FetchContent_Declare(mkw_mbedtls_upstream
URL "https://github.com/Mbed-TLS/mbedtls/releases/download/mbedtls-${MKW_MBEDTLS_VERSION}/mbedtls-${MKW_MBEDTLS_VERSION}.tar.bz2"
URL_HASH SHA256=${MKW_MBEDTLS_SHA256})
# Subproject mode already defaults ENABLE_TESTING off and skips codegen (GEN_FILES), but
# ENABLE_PROGRAMS defaults on and installation/package-config isn't wanted for a linked-in copy.
set(ENABLE_PROGRAMS OFF CACHE BOOL "" FORCE)
set(ENABLE_TESTING OFF CACHE BOOL "" FORCE)
set(MBEDTLS_FATAL_WARNINGS OFF CACHE BOOL "" FORCE)
set(DISABLE_PACKAGE_CONFIG_AND_INSTALL ON CACHE BOOL "" FORCE)
FetchContent_MakeAvailable(mkw_mbedtls_upstream)
target_link_libraries(mkw_mbedtls INTERFACE MbedTLS::mbedtls MbedTLS::mbedx509 MbedTLS::mbedcrypto)
endif()
set(MKW_TRANSLATED_COMPILE_JOBS 0 CACHE STRING
@@ -163,18 +168,6 @@ set(MKW_AURORA_DIR "${CMAKE_CURRENT_LIST_DIR}/../aurora-main")
# Fast-math may erase them and change guest-visible integer conversions.
set(MKW_TRANSLATED_PPC_FP_OPTIONS -fno-fast-math -ffp-contract=off)
set(MKW_PPC_SEMANTIC_RUNTIME_SOURCES
"${CMAKE_CURRENT_LIST_DIR}/src/ppc_helpers.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/fpu_helpers.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/ppc_quantized.cpp")
set_source_files_properties(${MKW_PPC_SEMANTIC_RUNTIME_SOURCES} PROPERTIES
SKIP_UNITY_BUILD_INCLUSION ON
SKIP_PRECOMPILE_HEADERS ON
COMPILE_OPTIONS "${MKW_TRANSLATED_PPC_FP_OPTIONS}")
# Match the optimization policy of the translated callers as well as their FP policy.
set_property(SOURCE "${CMAKE_CURRENT_LIST_DIR}/src/ppc_quantized.cpp" APPEND PROPERTY
COMPILE_OPTIONS -O2 -fno-slp-vectorize)
# ----------------------------------------------------------------------
# Third-party: aurora-main (provides SDL3 + GPU backends)
# ----------------------------------------------------------------------
@@ -323,27 +316,6 @@ set_target_properties(mkw_platform PROPERTIES UNITY_BUILD OFF)
# Keep these independent from Aurora's BUILD_TESTING option: they validate the
# project's host-platform contracts, not Aurora's third-party test suite.
enable_testing()
if(MKW_BUILD_PSQ_TESTS)
add_executable(mkw_psq_helpers_tests
"${CMAKE_CURRENT_LIST_DIR}/tests/psq_helpers_tests.cpp"
"${CMAKE_CURRENT_LIST_DIR}/src/ppc_quantized.cpp")
target_include_directories(mkw_psq_helpers_tests PRIVATE
"${CMAKE_CURRENT_LIST_DIR}/tests/psq_memory"
"${CMAKE_CURRENT_LIST_DIR}/include/isa"
"${CMAKE_CURRENT_LIST_DIR}/include")
target_compile_features(mkw_psq_helpers_tests PRIVATE cxx_std_17)
target_compile_options(mkw_psq_helpers_tests PRIVATE
-O2 ${MKW_TRANSLATED_PPC_FP_OPTIONS} -fno-slp-vectorize)
if(CMAKE_SYSTEM_PROCESSOR MATCHES "^(AMD64|amd64|x86_64|X86_64)$")
target_compile_options(mkw_psq_helpers_tests PRIVATE -march=x86-64-v3)
endif()
set_target_properties(mkw_psq_helpers_tests PROPERTIES UNITY_BUILD OFF)
add_test(NAME mkw_psq_helpers_tests COMMAND mkw_psq_helpers_tests)
add_test(NAME mkw_psq_reserved_tests COMMAND "${CMAKE_COMMAND}"
"-DPSQ_TEST_EXECUTABLE=$<TARGET_FILE:mkw_psq_helpers_tests>"
-P "${CMAKE_CURRENT_LIST_DIR}/tests/psq_reserved_tests.cmake")
endif()
add_executable(mkw_platform_paths_tests "${CMAKE_CURRENT_LIST_DIR}/tests/platform_paths_tests.cpp")
target_link_libraries(mkw_platform_paths_tests PRIVATE mkw_platform)
target_compile_features(mkw_platform_paths_tests PRIVATE cxx_std_17)
-4
View File
@@ -1,4 +0,0 @@
# Keep the release and verified archive hash together. The Linux native prebuilt
# fingerprint includes this file, so changing either value forces a new harvest.
set(MKW_MBEDTLS_VERSION "3.6.7")
set(MKW_MBEDTLS_SHA256 "a7e8bcbec0e6f761b4af24f25677626b35f762f68eef79c08677a363212d11f6")
-22
View File
@@ -42,28 +42,6 @@ endfunction()
mkw_np_resolve(_mkw_np_includes ${MKW_NP_INCLUDE_DIRECTORIES})
mkw_np_resolve(_mkw_np_links ${MKW_NP_LINK_LIBRARIES})
mkw_np_resolve(_mkw_np_dawn_config ${MKW_NP_DAWN_CONFIG_DIR})
if(NOT MKW_PLATFORM_WINDOWS)
if(NOT MKW_NP_MBEDTLS_LIBRARIES OR NOT MKW_NP_MBEDTLS_INCLUDE_DIR)
message(FATAL_ERROR
"The Linux native prebuilt package has no Mbed TLS archives; regenerate it with Prepare-NativePrebuilt.sh")
endif()
file(SHA256 "${CMAKE_CURRENT_LIST_DIR}/MbedTLSPin.cmake" _mkw_np_current_mbedtls_fingerprint)
if(NOT MKW_NP_MBEDTLS_FINGERPRINT STREQUAL _mkw_np_current_mbedtls_fingerprint)
message(FATAL_ERROR "The native prebuilt Mbed TLS version differs from this workspace; regenerate the package")
endif()
mkw_np_resolve(_mkw_np_mbedtls_links ${MKW_NP_MBEDTLS_LIBRARIES})
mkw_np_resolve(_mkw_np_mbedtls_include ${MKW_NP_MBEDTLS_INCLUDE_DIR})
foreach(_archive IN LISTS _mkw_np_mbedtls_links)
if(NOT EXISTS "${_archive}")
message(FATAL_ERROR "The native prebuilt package is missing Mbed TLS archive: ${_archive}")
endif()
endforeach()
if(NOT IS_DIRECTORY "${_mkw_np_mbedtls_include}")
message(FATAL_ERROR "The native prebuilt package is missing Mbed TLS headers: ${_mkw_np_mbedtls_include}")
endif()
target_include_directories(mkw_mbedtls SYSTEM INTERFACE "${_mkw_np_mbedtls_include}")
target_link_libraries(mkw_mbedtls INTERFACE ${_mkw_np_mbedtls_links})
endif()
foreach(_dir IN LISTS _mkw_np_includes)
if(NOT IS_DIRECTORY "${_dir}")
-23
View File
@@ -77,9 +77,6 @@ target_compile_features(mkw_np_probe PRIVATE cxx_std_20)
target_link_libraries(mkw_np_probe PRIVATE
aurora::gx aurora::pad aurora::si aurora::vi aurora::mtx
mkw::cryptopp)
if(NOT MKW_PLATFORM_WINDOWS)
target_link_libraries(mkw_np_probe PRIVATE mkw::mbedtls)
endif()
get_filename_component(_mkw_np_aurora_dir "${MKW_AURORA_DIR}" ABSOLUTE)
mkw_collect_buildsystem_targets("${_mkw_np_aurora_dir}" _mkw_np_all_targets)
@@ -87,25 +84,6 @@ mkw_collect_buildsystem_targets("${_mkw_np_aurora_dir}" _mkw_np_all_targets)
# the scan above cannot see it; it is appended explicitly. The type and closure
# checks below still apply to it.
list(APPEND _mkw_np_all_targets "mkw_cryptopp")
if(NOT MKW_PLATFORM_WINDOWS)
set(_mkw_np_mbedtls_targets mbedtls mbedx509 mbedcrypto)
# mbedcrypto links these third-party archives when upstream defines them.
# Keep dependencies after mbedcrypto for static linking on the consumer side.
foreach(_t everest p256m)
if(TARGET ${_t})
list(APPEND _mkw_np_mbedtls_targets ${_t})
endif()
endforeach()
list(APPEND _mkw_np_all_targets ${_mkw_np_mbedtls_targets})
# Keep the complete TLS archive set separate from aurora's aggregate link interface.
set(_mkw_np_mbedtls_lines "")
foreach(_t IN LISTS _mkw_np_mbedtls_targets)
string(APPEND _mkw_np_mbedtls_lines
"${_t}|$<TARGET_LINKER_FILE:${_t}>\n")
endforeach()
file(GENERATE OUTPUT "${MKW_NATIVE_PREBUILT_EXPORT_DIR}/mbedtls.txt"
CONTENT "${_mkw_np_mbedtls_lines}")
endif()
if(NOT _mkw_np_all_targets)
message(FATAL_ERROR "No buildsystem targets were found under ${_mkw_np_aurora_dir}")
endif()
@@ -158,7 +136,6 @@ string(REPLACE ";" "," _mkw_np_lib_targets_csv "${_mkw_np_lib_targets}")
file(WRITE "${MKW_NATIVE_PREBUILT_EXPORT_DIR}/meta.txt"
"aurora_dir=${_mkw_np_aurora_dir}\n"
"runtime_dir=${CMAKE_CURRENT_SOURCE_DIR}\n"
"mbedtls_source_dir=${mkw_mbedtls_upstream_SOURCE_DIR}\n"
"binary_dir=${CMAKE_BINARY_DIR}\n"
"dawn_config_dir=${_mkw_np_dawn_config_dir}\n"
"dawn_prebuilt_source_dir=${dawn_prebuilt_SOURCE_DIR}\n"
+10 -1
View File
@@ -118,7 +118,16 @@ foreach(source IN LISTS SOURCES)
endif()
set_source_files_properties("${source}" PROPERTIES UNITY_GROUP "${runtime_group}")
endforeach()
# PPC semantic sources are excluded from unity/PCH and configured in CMakeLists.txt.
# These translation units implement guest-visible floating-point bit
# semantics. Keep them out of the fast-math runtime unity groups and apply
# the same contraction/rounding policy as translated PPC shards.
set(MKW_PPC_SEMANTIC_RUNTIME_SOURCES
"${MKW_RUNTIME_SOURCE_DIR}/src/ppc_helpers.cpp"
"${MKW_RUNTIME_SOURCE_DIR}/src/fpu_helpers.cpp")
set_source_files_properties(${MKW_PPC_SEMANTIC_RUNTIME_SOURCES} PROPERTIES
SKIP_UNITY_BUILD_INCLUSION ON
SKIP_PRECOMPILE_HEADERS ON
COMPILE_OPTIONS "${MKW_TRANSLATED_PPC_FP_OPTIONS}")
set_target_properties(mkw_runtime_common PROPERTIES UNITY_BUILD ON UNITY_BUILD_MODE GROUP)
target_precompile_headers(mkw_runtime_common PRIVATE "${MKW_RUNTIME_SOURCE_DIR}/include/mkw_pch.h")
mkw_apply_common_compile_options(mkw_runtime_common)
+96 -66
View File
@@ -294,7 +294,7 @@ inline double PpcLoadPairPsqFloatFastInline(uint32_t addr)
return PpcLoadPairPsqFloatFromHostInline(host);
}
return PpcBitCastToDoubleInline(
PpcLoadPairPsqFloatBitsPackedInline(Memory::Read64(addr)));
PpcLoadPairPsqFloatBitsPackedInline(MemoryInline::Read64Slow(addr)));
}
inline double PpcLoadSinglePsqFloatFastInline(uint32_t addr)
@@ -349,7 +349,7 @@ inline void PpcStorePairPsqFloatFastInline(uint32_t addr, double value)
PpcStorePairPsqFloatToHostInline(host, value);
return;
}
Memory::Write64(
MemoryInline::Write64Slow(
addr, PpcStorePairPsqFloatBitsPackedInline(PpcBitCastToU64Inline(value)));
}
@@ -1385,13 +1385,37 @@ MKW_PPC_FORCE_INLINE void PPC_PsqStStackInline(uint32_t addr, double value)
// Context-free PSQ entries for translated regions which own GQR state as an
// ordinary native value. All architecturally valid quantization encodings are
// handled directly; reserved encodings retain the generic helper's abort.
template <uint32_t W, bool Stack>
MKW_PPC_NO_INLINE MKW_PPC_COLD double PPC_PsqLStateFallback(uint32_t gqr, uint32_t addr);
extern template double PPC_PsqLStateFallback<0u, false>(uint32_t, uint32_t);
extern template double PPC_PsqLStateFallback<0u, true>(uint32_t, uint32_t);
extern template double PPC_PsqLStateFallback<1u, false>(uint32_t, uint32_t);
extern template double PPC_PsqLStateFallback<1u, true>(uint32_t, uint32_t);
template <uint32_t W, uint32_t I, bool Stack>
MKW_PPC_NO_INLINE MKW_PPC_COLD inline double PPC_PsqLStateFallback(uint32_t gqr, uint32_t addr)
{
static_assert(W <= 1u && I < 8u);
const uint32_t type = (gqr >> 16) & 0x7u;
const uint32_t scale = (gqr >> 24) & 0x3Fu;
if constexpr (W == 0u)
{
switch (type)
{
case 0u: return Stack ? PpcLoadPairPsqFloatStackInline(addr) : PpcLoadPairPsqFloatFastInline(addr);
case 4u: return Stack ? PpcLoadPairPsqIntegerStackInline<uint8_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<uint8_t>(addr, scale);
case 5u: return Stack ? PpcLoadPairPsqIntegerStackInline<uint16_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<uint16_t>(addr, scale);
case 6u: return Stack ? PpcLoadPairPsqIntegerStackInline<int8_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<int8_t>(addr, scale);
case 7u: return Stack ? PpcLoadPairPsqIntegerStackInline<int16_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<int16_t>(addr, scale);
default: std::abort();
}
}
else
{
switch (type)
{
case 0u: return Stack ? PpcLoadSinglePsqFloatStackInline(addr) : PpcLoadSinglePsqFloatFastInline(addr);
case 4u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<uint8_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<uint8_t>(addr, scale);
case 5u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<uint16_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<uint16_t>(addr, scale);
case 6u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<int8_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<int8_t>(addr, scale);
case 7u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<int16_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<int16_t>(addr, scale);
default: std::abort();
}
}
}
// Keep the normal explicit-state path small and directly optimizable. Exact
// unscaled encodings cover the SDK's common GQR setup; scaled and reserved
@@ -1418,17 +1442,41 @@ MKW_PPC_FORCE_INLINE double PPC_PsqLStateInline(uint32_t gqr, uint32_t addr)
if constexpr (W == 0u) return Stack ? PpcLoadPairPsqIntegerStackInline<int16_t>(addr, 0u) : PpcLoadPairPsqIntegerFastInline<int16_t>(addr, 0u);
else return Stack ? PpcLoadSinglePsqQuantizedStackInline<int16_t>(addr, 0u) : PpcLoadSinglePsqQuantizedFastInline<int16_t>(addr, 0u);
default:
return PPC_PsqLStateFallback<W, Stack>(gqr, addr);
return PPC_PsqLStateFallback<W, I, Stack>(gqr, addr);
}
}
template <uint32_t W, bool Stack>
MKW_PPC_NO_INLINE MKW_PPC_COLD void PPC_PsqStStateFallback(uint32_t gqr, uint32_t addr, double value);
extern template void PPC_PsqStStateFallback<0u, false>(uint32_t, uint32_t, double);
extern template void PPC_PsqStStateFallback<0u, true>(uint32_t, uint32_t, double);
extern template void PPC_PsqStStateFallback<1u, false>(uint32_t, uint32_t, double);
extern template void PPC_PsqStStateFallback<1u, true>(uint32_t, uint32_t, double);
template <uint32_t W, uint32_t I, bool Stack>
MKW_PPC_NO_INLINE MKW_PPC_COLD inline void PPC_PsqStStateFallback(uint32_t gqr, uint32_t addr, double value)
{
static_assert(W <= 1u && I < 8u);
const uint32_t type = gqr & 0x7u;
const uint32_t scale = (gqr >> 8) & 0x3Fu;
if constexpr (W == 0u)
{
switch (type)
{
case 0u: Stack ? PpcStorePairPsqFloatStackInline(addr, value) : PpcStorePairPsqFloatFastInline(addr, value); return;
case 4u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<uint8_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<uint8_t>(addr, value, scale); return;
case 5u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<uint16_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<uint16_t>(addr, value, scale); return;
case 6u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<int8_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<int8_t>(addr, value, scale); return;
case 7u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<int16_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<int16_t>(addr, value, scale); return;
default: std::abort();
}
}
else
{
switch (type)
{
case 0u: if constexpr (Stack) PpcStoreSinglePsqFloatStackInline(addr, value); else PpcStoreSinglePsqFloatFastInline(addr, value); return;
case 4u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<uint8_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<uint8_t>(addr, value, scale); return;
case 5u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<uint16_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<uint16_t>(addr, value, scale); return;
case 6u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<int8_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<int8_t>(addr, value, scale); return;
case 7u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<int16_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<int16_t>(addr, value, scale); return;
default: std::abort();
}
}
}
template <uint32_t W, uint32_t I, bool Stack>
MKW_PPC_FORCE_INLINE void PPC_PsqStStateInline(uint32_t gqr, uint32_t addr, double value)
@@ -1457,18 +1505,11 @@ MKW_PPC_FORCE_INLINE void PPC_PsqStStateInline(uint32_t gqr, uint32_t addr, doub
else { if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<int16_t>(addr, value, 0u); else PpcStoreSinglePsqQuantizedFastInline<int16_t>(addr, value, 0u); }
return;
default:
PPC_PsqStStateFallback<W, Stack>(gqr, addr, value);
PPC_PsqStStateFallback<W, I, Stack>(gqr, addr, value);
return;
}
}
template <uint32_t W>
MKW_PPC_NO_INLINE MKW_PPC_COLD double PPC_PsqLResolvedStateFallback(
uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr);
extern template double PPC_PsqLResolvedStateFallback<0u>(uint32_t, uint8_t*, uint32_t, uint32_t);
extern template double PPC_PsqLResolvedStateFallback<1u>(uint32_t, uint8_t*, uint32_t, uint32_t);
template <uint32_t W, uint32_t I>
MKW_PPC_FORCE_INLINE double PPC_PsqLResolvedStateInline(
uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr)
@@ -1476,41 +1517,33 @@ MKW_PPC_FORCE_INLINE double PPC_PsqLResolvedStateInline(
static_assert(W <= 1u && I < 8u);
if (!resolvedHost) [[unlikely]] return PPC_PsqLStateInline<W, I, false>(gqr, addr);
const uint32_t type = (gqr >> 16) & 0x7u;
if (type == 0u) {
if constexpr (W == 0u) return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr);
else return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr);
}
const uint32_t scale = (gqr >> 24) & 0x3Fu;
if constexpr (W == 0u)
{
switch (gqr & 0x3F070000u)
switch (type)
{
case 0x00040000u: return PpcLoadPairPsqIntegerResolvedInline<uint8_t>(resolvedHost, offset, addr, 0u);
case 0x00050000u: return PpcLoadPairPsqIntegerResolvedInline<uint16_t>(resolvedHost, offset, addr, 0u);
case 0x00060000u: return PpcLoadPairPsqIntegerResolvedInline<int8_t>(resolvedHost, offset, addr, 0u);
case 0x00070000u: return PpcLoadPairPsqIntegerResolvedInline<int16_t>(resolvedHost, offset, addr, 0u);
default: return PPC_PsqLResolvedStateFallback<W>(gqr, resolvedHost, offset, addr);
case 0u: return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr);
case 4u: return PpcLoadPairPsqIntegerResolvedInline<uint8_t>(resolvedHost, offset, addr, scale);
case 5u: return PpcLoadPairPsqIntegerResolvedInline<uint16_t>(resolvedHost, offset, addr, scale);
case 6u: return PpcLoadPairPsqIntegerResolvedInline<int8_t>(resolvedHost, offset, addr, scale);
case 7u: return PpcLoadPairPsqIntegerResolvedInline<int16_t>(resolvedHost, offset, addr, scale);
default: std::abort();
}
}
else
{
switch (gqr & 0x3F070000u)
switch (type)
{
case 0x00040000u: return PpcLoadSinglePsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, 0u);
case 0x00050000u: return PpcLoadSinglePsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, 0u);
case 0x00060000u: return PpcLoadSinglePsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, 0u);
case 0x00070000u: return PpcLoadSinglePsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, 0u);
default: return PPC_PsqLResolvedStateFallback<W>(gqr, resolvedHost, offset, addr);
case 0u: return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr);
case 4u: return PpcLoadSinglePsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, scale);
case 5u: return PpcLoadSinglePsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, scale);
case 6u: return PpcLoadSinglePsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, scale);
case 7u: return PpcLoadSinglePsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, scale);
default: std::abort();
}
}
}
template <uint32_t W>
MKW_PPC_NO_INLINE MKW_PPC_COLD void PPC_PsqStResolvedStateFallback(
uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value);
extern template void PPC_PsqStResolvedStateFallback<0u>(uint32_t, uint8_t*, uint32_t, uint32_t, double);
extern template void PPC_PsqStResolvedStateFallback<1u>(uint32_t, uint8_t*, uint32_t, uint32_t, double);
template <uint32_t W, uint32_t I>
MKW_PPC_FORCE_INLINE void PPC_PsqStResolvedStateInline(
uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value)
@@ -1522,32 +1555,29 @@ MKW_PPC_FORCE_INLINE void PPC_PsqStResolvedStateInline(
return;
}
const uint32_t type = gqr & 0x7u;
if (type == 0u) {
if constexpr (W == 0u) PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value);
else PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value);
return;
}
const uint32_t scale = (gqr >> 8) & 0x3Fu;
if constexpr (W == 0u)
{
switch (gqr & 0x3F07u)
switch (type)
{
case 0x3D04u: PpcStorePairPsqU8Scale61ResolvedInline(resolvedHost, offset, addr, value); return;
case 4u: PpcStorePairPsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, value, 0u); return;
case 5u: PpcStorePairPsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, value, 0u); return;
case 6u: PpcStorePairPsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, value, 0u); return;
case 7u: PpcStorePairPsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, value, 0u); return;
default: PPC_PsqStResolvedStateFallback<W>(gqr, resolvedHost, offset, addr, value); return;
case 0u: PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value); return;
case 4u: PpcStorePairPsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, value, scale); return;
case 5u: PpcStorePairPsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, value, scale); return;
case 6u: PpcStorePairPsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, value, scale); return;
case 7u: PpcStorePairPsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, value, scale); return;
default: std::abort();
}
}
else
{
switch (gqr & 0x3F07u)
switch (type)
{
case 4u: PpcStoreSinglePsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, value, 0u); return;
case 5u: PpcStoreSinglePsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, value, 0u); return;
case 6u: PpcStoreSinglePsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, value, 0u); return;
case 7u: PpcStoreSinglePsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, value, 0u); return;
default: PPC_PsqStResolvedStateFallback<W>(gqr, resolvedHost, offset, addr, value); return;
case 0u: PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value); return;
case 4u: PpcStoreSinglePsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, value, scale); return;
case 5u: PpcStoreSinglePsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, value, scale); return;
case 6u: PpcStoreSinglePsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, value, scale); return;
case 7u: PpcStoreSinglePsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, value, scale); return;
default: std::abort();
}
}
}
+2 -3
View File
@@ -132,9 +132,8 @@ using CryptoEcdsa = CryptoPP::ECDSA<CryptoPP::EC2N, CryptoPP::SHA1>;
inline CryptoEcdsa::PrivateKey MakePrivateKey(const uint8_t* key) {
CryptoPP::DL_GroupParameters_EC<CryptoPP::EC2N> parameters(CryptoPP::ASN1::sect233r1());
// Wii keys need not be canonical scalars; reduction preserves their public key.
const CryptoPP::Integer exponent = CryptoPP::Integer(key, 30) % parameters.GetSubgroupOrder();
if (exponent == CryptoPP::Integer::Zero()) {
const CryptoPP::Integer exponent(key, 30);
if (exponent <= CryptoPP::Integer::Zero() || exponent >= parameters.GetSubgroupOrder()) {
throw std::invalid_argument("Wii ES private key is outside the sect233r1 subgroup");
}
+4 -4
View File
@@ -833,8 +833,8 @@ extern "C" double PPC_PsqL(uint32_t addr, uint32_t w, uint32_t i)
}
const uint32_t gqr = cpu->gqr[i & 7];
return w == 0 ? PPC_PsqLStateFallback<0u, false>(gqr, addr)
: PPC_PsqLStateFallback<1u, false>(gqr, addr);
return w == 0 ? PPC_PsqLStateFallback<0u, 0u, false>(gqr, addr)
: PPC_PsqLStateFallback<1u, 0u, false>(gqr, addr);
}
extern "C" void PPC_PsqSt(uint32_t addr, double value, uint32_t w, uint32_t i)
@@ -848,11 +848,11 @@ extern "C" void PPC_PsqSt(uint32_t addr, double value, uint32_t w, uint32_t i)
const uint32_t gqr = cpu->gqr[i & 7];
if (w == 0)
{
PPC_PsqStStateFallback<0u, false>(gqr, addr, value);
PPC_PsqStStateFallback<0u, 0u, false>(gqr, addr, value);
}
else
{
PPC_PsqStStateFallback<1u, false>(gqr, addr, value);
PPC_PsqStStateFallback<1u, 0u, false>(gqr, addr, value);
}
}
-154
View File
@@ -1,154 +0,0 @@
#include "isa/ppc_isa_quantized.h"
#if defined(__FAST_MATH__) || __FINITE_MATH_ONLY__
#error "PSQ helpers require strict PPC floating-point options"
#endif
template <uint32_t W, bool Stack>
MKW_PPC_NO_INLINE MKW_PPC_COLD double PPC_PsqLStateFallback(uint32_t gqr, uint32_t addr)
{
static_assert(W <= 1u);
const uint32_t type = (gqr >> 16) & 0x7u;
const uint32_t scale = (gqr >> 24) & 0x3Fu;
if constexpr (W == 0u)
{
switch (type)
{
case 0u: return Stack ? PpcLoadPairPsqFloatStackInline(addr) : PpcLoadPairPsqFloatFastInline(addr);
case 4u: return Stack ? PpcLoadPairPsqIntegerStackInline<uint8_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<uint8_t>(addr, scale);
case 5u: return Stack ? PpcLoadPairPsqIntegerStackInline<uint16_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<uint16_t>(addr, scale);
case 6u: return Stack ? PpcLoadPairPsqIntegerStackInline<int8_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<int8_t>(addr, scale);
case 7u: return Stack ? PpcLoadPairPsqIntegerStackInline<int16_t>(addr, scale) : PpcLoadPairPsqIntegerFastInline<int16_t>(addr, scale);
default: std::abort();
}
}
else
{
switch (type)
{
case 0u: return Stack ? PpcLoadSinglePsqFloatStackInline(addr) : PpcLoadSinglePsqFloatFastInline(addr);
case 4u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<uint8_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<uint8_t>(addr, scale);
case 5u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<uint16_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<uint16_t>(addr, scale);
case 6u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<int8_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<int8_t>(addr, scale);
case 7u: return Stack ? PpcLoadSinglePsqQuantizedStackInline<int16_t>(addr, scale) : PpcLoadSinglePsqQuantizedFastInline<int16_t>(addr, scale);
default: std::abort();
}
}
}
template <uint32_t W, bool Stack>
MKW_PPC_NO_INLINE MKW_PPC_COLD void PPC_PsqStStateFallback(uint32_t gqr, uint32_t addr, double value)
{
static_assert(W <= 1u);
const uint32_t type = gqr & 0x7u;
const uint32_t scale = (gqr >> 8) & 0x3Fu;
if constexpr (W == 0u)
{
switch (type)
{
case 0u: Stack ? PpcStorePairPsqFloatStackInline(addr, value) : PpcStorePairPsqFloatFastInline(addr, value); return;
case 4u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<uint8_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<uint8_t>(addr, value, scale); return;
case 5u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<uint16_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<uint16_t>(addr, value, scale); return;
case 6u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<int8_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<int8_t>(addr, value, scale); return;
case 7u: if constexpr (Stack) PpcStorePairPsqQuantizedStackInline<int16_t>(addr, value, scale); else PpcStorePairPsqQuantizedFastInline<int16_t>(addr, value, scale); return;
default: std::abort();
}
}
else
{
switch (type)
{
case 0u: if constexpr (Stack) PpcStoreSinglePsqFloatStackInline(addr, value); else PpcStoreSinglePsqFloatFastInline(addr, value); return;
case 4u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<uint8_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<uint8_t>(addr, value, scale); return;
case 5u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<uint16_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<uint16_t>(addr, value, scale); return;
case 6u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<int8_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<int8_t>(addr, value, scale); return;
case 7u: if constexpr (Stack) PpcStoreSinglePsqQuantizedStackInline<int16_t>(addr, value, scale); else PpcStoreSinglePsqQuantizedFastInline<int16_t>(addr, value, scale); return;
default: std::abort();
}
}
}
template <uint32_t W>
MKW_PPC_NO_INLINE MKW_PPC_COLD double PPC_PsqLResolvedStateFallback(
uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr)
{
static_assert(W <= 1u);
if (!resolvedHost) [[unlikely]] return PPC_PsqLStateInline<W, 0u, false>(gqr, addr);
const uint32_t type = (gqr >> 16) & 0x7u;
const uint32_t scale = (gqr >> 24) & 0x3Fu;
if constexpr (W == 0u)
{
switch (type)
{
case 0u: return PpcLoadPairPsqFloatResolvedInline(resolvedHost, offset, addr);
case 4u: return PpcLoadPairPsqIntegerResolvedInline<uint8_t>(resolvedHost, offset, addr, scale);
case 5u: return PpcLoadPairPsqIntegerResolvedInline<uint16_t>(resolvedHost, offset, addr, scale);
case 6u: return PpcLoadPairPsqIntegerResolvedInline<int8_t>(resolvedHost, offset, addr, scale);
case 7u: return PpcLoadPairPsqIntegerResolvedInline<int16_t>(resolvedHost, offset, addr, scale);
default: std::abort();
}
}
else
{
switch (type)
{
case 0u: return PpcLoadSinglePsqFloatResolvedInline(resolvedHost, offset, addr);
case 4u: return PpcLoadSinglePsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, scale);
case 5u: return PpcLoadSinglePsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, scale);
case 6u: return PpcLoadSinglePsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, scale);
case 7u: return PpcLoadSinglePsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, scale);
default: std::abort();
}
}
}
template <uint32_t W>
MKW_PPC_NO_INLINE MKW_PPC_COLD void PPC_PsqStResolvedStateFallback(
uint32_t gqr, uint8_t* resolvedHost, uint32_t offset, uint32_t addr, double value)
{
static_assert(W <= 1u);
if (!resolvedHost) [[unlikely]]
{
PPC_PsqStStateInline<W, 0u, false>(gqr, addr, value);
return;
}
const uint32_t type = gqr & 0x7u;
const uint32_t scale = (gqr >> 8) & 0x3Fu;
if constexpr (W == 0u)
{
switch (type)
{
case 0u: PpcStorePairPsqFloatResolvedInline(resolvedHost, offset, addr, value); return;
case 4u: PpcStorePairPsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, value, scale); return;
case 5u: PpcStorePairPsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, value, scale); return;
case 6u: PpcStorePairPsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, value, scale); return;
case 7u: PpcStorePairPsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, value, scale); return;
default: std::abort();
}
}
else
{
switch (type)
{
case 0u: PpcStoreSinglePsqFloatResolvedInline(resolvedHost, offset, addr, value); return;
case 4u: PpcStoreSinglePsqQuantizedResolvedInline<uint8_t>(resolvedHost, offset, addr, value, scale); return;
case 5u: PpcStoreSinglePsqQuantizedResolvedInline<uint16_t>(resolvedHost, offset, addr, value, scale); return;
case 6u: PpcStoreSinglePsqQuantizedResolvedInline<int8_t>(resolvedHost, offset, addr, value, scale); return;
case 7u: PpcStoreSinglePsqQuantizedResolvedInline<int16_t>(resolvedHost, offset, addr, value, scale); return;
default: std::abort();
}
}
}
template double PPC_PsqLStateFallback<0u, false>(uint32_t, uint32_t);
template void PPC_PsqStStateFallback<0u, false>(uint32_t, uint32_t, double);
template double PPC_PsqLStateFallback<0u, true>(uint32_t, uint32_t);
template void PPC_PsqStStateFallback<0u, true>(uint32_t, uint32_t, double);
template double PPC_PsqLResolvedStateFallback<0u>(uint32_t, uint8_t*, uint32_t, uint32_t);
template void PPC_PsqStResolvedStateFallback<0u>(uint32_t, uint8_t*, uint32_t, uint32_t, double);
template double PPC_PsqLStateFallback<1u, false>(uint32_t, uint32_t);
template void PPC_PsqStStateFallback<1u, false>(uint32_t, uint32_t, double);
template double PPC_PsqLStateFallback<1u, true>(uint32_t, uint32_t);
template void PPC_PsqStStateFallback<1u, true>(uint32_t, uint32_t, double);
template double PPC_PsqLResolvedStateFallback<1u>(uint32_t, uint8_t*, uint32_t, uint32_t);
template void PPC_PsqStResolvedStateFallback<1u>(uint32_t, uint8_t*, uint32_t, uint32_t, double);
-140
View File
@@ -1,140 +0,0 @@
#include "isa/ppc_isa_quantized.h"
#include <csignal>
#include <iostream>
#include <stdexcept>
#include <string>
static uint64_t checksum = 0;
static unsigned checks = 0;
static void Require(bool condition, const char* message) {
++checks;
if (!condition) throw std::runtime_error(message);
}
static void Hash(uint64_t value) { checksum = (checksum ^ value) * 1099511628211ull; }
template <uint32_t W> static double ReferenceLoad(uint32_t type, uint32_t scale, uint32_t addr) {
if constexpr (W == 0u) {
switch (type) {
case 0: return PpcLoadPairPsqFloatFastInline(addr);
case 4: return PpcLoadPairPsqIntegerFastInline<uint8_t>(addr, scale);
case 5: return PpcLoadPairPsqIntegerFastInline<uint16_t>(addr, scale);
case 6: return PpcLoadPairPsqIntegerFastInline<int8_t>(addr, scale);
case 7: return PpcLoadPairPsqIntegerFastInline<int16_t>(addr, scale);
}
} else {
switch (type) {
case 0: return PpcLoadSinglePsqFloatFastInline(addr);
case 4: return PpcLoadSinglePsqQuantizedFastInline<uint8_t>(addr, scale);
case 5: return PpcLoadSinglePsqQuantizedFastInline<uint16_t>(addr, scale);
case 6: return PpcLoadSinglePsqQuantizedFastInline<int8_t>(addr, scale);
case 7: return PpcLoadSinglePsqQuantizedFastInline<int16_t>(addr, scale);
}
}
std::abort();
}
template <uint32_t W> static void ReferenceStore(uint32_t type, uint32_t scale, uint32_t addr, double value) {
if constexpr (W == 0u) {
switch (type) {
case 0: PpcStorePairPsqFloatFastInline(addr, value); return;
case 4: PpcStorePairPsqQuantizedFastInline<uint8_t>(addr, value, scale); return;
case 5: PpcStorePairPsqQuantizedFastInline<uint16_t>(addr, value, scale); return;
case 6: PpcStorePairPsqQuantizedFastInline<int8_t>(addr, value, scale); return;
case 7: PpcStorePairPsqQuantizedFastInline<int16_t>(addr, value, scale); return;
}
} else {
switch (type) {
case 0: PpcStoreSinglePsqFloatFastInline(addr, value); return;
case 4: PpcStoreSinglePsqQuantizedFastInline<uint8_t>(addr, value, scale); return;
case 5: PpcStoreSinglePsqQuantizedFastInline<uint16_t>(addr, value, scale); return;
case 6: PpcStoreSinglePsqQuantizedFastInline<int8_t>(addr, value, scale); return;
case 7: PpcStoreSinglePsqQuantizedFastInline<int16_t>(addr, value, scale); return;
}
}
std::abort();
}
template <uint32_t W, uint32_t I> static void Check() {
constexpr uint32_t edges[] = {
0, 0x80000000u, 1, 0x80000001u, 0x007FFFFFu, 0x00800000u,
0x3F000000u, 0xBF000000u, 0x3F800000u, 0xBF800000u,
0x437F0000u, 0x477FFF00u, 0xC7000000u, 0x7F7FFFFFu,
0x7F800000u, 0xFF800000u, 0x7F800001u, 0x7FC01234u, 0xFFC01234u
};
for (uint32_t type : {0u, 4u, 5u, 6u, 7u}) for (uint32_t scale = 0; scale < 64; ++scale)
for (unsigned n = 0; n < std::size(edges); ++n) {
// Include ignored GQR bits and a different type/scale in the unused half.
const uint32_t half = (scale << 8) | type | 0xC0F8u;
const uint32_t loadGqr = (half << 16) | 0x2105u;
const uint32_t storeGqr = half | 0x21050000u;
const uint64_t raw = (uint64_t(edges[n]) << 32) | edges[(n + 7) % std::size(edges)];
const double value = PpcBitCastToDoubleInline(raw);
for (unsigned mode = 0; mode < 5; ++mode) {
const uint32_t addr = mode == 0 ? 32u : mode == 1 ? 0xCC008000u : mode == 2 ? 0u : 0xFFFFFF00u;
constexpr uint32_t offset = 17;
PsqTestMemory::directStack = mode == 4;
PsqTestMemory::bytes.fill(0xCD);
BigEndian::Write64(PsqTestMemory::Pointer(addr), raw);
const auto expected = PpcBitCastToU64Inline(ReferenceLoad<W>(type, scale, addr));
PsqTestMemory::accesses = 0;
double loaded;
if (mode == 0) loaded = PPC_PsqLResolvedStateInline<W, I>(loadGqr, PsqTestMemory::Pointer(addr) - offset, offset, addr);
else if (mode == 1) loaded = PPC_PsqLResolvedStateInline<W, I>(loadGqr, nullptr, offset, addr);
else if (mode == 2) loaded = PPC_PsqLStateInline<W, I, false>(loadGqr, addr);
else loaded = PPC_PsqLStateInline<W, I, true>(loadGqr, addr);
Require(PpcBitCastToU64Inline(loaded) == expected, "load bits / lane order");
Hash(expected);
const size_t width = (type == 0 ? 4u : (type == 4 || type == 6) ? 1u : 2u) * (2u - W);
Require(PsqTestMemory::accesses == ((mode == 0 || mode == 4) ? 0u : 1u), "load route");
if (PsqTestMemory::accesses) Require(PsqTestMemory::address == addr && PsqTestMemory::width == width, "load slow address / width");
PsqTestMemory::bytes.fill(0xCD);
ReferenceStore<W>(type, scale, addr, value);
const auto expectedBytes = PsqTestMemory::bytes;
PsqTestMemory::bytes.fill(0xCD);
PsqTestMemory::accesses = 0;
if (mode == 0) PPC_PsqStResolvedStateInline<W, I>(storeGqr, PsqTestMemory::Pointer(addr) - offset, offset, addr, value);
else if (mode == 1) PPC_PsqStResolvedStateInline<W, I>(storeGqr, nullptr, offset, addr, value);
else if (mode == 2) PPC_PsqStStateInline<W, I, false>(storeGqr, addr, value);
else PPC_PsqStStateInline<W, I, true>(storeGqr, addr, value);
Require(PsqTestMemory::bytes == expectedBytes, "store bits / untouched lanes");
Hash(PsqTestMemory::ReadHost<uint64_t>(PsqTestMemory::Pointer(addr)));
Require(PsqTestMemory::accesses == ((mode == 0 || mode == 4) ? 0u : 1u), "store route");
if (PsqTestMemory::accesses) Require(PsqTestMemory::address == addr && PsqTestMemory::width == width, "store slow address / width");
}
}
}
int main(int argc, char** argv) {
try {
if (argc > 1) {
std::signal(SIGABRT, [](int) { std::_Exit(86); });
const uint32_t type = static_cast<uint32_t>(std::stoul(argv[2]));
const bool single = std::string(argv[3]) == "1";
uint8_t* host = std::string(argv[4]) == "resolved" ? PsqTestMemory::bytes.data() : nullptr;
if (std::string(argv[1]) == "load") {
if (single) PPC_PsqLResolvedStateInline<1, 7>(type << 16, host, 0, 0);
else PPC_PsqLResolvedStateInline<0, 7>(type << 16, host, 0, 0);
} else {
if (single) PPC_PsqStResolvedStateInline<1, 7>(type, host, 0, 0, 0);
else PPC_PsqStResolvedStateInline<0, 7>(type, host, 0, 0, 0);
}
return 0;
}
const auto saved = MkwGetHostFpControl();
CpuContext ctx{};
for (uint32_t ni : {0u, 4u}) for (uint32_t rounding = 0; rounding < 4; ++rounding) {
ctx.fpscr = ni;
CpuContextScope scope(&ctx);
#if defined(__x86_64__)
MkwSetHostFpControl((MkwGetHostFpControl() & ~(3u << 13)) | (rounding << 13));
#endif
Check<0, 0>(); Check<1, 0>(); Check<0, 7>(); Check<1, 7>();
}
MkwRestoreHostMxcsr(saved);
std::cout << "passed " << checks << " checks, checksum " << std::hex << checksum << '\n';
} catch (const std::exception& error) {
std::cerr << error.what() << '\n';
return 1;
}
}
-83
View File
@@ -1,83 +0,0 @@
#pragma once
// Instrumented ISA memory seam: no guest VM reservation or GPU is needed.
#include "big_endian.h"
#include <array>
#include <cstdint>
#include <cstring>
namespace PsqTestMemory {
inline std::array<uint8_t, 512> bytes{};
inline uint32_t address = 0;
inline size_t width = 0;
inline unsigned accesses = 0;
inline bool directStack = false;
inline uint8_t* Pointer(uint32_t addr) { return bytes.data() + (addr & 255u); }
inline void Record(uint32_t addr, size_t size) { address = addr; width = size; ++accesses; }
template <typename T> T ReadHost(const uint8_t* host) {
if constexpr (sizeof(T) == 1) return *host;
else if constexpr (sizeof(T) == 2) return BigEndian::Read16(host);
else if constexpr (sizeof(T) == 4) return BigEndian::Read32(host);
else return (uint64_t(BigEndian::Read32(host)) << 32) | BigEndian::Read32(host + 4);
}
template <typename T> void WriteHost(uint8_t* host, T value) {
if constexpr (sizeof(T) == 1) *host = value;
else if constexpr (sizeof(T) == 2) BigEndian::Write16(host, value);
else if constexpr (sizeof(T) == 4) BigEndian::Write32(host, value);
else BigEndian::Write64(host, value);
}
template <typename T> T Read(uint32_t addr) {
Record(addr, sizeof(T)); return ReadHost<T>(Pointer(addr));
}
template <typename T> void Write(uint32_t addr, T value) {
Record(addr, sizeof(T)); WriteHost(Pointer(addr), value);
}
}
namespace GuestFlat {
inline bool RequiresCheckedAccess() noexcept { return true; }
}
#define MKW_FLAT_GUEST_BASE (PsqTestMemory::bytes.data())
class Memory {
public:
static uint8_t Read8(uint32_t a) { return PsqTestMemory::Read<uint8_t>(a); }
static uint16_t Read16(uint32_t a) { return PsqTestMemory::Read<uint16_t>(a); }
static uint32_t Read32(uint32_t a) { return PsqTestMemory::Read<uint32_t>(a); }
static uint64_t Read64(uint32_t a) { return PsqTestMemory::Read<uint64_t>(a); }
static void Write8(uint32_t a, uint8_t v) { PsqTestMemory::Write(a, v); }
static void Write16(uint32_t a, uint16_t v) { PsqTestMemory::Write(a, v); }
static void Write32(uint32_t a, uint32_t v) { PsqTestMemory::Write(a, v); }
static void Write64(uint32_t a, uint64_t v) { PsqTestMemory::Write(a, v); }
};
namespace MemoryInline {
inline bool FlatWriteNeedsPolicy(uint32_t) { return true; }
inline bool TryGetPointerFast(uint32_t a, size_t, uint8_t*& host) {
host = PsqTestMemory::directStack ? PsqTestMemory::Pointer(a) : nullptr;
return host != nullptr;
}
inline bool TryGetWritablePointerFast(uint32_t a, size_t n, uint8_t*& host) {
return TryGetPointerFast(a, n, host);
}
template <typename T> T ReadResolvedFallback(uint32_t a) { return PsqTestMemory::Read<T>(a); }
template <typename T> void WriteResolvedFallback(uint32_t a, T v) { PsqTestMemory::Write(a, v); }
template <typename T> T ReadResolved(uint8_t* host, uint32_t o, uint32_t a) {
return host ? PsqTestMemory::ReadHost<T>(host + o) : ReadResolvedFallback<T>(a);
}
template <typename T> void WriteResolved(uint8_t* host, uint32_t o, uint32_t a, T v) {
if (host) PsqTestMemory::WriteHost(host + o, v); else WriteResolvedFallback(a, v);
}
#define PSQ_TEST_MEMORY_WIDTH(Bits, Type) \
inline Type ReadStack##Bits(uint32_t a) { \
return PsqTestMemory::directStack ? PsqTestMemory::ReadHost<Type>(PsqTestMemory::Pointer(a)) : PsqTestMemory::Read<Type>(a); } \
inline void WriteStack##Bits(uint32_t a, Type v) { \
if (PsqTestMemory::directStack) PsqTestMemory::WriteHost(PsqTestMemory::Pointer(a), v); else PsqTestMemory::Write(a, v); } \
inline Type ReadResolved##Bits(uint8_t* h, uint32_t o, uint32_t a) { return ReadResolved<Type>(h, o, a); } \
inline void WriteResolved##Bits(uint8_t* h, uint32_t o, uint32_t a, Type v) { WriteResolved(h, o, a, v); }
PSQ_TEST_MEMORY_WIDTH(8, uint8_t)
PSQ_TEST_MEMORY_WIDTH(16, uint16_t)
PSQ_TEST_MEMORY_WIDTH(32, uint32_t)
PSQ_TEST_MEMORY_WIDTH(64, uint64_t)
#undef PSQ_TEST_MEMORY_WIDTH
}
-13
View File
@@ -1,13 +0,0 @@
foreach(operation load store)
foreach(type 1 2 3)
foreach(lanes 0 1)
foreach(route resolved null)
execute_process(COMMAND "${PSQ_TEST_EXECUTABLE}" ${operation} ${type} ${lanes} ${route}
RESULT_VARIABLE result OUTPUT_VARIABLE output ERROR_VARIABLE error)
if(NOT result EQUAL 86)
message(FATAL_ERROR "Reserved PSQ ${operation}/${type}/${lanes}/${route}: ${result} ${output} ${error}")
endif()
endforeach()
endforeach()
endforeach()
endforeach()
+2 -2
View File
@@ -18,7 +18,7 @@ entry point, decodes every reachable function, and emits C++ (plus JSON metadata
what was emitted).
2. **`generate-data-init --project <manifest>`** - writes the embedded `.data`/`.rodata`/`.sdata`
section initializer and `RuntimeConfig.h`.
section initializer and `RuntimeConfig.h`.
3. **`emit-build-shards --project <manifest>`** - emits the CMake build graph (`shards.cmake`)
covering both generated sources and `runtime/src`.
@@ -36,7 +36,7 @@ See `projects/examples/generic-dol.yml` for a minimal manifest driven by `RECOMP
| Tool | Notes |
| --- | --- |
| .NET 8 SDK | Builds and runs the translator. |
| CMake ≥ 3.25 and Ninja | Configures and drives the native build. |
| CMake ≥ 3.16 and Ninja | Configures and drives the native build. |
| Clang / LLVM | The shipped build uses LLVM-MinGW targeting `x86-64-v3`. MSVC is not the tested path. |
Build the CLI once and invoke the assembly directly:
@@ -15,7 +15,6 @@ internal static class TranslatorCppTestHarness
Path.Combine("runtime", "src", "fpu_helpers.cpp"),
Path.Combine("runtime", "src", "memory.cpp"),
Path.Combine("runtime", "src", "ppc_helpers.cpp"),
Path.Combine("runtime", "src", "ppc_quantized.cpp"),
};
public static string BuildCompileArguments(
@@ -32,7 +31,6 @@ internal static class TranslatorCppTestHarness
args.Append("-std=c++17 ");
args.Append("-D_CRT_SECURE_NO_WARNINGS ");
args.Append("-march=x86-64-v3 ");
args.Append("-fno-fast-math -ffp-contract=off ");
if (!RuntimeHeadersDefineRestrictMacro(repoRoot))
{
// Fallback for the window between an emitter change using MKW_RESTRICT and the runtime