diff --git a/.github/workflows/auto-release.yml b/.github/workflows/auto-release.yml index 2a551cf2..7a374bc1 100644 --- a/.github/workflows/auto-release.yml +++ b/.github/workflows/auto-release.yml @@ -1,9 +1,8 @@ +# Publish a zip on push/merge to main (release) or dev (prerelease). +# Does not run on pull_request — open PRs must not create a Release or tag. +# Dump bins (nk.bin, etc.bin, UverseDriveE) are never attached. name: Auto Release -# Restores the old ci.yml "Build & Auto Release" path (last working -# cut was v1.0.7). PRs do not publish a release. Merging a PR is a -# push to main (release) or dev (prerelease), and that is what cuts -# the GitHub Release. Leave the empty/no-jobs ci.yml alone. on: push: branches: [main, dev] @@ -13,8 +12,8 @@ permissions: contents: write jobs: - build-and-release: - name: Build and release + release: + name: Build and publish zip runs-on: windows-latest steps: - name: Checkout @@ -25,68 +24,77 @@ jobs: - name: Setup .NET uses: actions/setup-dotnet@v4 with: - dotnet-version: 8.0.x + dotnet-version: '8.0.x' - name: Restore run: dotnet restore ProcessorEmulator.csproj - name: Build - run: dotnet build ProcessorEmulator.csproj --configuration Release --no-restore + run: dotnet build ProcessorEmulator.csproj -c Release --no-restore - - name: Tag next version - id: tag + - name: Publish + run: dotnet publish ProcessorEmulator.csproj -c Release -f net8.0-windows -o publish + + - name: Next version + id: version shell: pwsh run: | - $latestTag = git describe --tags --abbrev=0 2>$null - if ($LASTEXITCODE -ne 0 -or [string]::IsNullOrWhiteSpace($latestTag)) { - if ("${{ github.ref }}" -eq "refs/heads/dev") { - $newTag = "v1.0.0-dev.$(Get-Date -Format 'yyyyMMddHHmm')" - } else { - $newTag = "v1.0.0" + git fetch --tags --force + $tags = git tag -l "v*" | Where-Object { $_ -match '^v\d+\.\d+\.\d+$' } + $latest = $null + $maxMajor = -1; $maxMinor = -1; $maxPatch = -1 + foreach ($t in $tags) { + $p = $t.TrimStart('v').Split('.') + $maj = [int]$p[0]; $min = [int]$p[1]; $pat = [int]$p[2] + if ($maj -gt $maxMajor -or ($maj -eq $maxMajor -and $min -gt $maxMinor) -or ($maj -eq $maxMajor -and $min -eq $maxMinor -and $pat -gt $maxPatch)) { + $maxMajor = $maj; $maxMinor = $min; $maxPatch = $pat + $latest = $t } + } + if (-not $latest) { + $next = "v1.0.0" } else { - $version = $latestTag -replace '^v', '' -replace '-.*$', '' - $parts = $version.Split('.') - $major = [int]$parts[0] - $minor = [int]$parts[1] - $patch = [int]$parts[2] - if ("${{ github.ref }}" -eq "refs/heads/dev") { - $newTag = "v$major.$minor.$($patch + 1)-dev.$(Get-Date -Format 'yyyyMMddHHmm')" - } else { - $newTag = "v$major.$minor.$($patch + 1)" - } + $next = "v$maxMajor.$maxMinor.$($maxPatch + 1)" } - git config user.name "github-actions[bot]" - git config user.email "github-actions[bot]@users.noreply.github.com" - git tag $newTag - git push origin $newTag - "NEW_TAG=$newTag" | Out-File -FilePath $env:GITHUB_ENV -Append - "new_tag=$newTag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append - Write-Host "Tagged $newTag" + $isDev = '${{ github.ref }}' -eq 'refs/heads/dev' + if ($isDev) { + $stamp = Get-Date -Format "yyyyMMddHHmmss" + $tag = "$next-dev.$stamp" + $prerelease = "true" + } else { + $tag = $next + $prerelease = "false" + } + "tag=$tag" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + "prerelease=$prerelease" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + Write-Host "Latest release tag: $latest" + Write-Host "Publishing: $tag (prerelease=$prerelease)" - - name: Package + - name: Zip Windows build shell: pwsh run: | - $out = "bin\Release\net8.0-windows" - if (-not (Test-Path $out)) { - Write-Host "Build output missing at $out" - Get-ChildItem bin -Recurse -ErrorAction SilentlyContinue | ForEach-Object { Write-Host $_.FullName } - exit 1 - } - New-Item -ItemType Directory -Path release-package -Force | Out-Null - Copy-Item -Path "$out\*" -Destination release-package\ -Recurse -Force - if (Test-Path README.md) { Copy-Item README.md release-package\ } - Compress-Archive -Path "release-package\*" -DestinationPath "ProcessorEmulator-$env:NEW_TAG.zip" -Force + $src = "publish" + $stage = "release-stage" + if (Test-Path $stage) { Remove-Item $stage -Recurse -Force } + New-Item -ItemType Directory -Path $stage | Out-Null + Copy-Item "$src\*" $stage -Recurse -Force + $dumpNames = @('nk.bin','etc.bin','sec.bin','raven_fw.bin','UverseDriveE') + Get-ChildItem $stage -Recurse -Force | Where-Object { + $dumpNames -contains $_.Name + } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + $zip = "ProcessorEmulator-${{ steps.version.outputs.tag }}.zip" + Compress-Archive -Path "$stage\*" -DestinationPath $zip -Force + "zip=$zip" | Out-File -FilePath $env:GITHUB_OUTPUT -Append + id: pack - - name: Create GitHub Release + - name: Publish GitHub Release uses: softprops/action-gh-release@v2 with: - files: ProcessorEmulator-*.zip + tag_name: ${{ steps.version.outputs.tag }} + name: ${{ steps.version.outputs.tag }} generate_release_notes: true - prerelease: ${{ github.ref == 'refs/heads/dev' }} - tag_name: ${{ env.NEW_TAG }} - name: Processor Emulator ${{ env.NEW_TAG }} - body: | - Automated release from `${{ github.ref_name }}` (`${{ github.sha }}`). + prerelease: ${{ steps.version.outputs.prerelease == 'true' }} + files: ${{ steps.pack.outputs.zip }} + fail_on_unmatched_files: true env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 31b1e599..1bd7a39f 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -1,31 +1,48 @@ +# One Windows job on open PRs. Uploads a zip artifact. Does not create a Release or tag. +# Dump bins (nk.bin, etc.bin, UverseDriveE) are never attached. name: CI on: - push: - # Only run CI on version tag pushes - tags: ['v*'] pull_request: - # Run CI on PRs targeting dev - branches: [dev] - + branches: [main, dev] + +permissions: + contents: read + jobs: - build: - name: Build on Windows + windows: + name: Windows build runs-on: windows-latest steps: - - name: Checkout repository + - name: Checkout uses: actions/checkout@v4 - - name: Setup .NET SDK - uses: actions/setup-dotnet@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v4 with: dotnet-version: '8.0.x' - - name: Restore dependencies - run: dotnet restore Processor-Emulator.sln + - name: Restore + run: dotnet restore ProcessorEmulator.csproj + + - name: Build + run: dotnet build ProcessorEmulator.csproj -c Release --no-restore - - name: Build solution - run: dotnet build Processor-Emulator.sln --configuration Release --no-restore + - name: Publish + run: dotnet publish ProcessorEmulator.csproj -c Release -f net8.0-windows -o publish - - name: Run tests (if any) - run: echo "Skipping tests: no test projects defined." \ No newline at end of file + - name: Zip (no dump bins) + shell: pwsh + run: | + $dumpNames = @('nk.bin','etc.bin','sec.bin','raven_fw.bin','UverseDriveE') + Get-ChildItem publish -Recurse -Force -ErrorAction SilentlyContinue | Where-Object { + $dumpNames -contains $_.Name + } | Remove-Item -Recurse -Force -ErrorAction SilentlyContinue + Compress-Archive -Path publish\* -DestinationPath ProcessorEmulator-pr.zip -Force + + - name: Upload zip artifact + uses: actions/upload-artifact@v4 + with: + name: ProcessorEmulator-windows + path: ProcessorEmulator-pr.zip + if-no-files-found: error diff --git a/.github/workflows/release-drafter.yml b/.github/workflows/release-drafter.yml index 16666744..d1b70577 100644 --- a/.github/workflows/release-drafter.yml +++ b/.github/workflows/release-drafter.yml @@ -6,15 +6,12 @@ on: pull_request: types: [opened, reopened, synchronize, closed] branches: [main, dev] + workflow_dispatch: permissions: contents: write pull-requests: write -permissions: - contents: read - pull-requests: write - jobs: update_release_draft: runs-on: ubuntu-latest diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index bfcaabd4..efca0b47 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -16,17 +16,17 @@ jobs: steps: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup .NET 6 SDK - uses: actions/setup-dotnet@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v4 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Build Dev (Debug) run: | - dotnet restore + dotnet restore ProcessorEmulator.csproj dotnet build ProcessorEmulator.csproj --configuration Debug dotnet publish ProcessorEmulator.csproj --configuration Debug --output dev-artifacts - name: Upload Dev Artifact - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 with: name: dev-build-${{ github.run_number }} path: dev-artifacts @@ -41,13 +41,13 @@ jobs: - name: Checkout repository uses: actions/checkout@v4 - - name: Setup .NET 6 SDK - uses: actions/setup-dotnet@v3 + - name: Setup .NET + uses: actions/setup-dotnet@v4 with: - dotnet-version: '6.0.x' + dotnet-version: '8.0.x' - name: Cache NuGet packages - uses: actions/cache@v3 + uses: actions/cache@v4 with: path: ~/.nuget/packages key: ${{ runner.os }}-nuget-${{ hashFiles('**/*.csproj') }} @@ -56,7 +56,7 @@ jobs: - name: Build solution run: | - dotnet restore + dotnet restore ProcessorEmulator.csproj dotnet build ProcessorEmulator.csproj --configuration Release - name: Publish artifacts diff --git a/App.cs b/App.cs index 195438f7..4cee1920 100644 --- a/App.cs +++ b/App.cs @@ -34,7 +34,7 @@ protected override void OnStartup(StartupEventArgs e) var host = new MediaroomHostForm(); if (!string.IsNullOrEmpty(feed)) - host.DumpPath = feed; + host.DiskFolder = feed; System.Windows.Forms.Application.Run(host); Shutdown(); } diff --git a/CP0.cs b/CP0.cs index 8d7a2a0e..e36dd48c 100644 --- a/CP0.cs +++ b/CP0.cs @@ -248,6 +248,27 @@ public TlbTranslateStatus TryTranslate(uint vaddr, out uint paddr) return TlbTranslateStatus.Miss; } + // Live 674d704: page 0xFFFFF000 TLBL. Scan VPN + // even if ASID mismatches. Do not invent a PFN. + public bool TryFindTlbPfn(uint vaddr, out uint pfn, out bool valid) + { + pfn = 0; + valid = false; + uint vpn2 = (vaddr >> 13) & 0x7FFFF; + bool odd = (vaddr & 0x1000) != 0; + for (int i = 0; i < TLB_ENTRIES; i++) + { + uint tlbVpn2 = (_tlb[i].EntryHi >> 13) & 0x7FFFF; + if (tlbVpn2 != vpn2) + continue; + uint lo = odd ? _tlb[i].EntryLo1 : _tlb[i].EntryLo0; + pfn = (lo >> 6) & 0xFFFFF; + valid = (lo & 2) != 0; + return true; + } + return false; + } + public void PrepareTlbException(uint vaddr) { BadVAddr = vaddr; diff --git a/Core/BootLog.cs b/Core/BootLog.cs new file mode 100644 index 00000000..6e131e3e --- /dev/null +++ b/Core/BootLog.cs @@ -0,0 +1,381 @@ +using System; +using System.Diagnostics; +using System.IO; +using System.Text; + +namespace ProcessorEmulator.Core +{ + // Text log of ExtraROM FILE/TOC attach and OpenFile/LoadLibrary + // names. WinExe has no console, so NkBinLoader WriteLine is + // otherwise lost. Written next to ProcessorEmulator.exe, or + // %TEMP%\ProcessorEmulator-extrarom\boot.log if that folder is + // not writable. Never the dump folder. Flush each line so a + // live Boot can be tailed. Do not invent FILE[26] bytes, + // 0x81360000, or xdrm.dll. + public static class BootLog + { + public const string FileName = "boot.log"; + public const string TempFolderName = "ProcessorEmulator-extrarom"; + + private static readonly object Gate = new object(); + private static StreamWriter _writer; + private static string _path = ""; + private static string _dumpFolder = ""; + private static string _lastLine = ""; + private static Action _listener; + private static StringBuilder _uart; + + public static string FilePath + { + get { lock (Gate) return _path; } + } + + public static string LastLine + { + get { lock (Gate) return _lastLine; } + } + + public static Action Listener + { + get { lock (Gate) return _listener; } + set { lock (Gate) _listener = value; } + } + + public static string ResolvePath(string exeDir, string dumpFolder) + { + if (CanWriteBesideExe(exeDir, dumpFolder)) + return Path.Combine(exeDir, FileName); + string temp = Path.Combine(Path.GetTempPath(), TempFolderName); + Directory.CreateDirectory(temp); + return Path.Combine(temp, FileName); + } + + public static void Open(string dumpFolder) + { + lock (Gate) + { + CloseUnlocked(); + if (_uart != null) + _uart.Length = 0; + _dumpFolder = dumpFolder ?? ""; + string exeDir = ExeDirectory(); + _path = ResolvePath(exeDir, _dumpFolder); + string dir = Path.GetDirectoryName(_path); + if (!string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + var fs = new FileStream(_path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); + _writer = new StreamWriter(fs, new UTF8Encoding(false)) { AutoFlush = true }; + _writer.WriteLine("boot log " + DateTime.UtcNow.ToString("o")); + _writer.WriteLine("file=" + _path); + if (!string.IsNullOrEmpty(_dumpFolder)) + _writer.WriteLine("dump=" + _dumpFolder + " (not written)"); + _writer.Flush(); + } + } + + // Hive essays filled boot.log to 579KB in ~70s (484 LoadE32 + // lines, 1-2KB each). One short line per event. Cap so + // Launch56 stays under 400KB. leftover-wait99-o32-nk / + // ffff-e000 lines need dis=/prev=/next=/ra=; 180 cut + // those on live 9f90c5f. + public const int HiveLineMax = 180; + public const int HiveLineMaxNk = 320; + + public static void Write(string line) + { + if (line == null) + return; + int max = HiveLineMax; + if (line.IndexOf("leftover-wait99-o32-nk", StringComparison.Ordinal) >= 0 + || line.IndexOf("ffff-e000", StringComparison.Ordinal) >= 0) + max = HiveLineMaxNk; + if (line.Length > max + && (line.StartsWith("[Hive]", StringComparison.Ordinal) + || line.StartsWith("[Rom]", StringComparison.Ordinal))) + line = line.Substring(0, max - 3) + "..."; + Action listener; + lock (Gate) + { + if (_writer == null) + OpenUnlocked(_dumpFolder); + _lastLine = line; + if (_writer != null) + { + _writer.WriteLine(line); + _writer.Flush(); + } + listener = _listener; + } + try { Console.WriteLine(line); } + catch { } + if (listener != null) + { + try { listener(line); } + catch { } + } + } + + // WinExe hides Console.Write of MipsUart UART_DR. Buffer + // printable TX into lines, flush each line (and leftover + // on Stop). Do not invent a second UART or a NIC. + public static void UartTx(byte value) + { + char c = (char)(value & 0xFF); + try { Console.Write(c); } + catch { } + try { Debug.Write(c); } + catch { } + if (c == '\0') + return; + string line = null; + string hex = null; + lock (Gate) + { + if (_writer == null) + OpenUnlocked(_dumpFolder); + if (_uart == null) + _uart = new StringBuilder(); + if (c == '\n' || c == '\r') + { + if (_uart.Length > 0) + { + line = _uart.ToString(); + _uart.Length = 0; + } + } + else if (c >= 32 && c < 127) + { + _uart.Append(c); + if (_uart.Length >= 240) + { + line = _uart.ToString(); + _uart.Length = 0; + } + } + else if (c == '\t') + { + _uart.Append('\t'); + } + else + { + if (_uart.Length > 0) + { + line = _uart.ToString(); + _uart.Length = 0; + } + hex = "0x" + ((int)c).ToString("X2"); + } + } + if (line != null) + Write("[Uart] " + line); + if (hex != null) + Write("[Uart] byte=" + hex); + } + + public static void UartFlush() + { + string line = null; + lock (Gate) + { + if (_uart != null && _uart.Length > 0) + { + line = _uart.ToString(); + _uart.Length = 0; + } + } + if (line != null) + Write("[Uart] " + line); + } + + public static bool IsGuestIoName(string name) + { + if (string.IsNullOrEmpty(name)) + return false; + return ContainsFold(name, "rtl8139") + || ContainsFold(name, "bcm7038mac") + || ContainsFold(name, "ndis") + || ContainsFold(name, "bcmuart") + || ContainsFold(name, "com16550") + || ContainsFold(name, "serial.dll") + || EndsWithFold(name, "serial"); + } + + // LoadE32 / CEDecompressROM outer return only. WinExe hides + // Hive Console.WriteLine. Do not log every inner LZX page. + public static void LoadE32(string name, int index, uint v0, string why) + { + var sb = new StringBuilder(); + sb.Append("[Hive] LoadE32"); + if (index >= 0) + sb.Append(" ExtraROM TOC[").Append(index).Append(']'); + if (!string.IsNullOrEmpty(name)) + sb.Append(' ').Append(name); + sb.Append(" ret v0=0x").Append(v0.ToString("X8")); + if (!string.IsNullOrEmpty(why)) + sb.Append(" (").Append(why).Append(')'); + Write(sb.ToString()); + } + + public static void DecompressRom(string name, uint dest, uint v0, string why) + { + var sb = new StringBuilder(); + sb.Append("[Hive] ExtraROM CEDecompressROM"); + if (!string.IsNullOrEmpty(name)) + sb.Append(' ').Append(name); + sb.Append(" ret v0=0x").Append(v0.ToString("X8")); + if (dest != 0) + sb.Append(" dest=0x").Append(dest.ToString("X8")); + if (!string.IsNullOrEmpty(why)) + sb.Append(" (").Append(why).Append(')'); + Write(sb.ToString()); + } + + public static void Rom(string? result, string? source, string? kind, int index, + string? name, int type, uint dest, uint real, uint comp, string? why) + { + var sb = new StringBuilder(); + sb.Append("[Rom] ").Append(string.IsNullOrEmpty(result) ? "?" : result); + if (!string.IsNullOrEmpty(source)) + sb.Append(' ').Append(source); + if (!string.IsNullOrEmpty(kind)) + { + sb.Append(' ').Append(kind); + if (index >= 0) + sb.Append('[').Append(index).Append(']'); + } + if (!string.IsNullOrEmpty(name)) + sb.Append(' ').Append(name); + if (type == 7 || type == 8) + sb.Append(" type=").Append(type); + if (dest != 0) + sb.Append(" dest=0x").Append(dest.ToString("X8")); + if (real != 0 || comp != 0) + sb.Append(" real=").Append(real).Append(" comp=").Append(comp); + if (!string.IsNullOrEmpty(why)) + sb.Append(" (").Append(why).Append(')'); + Write(sb.ToString()); + } + + public static bool SameFolder(string a, string b) + { + if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b)) + return false; + try + { + string na = Path.GetFullPath(a).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + string nb = Path.GetFullPath(b).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + return string.Equals(na, nb, StringComparison.OrdinalIgnoreCase); + } + catch + { + return false; + } + } + + public static bool FolderIsDumpOrInside(string folder, string dumpFolder) + { + if (string.IsNullOrEmpty(folder) || string.IsNullOrEmpty(dumpFolder)) + return false; + try + { + string f = Path.GetFullPath(folder).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + string d = Path.GetFullPath(dumpFolder).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar); + if (string.Equals(f, d, StringComparison.OrdinalIgnoreCase)) + return true; + if (!d.EndsWith(Path.DirectorySeparatorChar.ToString(), StringComparison.Ordinal)) + d += Path.DirectorySeparatorChar; + return f.StartsWith(d, StringComparison.OrdinalIgnoreCase); + } + catch + { + return false; + } + } + + private static bool ContainsFold(string name, string token) + { + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(token)) + return false; + return name.IndexOf(token, StringComparison.OrdinalIgnoreCase) >= 0; + } + + private static bool EndsWithFold(string name, string token) + { + if (string.IsNullOrEmpty(name) || string.IsNullOrEmpty(token) || name.Length < token.Length) + return false; + return name.EndsWith(token, StringComparison.OrdinalIgnoreCase); + } + + private static void OpenUnlocked(string dumpFolder) + { + _dumpFolder = dumpFolder ?? ""; + string exeDir = ExeDirectory(); + _path = ResolvePath(exeDir, _dumpFolder); + string dir = Path.GetDirectoryName(_path); + if (!string.IsNullOrEmpty(dir)) + Directory.CreateDirectory(dir); + var fs = new FileStream(_path, FileMode.Create, FileAccess.Write, FileShare.ReadWrite); + _writer = new StreamWriter(fs, new UTF8Encoding(false)) { AutoFlush = true }; + } + + private static void CloseUnlocked() + { + if (_writer != null) + { + try { _writer.Flush(); } + catch { } + try { _writer.Dispose(); } + catch { } + _writer = null; + } + } + + private static bool CanWriteBesideExe(string exeDir, string dumpFolder) + { + if (string.IsNullOrEmpty(exeDir)) + return false; + try + { + if (!Directory.Exists(exeDir)) + return false; + if (FolderIsDumpOrInside(exeDir, dumpFolder)) + return false; + string probe = Path.Combine(exeDir, ".bootlog-write-probe"); + File.WriteAllText(probe, "ok"); + File.Delete(probe); + return true; + } + catch + { + return false; + } + } + + private static string ExeDirectory() + { + try + { + string file = System.Diagnostics.Process.GetCurrentProcess().MainModule?.FileName; + if (!string.IsNullOrEmpty(file)) + { + string dir = Path.GetDirectoryName(file); + if (!string.IsNullOrEmpty(dir)) + return dir; + } + } + catch + { + } + try + { + string bas = AppDomain.CurrentDomain.BaseDirectory; + if (!string.IsNullOrEmpty(bas)) + return Path.GetFullPath(bas); + } + catch + { + } + return ""; + } + } +} diff --git a/Core/CeRomTocFiles.cs b/Core/CeRomTocFiles.cs index 836cf71b..2a84894d 100644 --- a/Core/CeRomTocFiles.cs +++ b/Core/CeRomTocFiles.cs @@ -15,15 +15,2735 @@ namespace ProcessorEmulator.Core public static class CeRomTocFiles { public const uint CreateFileFail = 0x8001D400; + // 0x8001D3A0 jal 0x8003D700 then bne v0,-1 at + // 0x8001D3F8. 0x8001D400 only runs on INVALID_HANDLE. + // wait59: OpenExe \mscoree.dll entered CreateFile and + // never hit 0x8001D400, so filesys returned a handle. + // NK/ExtraROM FILE tables and the volume have no + // mscoree.dll. That type-8 handle is 193. Force + // INVALID_HANDLE here so type-7 attaches TOC[46]. + public const uint CreateFileWin32Chk = 0x8001D3F8; public const uint NameCopyContinue = 0x8001D464; + // CreateFile success epilogue. Type 7 must not take + // NameCopyContinue: that CreateFileMappings object+0. + // A TOCentry is not a handle. CreateFile then returned + // 14/1392, OpenExe failed, 0x8001DFC4 retried + // .dll.dll, and 0x8001E3AC was 126. Same object as + // TocWalk (entry + type 7); v0=0 so LoadE32 runs. + public const uint CreateFileOk = 0x8001D568; + // 0x80016AFC walks *(0x80342B10) ROMHDR nodes + // (lw head; node+4 ROMHDR; TOC at hdr+0x54; name at + // entry+0x10; miss v0=2). ExtraROM 0x8134DA84 is + // mapped but never linked, so LoadDriver/ActivateDevice + // never sees ExtraROM TOC names without host attach. + // Dump nk.exe DOES sw 0x80342B10. Earlier lui/lw + // scan missed the addiu form. Linker is 0x8001728C: + // a2=0x803429C8 source chain ptr + // a1=0x80342B10 published ROMHDR list head + // s6=0x8001101C dump word is NK romhdr 0x802808B4 + // (pExtensions 0x80011020 is still 32 zeros next + // to this; not a linker) + // walk *0x803429C8: if node+4 == *0x8001101C, + // 0x80017308 sw a3,(a1) publishes that source chain + // as head; else if walk misses and a3!=0: 0x8001731C + // lw old head; sw old,(a0 last node); sw *0x803429C8, + // (a1) splices source chain in front. + // Linker 0x8001728C has ONE caller: 0x80014420 + // (early kernel, before mtc0 Status at 0x8001442C). + // One-shot. ExtraROM bytes can already be mapped + // (host NkBinLoader at Boot), but dump never + // publishes *0x803429C8: nk.exe .text only + // 0x800172B8 addiu/lw of 0x29c8, no sw; ExtraROM + // extracted PEs: zero lui 0x8034 + imm 0x29c8. + // If live *0x803429C8 is 0 at 0x80014420, firmware + // never links 0x8134DA84. Do not invent a + // ROMChain_t before that jal. Do not host-write + // 0x803429C8. ExtraROM ulCopyEntries=0, copy_table + // empty. NK copy[0] src=0x8021F8EC dst=0x80320000 + // copy_len=0x5A4 dest_len=0x22C88. 0x80342B10 is + // dst+0x22B10 (BSS tail past copy_len) until the + // linker sw. Host attach is a workaround because + // ExtraROM is unlinked. + // LoadO32 jal CreateFileMapping 0x8003DA64 at + // 0x800167AC is on the 0x200 TAKEN path (after + // 0x8001665C andi/beqz skip). ExtraROM dumpToc0 + // 0x807 never reaches it. ddi_nop dest is MapO32 + // 0x8001AEB4 CreateFileMapping miss then 0x8001AECC + // SetFilePointer (object+6>=2), not LoadO32 + // 0x800167AC. Do not set 0x200. Do not write + // object+6. Firmware sh s5,6(fp) at 0x8001D4F0 + // only when CreateFileMapping 0x8003DA64 returns 0. + // BuiltIn LoadLibrary never takes that jal. + public const uint TocWalkMiss = 0x80016B74; + public const uint TocWalkMissContinue = 0x80016B78; + public const uint LoadE32Rom = 0x800196E4; + public const uint LoadE32RomRet = 0x8001E3E8; + // LoadE32 0x800196E4: addiu sp,-0x1A0; lbu v0,4(a0); + // andi v1,v0,2. Bit 1 of object+4 is the ROM path + // (type 7 has it; type 8 FILE does not). Then e32 + // copy and jal memcpy 0x80058B24 (e32_lite+0x1C <- + // e32_rom+0x24, a2=0x38). Dump nk.exe: 0x80055DB0 + // is CurMSec / OEM tick, not an o32 probe. Incoming + // a0/a1/a2 are leftover LoadE32 regs; jal a1 is + // overwritten. Do not treat CurMSec v0=0 as LoadE32 + // fail. Do not invent a +0x5C pointer. + public const uint LoadE32UnitCopy = 0x80058B24; + public const uint LoadE32Frame = 0x1A0; + public const uint LoadE32RomBit = 2; + public const uint LoadE32BodyLim = 0x8001A800; + // Dump nk.exe LoadE32: type-7 obj+4=7 takes the ROM + // path (andi 2 / andi 4), memcpy e32_lite+0x1C, then + // 0x80019990 b 0x800199A4; move v0,0. That v0=0 is + // SUCCESS. Fail is v0=0x47E at 0x80019998 or v0=0xC1 + // ERROR_BAD_EXE_FORMAT at 0x800199A0. Epilogue + // 0x800199A4 jr ra. Do not treat ExtraROM v0=0 as + // miss. Do not force v0=1. + public const uint LoadE32Ok = 0x80019990; + public const uint LoadE32Fail47E = 0x80019998; + public const uint LoadE32FailBadExe = 0x800199A0; + public const uint LoadE32Epilogue = 0x800199A4; + public const uint LoadE32Err47E = 0x47E; + public const uint LoadE32BadExe = 0xC1; + public const uint E32RomPublicSize = 0x24; + public const uint E32RomPackedSize = 0x5C; + public const uint E32RomRetryOff = 0x44; + // Dump nk.exe ImageBase 0x80010000 PE R4000 LE: + // 0x8005730C jr ra; mfc0 v0,Count + // 0x80057314 jr ra; mfc0 v0,Compare + // 0x8005731C jr ra; mtc0 a0,Compare + // 0x8002C070 jr ra; move v0,a0 + // 0x80055DB0 CurMSec (jal ReadCount; 0x803392B0 / + // 0x80342C60 scale; sw tick at 0xFFFFD894). + // 0x800557F4 tick vs 0x80338F70; MMIO 0xB04007D4. + // 0x80059CE8 Count+Compare stall. + public const uint OemCurMSec = 0x80055DB0; + public const uint OemReadCount = 0x8005730C; + public const uint OemReadCompare = 0x80057314; + public const uint OemWriteCompare = 0x8005731C; + public const uint OemTickDelta = 0x800557F4; + public const uint OemCountStall = 0x80059CE8; + public const uint NkMoveV0A0 = 0x8002C070; + // Dump nk.exe wrapper at 0x8001E3E0: + // jal 0x800196E4 LoadE32 + // bnez v0, 0x8001E538 # LoadE32RomRet 0x8001E3E8 + // jal 0x800165DC # LoadO32 a0=obj a1=s7 a2=s4 a3=0 + // bnez v0, 0x8001E538 + // 0x8001637C is a 0x400 predicate, not heap alloc: + // **(obj) or obj+8; andi 0x400; 0 -> v0=1; busy -> v0=0. + // ExtraROM e32 live0 0x212E0003 & 0x400 = 0, so v0=1. + // Dump nk.exe LoadO32 0x800165DC (live 183c8f4 + // leftover-wait99-o32-nk-ret dest-word=2): + // s2=a0 obj; s4=a3 dest-addr out; s5=a2 byte out; + // s7=a1; sw 0,0x20(sp). obj+4 bit1 ROM path. + // fp=**(obj) or obj+8; jal pred 0x8001637C; + // 0x80016654 beqz v0,0x80016810. andi fp,0x200; + // beqz -> 0x80016830. ExtraROM LiveEntry0 is + // dump TOC dwFileAttributes (0x807), not e32 + // 0x212E0003. 0x80016830 lw v0,0x20(sp); + // beqz 0x80016848; beqz s4,0x80016848; + // sw v0,0(s4) dest-addr only if thunk filled + // 0x20(sp) AND a3!=0. 0x80016848 move v0,0 + // success; $ra still pred 0x80016654 until + // lw $ra,1100(sp) at 0x80016870. Wrapper + // 0x8001E40C addiu a3,0 so dest-addr out is + // 0; skip never stores dest. 0x8003E660 only + // when fp&0x200 (a0=-1 a1=sp+0x20 a2=s7). + // ExtraROM 0x807 / ddi_nop 0x807 / NK 0x1007 + // all skip. Do not set 0x200. + // Wrapper 0x8001E284 addiu s4,fp,0xCE; + // 0x8001E27C s0=2; 0x8001E2C8 sb s0,0(s4); + // 0x8001E2C4 sw 0,0xD0(fp). LoadO32 a2=s4 + // is that byte-out. dest-word=2 is unaligned + // peek of sb-2 at fp+0xCE, not dest-set. + // Wrapper after LoadO32 v0=0: + // 0x8001E428 andi v0,s5,2; beqz 0x8001E45C + // skip VALLOC. bit2 jal 0x800283FC is + // 0x8001E444 $ra=0x8001E44C a0=0x7E000000 + // a2=0x1102000 VirtualAlloc-like, not + // CEDecompressROM. Live fbfeebf wrap at + // 0x800283FC v0=0x80340040 s5=0 is shared + // VALLOC (39 jals); v0 leftover NK + // 0x80340040, not a return. Only $ra + // 0x8001E44C is wrapper VALLOC. + // s5 is lhu 112(sp) incoming flags. If + // LoadE32 dest 0x20(sp) is 0: ori flags 3 + // so bit2 takes VALLOC. LoadO32 a3=0 so + // dest-addr out never stores. VALLOC dest + // is sw v0,80(fp) then 0x8001E6E0 CopyO32 + // 0x8001AFA4. o32walk 0x8001E45C andi + // 0x8000 is the bit2-clear skip, not after + // VALLOC. leftover-wait99-o32-nk-wrap- + // after names s5/dest-e32/dest-fp50. + // Live 0be2cb9 dest-e32=0x1B0C is SIZE + // not dest-live hop. dest-fp50 + // 0x8006C000 is CopyO32 dest fill. + // leftover-wait99-o32-nk-wrap-copy-ret + // names post-CopyO32 BindImp / CallDLL + // / leftover-wrap-after-copy. + // leftover-wait99-o32-nk-e32 peeks + // dest-fp50 e32/image after CopyO32 + // fill (w0/objcnt/entryrva/vbase/ + // vsize/imp). Do not hop dest-e32 + // size. Do not hop dest-fp50 as PC. + // 0x8001E4A8 lw + // 0x24(sp); andi 0x2000; beqz + // 0x8001E534 v0=0xC1. Do not invent 0x2000. + // ddi_nop dest is MapO32 0x8001AEB4 + // CreateFileMapping miss then 0x8001AECC + // SetFilePointer (object+6>=2), not LoadO32 + // 0x800167AC. Do not write object+6. + // Honest miss: after BuiltIn LoadO32 skip, + // firmware never VirtualCopys ExtraROM o32. + // ddi_nop dest remains OpenFile/LoadDriver + // MapO32/CEDecompressROM object+6>=2 (c1c0bc4). + // Do not write object+6. Do not invent dest. + // Do not invent a map at 0x8178C000. + public const uint LoadE32WrapJal = 0x8001E3E0; + public const uint LoadO32ThunkLookup = 0x8003CA70; + public const uint LoadO32ThunkTail = 0x8003CE44; + public const uint LoadE32WrapFail = 0x8001E538; + public const uint LoadO32Rom = 0x800165DC; + public const uint LoadO32RomRet = 0x8001E420; + // Dump wrapper jal LoadO32; $ra becomes + // LoadO32RomRet. Live 0ab1b68 leftover- + // wait99-o32-ra-src dest=0x03F716F0 is + // leftover→wrap, not this jal. + public const uint LoadO32WrapJalO32 = 0x8001E418; + public const uint LoadO32WrapAfter = 0x8001E428; + public const uint LoadO32Pred = 0x8001637C; + public const uint LoadO32PredRet = 0x80016654; + public const uint LoadO32PredFail = 0x80016810; + public const uint LoadO32SkipStore = 0x8001662C; + public const uint LoadO32Andi200 = 0x8001665C; + // Dump wrapper 0x8001E284 addiu $s4,$fp,0xCE; + // 0x8001E2C8 sb 2,0($s4). LoadO32 a2 is that + // byte-out, not dest-addr (a3). dest-word=2 + // is this init byte. Do not treat as dest-set. + public const uint LoadO32DestCeOff = 0xCE; + public const uint LoadO32DestCeInit = 2; + public const uint LoadO32CreateFileMapping = 0x800167AC; + public const uint LoadO32SkipValloc = 0x80016830; + public const uint LoadO32OkRet = 0x80016848; + public const uint LoadO32WrapValloc = 0x800283FC; + public const uint LoadO32WrapVallocJal = 0x8001E444; + public const uint LoadO32WrapVallocRa = 0x8001E44C; + public const uint LoadO32WrapCopy = 0x8001E6E0; + public const uint LoadO32WrapCopyJal = 0x8001E750; + public const uint LoadO32WrapCopyRet = 0x8001E758; + // Wrapper 0x8001E960 skips startip store when + // 32($sp) entryrva is 0. Live fb2d4b3 + // leftover-wait99-o32-nk-iat name=hd.dll + // via=bindlib then leftover-wait99-o32- + // nk-iat-stub GetProc 0x8001F7BC + // v0=0x87000000 (incoming leftover) and + // 0x8001F7D0 v0=0x7FFA0 (lw MODULE+0x8C + // ExpRva). dest-fp50 leaked to coredll + // 0x03F50000; slots marched 0x800370E8 + // word=0x3C038034 lui $v1,0x8034; + // stub=-. Live 7bb467b named stub= + // HdstubDLLEntry but latched iat/entry + // to dest+0x1B0C and UNIQUE_SLOTS=0. + // dest-e32 0x1B0C is SIZE. Live nk-e32 + // w0=0x52 objcnt=0x52 is not e32_rom; + // do not name entryrva=0x1B0C. Dump + // export HdstubDLLEntry 0x8006DB0C + // ord=1 / HdstubInit 0x8006D9D0 ord=2 + // for stub= / plant only. Latch dest- + // fp50 to CopyO32 fill. leftover dest + // 0x03F74DEC / GetProc dest 0x8008C844 + // leftover hop forbidden. Do not hop + // dest-e32 0x1B0C or dest-fp50 as PC. + // Live 2b02f4e named nk-entry + // Target_VA=0x8006DB0C via= + // HdstubDLLEntry; e32_entryrva=0 + // objcnt=0 hdr-off=0; no guest jalr + // into dest. Feed MODULE+0x5C startip + // so CallDLL jalrs that VA. Live a273e3a + // nk-jalr pc=0x80018B34 / 0x80018BAC + // via=calldll startip=0x8006DB0C; cap 2 + // burned before guest PC at Target_VA. + // Observe PC-at-export / CallDLL ret / + // leftover-wait99-o32-nk-after. Live + // 4643c74 FIRST-WIN: jalr pc=0x8006DB0C + // word=0x27BDFFD0 via=HdstubDLLEntry; + // after v0=1 saw=y via=ret; next= + // osaxst0.dll. Live 37ce7dd FIRST-WIN + // naming: osaxst0 startip=0 bindlib/ + // loade32; CallDLL startip=0x80061CA0 + // name=-. Do not plant osaxst0/osaxst1/ + // kd/kcover. Name 0x80061CA0 from MODULE + // +8 / +0x50 (coredll ImageBase + // 0x03F50000). Observe jalr/after and + // filesys. Do not leftover-hop dest. + // FILE[26] unchanged. Display + // ddi_nop.dll. + public const uint LoadO32WrapStartip = 0x8001E960; + public const uint WrapCopyRetScanHi = 0x8001EA00; + // Live 0be2cb9 leftover-wait99-o32-nk- + // wrap-after dest-e32=0x1B0C dest-fp50=0 + // via=dest-e32 then leftover-wait99-o32- + // cont dest=0x1B0C. Do not hop PC to + // 0x1B0C. Live 7bb467b named + // entryrva=0x1B0C Target_VA=0x8006DB0C + // and iat=0x8006DB0C; that collapsed + // UNIQUE_SLOTS. dest-e32 0x1B0C is SIZE. + // Live nk-e32 hdr-off=0x1010 w0=0x52 + // objcnt=0x52 is not e32_rom. Do not + // name 0x1B0C as entryrva / Target_VA / + // IAT base. Dump export VA 0x8006DB0C + // is HdstubDLLEntry for stub= / plant + // only. leftover-wait99-o32-nk-wrap- + // copy dest-fp50=0x8006C000 a3=0x7 is + // CopyO32 dest fill (type-7) and dump + // hd.dll ImageBase. leftover-wrap- + // during-bind is leftover jal INTO wrap + // residue; refuse that hop during bind. + public const uint WrapDestE32SizeLive = 0x1B0C; + public const uint WrapDestFp50FillLive = 0x8006C000; + public const uint HdDllImageBase = 0x8006C000; + public const uint HdDllEntryRva = 0x1B0C; + public const uint HdDllEntryVa = 0x8006DB0C; + public const uint HdDllInitRva = 0x19D0; + public const uint HdDllInitVa = 0x8006D9D0; + public const uint HdDllExpRva = 0x2BC0; + public const uint HdDllGetProcInV0 = 0x87000000; + public const uint HdDllModExpRvaLive = 0x7FFA0; + public const uint NkGetProcStoreSlot = 0x800370E8; + public const uint NkGetProcStoreHi = 0x80037200; + public const uint NkLuiV1Word = 0x3C038034; + public const uint WrapDestSizeMax = 0x10000; + public const uint WrapCopySectCount = 7; + // Live 84dd0ca nk-e32 via=empty w0=0 at + // dest-fp50+0. Live 26cbe16 nk-e32 + // hdr-off=0x1010 fill-off=0x1010 w0= + // 0x52 objcnt=0x52 entryrva=0. Header + // is not at +0 and +0x1010 fill is not + // e32_rom (objcnt 0x52). First o32 is + // usually RVA 0x1000; dest-fp50 may be + // that section dest (vbase = dest-fp50- + // 0x1000) or image dest (fill at + // +0x1000). Scan those offs plus + // e32_lite / dump TOC e32 / BindImp + // IAT. Do not hop dest-fp50 or dest-e32 + // size as PC. + public const uint WrapO32RvaLive = 0x1000; + public const uint WrapE32ScanMax = 0x2000; + // WinCE e32_rom (pehdr.h / ExtraROM dump), not + // IMAGE_OPTIONAL_HEADER. e32_entryrva +4, + // e32_vbase +8, e32_vsize +0x14. e32_rva is + // e32_unit[0].rva: pehdr +0x20, ExtraROM + // packed units after public 0x24 (EXP +0x24). + // Do not read PE OptionalHeader+0x10 as entry. + public const uint E32RomEntryRvaOff = 4; + public const uint E32RomVbaseOff = 8; + public const uint E32RomVsizeOff = 0x14; + public const uint E32RomRvaOff = 0x20; + public const uint E32RomImpRvaOff = 0x28; + public const uint E32LiteImpRvaOff = 0x2C; + public const uint E32ImpNameOff = 0xC; + public const uint E32ImpIatOff = 0x10; + public const int E32ImpNameMax = 24; + public const uint E32MzMagic = 0x5A4D; + public const uint LoadO32WrapO32Walk = 0x8001AF20; + public const uint LoadO32WrapS5Hi = 0x8001E45C; + public const uint LoadO32WrapFlagsChk = 0x8001E4A8; + public const uint LoadO32WrapC1 = 0x8001E534; + // Dump wrapper dest after VALLOC is + // sw v0,80(fp). Incoming flags are + // lhu 112(sp) / sh fp+0xCC. ori 3 when + // LoadE32 dest 0x20(sp) is 0. + public const uint LoadO32WrapDestFpOff = 0x50; + public const uint LoadO32WrapFlagsFpOff = 0xCC; + public const uint LoadO32WrapFlagsSpOff = 0x70; + public const uint WrapS5Ori3 = 3; + // Dump nk.exe: 0x8001AC9C is bnez flags&0x80002000. + // jal 0x80028844 is at 0x8001ACC4. nleddrvr flags + // 0x60002020 skip 28844 then 0x8001AD50 jal + // 0x800283FC(o32.real, size, 0x40). 0x8001AE08 + // beqz v0 then 0x8001AD4C v0=0xE ERROR_OUTOFMEMORY. + // Wrapper 0x8001E758 passes 0xE to 0x8001E538. + // LoadO32 0x8001E420 v0=0. Do not treat 0xE as + // LoadO32 fail. Do not treat 0x8001AC9C as jal 28844. + public const uint MapO32FlagsBnez = 0x8001AC9C; + public const uint MapO32InnerJal = 0x8001ACC4; + public const uint MapO32VallocJal = 0x8001AD50; + public const uint E32ImageDllBit = 0x2000; + public const uint WrapS5Bit2 = 2; + public const uint WrapS5CallDll = 0x8000; + public const uint BcmuartImageBase = 0x02F20000; + public const uint BcmuartPsizeSum = 13471; + public const uint BcmuartRealSize = 31744; + // Extract etc/rom_meta + load_graph.json (not a live + // log). ExtraROM phys 0x80630000–0x8134EA18. + // TOC[63] bcmuart load_va 0x8178C000 PAST physlast. + // TOC[33] ddi_nop load_va 0x80C68000 in-ROM. Both + // cerom_attributes 0x807; dumpToc0&0x200=0. NK + // coredll/fsdmgr/ceddk 0x1007 also lacks 0x200. + public const uint ExtraRomPhysFirst = 0x80630000; + public const uint ExtraRomPhysLast = 0x8134EA18; + public const uint DumpTocAttr807 = 0x00000807; + public const uint NkTocAttr1007 = 0x00001007; + public const uint DumpTocAttr1807 = 0x00001807; + public const uint BcmuartLoadVa = 0x8178C000; + public const uint DdiNopLoadVa = 0x80C68000; + public const uint LoadO32VallocOpen = 0x8003E660; + public const uint LoadO32LockBit = 0x400; + public const uint LoadO32VallocBit = 0x200; + public const uint LoadE32RomBit2 = 4; + public const uint CopyO32Rom = 0x8001AFA4; + public const uint MapO32Rom = 0x8001AC30; + // 0x8001ACC4 jal 0x80028844 is MapO32 inner. + // 0x8001AC9C is flags bnez, not that jal. Dump + // nk.exe: 28844 is not on the LoadO32 skip path. + // ddi_nop dest remains OpenFile/LoadDriver. + // Do not invent dest. Do not write object+6. + public const uint MapO32RomEpilogue = 0x8001AE50; + public const uint MapO32CreateFileMapping = 0x8001AEB4; + public const uint MapO32SetFilePointer = 0x8001AECC; + public const uint MapO32Decompress = 0x80028844; + public const uint MapO32DecompressSrcChk = 0x80028A48; + public const uint MapO32DecompressFail = 0x80028A90; + public const uint MapO32DecompressCommitChk = 0x800289F8; + public const uint MapO32CommitDest = 0x80026F50; + public const uint MapO32VirtualCopy = 0x80043298; + public const uint MapO32VallocRet = 0x8001AE08; + // 0x80028844 remaps dest PTEs onto src (XIP alias). Its + // kseg0 src path (0x80028A60) sets 32($sp)=1 and never + // writes dest bytes, so startip stays VALLOC zeros. + // Kernel 0x80050974 is CEDecompress (CE3 inner + // 0x800504B4). ExtraROM pages are not that codec: + // after the 3-byte table each slice is + // window=16 / vsize / … (LZX). 0x800504B4 then + // returns -10/-12 on B5/B4. Official 4K wrapper + // 0x80043B8C jals CEDecompressROM 0x8004DBF8 + // (inner 0x80050F78). Same args: skip, convert, + // stepsize. Byte 3 stays the first page-offset + // low byte. Do not cap leftover at 0x1000. + public const uint BinaryDecompressRom = 0x8004DBF8; + public const uint BinaryDecompressInner = 0x80050F78; + public const uint BinaryDecompressAfterInner = 0x8004DD80; + public const uint MemReserve = 0x2000; + public const uint SlotMask = 0x01FFFFFF; + public const uint LoadLibSyscallRet = 0x03F6C8F4; public const uint BindImpMiss = 0x80018F9C; public const uint BindImpWalk = 0x80018F3C; + // 0x80018E94 lw ImpHdr+0; 0x80018EC0 lbu name at + // vbase+NameRVA. ExtraROM IMP is RVA 0x18350 + // (e32+0x2C). Name RVA 0 reads the unmapped + // header page at vbase (0x01980000). + public const uint BindImpHdr = 0x80018E94; + public const uint BindImpDllName = 0x80018EC0; + public const uint BindImpLoadLib = 0x8001E9D4; + public const uint BindImpLoadLibRet = 0x80018EF8; + // Live 404d06b BindImp-stall pc=0x8001F7D0. + // Same nk cluster as LoadExeE32Ret 0x8001F870. + // BindImp jal 0x8001F7BC (ordinal GetProc) from + // 0x80019090; ret 0x80019098. lw v1,80(a0) is + // MODULE+0x50 BasePtr. Observe only. Do not + // invent COREDLL BasePtr or export bytes. + public const uint BindImpOrdLookup = 0x8001F7BC; + public const uint BindImpOrdBaseLw = 0x8001F7D0; + public const uint BindImpOrdJalRet = 0x80019098; + // Live d79cd40: after beq $a2,$v0 at 0x80019104 + // BindImp addiu $a3,$0,0x5800 sign-extends to + // 0xFFFF5800, lw 0($a3), then sw $v0,0($v1) at + // 0x80019124. v1 was *(fp+0x1C) at 0x800190FC. + public const uint BindImpIatKdata = 0x8001910C; + public const uint BindImpIatSw = 0x80019124; + public const uint BindImpIatAfter = 0x80019128; + // Live 19656e2: lw $v1,0x1C($fp) then sw $v0,0($v1). + public const uint BindImpIatSlotLw = 0x800190FC; + // Live 1c3b70a: after slot0, firmware +4 *(fp+0x1C) + // here then loops GetProc. Keep VALLOC dest+n*4. + public const uint BindImpIatNext = 0x800192EC; + public const uint BindImpIatNextAfter = 0x800192F0; + public const uint BindImpFpIatOff = 0x1C; + // Live d19770c: after IAT slot7, stall at + // 0x8001528C sw $t1,132($s0) in the exception + // register-save. Observe Cause/EPC/BadVAddr. + public const uint BindImpExnLo = 0x80015240; + public const uint BindImpExnHi = 0x8001528C; + public const int BindImpObserveMax = 24; + public const uint ModuleExpRva = 0x8C; + public const uint ModuleExpEnd = 0x90; // 0x80018B34 CallDLLEntry jalrs module+0x5C with no // null check. TOC-attach writes object+0/4 so 0x800196E4 // can read e32, but 0x8001E960 skips the startip store - // when 32($sp) entryrva is still 0. jalr 0 never returns - // to FSDMGR 0x03E8604C. Fill vbase+entryrva from TOC e32. + // when 32($sp) entryrva is still 0. jalr 0 never returns. + // DLL vbase is unique: store vbase+entryrva. EXE vbase + // 0x00010000 is shared (filesys/gwes/device) and the + // image is linked there: jal/j stay in region 0. A ROM + // startip (0x8014B3C8) makes entry's jal go to + // 0x80016014, not WinMain. 0x800140A8 (ASID/slot + // attach after VALLOC) is jr $ra, so slot 0 still + // fetches filesys. Alias current-process uncompressed + // XIP o32[0] VA to dataptr, and store startip as VA. + // 0x8001DD6C skips CallDLL when module+0x50 is useg + // or 0xC2xxxxxx; that skip never jalrs EXE entry. + // 0x8001DD90 is addiu a1,0,0 / jal 0x80018B34. EXE + // wants reason 0. ExtraROM ddi_nop DllMain needs + // a1=1 (PROCESS_ATTACH); landing on 0x8001DD90 + // wipes that and CallDLL returns 0 (last-error 1114). + // 0x8001DD94 is the jal; delay or $a0, $fp, $0. + public const uint CallDllEntry = 0x80018B34; public const uint CallDllStartip = 0x80018BAC; + public const uint CallDllAfterJalr = 0x80018BB8; + // 0x8001DD6C skips CallDLL when module+0x50 is useg + // or 0xC2xxxxxx. ExtraROM ddi_nop VALLOC 0x01980000 + // is useg, so firmware never jalrs startip. Force + // the existing DLL jal (a1=1) for that module only. + public const uint XipCallDllUsegChk = 0x8001DD6C; + public const uint XipExeCallDllSkip = 0x8001DDA4; + public const uint XipExeCallDllJal = 0x8001DD90; + public const uint XipDllCallDllJal = 0x8001DD94; + public const uint ThreadStartTrampoline = 0x8001FF38; + public const uint LoadExeE32Ret = 0x8001F870; + // LoadExe 0x8001F81C. 0x8001F870 is jal 0x800196E4 ret. + // startip is not stored there. 0x8001FD74 lw 28($sp) + // (FILE LoadE32 AddressOfEntryPoint) then jal 0x8001B388 + // unless e32_lite+16 (COM) takes BindImpLoadLib first. + public const uint LoadExeStartipArg = 0x8001FD74; + public const uint LoadExeStartipRet = 0x8001FD80; + public const uint ThreadContextSetup = 0x80020BE4; + // 0x80015404 / 0x8001566C lw k0, 236(s0) then ERET. + // wait68: tv2 thread+5C is firmware 0x014B9D98 but + // +0xEC is 0x800517B8 (mid CEDecompressROM). Resume + // that leftover never I-fetches _CorExeMain. + public const uint ThreadCtxRestore = 0x80015404; + public const uint ThreadCtxRestore2 = 0x8001566C; + public const uint ThreadCtxPc = 0xEC; + public const uint ThreadStartip = 0x5C; + public const uint ThreadCtxSr = 0xF0; + // 0x800397B0 stores +F0=3 when the syscall + // frame is kernel, +F0=0x13 when it is user + // (0x8003980C addiu $v0, $0, 19). 0x8001589C + // andi Status, 0x10: bit 4 takes the user + // frame/ERET path. 3 skips that and 0x80015A28 + // jr $ra of *(thread+0x18)+4. wait81 that + // return was 0, I-fetch 0, ra=0. Not a null + // user RA (that was 0x03F6C8F4). Do not map + // page 0. + public const uint ThreadCtxSrKernel = 3; + public const uint ThreadCtxSrUser = 0x13; + public const uint ThreadSyscallFrame = 0x18; + // 0x80020C30 / 0x80020D10 sw $0, 220(a0) at + // ThreadContextSetup. Implicit-API 0x8001586C + // never hits 0x800152CC, so +0xDC stays 0. + // 0x80015404 then lw ra, 220(s0) and ERET. + public const uint ThreadCtxRa = 0xDC; + // 0x800154DC sw $s7, 188(s0); 0x800155C4 lw. + // Implicit-API 0x8001586C never hits that save. + public const uint ThreadCtxS7 = 0xBC; + // dest 0x800908B0 / VA 0x03F6C8B0 addiu $s7, $0, 22528 + public const uint UserKData = 0x5800; + // firmware 0x80014488 / 0x800146AC lw $sp, 212(s0) + // then ERET. Implicit-API 0x8001586C never + // stores +0xD4. wait85 leftover ERET then + // TLB store 0x03F6CABC vaddr=0xE4DA9AA4 + // dest-word=0 pte-miss. va>>25=114, not a + // process slot, not BCM 0x10xxxxxx / kseg1 / + // 0xF0600000 / 0x1F000000. Garbage GPR, not + // MMIO. Do not map page 0. Do not invent dest + // at 0xE4DA9AA4. + public const uint ThreadCtxSp = 0xD4; + public const uint ThreadPrc = 0x0C; + // 0x8001554C beq s0, v0, 0x800155A8 skips CurProc + // update when the same thread is rescheduled. + // wait69: tv2 +0x0C was filesys, so even the slow path + // stored CurProc=0x80340110 and I-fetch 0x014B9D98 + // faulted to 0x8001588C. Do not invent a slot map. + public const uint ThreadSwitchProcChk = 0x8001554C; + public const uint ThreadSwitchProcSlow = 0x80015550; + public const uint ThreadSwitchProcStore = 0x80015570; + public const uint ExnAfterFetch = 0x8001588C; + public const uint ExnAfterFetch2 = 0x80015B9C; + // leftover 0x800159A8 jal 0x800397B0 then + // 0x800159B4 or $ra,$v0,$0. wait99: that jal + // returned -1 so EPC became 0xFFFFFFFF. + // 0x80015A08 mtc0 $t4,EPC; 0x80015A24 ERET. + public const uint LeftoverOrRa = 0x800159B4; + // Live 7607343 leftover-skip ra=0x800159B0 + // then silent freeze. Dump: jal 0x800397B0 + // return; 0x800159B0 lw $t0,32($sp). leftover + // mid, not a LoadO32 continue. leftover jr + // $ra there loops. leftover-halt that mid. + // Do not leftover hop. Do not invent dest. + public const uint LeftoverJalRet = 0x800159B0; + // Live 7ecd04b leftover-halt dest leftover- + // syscall jalr+8 was=0x8009573C +EC= + // 0x800382F8 ra=0x800159B0 leftover-jalr8= + // 0x03F7D73C. leftover-cstk-fix stored dest + // leftover-syscall jalr+8. ERET dest wrapper + // mid / poison +EC. leftover dest leftover- + // syscall return is leftover dest leftover- + // syscall $ra (live 0x03F71740 dest + // 0x80089740 mid-hash), not jalr+8. Plant + // root 0x8001597C sw $ra,40($sp). Live + // a6102f2 leftover-wait99-fix dest-live + // continue leftover dest leftover-syscall + // $ra then leftover-wait99-spin pc= + // 0x80015368 v0=0 a0=1 ra=0x80015360. + // Dump 0x80015358 jalr $a1; 0x80015360 + // mfc0 Status; 0x80015368 xori IE; + // 0x80015380 beq $v0,$0, restore/ERET. + // dest-live continue leftover dest leftover- + // syscall $ra I-fetches leftover dest + // mid-hash; exception ERET storm. leftover + // dest leftover-syscall $ra mid-hash is + // not a LoadO32 resume. Live 2239756 + // leftover-wait99-halt then leftover-cstk + // +4 leftover dest api=0xFFFFFF68 + // leftover-cstk-fix jalr+8 leftover-halt + // dest stub +EC=0x800382F8. leftover-wait99- + // halt returned false so firmware sw $ra / + // jal ObjectCall 0x80015980 still ran. + // Dump 0x80015980 jal 0x80039148. dest + // leftover-syscall jalr+8 is not a LoadO32 + // continue past wait99/-1630. Halt at + // wait99 plant root; do not execute sw $ra + // / jal ObjectCall. Do not leftover hop. + // Do not invent dest. + public const uint LeftoverWait99RaSw = 0x8001597C; + // Live 0c21f53 leftover-wait99-need dest= + // 0x80088B94 dest-word=0x01495825 (or $t3, + // $t2,$t1 mid-hash). leftover dest leftover- + // syscall $ra dest mid-hash is not a + // LoadO32 continue. leftover dest GetProc + // dest leftover hop forbidden. Do not leftover + // hop. Do not invent dest. + public const uint LeftoverWait99NeedDest = 0x80088B94; + public const uint LeftoverWait99JalrRa = 0x80015360; + public const uint LeftoverWait99IeClr = 0x80015368; + // Live a2375d3 leftover-wait99-halt then leftover- + // wait99-spin pc=0x800558A0 v0=0 a0=0x80338F68 + // ra=0x80055808 dest=0. leftover-cstk / leftover- + // halt dest stub gone. Dump 0x800557F4 tick vs + // 0x80338F70; MMIO 0xB04007D4. 0x800558A0 is mid + // OEM tick (ra 0x80055808 is +0x14 of TickDelta). + // a0=0x80338F68 is tick word-8. v0=0 is tick + // leftover, not LoadO32 / LoadE32 fail. Not + // leftover dest. Not a LoadO32 continue past + // wait99. leftover-wait99-tick-halt that PC. + // Do not leftover hop. Do not invent dest. + public const uint LeftoverWait99Tick = 0x800558A0; + // Live 98463a8 leftover-wait99-wrap-cont at + // GetProc-wrapper $ra then leftover-wait99- + // halt was=0x8001597C ra=0x03F70B94 dest= + // 0x80088B94 dest-word=0x01495825 (or $t3, + // $t2,$t1 mid-hash) leftover-wait99-spin + // pc=0x80055814 v0=0x044B2C8D a0=0 ra= + // 0x80055808 dest=0. leftover dest leftover- + // syscall $ra dest mid-hash is not a + // LoadO32 continue. leftover-wait99-halt + // stays at plant root; timer tick escapes + // to dump OEM tick mid 0x80055814 (+0x20 + // of 0x800557F4). leftover-wait99-tick- + // halt that PC and stay. leftover dest + // GetProc dest leftover hop forbidden. Do + // not leftover hop. Do not invent dest. + public const uint LeftoverWait99TickMid = 0x80055814; + public const uint LeftoverWait99TickRa = 0x80055808; + public const uint LeftoverWait99TickA0 = 0x80338F68; + public const uint LeftoverWait99TickWord = 0x80338F70; + // Live a77cd06 leftover-wait99-need ra-word= + // 0x8FC60000 dest-word=0x01873821 +EC= + // 0x03F71720 plant=0x03F74844. ra-word is + // dump dest wrapper mid lw $a2,0($fp). dest- + // word is mid-hash addu $a3,$t4,$a3. +EC is + // leftover dest dest-wrapper. plant leftover + // dest GetProc dest 0x8008C844. leftover dest + // GetProc leftover dest dest-wrapper jalr + // leftover-syscall -1630 / wait99. leftover + // dest dest-wrapper mid leftover $fp is + // poison, not LoadO32. leftover dest GetProc + // dest leftover hop forbidden. leftover- + // wait99-wrap-halt leftover dest dest-wrapper + // so leftover-syscall -1630 is never entered. + // Do not leftover hop. Do not invent dest. + // Live c673486 leftover-wait99-wrap-halt pc= + // 0x03F71720 word=0x8EC20000 plant=0x03F74844 + // after LoadO32-ret v0=0. word is dump lw $v0, + // 0($s6) (leftover-CAE8 dest-word 0x8EC20000), + // not leftover-syscall jalr / dest wrapper mid + // lw $a2,0($fp). leftover dest GetProc leftover + // dest 0x03F71720 is leftover dest GetProc + // leftover dest load. leftover dest GetProc dest + // 0x8008C844 leftover hop forbidden. leftover + // dest GetProc leftover dest load continues. + // leftover dest dest-wrapper jalr leftover- + // syscall / dest wrapper mid wrap-halt stays. + // Do not leftover hop. Do not invent dest. + // Live b66258b leftover-wait99-wrap-cont pc= + // 0x03F71720 word=0x8EC20000 s6=0x01FFFCA4 + // plant=0x03F74844 then leftover-wait99-wrap- + // halt pc=0x03F71734 word=0x2402F9A2. wrap- + // cont ran dump lw $v0,0($s6). leftover dest + // leftover-syscall addiu $v0,$0,-1630 wrap- + // halt correct. Dump dest leftover-syscall + // -1630 wrapper 0x80095720: 0x80095710 lui + // $v0,0x200; 0x8009571C addiu $s6,$v0,-860 + // → $s6=0x01FFFCA4 (GetProc cache / same + // ProcessInfoFaultVa). 0x80095720 lw $v0, + // 0($s6) 0x8EC20000; 0x80095724 beq $v0,$0, + // +3 0x10400003; 0x8009572C b +2 0x10000002; + // 0x80095730 lw $v0,608($v0) 0x8C420260 + // (real GetProc); 0x80095734 addiu $v0,$0, + // -1630 leftover-syscall fallback; + // 0x80095738 jalr $v0 0x0040F809. leftover + // dest useg 0x03F71720 is dest wrapper + // overlay (same page offset). leftover dest + // dest-wrapper success does not enter + // leftover-syscall -1630. leftover dest + // GetProc dest 0x8008C844 leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. + public const uint LeftoverWait99Wrap = 0x03F71720; + public const uint LeftoverWait99WrapWord = 0x8EC20000; + public const uint LeftoverWait99WrapBeq = 0x03F71724; + public const uint LeftoverWait99WrapBeqWord = 0x10400003; + public const uint LeftoverWait99WrapSkip = 0x03F7172C; + public const uint LeftoverWait99WrapSkipWord = 0x10000002; + public const uint LeftoverWait99WrapGetProcLw = 0x03F71730; + public const uint LeftoverWait99WrapGetProcLwWord = 0x8C420260; + public const uint LeftoverWait99WrapSyscall = 0x03F71734; + public const uint LeftoverWait99WrapSyscallWord = 0x2402F9A2; + public const uint LeftoverWait99WrapJalr = 0x03F71738; + public const uint LeftoverWait99WrapJalrWord = 0x0040F809; + // Live 58f17ea leftover-api-54-cont dest= + // 0x8005A6D0 leftover-wait99-wrap-halt + // pc=0x03F71740 word=0x8FC60000 plant= + // 0x03F74844 (refuse leftover dest leftover + // $fp). wrap-plant dest-live GetProc + // gp=0x8003EABC / methods[152] already + // present. leftover $fp gate blocked + // leftover-wait99-wrap-cont. leftover- + // wait99-wrap-cont at GetProc-wrapper $ra + // when dest-live methods[152] is present + // even if leftover $fp is leftover dest. + // leftover dest leftover-syscall -1630 / + // missing GetProc wrap-halt stays. leftover + // dest GetProc dest leftover hop forbidden. + // Do not leftover hop. Do not invent dest. + public const uint LeftoverWait99WrapRa = 0x03F71740; + public const uint LeftoverWait99WrapRaWord = 0x8FC60000; + // Dump dest leftover-syscall wrapper 0x800956F0. + // Same page offset as leftover dest useg 0x03F716F0 + // (coredll 0x03F70000 alias of 0x80094000). After + // dest-live GetProc jalr, wrap-cont $ra is dump + // 0x80095740 lw $a2,0($fp). leftover $fp / plant + // 0x03F74844 is leftover dest GetProc dest + // 0x8008C844 leftover hop forbidden. Dump + // prologue sw $ra,N($sp) is the LoadO32 / + // BindImp caller after dest-live GetProc + // returns. Do not resume leftover-wait99- + // o32-halt +5C/+EC/+DC. Do not leftover hop. + public const uint LeftoverWait99WrapDumpPrologue = 0x800956F0; + public const uint LeftoverWait99WrapDumpSw = 0x800956F4; + public const uint LeftoverWait99WrapDump = 0x80095720; + public const uint LeftoverWait99WrapDumpRa = 0x80095740; + public const uint LeftoverWait99WrapPrologue = 0x03F716F0; + public const uint LeftoverWait99WrapSw = 0x03F716F4; + // Live 0142875 leftover-wait99-o32-halt + // dump-pro=0x27BDFFE0 addiu $sp,-32. + // dump-sw=useg-sw=0xAFBF001C sw $ra,0x1C($sp). + // via refuse 0x03F74DEC dest=0: slot +1C is + // leftover dest (plant 0x03F74844 + // neighborhood), not dest-live LoadO32. + // leftover-wait99-o32-halt logs dump-sp10/ + // dump-sp14/dump-sp18/dump-sp1c. leftover- + // wait99-o32-cont only when that slot is + // dest-live NK LoadO32 / BindImp. leftover + // dest GetProc dest leftover hop forbidden. + // Live 92eb906 leftover-wait99-o32-halt + // ra=0x03F71740 dump-sp10=0x03FBF69C + // dump-sp14=0x86F5F8BA dump-sp18= + // 0x2007FCB8 dump-sp1c leftover dest + // 0x03F74DEC via refuse; fp=0x00005800 + // junk. wrap $ra 32-byte frame already + // poisoned. First dump-true AFBF001C is + // wrap entry 0x03F716F4 / dump 0x800956F4. + // leftover dest 0x03F74DE0 neighborhood + // is observe-only when that PC is + // AFBF001C. leftover-wait99-o32-cont only + // dest-live NK LoadO32 / BindImp $ra of + // that first write. leftover dest + // 0x03F74DEC / leftover dest GetProc dest + // 0x8008C844 leftover hop forbidden. + // Live db3d277 leftover-wait99-o32-sw-halt + // pc=0x03F716F4 ra=0x03F74DEC dest= + // 0x8008CDEC dump-sp1c=0 via refuse. + // First AFBF001C already has leftover + // $ra. Stack overwrite is wrong: $ra is + // poisoned before the save. jal/jalr at + // $ra-8 0x03F74DE4 (leftover dest + // 0x8008CDE4 / coredll dump 0x80098DE4) + // is the implied $ra source. Observe + // that prior jalr (word / dest). + // Live 0ab1b68 leftover-wait99-o32-ra-src + // pc=0x03F74DE4 word=0x0CFDC5BC dest= + // 0x03F716F0 via=jal. leftover jal INTO + // wrap entry. leftover→wrap loop, NOT + // LoadO32. Do not continue via that jal + // dest. Live 183c8f4 leftover-wait99- + // o32-nk-call pc=0x8001E418 ra= + // 0x8001E420 dest=0x800165DC word= + // 0x0C005977 via=jal (good $ra). + // leftover-wait99-o32-nk-ret pc= + // 0x80016848 v0=0 dest-word=0x2 ra= + // 0x80016654 skip200=y bit200=n via= + // dest-set was a miss-name: dest-word=2 + // is dump wrapper sb 2 at fp+0xCE + // (a2 byte-out); dest-addr a3=0; + // skip200 is dump-true ExtraROM 0x807. + // leftover-wait99-o32-nk-wrap-after + // names wrapper 0x8001E428 s5 dest-e32 + // dest-fp50. Live 0be2cb9 dest-e32= + // 0x1B0C is SIZE not dest-live hop; + // dest-fp50 0x8006C000 is CopyO32 dest + // fill. leftover-wait99-o32-nk-wrap- + // copy-ret names post-CopyO32 BindImp / + // CallDLL. leftover-wrap-after-copy is + // leftover jal INTO wrap residue, not + // dump-true next. leftover-wait99-o32- + // cont only dump-true dest-live NK + // LoadO32 / BindImp / wrap-copy dest- + // fp50 / wrap-copy-ret. leftover dest + // 0x03F74DEC / leftover dest GetProc dest + // 0x8008C844 leftover hop forbidden. + // Live 26cbe16 leftover-wait99-o32-nk-iat + // name=hd.dll via=bindlib. leftover-wrap- + // during-bind stays leftover. Live fb2d4b3 + // GetProc v0=0x87000000 leftover-in / + // 0x7FFA0 exprva decode to dump-true + // HdstubDLLEntry 0x8006DB0C / + // HdstubInit 0x8006D9D0. Do not hop + // dest-e32 0x1B0C or dest-fp50 as PC. + public const uint LeftoverWait99WrapAddiuSp = 0x27BDFFE0; + public const uint LeftoverWait99WrapSwRaWord = 0xAFBF001C; + public const int LeftoverWait99WrapRaOff = 0x1C; + public const int LeftoverWait99WrapFrame = 32; + public const uint LeftoverWait99O32RefuseRa = 0x03F74DEC; + public const uint LeftoverWait99O32RefusePrologue = 0x03F74DE0; + public const uint LeftoverWait99O32RefuseJalr = 0x03F74DE4; + public const uint LeftoverWait99O32RefuseDump = 0x8008CDE0; + public const uint LeftoverWait99O32RefuseDumpJalr = 0x8008CDE4; + public const uint LeftoverWait99O32RefuseCoredllJalr = 0x80098DE4; + // Live 489b416 leftover-wait99-wrap-cont + // pc=0x03F71740 getproc=0x8003EABC meth= + // 0x8005D400 leftover-api-54-cont dest= + // 0x8005A6D0 leftover-wait99-halt dest= + // 0x80088B94 leftover-wait99-o32-halt + // +5C=0x03FBF69C +EC=0x03F74B5C +DC= + // 0x03F71618 plant=0x03F74844 leftover- + // wait99-tick-halt pc=0x800557F4. Frame + // after wait99-halt is dead (ThreadExceptionExit + // / leftover dest dest-wrapper / mid-hash). + // Do not resume those. leftover dest GetProc + // dest leftover hop forbidden. + public const uint LeftoverWait99O32Halt5C = 0x03FBF69C; + public const uint LeftoverWait99O32HaltEc = 0x03F74B5C; + public const uint LeftoverWait99O32HaltDc = 0x03F71618; + public const uint LeftoverWait99HashWord = 0x01873821; + public const uint LeftoverWait99GetProc = 0x03F74844; + public const uint LeftoverWait99GetProcDest = 0x8008C844; + public const uint LeftoverWait99GetProcOff = 0x260; + // Live 2b0bcf3 leftover-wait99-wrap-plant + // via=ptr now=0x8005D400 gp=0x8003EABC + // leftover-wait99-wrap-cont pc=0x03F7172C + // cache=0x8005D400 getproc=0x8003EABC then + // leftover-wait99-wrap-halt pc=0x03F71740 + // (missing dest-live GetProc). *0x01FFFCA4 + // at GetProc-wrapper $ra is not the plant + // table. dump dest leftover-syscall wrapper + // plant table 0x8005D400 methods[152] + // 0x8003EABC still dest-live. leftover- + // wait99-wrap-cont at $ra peeks plant + // table / KData when the slot is cleared. + // leftover dest GetProc dest leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. + public const uint LeftoverWait99WrapPlantMeth = 0x8005D400; + public const uint LeftoverWait99WrapPlantGp = 0x8003EABC; + // Live 394f3fd leftover-wait99-wrap-cont s6= + // 0x01FFFCA4 cache=0x02000000 (lui 0x200 + // before the lw) getproc=0 then leftover- + // wait99-wrap-halt pc=0x03F71734. *0x01FFFCA4 + // is 0 so dump beq $v0,$0 → leftover-syscall + // -1630. Dump dest-wrapper: cache is Win32 + // ppfnMethods; lw $v0,608($v0) is methods[152] + // (api -152 / leftover-syscall -1630). KData + // cNest at +0x85 ⇒ ahSys[32] at +4; SH_WIN32 + // ahSys[0] CINFO+8 is ppfnMethods. Slot + // 0x01FFFCA4 aliases KData 0xFFFFDCA4. Fill + // dest-live methods table so dest-wrapper + // success runs. leftover dest GetProc dest + // 0x8008C844 leftover hop forbidden. Do not + // leftover hop. Do not invent dest. + public const uint LeftoverWait99CacheKdata = 0xFFFFDCA4; + public const uint LeftoverWait99CinfoPfn = 8; + // Live 41b58dc leftover-wait99-wrap-need slot= + // kdata=ahsys=methods=getproc=0 via=empty then + // wrap-halt -1630; LoadO32-ret v0=0. ahSys[0] + // unset / not the live Win32 CINFO at wrap. + // Dump NK CINFO acName "WN32" (0x32334E57); + // +8 is ppfnMethods. methods[152]=+0x260 is + // GetProc; methods[151]=+0x25C is the dump + // wrapper's second jalr. leftover dest + // GetProc dest 0x8008C844 leftover hop + // forbidden. BindImp 0x8001F7BC is LoadO32 + // GetProc, not a methods table. + // Live f316d35: kd-ok kd0=0xC202FF00 ahsys=0 + // ah-ok curproc=ProcTable 0x80340040; no + // wrap-plant; wrap-need truncated before via= + // (HiveLineMax 180). Scan started at + // 0x80200000 and missed dump nk.exe ImageBase + // 0x80010000 (Win32CreateFile 0x8003D700). + // Live 0e57fb6: via=wn32-miss wn32=hop=meth=gp=0 + // ib=y c0=y — ImageBase and copy dest readable, + // acName 0x32334E57 never on the live bus. Do + // not require WN32. Find ppfnMethods by dump- + // named Win32 thunks: CreateFile 0x8003D700 and + // ReadFile 0x8003D7E0 are 56 slots apart. + // methods[152] must be dest-live GetProc. Offline + // nk.bin B000FF extract if guest walk misses. + // leftover dest GetProc dest leftover hop + // forbidden. Do not leftover hop. Do not invent + // dest. + public const uint LeftoverWait99Wn32Name = 0x32334E57; + public const uint LeftoverWait99GetProcOffAlt = 0x25C; + public const uint LeftoverWait99NkDataLo = 0x80200000; + public const uint LeftoverWait99NkImage = 0x80010000; + public const int LeftoverWait99AhCount = 32; + public const uint LeftoverWait99ReadFileDelta = 0xE0; + // Dump 0x800397F8 lw $s3,4($a0) with $a0 + // = thread+0x18 syscall frame. 0x800399E8 + // or $v0,$s3 returns that. Live b757425 + // leftover-skip $v0 leftover dest. FD50 + // load at 0x800399A4 is skipped (was != + // plant). Sole FD50 store 0x800370F8 is + // GetProc. leftover-frame +18=0 after + // 0x80039860 unlinks the frame. Observe + // live frame+4 here. Do not leftover hop. + public const uint LeftoverLoadS3 = 0x800397F8; + // Live 05a9778 leftover-ret +4 leftover + // dest before this lw. Dump leftover + // ObjectCall 0x80039148 (sole jal + // 0x80015980): 0x800391C4 lw $t3,16($fp) + // is leftover 0x8001597C $ra; 0x800391CC + // sw $t3,4($s7) writes frame+4; 0x80039218 + // sw $s7,24(thread) links it. dest of + // leftover dest 0x03F71740 is mid-hash + // (0x80089740 addu), not jalr+8. Name + // that store. Do not leftover hop. Do + // not invent dest. + public const uint LeftoverCstkSw = 0x800391CC; + // Live 541bebf leftover-cstk api=0xFFFFFF68 + // +4 leftover dest mid-hash. Dump: + // (EPC+0x3FE)>>2 = -152 → EPC 0xFFFFF9A2 + // = -1630. Sole ROM stub 0x80095734 + // addiu $v0,$0,-1630; jalr $v0. jalr+8 + // is 0x8009573C (nop then wrapper). + // leftover dest of that is 0x03F7D73C, + // not live $ra 0x03F71740 (dest + // 0x80089740 addu mid-hash). Store the + // dest jalr+8. Do not leftover hop. + public const uint LeftoverApi1630 = 0xFFFFFF68; + public const uint LeftoverApi1630Ret = 0x8009573C; + // Live 84e6a7f leftover-ret +4 leftover dest + // 0x03F70830 (not 0x03F71740). Dump dest + // 0x80088830 is jr $ra delay addiu $sp,40 + // of leftover-syscall -938: 0x80088810 + // addiu $t2,$0,-938; 0x80088820 jalr $t2. + // jalr+8 is 0x80088828. EPC 0xFFFFFC56; + // (EPC+0x3FE)>>2 = 0x15. leftover dest of + // jalr+8 is 0x03F70828. Same leftover dest + // $ra class. Store dest jalr+8. Do not + // leftover hop. + public const uint LeftoverApi938 = 0x00000015; + public const uint LeftoverApi938Ret = 0x80088828; + public const uint LeftoverApi938RaLo = 0x03F70820; + public const uint LeftoverApi938RaHi = 0x03F70834; + // Live f99af0d GetProc plant win then leftover-cstk + // api=0xFFFFFFB2 (-78) +4 leftover dest 0x03F70830. + // IsLeftoverApi938Ra planted LeftoverApi938Ret + // 0x80088828 (dump leftover-syscall -938 jalr+8), + // then leftover-halt dest stub dest=0. api -78 is + // not -938: dump index api=(EPC+0x3FE)>>2 so + // imm=(api<<2)-0x3FE = -1334; methods[78] is + // ppfnMethods+0x138. Do not leftover hop to + // 0x80088828 for api -78. leftover dest GetProc + // dest leftover hop forbidden. Do not leftover + // hop. Do not invent dest. + // Live 509dd8f leftover-api-78-need refuse= + // 0x80094830 m78=0 then leftover-api-78-halt + // jalr8=0x80094830 m78=0 +EC=0x8003FD04. + // leftover dest was stays destPlant after + // refuse leftover-syscall jalr+8. leftover- + // api-78-cont required !IsJalCalleeMid(+EC, + // +DC). Live f99af0d +DC=0x800315F0 is + // leftover-dispatch $ra; +DC-8 jal target is + // not +EC, so JalCalleeMid hid dump-true + // thread+0xEC. leftover-api-78-cont replays + // that +EC when sane. wrap-plant via=ptr + // 0x8005D400 filled the table pointer / + // GetProc slot, not methods[78]. Fill +0x138 + // from dump nk.bin / a second dump-pair + // table with dest-live GetProc. Do not plant + // +EC as methods[78]. leftover dest GetProc + // dest leftover hop forbidden. Do not leftover + // hop. Do not invent dest. + public const uint LeftoverApi78 = 0xFFFFFFB2; + public const int LeftoverApi78Imm = -1334; + public const uint LeftoverApi78Meth = 78; + public const uint LeftoverApi78Off = 0x138; + public const uint LeftoverApi78Ec = 0x8003FD04; + // Live 6ac0299 leftover-api-78-cont FIRST-WIN + // +EC=0x8003FD04 then leftover-cstk-fix + // was=0x03F71EBC now=0x80095EBC api= + // 0xFFFFFFCA. leftover dest 0x03F71EBC is + // dest 0x80089EBC jalr delay (jalr+8 + // 0x80089EC0). api 0xFFFFFFCA is -54: + // leftover-syscall -1238 / methods[54] at + // ppfnMethods+0xD8, not dest-wrapper + // jalr+8. dest-ROM scan planted leftover- + // syscall jalr+8 0x80095EBC then leftover- + // cstk-spin / leftover-halt dest stub + // leftover-jalr8=0x03F7DEBC +EC=0x800305B0 + // +DC=0x800305AC. +DC is leftover-dispatch + // jal+8; +DC-8 jal is not +EC. leftover- + // api-54-need refuses leftover hop to + // 0x80095EBC. leftover-api-54-cont + // ObjectCall jalr dest-live methods[54] + // already present. Do not replay dump + // memset mid +EC. Dump-fill methods[54] + // from the same table as GetProc + // 0x8005D400. Do not plant +EC as + // methods[54]. leftover dest GetProc dest + // leftover hop forbidden. Do not leftover + // hop. Do not invent dest. + public const uint LeftoverApi54 = 0xFFFFFFCA; + public const int LeftoverApi54Imm = -1238; + public const uint LeftoverApi54Meth = 54; + public const uint LeftoverApi54Off = 0xD8; + // Live 11cf70a leftover-api-54-need refuse + // 0x80095EBC m54=0x8005A6D0 dest-live then + // leftover-api-54-halt leftover mid + // 0x800159B0 +EC=0x8005950C (dump memset + // mid 0x800593F0–0x80059588 / + // IsPoisonMidPlantResume). Live f0cb076 + // leftover-api-54-cont replayed that +EC + // (namedEc / memset-range accept) without + // leftover-api-54-cont log (_plantFixLogged + // leftover-api-78-cont) then silent freeze. + // leftover hop plant-fix to memset hung. + // leftover-api-54-cont after refuse leftover + // hop ObjectCall jalr dest-live methods[54] + // already present. Do not replay memset mid. + // leftover dest GetProc dest leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. + public const uint LeftoverApi54Ec = 0x8005950C; + public const uint LeftoverApi54MethLive = 0x8005A6D0; + public const uint LeftoverApi54Ret = 0x80095EBC; + // Live 8741ab2 plant-fix +EC=0x800397B8 + // then silent freeze. Dump leftover + // 0x800397B0 addiu $sp,-48; 0x800397B8 + // sw $fp,16($sp) is prologue mid, not a + // LoadO32 continue. Function jr $ra at + // 0x80039A0C; next is 0x80039A14. Refuse + // plant-fix in that range. Do not leftover + // hop. Do not invent dest. + public const uint LeftoverResumePlant = 0x800397B0; + public const uint LeftoverResumePlantEnd = 0x80039A14; + public const uint LeftoverMtc0Epc = 0x80015A08; + public const uint LeftoverJrRa = 0x80015A28; + public const uint LeftoverEret = 0x80015A24; + public const uint LeftoverContinue = 0x03F6CAF0; + // wait100: leftover jr to CAF0 (nop delay of + // beq $v0,$0,+12 at CAEC). Fallthrough CAF4 + // with the beq skipped I-fetched 0. Taken + // target is CAFC. Do not map page 0. + public const uint LeftoverAfterCaf0 = 0x03F6CAF4; + public const uint LeftoverBeqTaken = 0x03F6CAFC; + // wait101: leftover CAFC addiu $v0 then + // 0x03F6CB0C lw $a1,-20($s6) vaddr=0xFFFFFFEC. + // vaddr == -20 means $s6==0 (null-20). Not a + // ROM page. leftover-CAE8 already lw $v0,0($s6). + public const uint LeftoverCb0c = 0x03F6CB0C; + public const uint LeftoverCb0cNext = 0x03F6CB10; + // wait102: leftover past CB10 dest-word + // 0x30A40001 (andi $a0,$a1,1). Next coredll + // insn is CB14. After that, tv2 ctxPC is + // ERET2 0x80015B9C, not leftover mid + // 0x8001586C and not OEMIdle. Resume to + // CB14 after dest peek. Do not rewrite + // 0x80015B9C. + public const uint LeftoverCb14 = 0x03F6CB14; + // wait103: leftover past CB14 dest-word + // 0x10800007 (beq $a0,$0,+7). Taken target + // is CB34. After that, tv2 +DC=0x03F6CB34 + // then ctxPC is leftover mid 0x8001588C + // then ERET2 0x80015B9C. Not OEMIdle + // (later 600M DONE). Resume to CB34 after + // dest peek. Do not rewrite 0x80015B9C. + public const uint LeftoverCb34 = 0x03F6CB34; + // wait104: leftover past CB34 dest-word + // 0x02E01025 (or $v0,$s7,$0). Then ERET2 + // 0x80015B9C. Not leftover still mid + // 0x8001586C as the after-cb14 trigger. + // Not OEMIdle (later 600M DONE). Next + // dest-live insn is CB38. Resume there + // after dest peek. Do not rewrite + // 0x80015B9C. Do not rewind CB34. + public const uint LeftoverCb38 = 0x03F6CB38; + // wait105: leftover past CB38 dest-word + // 0x8FBE0010 (lw $fp,16($sp)). Then ERET2 + // 0x80015B9C. after-cb34 already one-shot. + // Not leftover still mid 0x8001586C. + // Not OEMIdle (later 600M DONE). Next + // dest-live insn is CB3C. Resume there + // after dest peek. Do not invent dest + // at CB3C. Do not rewrite 0x80015B9C. + // Do not rewind CB38. + public const uint LeftoverCb3c = 0x03F6CB3C; + // wait106: leftover past CB3C dest-word + // 0x8FB70014 (lw $s7,20($sp)). Then ERET2 + // 0x80015B9C. after-cb38 already one-shot. + // Not leftover still mid 0x8001586C. + // Not OEMIdle (later 600M DONE). Next + // dest-live insn is CB40. Resume there + // after dest peek. Do not invent dest + // at CB40. Do not rewrite 0x80015B9C. + // Do not rewind CB3C. + public const uint LeftoverCb40 = 0x03F6CB40; + // wait107: leftover past CB40 dest-word + // 0x8FB60018 (lw $s6,24($sp)). Then ERET2 + // 0x80015B9C. after-cb3c already one-shot. + // Not leftover still mid 0x8001586C. + // Not OEMIdle (later 600M DONE). Next + // dest-live insn is CB44. Resume there + // after dest peek. Do not invent dest + // at CB44. Do not rewrite 0x80015B9C. + // Do not rewind CB40. + public const uint LeftoverCb44 = 0x03F6CB44; + // wait108: leftover past CB44 dest-word + // 0x8FBF001C (lw $ra,28($sp)). Then ERET2 + // 0x80015B9C. after-cb40 already one-shot. + // Not leftover still mid 0x8001586C. + // Not OEMIdle (later 600M DONE). Next + // dest-live insn is CB48. Resume there + // after dest peek. Do not invent dest + // at CB48. Do not rewrite 0x80015B9C. + // Do not rewind CB44. Do not skip leftover + // 0x03F6CAC0 to 28($sp). + public const uint LeftoverCb48 = 0x03F6CB48; + // wait109: leftover past CB48 dest-word + // 0x03E00008 (jr $ra). Then leftover left. + // after-cb44 already one-shot. Next runner + // is ERET2 0x80015B9C. Resume at dest-live + // delay slot CB4C after dest peek, then + // follow live $ra (lw $ra,28($sp) at CB44). + // Do not invent dest at CB4C. Do not + // rewrite 0x80015B9C. Do not rewind + // leftover. Do not skip leftover 0x03F6CAC0 + // to 28($sp). + public const uint LeftoverCb4c = 0x03F6CB4C; + // wait111: leftover past leftover-jr-ra dest + // 0x03F731E4 dest-word 0x1040000A + // (beq $v0,$0,+10). leftover left. + // after-cb4c already one-shot. Next + // runner is ERET2 0x80015B9C / + // leftover mid 0x8001588C. Resume at + // dest-live next insn after that beq + // after dest peek of fallthrough + // 0x03F731E8 and taken 0x03F73210. + // Follow live $v0. Do not invent dest. + // Do not rewrite 0x80015B9C. Do not + // rewind leftover. Do not invent dest + // at 0x03F731E4. + public const uint LeftoverBeqRaFt = 0x03F731E8; + public const uint LeftoverBeqRaTk = 0x03F73210; + // wait112: leftover past 0x03F73210 dest-word + // 0x10000002 (b +2). leftover left. + // after-jr-ra already one-shot (did not + // fire). Next runner is ERET2 0x80015B9C + // / leftover mid 0x8001588C. Resume at + // dest-live next insn after that branch + // after dest peek of delay 0x03F73214 + // and taken 0x03F7321C. Do not invent + // dest. Do not rewrite 0x80015B9C. Do + // not rewind leftover. Do not invent + // dest at 0x03F731E4. + public const uint LeftoverBPlus2Delay = 0x03F73214; + public const uint LeftoverBPlus2Taken = 0x03F7321C; + // wait113: leftover past 0x03F7321C dest-word + // 0x03C0E825 (or $sp,$s8,$0). leftover left. + // after-b+2 already one-shot (did not fire). + // Next runner is ERET2 0x80015B9C / + // leftover mid 0x8001588C. Resume at + // dest-live next insn 0x03F73220 after + // dest peek. Do not invent dest. Do not + // rewrite 0x80015B9C. Do not rewind + // leftover. Do not invent dest at + // 0x03F731E4. + public const uint LeftoverBPlus2Next = 0x03F73220; + // wait114: leftover past 0x03F73220 dest-word + // 0x8FBE0010 (lw $fp,16($sp)). leftover left. + // after-taken already one-shot (did not + // fire). Next runner is ERET2 0x80015B9C + // / leftover mid 0x8001588C. Resume at + // dest-live next insn 0x03F73224 after + // dest peek. Do not invent dest. Do not + // rewrite 0x80015B9C. Do not rewind + // leftover. Do not invent dest at + // 0x03F731E4. + public const uint LeftoverFpNext = 0x03F73224; + // wait115: leftover past 0x03F73224 dest-word + // 0x8FB70014 (lw $s7,20($sp)). leftover left. + // after-fp already one-shot. Next runner + // is ERET2 0x80015B9C / leftover mid + // 0x8001588C. Resume at dest-live next + // insn 0x03F73228 after dest peek. Do + // not invent dest. Do not rewrite + // 0x80015B9C. Do not rewind leftover. + // Do not invent dest at 0x03F731E4. + public const uint LeftoverS7Next = 0x03F73228; + // wait117: leftover dest after leftover-past- + // 0x03F73228 (lw $s6,24($sp)). leftover left. + // after-s7 already one-shot. Next runner + // is ERET2 0x80015B9C / leftover mid + // 0x8001588C. Resume at dest-live next + // insn 0x03F7322C after dest peek. Do + // not invent dest. Do not rewrite + // 0x80015B9C. Do not rewind leftover. + public const uint LeftoverS6Next = 0x03F7322C; + // wait118: leftover dest after leftover-past- + // 0x03F7322C (lw $s5,28($sp)). leftover left. + // after-s6 already one-shot. Next runner + // is ERET2 0x80015B9C / leftover mid + // 0x8001588C. Resume at dest-live next + // insn 0x03F73230 after dest peek. Do + // not invent dest. Do not rewrite + // 0x80015B9C. Do not rewind leftover. + public const uint LeftoverS5Next = 0x03F73230; + // wait119: leftover dest after leftover-past- + // 0x03F73230 (lw $s4,32($sp)). leftover left. + // after-s5 already one-shot. Next runner + // is ERET2 0x80015B9C / leftover mid + // 0x8001588C. Resume at dest-live next + // insn 0x03F73234 after dest peek. Do + // not invent dest. Do not rewrite + // 0x80015B9C. Do not rewind leftover. + public const uint LeftoverS4Next = 0x03F73234; + // wait120: leftover dest-live next after leftover-past + // 0x03F73234 (lw $ra,36($sp)). Peek first. Do not + // invent dest. leftover dest-live continue, not a + // one-shot-per-insn. + public const uint LeftoverEpilogueNext = 0x03F73238; + // leftover-drop: leftover dest-live resume hijacks + // leftover mid / ERET2 I-fetch. leftover ERET + // 0x80015A24 uses $v0 not leftover ctxPC. leftover + // $v0 restore is one-shot leftover-CAE8 dest. After + // leftover dest-live lw leftover $v0 stays leftover + // mid. leftover ERET returns leftover mid / ERET2. + // leftover dest-live continue leftover ERET $v0 + // restore dest-live next. leftover dest-live + // continue stays live after leftover dest-live + // delay. wait124: leftover dest-live ERET $v0 + // restore after dest-live delay wrote dest-live + // $ra. leftover already past dest-live $ra + // (leftover past jr $ra). dest-live $ra is + // already walked. leftover I-fetch after + // dest-live delay is leftover mid / leftover + // dest-live delay's live leftover next first, + // not dest-live $ra. leftover still I-fetches + // ERET2 and PC+4. After dest-live delay, + // dest-live next is leftover dest-live delay's + // live leftover next (leftover $ra at dest-live + // jr $ra if live leftover dest), not dest-live + // $ra, not PC+4. leftover dest-live ERET $v0 + // restore writes leftover $v0 to leftover + // dest-live delay's live leftover next. prior + // peek named 0x03F731E4 as evidence only; do + // not invent dest. Do not follow dest-live $ra + // blindly. leftover DISPATCH after leftover + // dest-live I-fetch must not yank leftover + // ctxPC to ERET2. Do not hop 0x03F73238. Do + // not rewrite 0x80015B9C. + // wait74: after I-fetch, ctxPC=0x80040298 then + // ThreadExceptionExit. 0x800154EC beq a1,0 skips + // jal 0x80020D80; that jal 0x80040278. 0x80040298 + // is sw $s2,40($sp) in that VM/PTE check. Not a + // vector. I-fetch log is before FetchInstruction. + public const uint SwitcherExnCall = 0x80020D80; + public const uint ExnVmCheck = 0x80040278; + public const uint ExnVmCheckMid = 0x80040298; + public const uint ExnVmCheckEnd = 0x80040400; + // wait75: TLB I-fetch 0x03F73380 after startip+4. + // Slot 1. Coredll code is 0x03F5xxxx (IsApiReady + // 0x03F73240, CreateThread 0x03F71E04). wait77: + // 0x80018580 lw 0(s5) in the module name walk + // (a0+0x50 vbase + e32 RVA). 0x03FAC0A0 / + // 0x03FB4A60 / 0x03FBF69C / 0x03FD1FD8 are that + // same slot-1 module past the 0x03FA0000 code cap. + // Walk the live section. Do not invent 0x03FD0000. + public const uint CoredllSharedLo = 0x03F50000; + public const uint CoredllSharedHi = 0x03FE0000; + // Live b52708e leftover-wait99-o32-nk-chain + // name=coredll.dll startip=0x3F57A00 + // word=0x27BDFFD8 via=startip. Dump-true + // addiu $sp,$sp,-40 at ImageBase+0x7A00. + // CallDLL never jalr'd (useg +0x50 skip + // and/or MODULE+0x5C still 0 at + // 0x80018B34). Feed startip before + // CallDLL like Hdstub. Do not leftover- + // hop dest. + public const uint CoredllDllMainVa = 0x03F57A00; + public const uint CoredllDllMainWord = 0x27BDFFD8; + // Live c7dd951 FIRST-WIN body then leftover- + // refuse at 0x03F6EE0C word=0x27BDFFE0 + // (addiu $sp,$sp,-32). leftover dest RANGE + // includes live coredll APIs. Dump-true + // ImageBase 0x03F50000 → 0x80074000 so + // this VA is dump 0x80092E0C. Name $ra / + // next jal. Plant dest-live GetProc only + // when that dest is leftover 0x03F74DEC / + // GetProc dest 0x8008C844. Do not leftover- + // hop dest. Do not hop dest-fp50 / 0x1B0C. + public const uint CoredllDllMainJalVa = 0x03F6EE0C; + public const uint CoredllDllMainJalWord = 0x27BDFFE0; + // Live d6a8de5 via=api then exn-tlbl cause=2 + // epc=0x03F6EE3C bad=0x01FFFCA4. Same + // wrapper offset as leftover dest + // 0x03F71720 / dump 0x80095720 lw $v0, + // 0($s6) 0x8EC20000. Slot aliases KData + // 0xFFFFDCA4. leftover-wait99-halt ra= + // 0x03F6EE5C dest=0x80086E5C is wrap $ra + // overlay — refuse leftover hop. + public const uint CoredllDllMainJalLwVa = 0x03F6EE3C; + public const uint CoredllDllMainJalLwWord = 0x8EC20000; + public const uint CoredllDllMainJalRaVa = 0x03F6EE5C; + // Live f4b2558 FIRST-WIN proc-info map + // 0x01FFF000→0x86FB8000; GetProc-cache + // TLBL gone. Next I-fetch TLBL + // epc==bad=0x03FCEFF4 (slot-1 COREDLL + // ImageBase page past 0x03FA0000 cap). + // Demand-map via slot-1 firmware PTE + // (same as ddi_nop coredll-page after + // DllMain). Do not lift MapCoredllSharedVa + // cap. Do not leftover-hop dest. + public const uint CoredllDllMainPageVa = 0x03FCEFF4; + public const uint CoredllDumpBase = 0x80074000; + // Live 147e54f: I-fetch TLBL 0x03FB492C (IAT slot6). + // ImageBase keep-imagebase=0x03F50000. MapCoredllSharedVa + // still refuses >=0x03FA0000 until tv2 startip + // (wait77 OEMIdle). After DllMain, demand-map any + // remaining COREDLL page via slot-1 firmware PTE. + // Live 1bba9df: filesys-slot4 mapped. Next + // data-TLBL epc=0x0001E4DC badvaddr=0x09F574F8. + // Slot 4 view of IB page 0x03F57000→0x8007B000. + // Relative [0x01F50000, 0x01FF0000). Slot 0 is + // IAT real 0x01F57000 — exclude. Do not rewrite + // ImageBase. Do not lift MapCoredllSharedVa + // 0x03FA0000 cap. Live bb6cdc7: BindImp-exn + // cause=2 epc=0x800467E4 badvaddr=0x03FE135C + // (page 0x03FE1000, rel 0x01FE1000) sat one + // page past the old 0x01FE0000 hi. + public const int CoredllImagePageCap = 32; + public const uint CoredllImageRelLo = 0x01F50000; + public const uint CoredllImageRelHi = 0x01FF0000; + public const uint BindImpNameWalk = 0x80018580; + // KDataNest 0xFFFFD885 is cNest at KData+0x85. + // UserKData 0x5800 addiu sign-extends to this page. + public const uint KDataBase = 0xFFFFD800; + public const uint UserKPage = 0xFFFF5800; + public const uint KDataSection = 0xFFFFD8C0; + // Live 258ef59: coredll slot-4 aliased. Next + // data-TLBL epc=0x000593C8 badvaddr=0xFFFFFCE1 + // a1=1 v0=0x00013320 v1=0x78 stores=24. + // Live 674d704: lh t8,-800(s7) insn=0x86F8FCE0 + // rs=23 base=1 formed=0xFFFFFCE1. Page + // 0xFFFFF000 is SharedUserData wrap, not + // UserKPage 0xFFFF5800 / KData 0xFFFFD800. + // Map only live firmware peek or TLB PFN. + // Do not invent KData / TickCount. + public const uint FfffF000Page = 0xFFFFF000; + public const uint FfffFce1Fault = 0xFFFFFCE1; + public const uint FfffFce1Epc = 0x000593C8; + // Live e6f670d FIRST-WIN jalr-0-plant then + // store TLBS cause=3 epc=0x8002F180 + // bad=0xFFFFE380. Page 0xFFFFE000 is after + // KData page 0xFFFFD000 (KDataBase= + // 0xFFFFD800). Offset KDataBase+0xB80. + // Live 82b0d37 pte-miss tlb=none + // FFFFD800=0xC201FF00. word=0xA002E380 is + // sb $v0,0xE380($zero) (CE $zero+imm + // absolute). Classic KData window ends at + // 0xFFFFE000; this byte is the next page. + // Live 9f90c5f: sec0=0x80341BE0 + // l1=0x86FBCBA0 l2=0 for 0xFFFFE000 and + // for KData (kdata-pte-miss l2=0). KData + // is wired, not sec0 L2. MIPS TLB pair + // 0xFFFFC000/0xFFFFD000 owns KData; + // store is pair 0xFFFFE000/0xFFFFF000 + // (SharedUserData). NK never created that + // L2 / never wired that pair. v0=0 is a + // zero-byte. t9=0x80000065 is TLB-refill + // vector+0x65, not a hop. Map live peek, + // TLB PFN, or sec0 firmware PTE dest + // only. Do not alias KData. Do not + // invent/zero-fill. Do not leftover-hop. + public const uint FfffE000Page = 0xFFFFE000; + public const uint FfffC000Page = 0xFFFFC000; + public const uint CoredllDllMainKdataStore = 0xFFFFE380; + public const uint CoredllDllMainKdataEpc = 0x8002F180; + public const uint CoredllDllMainKdataInsn = 0xA002E380; + public const uint CoredllDllMainKdataT9 = 0x80000065; + // Live 734b895: prev=0x02E02025 or $a0,$s7,$0 + // next=0x2442FE54 addiu $v0,$v0,-428 + // (forms 0xFFFFFE54 after v0=0). ra= + // 0x8002F124. kdata-tlb pfn=0x345-v. + // Firmware still l2=0 / no E000 PFN — + // do not wire pfn+1. Continue past + // sb-zero when v0=0 and l2=0 only. + public const uint CoredllDllMainKdataPrev = 0x02E02025; + public const uint CoredllDllMainKdataNext = 0x2442FE54; + public const uint CoredllDllMainKdataRa = 0x8002F124; + // Live 9b62569 sb-zero-skip then TLBL + // epc=0x8002F188 bad=0xFFFFFE54 (addiu + // $v0,-428 formed SharedUserData+0xE54). + // Live 76d3299: word=0x8C430000 lw $v1,0($v0) + // next=0x1060001C beq $v1,$zero,+28. Dest + // is $v1 not $0. Firmware pte-miss tlb=none + // — no dump word at +0xE54. NK's own beq + // is the empty default. Do not invent F000 + // / pfn+1. Early adel 0xFFFFFB32 is the + // same SUD page (observe-only). + public const uint CoredllDllMainSudVa = 0xFFFFFE54; + public const uint CoredllDllMainSudEpc = 0x8002F188; + public const uint CoredllDllMainSudInsn = 0x8C430000; + public const uint CoredllDllMainSudBeq = 0x1060001C; + // Live ab4c991: after sud-beq0-skip, TLBS + // epc=0x8002F228 bad=0xFFFFE428 + // word=0xA002E428 sb $v0,0xE428($0) + // v0=0x80341A74 (NK data near sec0 + // 0x80341BE0 / ProcTable). next=0x0040F809 + // jalr $ra,$v0. t9=0x80057EB8. Nonzero + // byte 0x74 — sb-zero-skip must not + // apply. No E000 PFN. Swallow this sb + // only so jalr $v0 runs (dest peekable + // kseg). Do not invent page / pfn+1. + public const uint CoredllDllMainKdataStore2 = 0xFFFFE428; + public const uint CoredllDllMainKdataEpc2 = 0x8002F228; + public const uint CoredllDllMainKdataInsn2 = 0xA002E428; + public const uint CoredllDllMainKdataNext2 = 0x0040F809; + public const uint CoredllDllMainKdataT9_2 = 0x80057EB8; + // Live c4c77e1: after jr+delay skip, + // ~1869× TLBS epc=0x8003F888 + // bad=0xFFFFEA88 word=0xA003EA88 + // sb $v1,-5496($0). $v1=0x28 + // nonzero — sb-zero-skip must not + // apply. Dump at EPC is sltu + // 0x007E102B. Never-wired E000/ + // F000. Swallow this sb. Continue + // dump-true. Do not invent page / + // pfn+1 / SUD. + public const uint CoredllDllMainKdataStoreEa88 = 0xFFFFEA88; + public const uint CoredllDllMainKdataEpcEa88 = 0x8003F888; + public const uint CoredllDllMainKdataInsnEa88 = 0xA003EA88; + public const uint CoredllDllMainKdataDumpEa88 = 0x007E102B; + // Dump nk.exe $t9=0x80057EB8 (jalr-table dest): + // lui 0x8034; addiu $fp,11360 → 0x80342C60 + // (OemCurMSec scale). addiu $s6,-10092 → + // 0xFFFFD894 (same CurMSec word OemCurMSec + // sw $a0,0($v1)). jal 0x80059D68 ReadCount + // minus last at 0x80339B24; jal 0x80059D90 + // programs Compare. Do not invent tick. + public const uint CoredllDllMainT9Scale = 0x80342C60; + public const uint CoredllDllMainT9CurMSec = 0xFFFFD894; + public const uint CoredllDllMainT9LastCount = 0x80339B24; + public const uint CoredllDllMainT9ReadDelta = 0x80059D68; + public const uint CoredllDllMainT9ProgCmp = 0x80059D90; + // Live 07670a8: after jalr-t9 msec-scale, + // TLBS epc=0x8002F278 bad=0xFFFFE478 + // word=0xA002E478 sb $v0,0xE478($0) + // v0=0x7. prev=0x8FBF004C lw $ra,76($sp) + // next=0x27BD0050 addiu $sp,80 + // ra=0x8001552C. Dump nk.exe at that + // EPC is jr $ra (0x03E00008). Live + // overwrote the epilogue jr. Swallow + // sb alone falls through. Execute dump + // jr $ra (delay addiu). Never-wired + // E000. Do not invent page / pfn+1. + // Do not leftover-hop refuse dests. + public const uint CoredllDllMainKdataStore3 = 0xFFFFE478; + public const uint CoredllDllMainKdataEpc3 = 0x8002F278; + public const uint CoredllDllMainKdataInsn3 = 0xA002E478; + public const uint CoredllDllMainKdataPrev3 = 0x8FBF004C; + public const uint CoredllDllMainKdataNext3 = 0x27BD0050; + public const uint CoredllDllMainKdataDumpJr = 0x03E00008; + public const uint CoredllDllMainKdataWrapRefuse = 0x80086E5C; + // Live 8553edf: after sb-jr, TLBS + // epc=0x80043270 bad=0x2470 + // word=0xA0042470 sb $a0,0x2470($0). + // Dump nk.exe at EPC is sw $a2,8($sp) + // (0xAFA60008). prev=sw $a1,4($sp) + // next=sw $a3,12($sp). Live $sp= + // 0xFFFFD768 (KData), not 0x2468 — + // bad is abs imm with rs=$0. Same + // overwrite class as sb-jr. Rewrite + // fetch to dump sw. Do not invent + // page 0x2000 / kseg0 identity. + public const uint CoredllDllMainStk2470Epc = 0x80043270; + public const uint CoredllDllMainStk2470Bad = 0x2470; + public const uint CoredllDllMainStk2470Page = 0x2000; + public const uint CoredllDllMainStk2470Insn = 0xAFA60008; + public const uint CoredllDllMainStk2470Live = 0xA0042470; + public const uint CoredllDllMainStk2470Prev = 0xAFA50004; + public const uint CoredllDllMainStk2470Next = 0xAFA7000C; + // Live 9eea658: after dump-sw, TLBS + // epc=0x80042470 bad=0x1670 + // word=0xA0041670 sb $a0,0x1670($0). + // Dump is sb $a3,443($v0) (0xA04701BB). + // Same abs-rs=0 overwrite as dump-sw / + // sb-jr. Live $v0=0x86FBE028 (THREAD + // page already mapped). Rewrite fetch + // to dump sb. Do not invent page 0x1000. + public const uint CoredllDllMainStk1670Epc = 0x80042470; + public const uint CoredllDllMainStk1670Bad = 0x1670; + public const uint CoredllDllMainStk1670Page = 0x1000; + public const uint CoredllDllMainStk1670Insn = 0xA04701BB; + public const uint CoredllDllMainStk1670Live = 0xA0041670; + public const uint CoredllDllMainStk1670Prev = 0x2406D885; + public const uint CoredllDllMainStk1670Next = 0x80C50000; + public const uint CoredllDllMainStk1670ThrPage = 0x86FB0000; + // Live fcd07f0: after dump-sb, TLBS + // epc=0x80042628 bad=0x1828. Dump is + // lw $t4,0($fp) (0x8FCC0000) — ThreadPtr + // load, not a store. Live abs sb rs=0 + // imm=0x1828. General rewrite: live abs + // store rs=0 → dump load/store with + // rs!=0 from dump-only nk.bin. Log once + // per site. Do not invent page 0x1000. + public const uint CoredllDllMainAbs1828Epc = 0x80042628; + public const uint CoredllDllMainAbs1828Bad = 0x1828; + public const uint CoredllDllMainAbs1828Dump = 0x8FCC0000; + public const uint CoredllDllMainAbs1828Prev = 0x02A02025; + public const uint CoredllDllMainAbs1828Next = 0x11800005; + // Live 4ee7f9b: after dump-mem + // lw $t4,0($fp), TLBS + // epc=0x80057470 bad=0x6670. + // Dump is jal 0x8004326C + // (0x0C010C9B). Live d2ceddd + // word=0xA0056670 sb $a1, + // 0x6670($0). Jal rewrite + // worked but live RAM stayed + // corrupt → ping-pong with + // 0x80042628. Heal writes + // dump word at EPC. Do not + // invent page 0x6000. + public const uint CoredllDllMainAbs6670Epc = 0x80057470; + public const uint CoredllDllMainAbs6670Bad = 0x6670; + public const uint CoredllDllMainAbs6670Dump = 0x0C010C9B; + public const uint CoredllDllMainAbs6670Dest = 0x8004326C; + public const uint CoredllDllMainAbs6670Live = 0xA0056670; + // Dump delay of jal 0x80057470: + // addiu $a0,$v0,13292. Live f9afdbc + // fallthrough logged jal then spun + // (no c000). Heal delay + execute + // jal (set $ra, PC:=dest). Do not + // invent dest. + public const uint CoredllDllMainAbs6670Delay = 0x244433EC; + // Live d2ceddd: after ~4 dump-mem + // ping-pong pairs, TLBS + // epc=0x800151D0 bad=0xC0000088. + // Dump is sw $v0,0($a1) + // (0xACA20000) — CE list-insert + // (lw *a0; sw v0,*a1; sw a1,*a0). + // rs=$a1, not abs rs=0. Do not + // WalkFirmwarePte: (0xC000>>16) + // &0x1FF is page 0. Map only if + // TLB PFN peeks phys>=0x10000. + // Do not invent 0xC0000000. + public const uint CoredllDllMainC000Epc = 0x800151D0; + public const uint CoredllDllMainC000Bad = 0xC0000088; + public const uint CoredllDllMainC000Page = 0xC0000000; + public const uint CoredllDllMainC000Dump = 0xACA20000; + public const uint CoredllDllMainC000Prev = 0x8C820000; + public const uint CoredllDllMainC000Next = 0xAC850000; + public const uint CoredllDllMainC000NextPc = 0x800151D4; + // Live 98276c7: skip 0xC0000088 then + // sibling list-insert a1=0xC0001070 + // (page 0xC0001000). Live faf00f3: + // skip ×4 then a1=0xC1000070 (ckseg + // 0xC0000000–0xCFFFFFFF). Live + // e7f0f37: skip 0088…0E88 then + // a1=0xD0000028 (kseg2, outside + // 0xCxxxxxxx). Live 71fd3f6: + // skip ×16 through 0xC0001E70 + // then a1=0xE0000688 (outside + // C–D). Live e9baf25: skip ×24 + // through 0xC0002D58 then + // a1=0xF0000288 (outside C–E). + // Same dump sw $v0,0($a1). + // Skip dest-miss in + // 0xC0000000–0xFFFEFFFF when dest + // cannot peek. Do not invent. + // Never SUD 0xFFFFF000 / page 0 + // / KData 0xFFFFE000. + public const uint CoredllDllMainC0001070 = 0xC0001070; + public const uint CoredllDllMainC1000070 = 0xC1000070; + public const uint CoredllDllMainD0000028 = 0xD0000028; + public const uint CoredllDllMainE0000688 = 0xE0000688; + public const uint CoredllDllMainF0000288 = 0xF0000288; + public const uint CoredllDllMainCksegHi = 0xFFFEFFFF; + // Live f48c2dc: skip ×32 through + // 0xC0003B80 then a1=0xFFFF0288 + // (above FFFEFFFF; not SUD F000 / + // not E000). Same dump + // sw $v0,0($a1). Skip dest-miss + // in 0xFFFF0000–0xFFFFDFFF when + // dest cannot peek. Do not invent + // / map 0xFFFFE000 / 0xFFFFF000. + public const uint CoredllDllMainFfff0288 = 0xFFFF0288; + public const uint CoredllDllMainFfffKdataLo = 0xFFFF0000; + public const uint CoredllDllMainFfffKdataHi = 0xFFFFDFFF; + // Boot c3e1614: after c000-store-skip + // ×40 unique dests C000→C005 + // (climb, not same-VA spin), + // list-insert a1=0x14E88 + // via=exn-tlbs. Same dump + // sw $v0,0($a1). Low KUSEG + // above 0xFFFF (old 0x1028 + // cap). Skip dest-miss + // 0x1000–0x1FFFF when dest + // cannot peek. Do not invent + // / map useg / page 0 / E000 + // / F000 / SUD / 9A. No hop + // 0x8003F8B4. + public const uint CoredllDllMainLowUseg14E88 = 0x14E88; + public const uint CoredllDllMainLowUsegHi = 0x1FFFF; + // Live 20f3972: after C000 peeks + // (tlb map 0xC0000000->0x80345000), + // list-insert a1=0xFFFFE288 + // via=exn-tlbs-kdata dump-match + // sw $v0,0($a1). Continue-skip + // dest-miss on 0xFFFFE000–0xFFFFEFFF. + // NEVER invent/map E000 or SUD. + // Keep sb-zero / sud-beq0. + public const uint CoredllDllMainFfffE288 = 0xFFFFE288; + // Live c270933: after e000-store-skip, + // list-insert a1=0xFFFFF088 + // via=exn-tlbs-sud dump-match + // sw $v0,0($a1). Continue-skip + // dest-miss on 0xFFFFF000–0xFFFFFFFF. + // NEVER invent/map SUD / E000. + // Keep sud-beq0 / sb-zero. + public const uint CoredllDllMainFfffF088 = 0xFFFFF088; + // Live 738e467: after f000-store-skip, + // list-insert a1=0x70 via=exn-tlbs-c000 + // dump-match sw $v0,0($a1) v0=0xFFFFF270. + // Continue-skip dest-miss on a1<0x1000. + // NEVER invent page 0 / 0x80000070. + public const uint CoredllDllMainPage0Store = 0x70; + // Live fe74462: after page0-store-skip, + // list-insert a1=0x1028 via=exn-tlbs-c000 + // dump-match sw $v0,0($a1) v0=0x228. + // Continue-skip dest-miss on + // 0x1000–0xFFFF. NEVER invent + // those pages. No WalkFirmwarePte. + public const uint CoredllDllMainLowUsegStore = 0x1028; + // Live 0cb3d43: after jal, list-insert + // TLBS a1=0xC0000088 a0=0x80320254 + // v0=*a0=0xBFFFF288. TLB none. + // Map only if v0 / kseg0(v0) / + // kseg1(v0) peeks phys>=0x10000. + // Then genex dump-mem heal at + // 0x80015C28 sw $ra,284($sp). + // Fallthrough once per PC; name + // genex once. Do not invent + // 0xC0000000 / page 0. + public const uint CoredllDllMainExn15C28Epc = 0x80015C28; + public const uint CoredllDllMainExn15C28Dump = 0xAFBF011C; + public const uint CoredllDllMainExn15C28Live = 0xA0014E28; + public const uint CoredllDllMainExn15C28Next = 0xAFA00090; + public const uint CoredllDllMainExn15C28Off = 284; + public const uint CoredllDllMainExn15C28NextPc = 0x80015C2C; + public const uint CoredllDllMainExn15C28NextOff = 144; + public const uint CoredllDllMainExn15C28After = 0x80015C30; + // Dump after leave (nk.bin): + // 15C30 lui $t0,1 / ori 7 / + // sw $t0,292($sp) / jal 0x80020FA0 + // delay or $a0,$sp. Not LoadO32 + // (0x800165DC–0x8001E538). Do + // not invent dest / 0x9A02 / + // KData. No leftover-hop. + public const uint CoredllDllMainExn15C28AfterDump = 0x3C080001; + public const uint CoredllDllMainExn15C28After2 = 0x80015C34; + public const uint CoredllDllMainExn15C28After2Dump = 0x35080007; + public const uint CoredllDllMainExn15C28After3 = 0x80015C38; + public const uint CoredllDllMainExn15C28After3Dump = 0xAFA80124; + public const uint CoredllDllMainExn15C28JalPc = 0x80015C3C; + public const uint CoredllDllMainExn15C28JalDump = 0x0C0083E8; + public const uint CoredllDllMainExn15C28JalDest = 0x80020FA0; + public const uint CoredllDllMainExn15C28JalDelay = 0x80015C40; + public const uint CoredllDllMainExn15C28JalDelayDump = 0x03A02025; + public const uint CoredllDllMainExn15C28JalRa = 0x80015C44; + public const uint CoredllDllMainExn15C28JalDestDump = 0x27BDFF38; + // Dump 0x80020FCC addiu $v0,$0,-9536 + // (ThreadPtr 0xFFFFDAC0) then + // 0x80020FD0 lw $v1,0($v0). KData + // already live at 0xFFFFD800. + // Do not invent Thread* / 0x9A02. + public const uint CoredllDllMainExn15C28JalThr = 0x80020FCC; + public const uint CoredllDllMainExn15C28JalThrDump = 0x2402DAC0; + public const uint CoredllDllMainExn15C28JalThrLw = 0x80020FD0; + public const uint CoredllDllMainExn15C28JalThrLwDump = 0x8C430000; + // Live 71fd3f6: after leave/thr, + // abs store at 0x80059488 + // (sb $a1,-31096($0) live + // 0xA0058688) overwrote dump + // subu $t1,$a1,$t0 (0x00A84823). + // bad=0xFFFF8688 is high KData- + // class — rewrite+heal ALU, do + // not invent that page. Caller + // ra=0x8002102C (jal 0x800593F0). + public const uint CoredllDllMainAbs59488Epc = 0x80059488; + public const uint CoredllDllMainAbs59488Dump = 0x00A84823; + public const uint CoredllDllMainAbs59488Live = 0xA0058688; + public const uint CoredllDllMainAbs59488Bad = 0xFFFF8688; + // Dump memset after subu: + // addu $t2,$a0,$t1. Caller + // 0x8002102C lw $v0,284($fp) + // after jal 0x800593F0 + // (memset $sp+80, 0, 80). + // Do not invent F000 / 0x9A02. + public const uint CoredllDllMainAbs59488Next = 0x8005948C; + public const uint CoredllDllMainAbs59488NextDump = 0x00895021; + public const uint CoredllDllMainExn15C28JalRet = 0x8002102C; + public const uint CoredllDllMainExn15C28JalRetDump = 0x8FC2011C; + public const uint CoredllDllMainExn15C28JalRetNext = 0x80021030; + public const uint CoredllDllMainExn15C28JalRetNextDump = 0x3C038034; + public const uint CoredllDllMainExn15C28JalRetOff = 284; + // Dump after memset-ret skip: + // lui $v1,0x8034 then + // 0x80021040 lw $t1,0($s1). + // $s1 is Thread+24. Peek *s1 + // only. Do not invent dest / + // SUD / 0x9A02. + public const uint CoredllDllMainExn15C28JalS1 = 0x80021040; + public const uint CoredllDllMainExn15C28JalS1Dump = 0x8E290000; + /// Dump-true after lw $t1,0($s1): lui $s2,0x8000 at 0x80021044 (0x3C128000). + public const uint CoredllDllMainExn15C28JalS1Next = 0x80021044; + public const uint CoredllDllMainExn15C28JalS1NextDump = 0x3C128000; + /// Dump-true after lui $s2,0x8000: addiu $t4,$v1,6756 at 0x80021048 (0x246C1A64). + public const uint CoredllDllMainExn15C28JalS1After = 0x80021048; + public const uint CoredllDllMainExn15C28JalS1AfterDump = 0x246C1A64; + public const uint CoredllDllMainExn15C28JalS1After2 = 0x8002104C; + public const uint CoredllDllMainExn15C28JalS1After2Dump = 0x36520003; + public const uint CoredllDllMainExn15C28JalS1After3 = 0x80021050; + public const uint CoredllDllMainExn15C28JalS1After3Dump = 0x24140002; + public const uint CoredllDllMainExn15C28JalS1After4 = 0x80021054; + public const uint CoredllDllMainExn15C28JalS1After4Dump = 0x312A0001; + public const uint CoredllDllMainExn15C28JalS1After5 = 0x80021058; + public const uint CoredllDllMainExn15C28JalS1After5Dump = 0x3C108000; + /// Dump-true after ALU 0x80021048–0x80021058: sw $t3,52($sp) at 0x8002105C (0xAFAB0034). + public const uint CoredllDllMainExn15C28JalS1AluNext = 0x8002105C; + public const uint CoredllDllMainExn15C28JalS1AluNextDump = 0xAFAB0034; + /// Dump-true sw $t3,52($sp) dest miss on 0x9A02xxxx. Continue-skip; PC:=0x80021060. + public const uint CoredllDllMainExn15C28StkSwOff = 52; + public const uint CoredllDllMainExn15C28StkSwNext = 0x80021060; + public const uint CoredllDllMainExn15C28StkSwNextDump = 0x1540001C; + public const uint CoredllDllMainExn15C28StkSwDelay = 0x80021064; + public const uint CoredllDllMainExn15C28StkSwDelayDump = 0xAFAC0044; + public const uint CoredllDllMainExn15C28StkSwBneTaken = 0x800210D4; + public const uint CoredllDllMainExn15C28StkSwBneFall = 0x80021068; + /// Dump-true lw $t7,160($fp) dest miss on 0x9A02xxxx. Continue-skip; PC:=0x8002106C. + public const uint CoredllDllMainExn15C28FpLw = 0x80021068; + public const uint CoredllDllMainExn15C28FpLwDump = 0x8FCF00A0; + public const uint CoredllDllMainExn15C28FpLwOff = 160; + public const uint CoredllDllMainExn15C28FpLwNext = 0x8002106C; + public const uint CoredllDllMainExn15C28FpLwNextDump = 0x8FD800A4; + public const uint CoredllDllMainExn15C28FpLwBeq = 0x80021088; + public const uint CoredllDllMainExn15C28FpLwBeqDump = 0x10A00113; + public const uint CoredllDllMainExn15C28FpLwBeqDelay = 0x8002108C; + public const uint CoredllDllMainExn15C28FpLwBeqDelayDump = 0xAFB80054; + public const uint CoredllDllMainExn15C28FpLwBeqTaken = 0x800214D8; + public const uint CoredllDllMainExn15C28FpLwBeqTakenDump = 0x8FB90034; + public const uint CoredllDllMainExn15C28FpLwBeqFall = 0x80021090; + public const uint CoredllDllMainExn15C28FpLwBeqFallDump = 0x8FD700A8; + public const uint CoredllDllMainExn15C28FpLwAlu1 = 0x80021070; + public const uint CoredllDllMainExn15C28FpLwAlu1Dump = 0x240DFFFF; + public const uint CoredllDllMainExn15C28FpLwAlu2 = 0x80021074; + public const uint CoredllDllMainExn15C28FpLwAlu2Dump = 0x244EFFFC; + public const uint CoredllDllMainExn15C28FpLwA1 = 0x80021078; + public const uint CoredllDllMainExn15C28FpLwA1Dump = 0x8FC500AC; + public const uint CoredllDllMainExn15C28FpLwSw1 = 0x8002107C; + public const uint CoredllDllMainExn15C28FpLwSw1Dump = 0xAFAD0040; + public const uint CoredllDllMainExn15C28FpLwSw2 = 0x80021080; + public const uint CoredllDllMainExn15C28FpLwSw2Dump = 0xAFCE011C; + public const uint CoredllDllMainExn15C28FpLwSw3 = 0x80021084; + public const uint CoredllDllMainExn15C28FpLwSw3Dump = 0xAFAF0050; + /// Dump-true lw $t9,52($sp) dest miss on 0x9A02xxxx. Swallow; leave via dump-true jal-ra. + public const uint CoredllDllMainExn15C28SpT9 = 0x800214D8; + public const uint CoredllDllMainExn15C28SpT9Dump = 0x8FB90034; + public const uint CoredllDllMainExn15C28SpT9Off = 52; + public const uint CoredllDllMainExn15C28SpT9Next = 0x800214DC; + public const uint CoredllDllMainExn15C28SpT9NextDump = 0x8F220000; + public const uint CoredllDllMainExn15C28EpiJr = 0x800219A8; + public const uint CoredllDllMainExn15C28EpiJrDump = 0x03E00008; + public const uint CoredllDllMainExn15C28EpiDelay = 0x800219AC; + public const uint CoredllDllMainExn15C28EpiDelayDump = 0x27BD00C8; + public const uint CoredllDllMainExn15C28JalRaDump = 0x8FB000D0; + /// Dump-true outer jal-ra after list-insert jal 0x800151C0. Do not I-fetch 0x9A02. + public const uint CoredllDllMainExn15C28OuterRa = 0x8003F784; + public const uint CoredllDllMainExn15C28OuterRaDump = 0x0C01205D; + // Dump 0x8003F784 jal 0x80048174 + // (0x0C01205D). Encoded dest is + // dump-true. Delay 0x8003F788 + // dump-peek only. Do not invent + // dest / delay / 0x9A02. + public const uint CoredllDllMainExn15C28OuterJalDest = 0x80048174; + public const uint CoredllDllMainExn15C28OuterJalDestDump = 0x3C088005; + // Dump 0x80048174 lui $t0,0x8005 / + // addiu $t0,$t0,-32388 / + // addiu $k1,$t0,20 then + // lw $v0,0($a0). $t0:=0x8004817C + // $k1:=0x80048190 (dump jr cookie). + // Execute ALU only. Do not invent + // $a0 / $s7 / 0x9A02 / dest. + public const uint CoredllDllMainExn15C28OuterJalDest2 = 0x80048178; + public const uint CoredllDllMainExn15C28OuterJalDest2Dump = 0x2508817C; + public const uint CoredllDllMainExn15C28OuterJalDest3 = 0x8004817C; + public const uint CoredllDllMainExn15C28OuterJalDest3Dump = 0x251B0014; + public const uint CoredllDllMainExn15C28OuterJalDestNext = 0x80048180; + public const uint CoredllDllMainExn15C28OuterJalDestNextDump = 0x8C820000; + // Dump 0x80048180 lw $v0,0($a0) / + // nop / addiu $v0,1 / sw $v0,0($a0) + // / jr $ra / or $k1,$0,$0. + // Live 5d27a34: $a0=0x9A023E48. + // Swallow 0x9A lw; exec following + // ALU; skip 0x9A sw. Land cookie + // 0x80048190. Do not invent $a0 + // / $s7 / *a0 / 0x9A02 / dest. + public const uint CoredllDllMainExn15C28OuterJalDestNop = 0x80048184; + public const uint CoredllDllMainExn15C28OuterJalDestNopDump = 0x00000000; + public const uint CoredllDllMainExn15C28OuterJalDestInc = 0x80048188; + public const uint CoredllDllMainExn15C28OuterJalDestIncDump = 0x24420001; + public const uint CoredllDllMainExn15C28OuterJalDestSw = 0x8004818C; + public const uint CoredllDllMainExn15C28OuterJalDestSwDump = 0xAC820000; + public const uint CoredllDllMainExn15C28OuterJalDestJr = 0x80048190; + public const uint CoredllDllMainExn15C28OuterJalDestJrDump = 0x03E00008; + public const uint CoredllDllMainExn15C28OuterJalDestJrDelay = 0x80048194; + public const uint CoredllDllMainExn15C28OuterJalDestJrDelayDump = 0x0000D825; + public const uint CoredllDllMainExn15C28OuterJalDelay = 0x8003F788; + public const uint CoredllDllMainExn15C28OuterJalLink = 0x8003F78C; + public const uint CoredllDllMainExn15C28OuterJalLinkDump = 0x96E20000; + // Dump 0x8003F78C lhu $v0,0($s7) / + // subu $fp,$fp,$v0 / + // addu $s6,$v0,$s6 then + // lw $v0,0($s3). Peek *$s7 only. + // Dest-miss skips the $v0 ALU. + // Do not invent $s7 / dest / 0x9A02. + public const uint CoredllDllMainExn15C28OuterJalLinkAlu = 0x8003F790; + public const uint CoredllDllMainExn15C28OuterJalLinkAluDump = 0x03C2F023; + public const uint CoredllDllMainExn15C28OuterJalLinkAlu2 = 0x8003F794; + public const uint CoredllDllMainExn15C28OuterJalLinkAlu2Dump = 0x0056B021; + public const uint CoredllDllMainExn15C28OuterJalLinkAfter = 0x8003F798; + public const uint CoredllDllMainExn15C28OuterJalLinkAfterDump = 0x8E620000; + // Dump 0x8003F798 lw $v0,0($s3) / + // addiu $t1,$0,4 then bne $s4,$t1 + // -> 0x8003F7AC. Peek *$s3 only. + // Do not invent $s3 / $s4 / dest + // / taken / 0x9A02. + public const uint CoredllDllMainExn15C28OuterJalLinkT1 = 0x8003F79C; + public const uint CoredllDllMainExn15C28OuterJalLinkT1Dump = 0x24090004; + public const uint CoredllDllMainExn15C28OuterJalLinkBne = 0x8003F7A0; + public const uint CoredllDllMainExn15C28OuterJalLinkBneDump = 0x16890002; + // Dump bne $s4,$t1 -> 0x8003F7AC + // delay nop. Fall 0x8003F7A8 + // or $s1,$s0,$0. Taken addiu + // $t2,$s4,1. Live $s4 vs $t1. + // Do not invent $s4 / taken. + public const uint CoredllDllMainExn15C28OuterJalLinkBneFall = 0x8003F7A8; + public const uint CoredllDllMainExn15C28OuterJalLinkBneFallDump = 0x02008825; + public const uint CoredllDllMainExn15C28OuterJalLinkBneTaken = 0x8003F7AC; + public const uint CoredllDllMainExn15C28OuterJalLinkBneTakenDump = 0x268A0001; + // Both bne paths join at + // 0x8003F7B0 sltu $t3,$fp,$v0. + // Fall exec or $s1,$s0,$0 then + // addiu $t2. Taken exec addiu. + // Do not invent $s4 / 0x9A02. + public const uint CoredllDllMainExn15C28OuterJalLinkSltu = 0x8003F7B0; + public const uint CoredllDllMainExn15C28OuterJalLinkSltuDump = 0x03C2582B; + // Dump sltu then beq $t3,$0 -> + // 0x8003F748. sltu writes $t3 + // from live $fp/$v0 even if $fp + // is 0x9A (compare is 0/1, not + // a 0x9A memory op). That dest + // is MULT (SPECIAL fn=0x18). + // Never hop MUL. Do not invent + // $fp / $v0 / taken. + public const uint CoredllDllMainExn15C28OuterJalLinkBeq = 0x8003F7B4; + public const uint CoredllDllMainExn15C28OuterJalLinkBeqDump = 0x1160FFE4; + // beq $t3,$0 delay andi $s4,$t2,7 + // then fall addiu $v0,$0,-9384. + // Taken 0x8003F748 is MULT — + // refuse. Delay runs both paths. + // Do not invent taken / hop MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkBeqDelay = 0x8003F7B8; + public const uint CoredllDllMainExn15C28OuterJalLinkBeqDelayDump = 0x31540007; + public const uint CoredllDllMainExn15C28OuterJalLinkBeqFall = 0x8003F7BC; + public const uint CoredllDllMainExn15C28OuterJalLinkBeqFallDump = 0x2402DB58; + // Live 7964d8a: after beq fall, + // dump addiu $v0,$0,-9384 at + // 0x8003F7BC. Exec dump addiu + // (rs=$0). v0:=0xFFFFDB58. Next + // 0x8003F7C0 lw $t4,0($v0). + // Observe that I-fetch. Do not + // invent *$v0 / 0xFFFFDB58 / SUD + // / 0x9A02 / 0x320255. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkAddiuNext = 0x8003F7C0; + public const uint CoredllDllMainExn15C28OuterJalLinkAddiuNextDump = 0x8C4C0000; + // Live 87bbfea: lw $t4,0($v0) at + // 0x8003F7C0 v0=0xFFFFDB58 dump + // miss. Continue-skip; leave $t4. + // Do not invent *0xFFFFDB58 / SUD + // / KData. Next 0x8003F7C4 dump + // lw $s7,20($sp) — observe only. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwT4Next = 0x8003F7C4; + public const uint CoredllDllMainExn15C28OuterJalLinkLwT4NextDump = 0x8FB70014; + // Live 36e0bb7: lw $s7,20($sp) at + // 0x8003F7C4 sp/dest in 0x9A. + // Continue-skip; leave $s7. Do + // not invent 0x9A02. Next + // 0x8003F7C8 addu $t5,$t4,$fp — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS7Next = 0x8003F7C8; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS7NextDump = 0x019E6821; + // Live c5d44f3: addu $t5,$t4,$fp + // at 0x8003F7C8. Exec dump addu + // even if $fp is 0x9A (ALU write + // only; no 0x9A page). Next + // 0x8003F7CC lw $fp,16($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkAdduNext = 0x8003F7CC; + public const uint CoredllDllMainExn15C28OuterJalLinkAdduNextDump = 0x8FBE0010; + // Live e99a90c: lw $fp,16($sp) at + // 0x8003F7CC sp/dest in 0x9A. + // Continue-skip; leave $fp. Do + // not invent 0x9A02. Next + // 0x8003F7D0 lw $s6,24($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwFpNext = 0x8003F7D0; + public const uint CoredllDllMainExn15C28OuterJalLinkLwFpNextDump = 0x8FB60018; + // Live ab51f6e: lw $s6,24($sp) at + // 0x8003F7D0 sp/dest in 0x9A. + // Continue-skip; leave $s6. Do + // not invent 0x9A02. Next + // 0x8003F7D4 lw $s5,28($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS6Next = 0x8003F7D4; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS6NextDump = 0x8FB5001C; + // Live 417729e: lw $s5,28($sp) at + // 0x8003F7D4 sp/dest in 0x9A. + // Continue-skip; leave $s5. Do + // not invent 0x9A02. Next + // 0x8003F7D8 lw $s4,32($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS5Next = 0x8003F7D8; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS5NextDump = 0x8FB40020; + // Live fac4e01: lw $s4,32($sp) at + // 0x8003F7D8 sp/dest in 0x9A. + // Continue-skip; leave $s4. Do + // not invent 0x9A02. Next + // 0x8003F7DC lw $s3,36($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS4Next = 0x8003F7DC; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS4NextDump = 0x8FB30024; + // Live c9b2f7a: lw $s3,36($sp) at + // 0x8003F7DC sp/dest in 0x9A. + // Continue-skip; leave $s3. Do + // not invent 0x9A02 / 0x9F. Next + // 0x8003F7E0 lw $s2,40($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS3Next = 0x8003F7E0; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS3NextDump = 0x8FB20028; + // Live 8533465: lw $s2,40($sp) at + // 0x8003F7E0 sp/dest in 0x9A. + // Continue-skip; leave $s2. Do + // not invent 0x9A02 / 0x9F. Next + // 0x8003F7E4 lw $s1,44($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS2Next = 0x8003F7E4; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS2NextDump = 0x8FB1002C; + // Live e18b007: lw $s1,44($sp) at + // 0x8003F7E4 sp/dest in 0x9A. + // Continue-skip; leave $s1. Do + // not invent 0x9A02 / 0x9F. Next + // 0x8003F7E8 lw $s0,48($sp) — + // observe only. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS1Next = 0x8003F7E8; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS1NextDump = 0x8FB00030; + // Live d5e2773: lw $s0,48($sp) at + // 0x8003F7E8 sp/dest in 0x9A. + // Continue-skip; leave $s0. Do + // not invent 0x9A02 / 0x9F. Next + // 0x8003F7EC lw $ra,52($sp) — + // observe only. Never MUL. + // Never SPECIAL 0x16 as MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkLwS0Next = 0x8003F7EC; + public const uint CoredllDllMainExn15C28OuterJalLinkLwS0NextDump = 0x8FBF0034; + // Live ceee1bd: lw $ra,52($sp) at + // 0x8003F7EC sp/dest in 0x9A. + // Continue-skip; leave $ra. Do + // not invent stack return / + // 0x9A02 / 0x9F. Next 0x8003F7F0 + // addiu $sp,$sp,56 — observe + // only. Never MUL. Never jr hop. + public const uint CoredllDllMainExn15C28OuterJalLinkLwRaNext = 0x8003F7F0; + public const uint CoredllDllMainExn15C28OuterJalLinkLwRaNextDump = 0x27BD0038; + // Live e466bce: addiu $sp,$sp,56 + // at 0x8003F7F0. Exec dump addiu + // even if $sp stays 0x9A (ALU + // write only; no 0x9A page). + // Next 0x8003F7F4 jr $ra — + // observe only. Never jr hop. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext = 0x8003F7F4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump = 0x03E00008; + // Live 9fc60b8: jr $ra at + // 0x8003F7F4 named only. $ra is + // still outer link 0x8003F78C + // (lw-ra skipped). Do not jr hop. + // Delay 0x8003F7F8 sw $t5,0($v0) + // dest 0xFFFFDB58 — dest-miss + // skip; leave $t5. Next + // 0x8003F7FC lui $v0,0x8032 — + // observe only. Never invent + // *0xFFFFDB58 / SUD / $ra. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiJrDelay = 0x8003F7F8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiJrDelayDump = 0xAC4D0000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiJrNext = 0x8003F7FC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump = 0x3C028032; + // Live 166818f: lui $v0,0x8032 at + // 0x8003F7FC exec ($v0:=0x80320000). + // Next 0x8003F800 addiu $v0,$v0,588 + // named only. Exec dump addiu + // (ALU $v0:=0x8032024C). Next + // 0x8003F804 addiu $v1,$zero,-9448 + // — observe only (ALU-safe; do + // not invent 0xFFFFDB18 / SUD). + // Never jr hop 0x8003F78C. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiLuiNext = 0x8003F800; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump = 0x2442024C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext = 0x8003F804; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump = 0x2403DB18; + // Live 02dffcd: addiu $v1,$zero,-9448 + // at 0x8003F804 named only. Exec + // dump addiu (ALU $v1:=0xFFFFDB18). + // Next 0x8003F808 sw $v0,0($v1) — + // observe only (dest-miss; do not + // invent 0xFFFFDB18 / SUD / KData). + // Never jr hop 0x8003F78C. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext = 0x8003F808; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump = 0xAC620000; + // Live 7b548eb: sw $v0,0($v1) at + // 0x8003F808 named only. Dest + // 0xFFFFDB18 — dest-miss skip; + // leave $v0 / $v1. Next + // 0x8003F80C — observe only + // (peek dump; do not invent + // next word / 0xFFFFDB18 / + // SUD / KData). Never jr hop + // 0x8003F78C. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiSwNext = 0x8003F80C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiSwNextDump = 0x3C078034; + // Live 475ffcb: lui $a3,0x8034 at + // 0x8003F80C named only. Exec + // dump lui (ALU $a3:=0x80340000). + // Next 0x8003F810 lhu $v1,0($v0) + // — observe only (load; do not + // invent 0x8032 page / dest). + // Never jr hop 0x8003F78C. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext = 0x8003F810; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump = 0x94430000; + // Live dcf9658: lhu $v1,0($v0) at + // 0x8003F810 named only. Dest + // ~0x8032024C — dest-miss skip + // if peek fails; leave $v1. + // Next 0x8003F814 — observe + // only (peek dump; do not + // invent next word / 0x8032 + // page). Never jr hop + // 0x8003F78C. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiLhuNext = 0x8003F814; + // Live 5142c73: addiu $a2,$a3,-908 + // at 0x8003F814 named only. Exec + // dump addiu (ALU $a2:=0x8033FC74 + // from $a3=0x80340000). Next + // 0x8003F818 addiu $a1,$v0,160 — + // observe only (ALU-safe; name + // only). Then 0x8003F81C + // sw $v1,0($a2) — dest-miss skip; + // NEVER write SUD 0xFFFFFC74. + // Never jr hop 0x8003F78C. + // Never MUL. Do not invent + // 0x8033 page / SUD / 0x9A02 / + // 0x99FF. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiLhuNextDump = 0x24E6FC74; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext = 0x8003F818; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump = 0x244500A0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA2Sw = 0x8003F81C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump = 0xACC30000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext = 0x8003F820; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump = 0x94470000; + // Live e73cf23: addiu $a1,$v0,160 + // at 0x8003F818 named only. Exec + // dump addiu (ALU $a1:=0x803202EC + // from $v0=0x8032024C). Do not + // leave 0x8003F81C / 0x8003F820 + // until $a1 written. Then + // 0x8003F820 lhu $a3,0($v0) — + // live mapped peek dest + // 0x8032024C; unbacked $a3:=0. + // Next 0x8003F824 observe only. + // NEVER write SUD 0xFFFFFC74. + // Never jr hop 0x8003F78C. + // Never MUL. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext = 0x8003F824; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNextDump = 0x00E3202B; + // Live 479eba6: sltu $a0,$a3,$v1 + // at 0x8003F824 named only. Exec + // dump sltu (ALU compare; equal + // $a3=$v1=0x1E8 → $a0:=0). Next + // 0x8003F828 observe only (beq). + // Never jr hop 0x8003F78C. + // Never MUL. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF / *0xFFFFFC74. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiSltuNext = 0x8003F828; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump = 0x10800002; + // Live 9973a3b: beq $a0,$zero,+2 + // at 0x8003F828 named only. + // $a0==0 → taken dest + // 0x8003F828+4+(2<<2)=0x8003F834 + // (dump addiu $v0,$v0,20). Delay + // 0x8003F82C dump nop. Fall + // 0x8003F830 or $v1,$a3,$0 only + // if $a0!=0. Never hop MULT + // 0x8003F748 / jr 0x8003F78C. + // Never MUL. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF / *0xFFFFFC74. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqDelay = 0x8003F82C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqDelayDump = 0x00000000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqFall = 0x8003F830; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqFallDump = 0x00E01825; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken = 0x8003F834; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump = 0x24420014; + // Live db9d12b: addiu $v0,$v0,20 + // at 0x8003F834 named only. Exec + // dump addiu (ALU $v0:=0x80320260 + // from $v0=0x8032024C). Next + // 0x8003F838 observe only (slt + // $t0,$v0,$a1). Never jr hop + // 0x8003F78C. Never hop MULT + // 0x8003F748. Never MUL. Do not + // invent 0x8032 / 0x8033 page / + // SUD / 0x9A02 / 0x99FF / + // *0xFFFFFC74. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext = 0x8003F838; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump = 0x0045402A; + // Live 71d9731: slt $t0,$v0,$a1 + // at 0x8003F838 named only. Exec + // dump slt (signed ALU compare; + // $v0=0x80320260 < $a1=0x803202EC + // → $t0:=1). Next 0x8003F83C + // observe only (bne $t0,$0,-8). + // Never jr hop 0x8003F78C. Never + // hop MULT 0x8003F748. Never MUL. + // Do not invent 0x8032 / 0x8033 + // page / SUD / 0x9A02 / 0x99FF / + // *0xFFFFFC74. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext = 0x8003F83C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump = 0x1500FFF8; + // Live 721c102: bne $t0,$zero,-8 + // at 0x8003F83C named only. + // $t0!=0 → taken 0x8003F820 + // (re-enter lhu scan; rewind + // lhu/sltu/beq/addiu/slt so they + // re-fire). $t0==0 → fall + // 0x8003F844. Delay 0x8003F840 + // dump nop. Never jr hop + // 0x8003F78C. Never hop MULT + // 0x8003F748. Never MUL. Do not + // invent 0x8032 / 0x8033 page / + // SUD / 0x9A02 / 0x99FF / + // *0xFFFFFC74 / *0xFFFFDB58. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelay = 0x8003F840; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelayDump = 0x00000000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall = 0x8003F844; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump = 0x2409DB58; + // Live 75d1028: addiu $t1,$0,-10920 + // at 0x8003F844 named only. Exec + // dump addiu (ALU $t1:=0xFFFFDB58 + // from $0). Next 0x8003F848 + // observe only — peek dump, do + // not invent next word / + // *0xFFFFDB58. Never jr hop + // 0x8003F78C. Never hop MULT + // 0x8003F748. Never MUL. Do not + // invent 0x8032 / 0x8033 page / + // SUD / 0x9A02 / 0x99FF / + // *0xFFFFFC74 / *0xFFFFDB58 / + // KData. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext = 0x8003F848; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNextDump = 0xACC30000; + // Live d77479b: sw $v1,0($a2) at + // 0x8003F848 named only. Same + // dest family as 0x8003F81C + // (0x8033FC74). Dest-miss skip; + // leave $v1/$a2/$t1. NEVER write + // / invent 0x8033 page / SUD / + // *0xFFFFDB58 / 0x9A02 / 0x99FF. + // Next 0x8003F84C observe only + // (dump jr $ra; do not hop + // 0x8003F78C). Never hop MULT + // 0x8003F748. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext = 0x8003F84C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNextDump = 0x03E00008; + // Live f438996: jr $ra at + // 0x8003F84C named only. $ra is + // still outer link 0x8003F78C + // (lw-ra skipped). Do not jr hop. + // Next 0x8003F850 delay observe + // only — peek dump, do not invent + // delay word / dest / *0xFFFFDB58. + // Never hop MULT 0x8003F748. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay = 0x8003F850; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelayDump = 0xAD200000; + // Live f438996: delay sw $zero,0($t1) + // dest $t1=0xFFFFDB58 — dest-miss + // skip; NEVER write / invent + // *0xFFFFDB58 / SUD. Next + // 0x8003F854 observe only (dump + // addiu $sp,$sp,-48; do not exec + // / invent 0x9A frame). Never jr + // hop 0x8003F78C. Never hop MULT + // 0x8003F748. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext = 0x8003F854; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump = 0x27BDFFD0; + // Live c4c77e1: addiu $sp,$sp,-48 + // at 0x8003F854 named only. Exec + // dump addiu (ALU $sp:=$sp-48; + // $sp may stay 0x9A — ALU write + // only; do not invent 0x9A page). + // Next 0x8003F858 observe only — + // peek dump, do not invent next + // word. Never jr hop 0x8003F78C. + // Never hop MULT 0x8003F748. + // Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext = 0x8003F858; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNextDump = 0xAFBF0028; + // Live 89f8975: sw $ra,40($sp) at + // 0x8003F858 named only. Dest + // $sp+40=0x9A023EA0 — 0x9A02 + // dest-miss skip; NEVER write / + // invent 0x9A page. Leave $ra/ + // $sp. Next 0x8003F85C observe + // only — peek dump, do not invent + // next word. Never jr hop + // 0x8003F78C. Never hop MULT + // 0x8003F748. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext = 0x8003F85C; + // Live 1099cb8: prologue sw $fp/ + // $s7/$s6/$s5/$s4/$s3 at + // 0x8003F85C–0x8003F870 named + // only. Dest $sp+16..36 are + // 0x9A02 — dest-miss skip; + // NEVER write / invent 0x9A page. + // Leave regs. Next 0x8003F874 + // dump jal 0x80014F30 + delay + // or $fp,$a0. Never jr hop + // 0x8003F78C. Never hop MULT + // 0x8003F748. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw = 0x8003F85C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSwDump = 0xAFBE0010; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw2 = 0x8003F860; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw2Dump = 0xAFB70014; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw3 = 0x8003F864; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw3Dump = 0xAFB60018; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw4 = 0x8003F868; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw4Dump = 0xAFB5001C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw5 = 0x8003F86C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw5Dump = 0xAFB40020; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw6 = 0x8003F870; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw6Dump = 0xAFB30024; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal = 0x8003F874; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDump = 0x0C0053CC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelay = 0x8003F878; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelayDump = 0x0080F025; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa = 0x8003F87C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest = 0x80014F30; + // Live 5f426bf: trampoline at + // 0x80014F30 named lui $t0,0x8001. + // Exec dump-true lui/addiu/jr $t0 + // + nop → 0x80014F40; mtc0 $0,$12; + // nop; jr $ra ($ra=0x8003F87C) + + // nop. Dump-true hop to trampoline + // body — NOT stale-ra hop + // 0x8003F78C. Do not invent KSEG / + // 0x9A / SUD. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineDump = 0x3C088001; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiu = 0x80014F34; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiuDump = 0x25084F40; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJr = 0x80014F38; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrDump = 0x01000008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrDelay = 0x80014F3C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0 = 0x80014F40; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0Dump = 0x40806000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineNop = 0x80014F44; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRa = 0x80014F48; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDump = 0x03E00008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDelay = 0x80014F4C; + // Live 6e264a7: after trampoline + // jr $ra, named lui $v0,0x8034 at + // 0x8003F87C. Exec dump-true + // lui/addiu $s7:=0x8033FC78; lw + // peek-or-zero (NO invent 0x8033 + // page); sltu $v0,$v1,$fp; bne + // + nop take/fall from ALU. + // Never invent 0x9A / 0x9F / SUD. + // Never MUL / jr hop 0x8003F78C. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetLuiDump = 0x3C028034; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetAddiu = 0x8003F880; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetAddiuDump = 0x2457FC78; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetLw = 0x8003F884; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetLwDump = 0x8EE30000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetSltu = 0x8003F888; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetSltuDump = 0x007E102B; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBne = 0x8003F88C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneDump = 0x1440000B; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneDelay = 0x8003F890; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall = 0x8003F894; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump = 0x3C028034; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken = 0x8003F8BC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDump = 0x0C0053C7; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetS7 = 0x8033FC78; + // Live 17ec945: after ret bne, + // first I-fetch named. Fall + // 0x8003F894 dump lui $v0,0x8034. + // Taken 0x8003F8BC dump jal + // 0x80014F1C. Exec fall ALU + // $v0:=0x80340000; PC:=0x8003F898 + // observe (do not invent next). + // Exec taken jal: delay peek 0/nop + // only (do not invent delay); + // $ra:=0x8003F8C4; PC:=0x80014F1C + // observe (do not invent callee + // word / dest pages). Never hop + // PC to 0x8003F888. Never MUL / + // jr hop 0x8003F78C. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext = 0x8003F898; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDelay = 0x8003F8C0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenRa = 0x8003F8C4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest = 0x80014F1C; + // Live 17ec945 FALL path map (dump + // VA 0x8003F800==file 0x2E85F). + // Function 0x8003F854–0x8003F960: + // INT-OFF, adjust 0x8033FC70/FC78 + // if room, INT-ON, else skip to + // epi. $fp=$a0=0 → sltu fall. + // 14F1C is INT-ON (lw *0xFFFFD890 + // / ori 1 / jr / mtc0 Status) — + // NOT a 14F30 hop stub. Then + // b 0x8003F93C epi; $v0:=$s5; + // skip 9A lw; skip jr $ra. + // Leave 0x8003F964. No invent. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddiuDump = 0x2442FC70; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallLw = 0x8003F89C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallLwDump = 0x8C550000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubu = 0x8003F8A0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubuDump = 0x007E1823; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallSw = 0x8003F8A4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallSwDump = 0xAEE30000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddu = 0x8003F8A8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallAdduDump = 0x02BE1821; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallJal = 0x8003F8AC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDump = 0x0C0053C7; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelay = 0x8003F8B0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelayDump = 0xAC430000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa = 0x8003F8B4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRaDump = 0x10000021; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallGotoDelay = 0x8003F8B8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi = 0x8003F93C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiDump = 0x02A01025; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLw = 0x8003F940; + // Dump-true 3F854 epi lw restores + // match prologue sw $fp/$s7-$s3/ + // $ra at +16..+40. 9A dest-miss + // skip; do not invent 0x9A. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwDump = 0x8FBE0010; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS7 = 0x8003F944; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS7Dump = 0x8FB70014; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS6 = 0x8003F948; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS6Dump = 0x8FB60018; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS5 = 0x8003F94C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS5Dump = 0x8FB5001C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS4 = 0x8003F950; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS4Dump = 0x8FB40020; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS3 = 0x8003F954; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS3Dump = 0x8FB30024; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwRa = 0x8003F958; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwRaDump = 0x8FBF0028; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJr = 0x8003F95C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDump = 0x03E00008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelay = 0x8003F960; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelayDump = 0x27BD0030; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallNextFn = 0x8003F964; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetFallV0 = 0x8033FC70; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnDump = 0x8C08D890; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnNop = 0x80014F20; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnOri = 0x80014F24; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnOriDump = 0x35080001; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnJr = 0x80014F28; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnJrDump = 0x03E00008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0 = 0x80014F2C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0Dump = 0x40886000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiIntOnKdata = 0xFFFFD890; + // Live 29a9913: FIRST-WIN FALL leave + // 0x8003F964 then 9A/99FF after-stk + // spam + TLBL at 0x800151A4 + // a0=0xBDFE5B4 ra=0x8003F998. + // Caller 0x8003F964–0x8003F9E4: + // skip 9A sw/lw; ALU index*20 + + // table 0x8032024C (NO invent); + // jal 0x80015198 delay a0:=s7+8 + // BEFORE body; list-pop peek-or- + // zero (empty → v0=0); skip + // re-enter 0x8003F854 (FALL + // already logged); skip 9A epi; + // jr $ra + delay addiu $sp,32; + // honor sane 0x800xxxxx ra + // (Boot 90d6470 live 0x8003F8B4) + // else leave 0x8003F9E8. No MUL + // 0x16. No hop 0x80048190 / + // 0x8003F78C. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCaller = 0x8003F964; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerDump = 0x27BDFFE0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRa = 0x8003F968; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRaDump = 0xAFBF0018; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFp = 0x8003F96C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFpDump = 0xAFBE0010; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7 = 0x8003F970; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7Dump = 0xAFB70014; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0 = 0x8003F974; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0Dump = 0x24020014; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNop = 0x8003F978; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMult = 0x8003F97C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMultDump = 0x00820018; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLui = 0x8003F980; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLuiDump = 0x3C028032; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiu = 0x8003F984; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiuDump = 0x2442024C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMflo = 0x8003F988; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMfloDump = 0x00001812; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddu = 0x8003F98C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAdduDump = 0x0062B821; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJal = 0x8003F990; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDump = 0x0C005466; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelay = 0x8003F994; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelayDump = 0x26E40008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRa = 0x8003F998; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRaDump = 0x0040F025; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne = 0x8003F99C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBneDump = 0x17C0000A; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBneDelay = 0x8003F9A0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenter = 0x8003F9A4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDump = 0x0C00FE15; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelay = 0x8003F9A8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelayDump = 0x96E40000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFp = 0x8003F9AC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFpDump = 0x0040F025; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2 = 0x8003F9B0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2Dump = 0x17C00003; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGoto = 0x8003F9B8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDump = 0x10000006; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelay = 0x8003F9BC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelayDump = 0x00001025; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16 = 0x8003F9C0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Dump = 0x0C01205D; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Delay = 0x8003F9C4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16DelayDump = 0x26E40010; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12 = 0x8003F9C8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Dump = 0x0C01205D; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Delay = 0x8003F9CC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12DelayDump = 0x26E4000C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0 = 0x8003F9D0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0Dump = 0x03C01025; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLw = 0x8003F9D4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLwDump = 0x8FBE0010; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJr = 0x8003F9E0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDump = 0x03E00008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelay = 0x8003F9E4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelayDump = 0x27BD0020; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn = 0x8003F9E8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnDump = 0x27BDFFE8; + // Live 749ad1b: after fat caller, + // first I-fetch at 0x8003F9E8 + // named addiu $sp,$sp,-24. Exec + // ALU $sp:=$sp-24. $sp may stay + // 0x9A (ALU only; do not invent + // 0x9A page). PC:=0x8003F9EC + // observe (do not invent next). + // Never hop 0x8003F888 / + // 0x8003F78C / 0x80048190 / + // MULT 0x8003F748. Never MUL 0x16. + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnNext = 0x8003F9EC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerTable = 0x8032024C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop = 0x80015198; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopDump = 0x3C088001; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2 = 0x8001519C; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2Dump = 0x250851A0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3 = 0x800151A0; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3Dump = 0x251B0018; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLw = 0x800151A4; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLwDump = 0x8C820000; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeq = 0x800151A8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeqDump = 0x10400003; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJr = 0x800151B8; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDump = 0x03E00008; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelay = 0x800151BC; + public const uint CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelayDump = 0x0000D825; + // Taken dest 0x8003F748 MULT + // $s4,$s2 (0x02920018). Next + // MFLO. Never hop. Never MUL. + public const uint CoredllDllMainExn15C28OuterJalLinkBeqTaken = 0x8003F748; + public const uint CoredllDllMainExn15C28OuterJalLinkBeqTakenDump = 0x02920018; + public const uint CoredllDllMainExn15C28JalRaEpiEnd = 0x80015CFC; + public const uint CoredllDllMainExn15C28JalRaEpiEndDump = 0x42000018; + public const uint CoredllDllMainExn15C28JalRaOr = 0x80015CC4; + public const uint CoredllDllMainExn15C28JalRaOrDump = 0x00441025; + // Live e7f0f37: left wrote=0 frame + // at 0x80015C30. Observe first + // I-fetch and first TLBL/TLBS + // after leave. AfterLog>=2 was + // swallowing the next miss. + // Do not invent dest / 0x9A02. + // Live f550bee: after dump-mem-jal-dest + // land 0x8004326C sw $a1,4($sp) + // (a1=0x80013440 sp=KData), TLBL + // epc=0x8004294C bad=0xA. Dump is + // lhu $v1,0($a1) (0x94A30000). + // rs=$a1 so VA=$a1. Do not invent + // page 0 / 0xA. Map only if dest + // peeks phys>=0x10000. Name once. + public const uint CoredllDllMainBadAEpc = 0x8004294C; + public const uint CoredllDllMainBadADump = 0x94A30000; + public const uint CoredllDllMainBadABad = 0xA; + public const uint CoredllDllMainBadAPrev = 0xAFB00058; + public const uint CoredllDllMainBadANext = 0x0080B825; + // Live 4bd64a2: after dest land, + // lhu $v1,0($a1) a1=0xA ra=0x80043254. + // Dump 0x80043244 is or $a1,$a0,$0 + // (0x00802825). Caller jal 0x80042920 + // at 0x8004324C delay or $a0,$fp,$0. + // Dest jal delay addiu $a0,$v0,13292 + // logged a0=0x800133EC (GISB Timeout + // WCHAR). Then beq $v1,$0,+506 at + // 0x80042960 (0x106001FA) empty path. + // Prefer restore dest $a0 into $a1. + // Skip-zero only if dest $a0 cannot + // peek. Do not invent page 0 / 0xA. + public const uint CoredllDllMainBadAOrA1Pc = 0x80043244; + public const uint CoredllDllMainBadAOrA1Dump = 0x00802825; + public const uint CoredllDllMainBadABeqPc = 0x80042960; + public const uint CoredllDllMainBadABeqDump = 0x106001FA; + public const uint CoredllDllMainBadACallerRa = 0x80043254; + public const uint CoredllDllMainBadADestA0 = 0x800133EC; + // Dump after or $a1,$a0: addiu $a3,$0,384 + // then jal 0x80042920 (0x0C010A48) + // delay or $a0,$fp (0x03C02025). + // Boot 8cae3af then list-insert + // sw at 0x800151D0. Tip ProgressLeave + // yank / e000 kseg-busy aborted + // that next. Dump-true continue only. + public const uint CoredllDllMainBadAAddiuPc = 0x80043248; + public const uint CoredllDllMainBadAAddiuDump = 0x24070180; + public const uint CoredllDllMainBadAJalPc = 0x8004324C; + public const uint CoredllDllMainBadAJalDump = 0x0C010A48; + public const uint CoredllDllMainBadAJalDest = 0x80042920; + public const uint CoredllDllMainBadAJalDelayDump = 0x03C02025; + // Dump wrapper after jal 0x80042920: + // jal 0x800423F0 delay or $a0,$fp + // then lw $fp/$ra / jr $ra / + // addiu $sp,+24. Callee epi + // 0x8004314C. List-insert + // 0x800151C0 sw at 0x800151D0. + public const uint CoredllDllMainBadASecondJalPc = 0x80043254; + public const uint CoredllDllMainBadASecondJalDump = 0x0C0108FC; + public const uint CoredllDllMainBadASecondJalDest = 0x800423F0; + public const uint CoredllDllMainBadASecondJalDelayDump = 0x03C02025; + public const uint CoredllDllMainBadAWrapperEpi = 0x8004325C; + public const uint CoredllDllMainBadACalleeEpi = 0x8004314C; + public const uint CoredllDllMainBadAListInsert = 0x800151C0; + public const uint CoredllDllMainBadAWrapperCallerRa = 0x8004328C; + // Live f628fa6: after sb-jalr-skip, TLBL + // epc=0x80341A74 bad=0x7EB8. epc!=bad so + // data load at jalr dest, not I-fetch + // (kseg0 execute already worked). 0x7EB8 + // is t9=0x80057EB8 low 16. Map useg + // 0x7EB8→0x80007EB8 only if dest rs=$0 + // and that kseg0 word peeks. Map + // 0x7EB8→0x80057EB8 only if dest rs=$t9 + // and that t9 word peeks. Do not invent + // E000/F000. Do not leftover-hop. + public const uint CoredllDllMainJalrDest = 0x80341A74; + public const uint CoredllDllMainJalrBad = 0x7EB8; + public const uint CoredllDllMainJalrPage = 0x7000; + // Live fe1650b: jalr-7eb8 map via=kseg0 + // dest-word=0x80057EB8 dis=lb a1,32440(0) + // then TLBL epc=0x80341BE0 bad=0x1DB0. + // Same class: useg abs load (epc!=bad). + // epc is sec0 / 0x80341BE0. Map + // 0x1DB0→0x80001DB0 only if dest rs=$0 + // and that kseg0 word peeks. Map + // 0x1DB0→t9 page only if dest rs=$t9. + // After jalr-7eb8 only. Do not invent + // E000/F000. Do not leftover-hop. + public const uint CoredllDllMainJalrDest2 = 0x80341BE0; + public const uint CoredllDllMainJalrBad2 = 0x1DB0; + public const uint CoredllDllMainJalrPage2 = 0x1000; + // Live 5a06a4f: jalr-1db0 map via=kseg0 + // dest-word=0x80011DB0 dis=lb at,7600(0) + // then via=exn cause=10 epc=0x803426A4 + // bad=0x0. ExcCode 10 = RI, not TLB. + // Peek word at epc and epc-4 (fetch + // saves PC+4). Decode only. Do not + // invent an opcode / E000/F000 / + // leftover-hop / cache hierarchy. + public const uint CoredllDllMainRiEpc = 0x803426A4; + // Live 8c5855f: word=0x03C18016 + // SPECIAL rs=$fp rt=$at rd=$s0 + // sa=0 funct=0x16. Reserved / + // vendor-specific — NOT SPECIAL2 + // opcode 0x1C funct 0x02 MUL. + // e2d5b1c MUL implement retracted. + // prev=0xC4000000 next=0xC4002000 + // (data-like LWC1 encoding). ra= + // 0x8002F234 jalr return (after + // delay of jalr $v0). Not a dump- + // true no-op helper. Do not MUL. + // Do not ri-nop. Do not leftover-hop. + public const uint CoredllDllMainRiInsn = 0x03C18016; + public const uint CoredllDllMainRiRa = 0x8002F234; + // Live 5efd98e: s2=0xFFFFDAC0 ThreadPtr + // (caller lw $v1,0($s2) after return). + // s0=0x86FBE028 kseg RAM (0x86FB8000 + // proc-info class). fp=0x3140C useg. + // at=0 — SPECIAL rs=$fp rt=$at cannot + // be MUL (product 0) and is not a + // dump-true MMU/ASE no-op. Peek *s2 + // *s0 *fp. Do not MUL. Do not ri-nop. + public const uint CoredllDllMainRiS0Live = 0x86FBE028; + public const uint CoredllDllMainRiFpLive = 0x3140C; + // Live ee912b8: *s2==s0=0x86FBE028 + // (ThreadPtr → same THREAD). *s0=0x40 + // first word. *fp-miss (useg 0x31000; + // kseg0 0x8003140C is NK text, not + // that object — do not map). prev8=0 + // next8=0xC4002000 data stream. Caller + // lw $v1,0($s2) needs *s2 left as that + // PTHREAD (already). SPECIAL/0x16 is + // I-fetch in dest data, not a helper. + // Do not MUL. Do not ri-nop. + public const uint CoredllDllMainRiThrW0 = 0x40; + // 0x8001521C ori k1, epc, 0xFFFC / addiu 2 / beq + // syscall. 0xFFFFF3DA is coredll 0x80095A98 + // addiu $v0, $0, -3110 / jalr $v0. Same class as + // SetFilePointer 0xFFFFDFEE. Not KData. Not a slot. + public const uint KDataNest = 0xFFFFD885; + public const uint ExeVbase = 0x00010000; + public const uint ProcModule = 0x50; + public const uint ProcSlot = 0x0C; + public const uint ProcTable = 0x80340040; + public const uint ProcSize = 0xD0; + public const uint ThreadPtr = 0xFFFFDAC0; + public const uint ThreadLastErr = 56; + public const uint ThreadStack = 0x24; + // Dump 0x800158C8 lw $t2,44($t3) then + // 0x800158CC sw $t2,36($t3) and + // 0x800158DC addiu $sp,$t2,-48. +0x2C is + // the implicit-API stack cookie. + // 0x80030210 sw $v0,44($fp) writes + // (ThreadStack&0xFFFF)+$s0 there. + // Live fb58a7e: that word plus -48 is + // 0xC201FE88 (slot97 image-low). + public const uint ThreadStackAlt = 0x2C; + // Dump 0x800399A4 lw $s3,-688($v0) with + // $v0=0x80340000, then 0x800399E8 + // or $v0,$s3. leftover 0x800159B4 + // or $ra,$v0; 0x80015A08 mtc0 $t4,$14. + // That word is the 0x800397B0 resume + // plant (wait99: -1 → EPC 0xFFFFFFFF). + // Dump 0x800399A4 lw $s3,-688; branches to + // 0x800399A8 skip that load so $s3 stays + // stale. 0x800399E8 or $v0,$s3 returns it. + // Sole ROM store 0x800370F8 is a GetProc + // delay-slot (jal 0x8001C468 a1=6), not a + // per-exception EPC. Live f66919d: plant + // still -1 after adel-pc gone; leftover + // dest hop then Code-10 spin. Replay + // thread+0xEC or refuse leftover ERET. + public const uint ExnContinueWord = 0x8033FD50; + public const uint LeftoverDestLo = 0x03F6C000; + public const uint LeftoverDestHi = 0x03F80000; + // leftover dest VA - LeftoverDestLo + this = dest + // kseg. Live 0x03F70830 → 0x80088830 jr-delay + // of leftover-syscall -938; 0x03F71EBC → + // 0x80089EBC jalr-delay of dest thunk + // (jalr+8 0x80089EC0); 0x03F71618 / + // 0x03F71740 → dest mid-hash (and/addu), + // not jalr+8; 0x03F74844 → 0x8008C844 + // GetProc. Do not leftover hop. + public const uint LeftoverDestKseg = 0x80084000; + // Live 8d10132: plant-fix +EC=0x800382F8 + // +DC=0x8003B05C hung LoadO32. Dump: + // 0x8003B054 jal 0x80038294 (handle + // lookup); +EC is mid that callee + // (beq $t5,$0); +DC is the jal return + // (bne $v0,$0). Replay +EC with $ra= + // +EC then jr $ra loops. Poison mid. + // Do not leftover hop. Do not invent dest. + public const uint HandleLookupJal = 0x80038294; + public const uint HandleLookupEnd = 0x80038340; + public const uint HandleLookupRet = 0x8003B04C; + public const uint HandleLookupRetEnd = 0x8003B080; + // Live 1f83cb1 plant-fix +EC=0x80059420 + // +DC=0x800301E0 then silent freeze. + // Dump 0x800301D8 jal 0x800593F0 + // (memset); +EC is mid that callee + // (blez $t1); +DC is the jal return + // (lw $v0,36($fp)). Replay +EC then + // jr $ra loops. Poison mid. Refuse + // plant-fix. Do not leftover hop. + public const uint MemsetJal = 0x800593F0; + public const uint MemsetEnd = 0x80059588; + public const uint O32Compressed = 0x4000; + // ExtraROM o32[0] 0x60002020: 0x2000 lets CopyO32 accept + // unaligned dataptr 0x80764CE0. MapO32 still VirtualCopys + // those bytes as XIP unless 0x2000 is cleared on the lite. + public const uint O32RomXip = 0x2000; + public const uint O32Writable = 0x80000000; // 0x8001F12C andi s4, 0x8000 / beq skip CallDLL a1=1. // User-mode LoadLibrary keeps s4=0 (same for CEDDK/HAL/ // filter). coredll 0x03F73050 then walks 3 new modules @@ -47,14 +2767,87 @@ public static class CeRomTocFiles public const uint CallDllFlag = 0x8000; public const uint ModuleStartip = 0x5C; public const uint ModuleFileObj = 96; + // Live e65e45c leftover-wait99-o32-nk-chain + // name=osaxst0.dll startip=0x80061CA0 + // via=calldll/entry (MODULE+8). Not + // coredll. Do not leftover-hop this VA. + public const uint ChainCallVaLive = 0x80061CA0; public const uint CurProc = 0xFFFFDAC4; public const uint EcecTocPtr = 0x80010044; + public const uint RomHdrListPtr = 0x80342B10; + public const uint RomHdrSrcChain = 0x803429C8; + public const uint RomHdrWalk = 0x80016AFC; + public const uint RomHdrLink = 0x8001728C; + public const uint RomHdrLinkJal = 0x80014420; + public const uint RomHdrLinkJalStatus = 0x8001442C; + public const uint RomHdrSrcChainLw = 0x800172B8; + public const uint RomHdrLinkPublish = 0x80017308; + public const uint RomHdrLinkSplice = 0x8001731C; + // Dump 0x8001728C: addiu $sp,-248 + // then 10× prologue sw. Empty + // *0x803429C8 beq → 0x8001730C + // then beq $a3,$0 → 0x8001732C + // jal 0x80041AC4. Do not invent + // a ROMChain_t. + public const uint RomHdrLinkAddiuDump = 0x27BDFF08; + public const uint RomHdrLinkEmptyBeq = 0x8001730C; + public const uint RomHdrLinkJalNext = 0x8001732C; + public const uint ExtraRomDumpHdr = 0x8134DA84; + public const uint NkDumpHdr = 0x802808B4; + public const uint NkRomHdrPtr = 0x8001101C; + public const uint RomHdrCopyEntries = 0x20; + public const uint RomHdrCopyOffset = 0x24; + public const uint RomHdrExtensions = 0x48; + public const uint NkPExtensions = 0x80011020; + public const uint NkCopy0Src = 0x8021F8EC; + public const uint NkCopy0Dst = 0x80320000; + public const uint NkCopy0CopyLen = 0x5A4; + public const uint NkCopy0DestLen = 0x22C88; + public const uint RomHdrListBssOff = 0x22B10; + public const uint CreateFileMappingObj6 = 0x8001D4F0; + public const uint RomHdrListLoad0 = 0x80016B1C; + public const uint RomHdrListLoad1 = 0x8001B670; + public const uint RomHdrListLoad2 = 0x80022BEC; + public const uint RomHdrListLoad3 = 0x80036F6C; + public const uint RomHdrListLoad4 = 0x800458E8; + public const uint RomHdrListLoad5 = 0x80045C74; public const uint RomHdrNumMods = 0x10; + public const uint RomHdrNumFiles = 0x30; public const uint TocFirst = 0x54; public const uint TocEntrySize = 32; + public const uint FilesEntrySize = 28; + public const uint FilesRealSize = 0x0C; + public const uint FilesCompSize = 0x10; + public const uint FilesNameOff = 0x14; + public const uint FilesLoadOff = 0x18; public const byte TocAttachType = 7; + // CreateFile success stores 8 (file handle). LoadE32 + // (type&2)==0 then SetFilePointer/ReadFile and checks + // PE 0x4550. Type 7 reads entry+0x14 as e32 (wait55 193). + public const byte FileAttachType = 8; + public const uint KernelReadFile = 0x8003D7E0; + public const uint KernelCreateFileMapping = 0x8003DA64; + // jalr -8210 is SetFilePointer (a1=dist, a3=method). + public const uint Win32SetFilePointer = 0xFFFFDFEE; + // Scratch for FILE[25] CEDecompressROM. Not ExtraROM + // tail and not a dump 0x81360000 map. + public const uint Tv2FileDest = 0x8F140000; + public const uint Tv2FileSrcAlign = 0x8F030000; + // Scratch for ExtraROM FILE OpenFile after FILE[25]. + // FILE[11] 932864/356579 and FILE[26] 6398464/2612926. + // After VallocHostKsegLim. FILE[25] dest stays + // Tv2FileDest (5120). Not ExtraROM tail and not a + // dump 0x81360000 map. + public const uint ExtraRomFileDest = 0x8F400000; + public const uint ExtraRomFileSrc = 0x8FC00000; + public const uint ExtraRomFileCacheMax = 0x400000; + public const uint ExtraRomFileDestMax = 0x800000; + public const int ExtraRomFileMax = 48; public const uint O32RomSize = 0x18; public const uint O32LiteSize = 0x1C; + // Public CE: e32_rom is 0x24, then o32_rom[objcnt]. + // Host dump e32 then dump o32 after that copy. Do not + // pack o32 at +0x5C (that was leftover CurMSec a1). // coredll 0x03F7A960 bne v0,0 / delay sw v0, (0x01FFFFA0). // HeapCreate(0,0,0) returned 0 in device.exe and the delay // slot wrote that 0 over the heap filesys already stored. @@ -62,6 +2855,322 @@ public static class CeRomTocFiles // LocalAlloc call HeapAlloc(0) and RegOpen returns 14. public const uint HeapCreateStore = 0x03F7A964; public const uint ProcessHeapPtr = 0x01FFFFA0; + // Live edf15b0: after IAT stores=24, TLBL cause=2 + // epc=0x03F6C908 lw $v0,0($s5). $s5==BadVAddr== + // 0x01FFFCA4. Same page as *0x01FFFFA0 / wait96. + public const uint ProcessInfoPage = 0x01FFF000; + public const uint ProcessInfoFaultVa = 0x01FFFCA4; + // Live 6b8a9eb: after DllMain, I-fetch TLBL + // epc==badvaddr==0x0005D2E0. In-tree gwes + // Display 0x0005D250 (GwesVaDispAlloc) is the + // same page. Not COREDLL RVA 0x5D2E0 — do not + // invent 0x03FAD2E0. + public const uint GwesDispFetchPage = 0x0005D000; + public const uint GwesDispFetchFault = 0x0005D2E0; + // Live 4f43fe4: after gwes-disp fetch map, data + // TLBL epc=0x0005D310 badvaddr=0x000B6008. + // In-tree GwesIatGetProc. v0=0x000B0000 is the + // gwes IAT/data region. Same image as vbase + // 0x00010000 / vsize 0xBB000. Do not invent dest. + public const uint GwesDispDataPage = 0x000B6000; + public const uint GwesDispDataFault = 0x000B6008; + // Live 8623be5: after IAT data map, NK 0x80020174 + // (near ThreadContextSetup 0x80020BE4) data-TLBL + // badvaddr=0x00011C10. Same page as gwes VA + // 0x00011000 (GwesRomText) and FILESYS API table + // 0x000111A8. Do not invent dest / sipcfg dest. + public const uint GwesTextBasePage = 0x00011000; + public const uint GwesTextBaseFault = 0x00011C10; + // Live 04b8c34: after gwes-text map, Display + // 0x0005D380 data-TLBL badvaddr=0x000B7CA8. + // Same gwes data region as v0=0x000B0000 / + // GwesInitFlag 0x000B7A1D (page 0x000B7000). + // Adjacent to mapped IAT 0x000B6000. Do not + // invent dest. + public const uint GwesDispData2Page = 0x000B7000; + public const uint GwesDispData2Fault = 0x000B7CA8; + // Live 5db4c8e: after data2 map, Display 0x0005D38C + // data-TLBL badvaddr=0x000BA954. In-tree GwesDispObj + // (LocalAlloc 584 result). Page 0x000BA000 is still + // in gwes image (vbase 0x00010000 / vsize 0xBB000). + // Skipped B8000/B9000 - not an adjacent walk. v0=0 + // (unlike prior 0x000B0000 IAT base). Do not invent + // dest. + public const uint GwesDispData3Page = 0x000BA000; + public const uint GwesDispData3Fault = 0x000BA954; + // Live c36c2a4: after data3 map, I-fetch TLBL + // epc==badvaddr==0x00014B3C. Next gwes .text page + // after 0x00011000 (ROM 0x80149B3C = GwesRomText + + // 0x3B3C). Before WinMain 0x00016014 / entry + // 0x000163C8. Skipped 0x00012000/0x00013000 - not + // a successive adjacent walk. v0=0x000E1700 is + // leftover GwesDispObj dest-word. Do not invent + // dest or steal tv2 PE 0x00014000. + public const uint GwesText2Page = 0x00014000; + public const uint GwesText2Fault = 0x00014B3C; + // Live 831a196: o32-rom .text live (0x00026000 + // → 0x8015B000). Next data-TLBL epc=0x00026130 + // badvaddr=0x00010004 v0=0x00010000 + // a1=0x00011918 stores=24. TOC[7] ImageBase + // 0x00010000 is headers / pre-.text. .text + // realaddr starts 0x00011000 / dataptr + // 0x80146000. Slot 0 page is shared with + // filesys — TOC gwes dest only. Do not invent + // PE bytes. Do not invent SharedUserData. + public const uint GwesImageBasePage = 0x00010000; + public const uint GwesImageBaseFault = 0x00010004; + // Live 187f5be: I-fetch TLBL 0x000B4B80 (page + // 0x000B4000). Same page as jal 0x000B4D20 + // (IAT LocalAlloc thunk 0x000B60D0). Same miss + // class as prior gwes text/data pages. Image + // vbase 0x00010000 / vsize 0xBB000. Named pages + // keep their Hive tags; new pages demand-map + // via firmware PTE only. ImageBase headers + // are 0x00010000 (not this .text span). + // Do not invent dest. + public const uint GwesImageLo = 0x00011000; + public const uint GwesImageHi = 0x000CB000; + // Live 7214ee6: o32-sec correctly refused + // (TOC[7] o32[1] .data real 0x000B6000 vsize + // 0x50E4 psize 0xCF5 dataptr 0x802852C8 + // flags 0xC0002040 compressed; page-off 0x3000 + // >= psize). Naive 0x80288000 is invalid. + // Decompressed page is all-zero (0x000B9FF4=0). + // dest-word=0 is dump truth. 258ef59 won + // 0x000B9000→0x86F35000 dest-word=0 via + // firmware PTE. Do not invent XIP. Do not + // stretch .text. Do not hard-done pte-miss. + public const uint GwesDataB9Page = 0x000B9000; + public const uint GwesDataB9Fault = 0x000B9FF4; + // Live c0347e8: dest0 map won after a transient + // TLBL / BindImp-exn. Hive then froze while the + // host burned CPU. Do not consume BindImp-exn + // on that dest0 refill. One spin-observe if PC + // sticks after the map. Do not invent XIP. + // Live 98db5d5: 256K/16K never fired. Page + // changes reset the counter during the + // exception storm. Count total steps after + // the B9 map. Do not reset on page change. + public const int GwesDataB9SpinSame = 65536; + public const int GwesDataB9SpinVec = 4096; + // Live 98db5d5: after B9 dest0 + B9 skip, + // BindImp-exn cause=3 epc=0x00021ABC + // badvaddr=0 (TLBS store to null). Observe + // insn/rs/rt/base. Do not map VA 0. Do not + // invent SharedUserData / KData / dest. + public const uint GwesNullStoreEpc = 0x00021ABC; + // Live 73486bc: after 0x04021000→0x80115000, + // BindImp-exn cause=2 epc=0x80052010 + // badvaddr=0x50 a1=0x50 v0=0x74. Near-null + // TLBL. Observe insn/rs/rt/base. Do not + // map VA 0 / page 0. Do not invent + // SharedUserData / KData / dest. + public const uint NearNullTlblEpc = 0x80052010; + public const uint NearNullTlblVaddr = 0x00000050; + public const uint NearNullPageHi = 0x00001000; + // Live f3c2d62: after near-null observe, + // BindImp-exn cause=4 epc=badvaddr=0xFFFFFB2A + // (AdEL; 0xB2A unaligned). Observe only. + // Do not map 0xFFFFF000. Do not invent + // SharedUserData / KData / dest. FFFF* + // AdEL must not consume BindImp-exn. + public const uint FfffFb2aEpc = 0xFFFFFB2A; + public const uint FfffFb2aVaddr = 0xFFFFFB2A; + // Live 3ac5ed9: after 0x03FE1000 map, + // BindImp-exn cause=4 epc=badvaddr=0xC6FA7C9A + // (AdEL; 0x7C9A unaligned; not a module + // VA). Observe only. Do not map that VA. + // Do not invent dest. All AdEL / + // epc==badvaddr unaligned must not + // consume BindImp-exn. + public const uint AdelC6FaEpc = 0xC6FA7C9A; + public const uint AdelC6FaVaddr = 0xC6FA7C9A; + // Live 3275fe9: after adel-pc, BindImp-exn + // cause=3 epc=0x80031D38 badvaddr=0xC201FE84 + // a1=0x8033FE1C (nk ROM). Observe insn / + // rs / rt / base / formed. Do not invent + // dest for 0xC2xxxxxx. WalkFirmwarePte + // L1 ((va>>16)&0x1FF) aliases 0xC201xxxx + // to 0x0001xxxx — not a C2 PTE. Do not + // map. C2* TLBS does not consume + // BindImp-exn. + // Live 7827498: insn is sw ra,60(sp). Dump + // nk.exe 0x80031D34 is addiu $sp,-64 then + // that store (ThreadPtr 0xFFFFDAC0). Incoming + // $sp was 0xC201FE88. Slot 97 (NK.EXE) + + // 0x0001FE48 is image, not a thread stack. + // a1=0x8033FE1C is past B000FF end + // 0x8031B3BC (caller arg, not the C2 stack). + // Do not map 0xC201F000. Observe first C2 + // $sp. Do not invent dest. + public const uint C2TlbsEpc = 0x80031D38; + public const uint C2TlbsVaddr = 0xC201FE84; + public const uint C2VaPrefix = 0xC2000000; + public const uint C2TlbsFunc = 0x80031D34; + public const uint NkImageEnd = 0x8031B3BC; + // Live 155d918 / fb58a7e: first C2 $sp at + // 0x80015664. Dump: 0x80015660 lw $sp, + // 212($s0) (thread+0xD4). 0x8001563C lw + // $ra,220($s0) is 0x80030264 (saved $ra, + // not EPC). 0x8001566C lw $k0,236($s0) + // then ERET. +0xD4 writers: 0x80015264 + // sw $sp,212($t0) only when nest==1 + // (0xFFFFD885); nest!=1 takes 0x80015488 + // ($sp-248, not the thread). 0x80020BF4 + // ThreadContextSetup v0=a1+a2-256 → +0x24 + // / v1=v0-48 → +0xD4. 0x80030210 writes + // +0x2C; implicit-API 0x800158DC does + // $sp=+0x2C-48. 0xC201FE88 = slot97+ + // 0x1FE88 (image, not a stack). Adel-pc + // $sp was not C2 (nested). Replay that + // $sp into +0xD4 when +0xEC is a sane + // aligned NK PC. Else refuse ERET. Do + // not map 0xC201F000. Do not hop EPC + // to 0x80030264. Do not leftover/ERET2. + // Live 695e734: +EC=0x800373C0 is mid NK + // idle (dump: jal 0x80031D34 poll at + // 0x800373CC). After AdEL, COP0 EPC is + // still 0xC6FA7C9A at 0x80015664. sp-fix + // then ERET2 resumes that idle / re-AdEL. + // Refuse ERET while EPC is adel-pc poison. + // Live cf2477b: after sp-fix $sp is + // 0x040DFE80 (not C2). Live PeekEpc is + // already rewritten (plant / +EC idle). + // C2-$sp gate and live-EPC==C6FA both + // missed; zero epc-halt; silent CPU + // burn. Latch adel-pc EPC. Refuse ERET + // while that latch is set. Do not + // leftover hop. Do not invent dest. + // Live aa0b26c: epc-halt fired. This + // Boot +D4=0x040DFE60 (not C2). Poison + // is live EPC and +DC=0xC6FA7C9A. + // Dump leftover: 0x800159A8 jal + // 0x800397B0; 0x800159B4 or $ra,$v0; + // 0x800159CC or $t4,$ra; 0x80015A08 + // mtc0 $t4,$14 (wait99). Exception + // 0x800152CC sw $ra,220($s0) saves + // that $ra to +DC. +EC this Boot is + // 0x80015B9C (ExnAfterFetch2; aligned + // NK leftover mid, not adel resume). + // Replay +EC into COP0 EPC / +DC / $ra + // only when that is a sane aligned + // NK/useg PC, not leftover mid / idle. + // Clear latch only then. Do not leftover + // hop. Do not invent dest. + // Live 3b847b7: plant-clr first-win + // (+EC=0x80015B9C). Later C2 $sp + // 0xC201FE88; sp-fix +EC=0x800373C0 + // (dump: or $a3,$s0 then jal + // 0x80031D34 poll). Latch already + // clear; ERET2 idle; silent CPU burn + // (same as 695e734). Refuse ERET when + // +EC is that idle mid-poll. Do not + // leftover hop. Do not invent dest. + public const uint C2SpLoadPc = 0x80015660; + public const uint C2SpFirstPc = 0x80015664; + public const uint ThreadCtxEret = 0x8001568C; + public const uint NkIdleJal = 0x800373C0; + // Live ac46757 leftover-frame +5C= + // 0x800356FC. Dump: addiu $sp,-32 then + // jal 0x80031D34 (same idle poll as + // 0x800373CC). Thread startip, not a + // leftover resume. leftover-frame + // +18/v016=0; FD50/ra40 leftover dest. + // leftover-halt stays. Do not leftover + // hop. Do not invent dest. + public const uint NkIdleStart = 0x800356FC; + public const uint C2SlotImageHi = 0x00100000; + public const int GwesImagePageCap = 32; + // TOC[7] o32[0] dataptr. Same as HostHardDisk. + // VA 0x00011000 → 0x80146000. Live d01f68a: + // 0x00059000 → 0x86FA1000 dest-word=0 (RAM). + // ROM page = 0x80146000+(0x59000-0x11000) + // = 0x8018E000. Dump insn at 0x000593C8 is + // 0x15400002, not 0x86F8FCE0. Dest-word=0 + // .text falls back to this o32 page. + public const uint GwesRomText = 0x80146000; + public const uint GwesRomTextEnd = 0x801EADE0; + // Live a633b83: after ddi-data dest6-adj, NK + // 0x8003D254 data-TLBL 0x040110FC (a1=1, + // v0=0x86FA7800 next MODULE*). CE 32MB slot 2: + // 0x04000000 + 0x000110FC. Same page as filesys + // VA 0x00011000 / FILESYS API 0x000111A8. + // HostHardDisk: slot 0 is filesys. MapFirmwareSlotVa: + // slot 2 is filesys. TryGetTocO32ByVbase: ROM DLL + // vbases are unique and < 0x04000000 — not a + // BuiltIn preferred base. Do not walk all slot-2 + // (wait77 OEMIdle). Firmware PTE only. Do not + // invent dest. + public const uint FilesysSlot2Page = 0x04011000; + public const uint FilesysSlot2Fault = 0x040110FC; + // Live 5b54d07: filesys-48d pages mapped. + // Next data-TLBL epc=0x0001E4DC + // badvaddr=0x08011BE8 a1=0x80000002 + // v0=0x080DF61C stores=24. Same + // relative FILESYS API page as + // 0x04011000→0x80105000: slot 4 + // 0x08000000+0x11000. epc is filesys + // (near 0x0001E534). Slot 0 is + // gwes-text — other handlers. Do + // not invent dest. Do not walk all + // slot-4. + public const uint FilesysSlot4Page = 0x08011000; + public const uint FilesysSlot4Fault = 0x08011BE8; + public const uint FilesysSlotRelPage = 0x00011000; + public const uint FilesysSlotMask = 0x01FFFFFFu; + // Live 725f2f4: 0x0405C000→0x86F95000 and + // 0x0405D000→0x86F96000. Next BindImp-exn + // cause=2 epc=0x800525D8 badvaddr=0x04021ABC + // a1=1 v0=0x00021ABC (slot-2 view of gwes + // null-store PC). Widen extra Lo down to + // the page after FILESYS API 0x04011000. + // [0x04012000, 0x04080000) includes + // 0x04021000 / 0x0405C000 / 0x0407F000. + // Per-page firmware PTE, own kseg. Do not + // alias onto 0x80105000. Do not walk all + // slot-2 (wait77 OEMIdle). Do not steal + // slot-0 gwes (rel 0x00021000). Do not + // invent dest. Do not map VA 0. + public const uint FilesysSlot2ExtraLo = 0x04012000; + public const uint FilesysSlot2ExtraHi = 0x04080000; + public const int FilesysSlot2ExtraCap = 32; + public const uint FilesysSlot27FPage = 0x0407F000; + public const uint FilesysSlot27FFault = 0x0407FEC0; + // Live 017b67e: filesys-slot2 mapped. Next miss is + // data-TLBL epc=0x0001E534 badvaddr=0x48D000F0. + // Slot 0 is filesys (HostHardDisk). ROM = + // FilesysRomText+(0x0001E534-0x00011000)=0x80112534. + // Between CreateFile 0x00019CB8 and RegOpen + // 0x0001FEB0. Not kernel LoadO32WrapC1 0x8001E534. + // 0x48D000F0>>25=36 — outside CE 32MB slots 0-31. + // Equals 0x40000000|0x08D000F0 (PTE-flag bit; + // WalkFirmwarePte wait77 l2 0x40002A1A). v0= + // 0x080DF51C is gwes-slot VALLOC 0x080D0000 + // (wait42), not KData 0xFFFFD800. + // Live 98b8fa6: insn 0x8D4B00F0 lw t3,0xF0(t2) + // t2=0x48D00000. Same word is dest-word of + // gwes-page 0x00081000→0x86F8C000 l2=0x001BE31E + // (firmware PTE consistent; not a backing miss). + // Tagged gwes-slot VA: clear bit30 → 0x08D00000 + // (GwesSlot|0x00D00000). Demand-map that page + // via slot-4 firmware PTE only. Do not invent + // 0x48D dest. Do not walk slot-2. Observe stays. + public const uint Filesys48dEpc = 0x0001E534; + public const uint Filesys48dPage = 0x48D00000; + public const uint Filesys48dFault = 0x48D000F0; + public const uint Filesys48dClearPage = 0x08D00000; + public const uint Filesys48dGwesSlot = 4; + // Live 82240a0: page0 mapped 0x48D00000→0x08D00000→ + // 0x87B63000 (valloc-dest-adj). Next data-TLBL + // epc=0x00031A10 badvaddr=0x48D01000 v1=0x48D05000. + // gwes dest-words 0x00081000=0x48D00000, + // 0x00082000=0x48D01000. Inclusive through + // 0x48D05000. Bit30 clear 0x48Dxxxxx→0x08Dxxxxx. + // Do not invent dest. Do not walk slot-2. + public const uint Filesys48dBit30 = 0x40000000; + public const uint Filesys48dClearLo = 0x08D00000; + public const uint Filesys48dClearHi = 0x08D06000; + public const int Filesys48dPageCap = 6; // FSDMGR 0x03E896D8 is GetProcAddress. After TOC-attach, // 0x800196E4 copies e32_rom units to e32_lite+0x1C. // Kernel GPA reads EXP at +0x20 (that dword is the @@ -75,143 +3184,47578 @@ public static class CeRomTocFiles public const uint FsGetProc = 0x03E896D8; public const uint FilterVbase = 0x03DF0000; public const uint E32RomExpRva = 0x24; + public const uint ExtraRomCece = 0x43454345; + public const uint DdiNopVbase = 0x03980000; + private static uint _extraRomStart; + private static uint _extraRomHdr; + private static string _pendingRomFile; + private static uint _ddiNopTocEntry; + private static uint _ddiNopAttr; + // ExtraROM TOC/e32/o32 live at 0x8134xxxx / 0x80E99Cxx. + // Firmware later reuses that phys as RAM and zeros the + // TOC. Cache the dump bytes at map time and put them + // back when LoadDriver asks. Do not invent 0x81360000. + private static uint[] _ddiNopTocWords; + private static uint _ddiNopE32; + private static uint[] _ddiNopE32Words; + private static uint _ddiNopO32; + private static uint[] _ddiNopO32Words; + private static uint[] _ddiNopDataPtr; + private static uint[] _ddiNopDataLen; + private static uint[][] _ddiNopData; + // wait59: ExtraROM TOC[46] mscoree.dll. FILE table has + // mscorlib.dll / system*.dll, not this name. Same tail + // reuse as TOC[33] / FILE[25]. Cache at map time. + // Do not invent a FILE. Do not invent 0x81360000. + private static uint _mscoreeTocEntry; + private static uint _mscoreeAttr; + private static uint[] _mscoreeTocWords; + private static uint _mscoreeE32; + private static uint[] _mscoreeE32Words; + private static uint _mscoreeO32; + private static uint[] _mscoreeO32Words; + private static uint[] _mscoreeDataPtr; + private static uint[] _mscoreeDataLen; + private static uint[][] _mscoreeData; + // wait65: OpenExe \ole32.dll after TOC[46] MapO32, then + // CreateProcess 193. ExtraROM TOC[34] is that name + // (e32 0x80E99CC8). FILE table has no ole32.dll. + // Do not invent a FILE. Do not attach oleaut32 (TOC[35]) + // unless firmware asks. + private static uint _ole32TocEntry; + private static uint _ole32Attr; + private static uint[] _ole32TocWords; + private static uint _ole32E32; + private static uint[] _ole32E32Words; + private static uint _ole32O32; + private static uint[] _ole32O32Words; + private static uint[] _ole32DataPtr; + private static uint[] _ole32DataLen; + private static uint[][] _ole32Data; + private static bool _ole32DestOn; + private static uint _ole32Slot0; + private static uint _ole32Vbase; + // wait54: ExtraROM FILE[25] tv2clientce.exe lives at + // 0x8134E794 (28-byte FILESentry). Firmware later reuses + // that tail as RAM (same class as TOC[33]). Cache at map + // time and put the dump bytes back before CreateFileFail + // attach. Do not invent 0x81360000. + private static uint _tv2FileEntry; + private static uint[] _tv2FileWords; + private static uint _tv2FileName; + private static uint[] _tv2FileNameWords; + private static uint _tv2FileReal; + private static uint _tv2FileComp; + private static uint _tv2FileLoad; + private static uint[] _tv2FileData; + private static uint _tv2FileDecompRa; + private static uint _tv2FileSavedSp; + private static uint _tv2FilePos; + private static bool _tv2FileDestOn; + private static bool _tv2FileIoLogged; + // ExtraROM FILE OpenFile after FILE[25]+TOC[46]: + // mscorlib.dll then tv2clientcorece.dll (and the + // other ExtraROM FILE names of that class). Same + // type-8 as FILE[25]. dest/cache sized for THAT + // file. FILE[25] _tv2File* stays so leftover + // dest-live is not hopped. Do not invent bytes. + private static ExtraRomOpenFile[] _romFiles; + private static int _romFileCount; + private static ExtraRomOpenFile _romFile; + private static uint _romFileDecompRa; + private static uint _romFileSavedSp; + private static uint _romFilePos; + private static bool _romFileDestOn; + private static bool _romFileIoLogged; + private static bool _romFileAttach; + // wait56: firmware VALLOC a0=0x00010000 a1=0x00008000 + // a2=0x01002000 (MEM_IMAGE|RESERVE) for this dump PE. + // MapO32 dests 0x00012000/0x00014000/0x00016000 are in + // that range; dataptr 0x200/0xC00/0x1200 are PE raw + // offsets, not ExtraROM XIP. Dedicated RA: the shared + // _vallocRa slot is overwritten before return. + private static uint _tv2PeImageVa; + private static uint _tv2PeImageBytes; + private static uint _tv2PeVallocRa; + private static bool _tv2BindLogged; + private static uint _tv2PeEntryRva; + private static uint _tv2PeImageBase; + private static uint _tv2PeComRva; + private static uint _tv2Proc; + // wait67: LoadExe 0x8001F870 logs proc+0x5C before + // e32+16 COM takes BindImpLoadLib(mscoree) / + // GetProcAddress(_CorExeMain). That VA is s3 at + // 0x8001FD80 and thread+5C (0x014B9D98). Type-8 + // never fills proc+0x5C. Keep firmware s3 only + // when it lands on a mapped dest. Do not write + // dump AddressOfEntryPoint 0x7F54 (that invents + // 0x00017F54; filesys already I-fetches there). + private static uint _tv2Startip; + private static uint _tv2Thread; + private static bool _tv2FetchLogged; + private static bool _tv2ContinueLogged; + private static bool _tv2ExnHelperLogged; + private static bool _tv2PostFetchExnLogged; + private static bool _tv2ImplAdelLogged; + private static bool _tv2AfterExnContLogged; + private static bool _pteMapBusy; + private static bool _pteMapLogged; + private static bool _slot2MapLogged; + private static bool _slot0InfoMapLogged; + private static bool _slot0FetchMapLogged; + private static bool _tv2CoredllLogged; + private static bool _tv2CoredllContLogged; + private static uint _coredllLiveSec; + private static bool _coredllLiveLogged; + private static bool _coredllMapLogged; + private static bool _coredllHighLogged; + private static bool _coredllZeroLogged; + private static bool _tv2ZeroContLogged; + private static bool _tv2HighContLogged; + private static uint _tv2ImplRa; + private static uint _tv2ImplResume; + private static uint _tv2ImplEpc; + private static uint _tv2ImplK1Before; + private static bool _tv2ImplContLogged; + private static bool _tv2ImplPastLogged; + private static bool _tv2UserSrLogged; + private static bool _tv2DispatchCtxLogged; + private static bool _tv2UserSpLogged; + private static bool _tv2UserRaLogged; + private static uint _tv2StoreSp; + private static bool _tv2StoreContLogged; + private static bool _tv2LeftoverStoreFrame; + private static bool _tv2StoreFrameLogged; + private static bool _tv2LeftoverLiveLogged; + private static bool _tv2LeftoverPastLogged; + private static bool _tv2LeftoverCae8Logged; + private static bool _tv2LeftoverSkipLogged; + private static bool _tv2LeftoverCaf0Logged; + private static bool _tv2LeftoverCaf0Peeked; + private static uint _tv2LeftoverCaf0Word; + private static bool _tv2LeftoverCae8V0Set; + private static uint _tv2LeftoverCae8V0; + private static bool _tv2LeftoverCae8S6Set; + private static uint _tv2LeftoverCae8S6; + private static bool _tv2LeftoverS6Logged; + private static bool _tv2LeftoverCaf4Peeked; + private static uint _tv2LeftoverCaf4Word; + private static bool _tv2LeftoverCafcPeeked; + private static uint _tv2LeftoverCafcWord; + private static bool _tv2LeftoverAfterCaf0Logged; + private static bool _tv2LeftoverPastAfterLogged; + private static bool _tv2LeftoverPastCb0cLogged; + private static bool _tv2LeftoverCb14Peeked; + private static uint _tv2LeftoverCb14Word; + private static bool _tv2LeftoverAfterCb10Logged; + private static bool _tv2LeftoverPastCb14Logged; + private static bool _tv2LeftoverCb34Peeked; + private static uint _tv2LeftoverCb34Word; + private static bool _tv2LeftoverAfterCb14Logged; + private static bool _tv2LeftoverPastCb34Logged; + private static bool _tv2LeftoverCb38Peeked; + private static uint _tv2LeftoverCb38Word; + private static bool _tv2LeftoverAfterCb34Logged; + private static bool _tv2LeftoverPastCb38Logged; + private static bool _tv2LeftoverCb3cPeeked; + private static uint _tv2LeftoverCb3cWord; + private static bool _tv2LeftoverAfterCb38Logged; + private static bool _tv2LeftoverPastCb3cLogged; + private static bool _tv2LeftoverCb40Peeked; + private static uint _tv2LeftoverCb40Word; + private static bool _tv2LeftoverAfterCb3cLogged; + private static bool _tv2LeftoverPastCb40Logged; + private static bool _tv2LeftoverCb44Peeked; + private static uint _tv2LeftoverCb44Word; + private static bool _tv2LeftoverAfterCb40Logged; + private static bool _tv2LeftoverPastCb44Logged; + private static bool _tv2LeftoverCb48Peeked; + private static uint _tv2LeftoverCb48Word; + private static bool _tv2LeftoverAfterCb44Logged; + private static bool _tv2LeftoverPastCb48Logged; + private static bool _tv2LeftoverCb4cPeeked; + private static uint _tv2LeftoverCb4cWord; + private static bool _tv2LeftoverAfterCb48Logged; + private static bool _tv2LeftoverPastCb4cLogged; + private static bool _tv2LeftoverAfterCb4cLogged; + private static bool _tv2LeftoverPastJrRaLogged; + private static uint _tv2LeftoverJrRaDest; + private static bool _tv2LeftoverBeqRaV0Set; + private static uint _tv2LeftoverBeqRaV0; + private static bool _tv2LeftoverBeqRaFtPeeked; + private static uint _tv2LeftoverBeqRaFtWord; + private static bool _tv2LeftoverBeqRaTkPeeked; + private static uint _tv2LeftoverBeqRaTkWord; + private static bool _tv2LeftoverAfterJrRaLogged; + private static bool _tv2LeftoverPastBeqRaFtLogged; + private static bool _tv2LeftoverPastBeqRaTkLogged; + private static bool _tv2LeftoverBPlus2DelayPeeked; + private static uint _tv2LeftoverBPlus2DelayWord; + private static bool _tv2LeftoverBPlus2TakenPeeked; + private static uint _tv2LeftoverBPlus2TakenWord; + private static bool _tv2LeftoverAfterBPlus2Logged; + private static bool _tv2LeftoverPastBPlus2DelayLogged; + private static bool _tv2LeftoverPastBPlus2TakenLogged; + private static bool _tv2LeftoverBPlus2NextPeeked; + private static uint _tv2LeftoverBPlus2NextWord; + private static bool _tv2LeftoverAfterBPlus2TakenLogged; + private static bool _tv2LeftoverPastBPlus2NextLogged; + private static bool _tv2LeftoverFpNextPeeked; + private static uint _tv2LeftoverFpNextWord; + private static bool _tv2LeftoverAfterFpLogged; + private static bool _tv2LeftoverPastFpNextLogged; + private static bool _tv2LeftoverS7NextPeeked; + private static uint _tv2LeftoverS7NextWord; + private static bool _tv2LeftoverAfterS7Logged; + private static bool _tv2LeftoverPastS7NextLogged; + private static bool _tv2LeftoverS6NextPeeked; + private static uint _tv2LeftoverS6NextWord; + private static bool _tv2LeftoverAfterS6Logged; + private static bool _tv2LeftoverPastS6NextLogged; + private static bool _tv2LeftoverS5NextPeeked; + private static uint _tv2LeftoverS5NextWord; + private static bool _tv2LeftoverAfterS5Logged; + private static bool _tv2LeftoverPastS5NextLogged; + private static bool _tv2LeftoverS4NextPeeked; + private static uint _tv2LeftoverS4NextWord; + private static bool _tv2LeftoverAfterS4Logged; + private static bool _tv2LeftoverPastS4NextLogged; + private static bool _tv2LeftoverEpiloguePeeked; + private static uint _tv2LeftoverEpilogueWord; + private static bool _tv2LeftoverPastEpilogueLogged; + private static bool _tv2LeftoverPastEpilogueDelayLogged; + private static uint _tv2LeftoverDestLiveNext; + private static bool _tv2LeftoverUserRaSet; + private static uint _tv2LeftoverUserRa; + private static bool _tv2LeftoverEretLogged; + private static bool _tv2LeftoverDropLogged; + private static bool _tv2LeftoverDestLiveEretLogged; + private static bool _tv2LeftoverDispatchLogged; + private static bool _tv2GwesFetchLogged; + private static bool _tv2GwesContLogged; + private static bool _tv2MscoreeSlotLogged; + private static bool _coredllMapBusy; + private static bool _tv2ProcSwitchLogged; + private static bool _tv2CurThreadLogged; + private static bool _tv2RestoreLogged; + private static bool _tv2SwitchForced; + private static bool _tv2SwitchStoreLogged; + + // ExtraROM TOC type-7 modules from the dump ROMHDR walk. + // Firmware later reuses ExtraROM tail and zeros TOC words. + // Cache every ExtraROM TOC name at map time so CreateFileFail + // / OpenFile / LoadLibrary can attach ANY ExtraROM TOC module + // (same type-7 as ddi_nop/mscoree/ole32). Do not invent a + // name that is not in ExtraROM TOC. FILE type-8 dest/cache + // stays on IsExtraRomOpenFile / FILE[25]. + private static ExtraRomTocMod[] _romTocMods; + private static int _romTocCount; + private static uint _e32HostPool = ExtraRomE32Host; + private static bool _e32HostCommitted; + private static uint _tocDestHostPool = ExtraRomTocDestHost; + private static uint[] _tocDestSlot0; + private static uint[] _tocDestDump; + private static uint[] _tocDestVsize; + private static uint[] _tocDestKseg; + private static bool[] _tocDestReady; + private static int _tocDestN; + private static uint _tocSrcPool = ExtraRomTocSrc; + private static uint[] _tocSrcPtr; + private static uint[] _tocSrcLen; + private static uint[] _tocSrcKseg; + private static int _tocSrcN; + private static ExtraRomTocMod _tocDecompSlot; + private static uint _loadE32Obj; + private static string _pendingLoadE32Name; + private static int _pendingLoadE32Index; + private static bool _loadE32Watch; + private static string _loadE32WatchName; + private static int _loadE32WatchIndex; + private static uint _loadE32WatchA0; + private static uint _loadE32WatchA1; + private static uint _loadE32WatchA2; + private static uint _loadE32WatchA3; + private static uint _loadE32WatchErr0; + private static uint _loadE32WatchErrNow; + private static uint _loadE32WatchErrPc; + private static uint _loadE32WatchErrNew; + private static int _loadE32WatchErrHits; + private static int _loadE32WatchJalN; + private static string _loadE32WatchJal; + private static int _loadE32WatchSteps; + private static uint _loadE32CopyRa; + private static uint _loadE32CopyV0; + private static uint _loadE32CopyA0; + private static uint _loadE32CopyA1; + private static uint _loadE32CopyA2; + private static uint _loadE32CopyWord; + private static uint _loadE32ChkRa; + private static uint _loadE32ChkV0; + private static uint _loadE32ChkA0; + private static uint _loadE32ChkA1; + private static uint _loadE32ChkA2; + private static uint _loadE32ChkWord; + private static uint _loadE32ChkOff; + private static string _loadE32ChkSpan; + private static bool _loadE32CopySeen; + private static bool _loadE32ChkSeen; + private static uint _loadE32RomBit; + private static uint _loadE32CmpPc; + private static string _loadE32CmpOp; + private static uint _loadE32CmpLhs; + private static uint _loadE32CmpRhs; + private static uint _loadE32CmpFirstPc; + private static string _loadE32CmpFirstOp; + private static uint _loadE32CmpFirstLhs; + private static uint _loadE32CmpFirstRhs; + private static uint _loadE32CmpAfterPc; + private static string _loadE32CmpAfterOp; + private static uint _loadE32CmpAfterLhs; + private static uint _loadE32CmpAfterRhs; + private static int _loadE32CmpN; + private static string _loadE32CmpLog; + private static uint _loadE32RetPc; + private static uint _loadE32RetV0; + private static bool _loadE32RetLogged; + private static bool _loadE32OkWatch; + private static string _loadE32OkName; + private static int _loadE32OkIndex; + private static uint _loadE32OkObj; + private static uint _loadE32OkDest; + private static uint _loadE32OkDest0; + private static uint _loadE32OkWrapPc; + private static bool _loadE32OkLoadO32; + private static bool _loadE32OkCopyO32; + private static bool _loadE32OkPred; + private static bool _loadE32OkPredFail; + private static bool _loadE32OkLoadO32Ret; + private static bool _loadE32OkWrapFail; + private static uint _loadE32OkPredRa; + private static uint _loadE32OkPredV0; + private static uint _loadE32OkLiveEntry; + private static uint _loadE32OkLiveE32; + private static uint _loadE32OkDumpToc0; + private static uint _loadE32OkFp; + private static bool _loadE32OkBit200; + private static bool _loadE32OkBit200Seen; + private static bool _loadE32OkSkip200; + private static bool _loadE32OkValloc; + private static uint _loadE32OkVallocRa; + private static uint _loadE32OkVallocV0; + private static uint _loadE32OkLoadVa; + private static uint _loadE32OkObj6; + private static bool _loadE32OkWrapAfter; + private static bool _loadE32OkMapO32; + private static bool _loadE32OkMapInner; + private static bool _loadE32OkMap28844; + private static bool _loadE32OkMapValloc; + private static uint _loadE32OkMapVallocV0; + private static uint _loadE32OkMapVallocA0; + private static uint _loadE32OkMapVallocA2; + private static uint _loadE32OkMapVallocA3; + private static bool _loadE32OkWrapValloc; + private static bool _loadE32OkO32Walk; + private static bool _loadE32OkS5Hi; + private static bool _loadE32OkFlagsChk; + private static bool _loadE32OkC1; + private static uint _loadE32OkS5; + private static uint _loadE32OkSp24; + private static uint _loadE32OkDestAfter; + private static string _bcmSkipSnap; + private static string _bcmMapSnap; + private static string _ddiSkipSnap; + private static bool _loadE32OkBindImp; + private static bool _loadE32OkCallDll; + private static bool _loadE32OkDecomp; + private static bool _skipDisasmLogged; + private static bool _wrapAfterDisasmLogged; + private static bool _romHdrChainLogged; + private static bool _romHdrListWalkLogged; + private static bool _obj6ShLogged; + private static int _romHdrLinkEnterCount; + private static int _romHdrLinkPublishCount; + private static int _romHdrLinkSpliceCount; + private static bool _romHdrLinkJalLogged; + private static bool _romHdrLinkContinueLogged; + private const int RomHdrLinkLogMax = 8; + private static int _loadE32OkSteps; + private static bool _nkLoadE32Watch; + private static string _nkLoadE32Name; + private static uint _nkLoadE32E32; + private static uint _nkLoadE32O32; + private static uint _nkLoadE32O32Vsize; + private static uint _nkLoadE32O32Ptr; + private static uint _nkChkRa; + private static uint _nkChkA0; + private static uint _nkChkA1; + private static uint _nkChkA2; + private static uint _nkChkWord; + private static uint _nkChkV0; + private static string _nkChkSpan; + private static bool _nkChkSeen; + private static uint _nkRomBit; + private static uint _nkCmpPc; + private static string _nkCmpOp; + private static uint _nkCmpLhs; + private static uint _nkCmpRhs; + private static uint _nkCmpFirstPc; + private static string _nkCmpFirstOp; + private static uint _nkCmpFirstLhs; + private static uint _nkCmpFirstRhs; + private static uint _nkRetPc; + private static int _nkLoadE32Logged; + private static string _nkLoadE32Ok; + private static uint _nkLoadE32Obj; + private static uint _nkLoadE32Toc; + private static uint _nkLoadE32DumpToc0; + private static bool _nkLoadO32Watch; + private static string _nkLoadO32Name; + private static uint _nkLoadO32Obj; + private static uint _nkLoadO32Toc; + private static uint _nkLoadO32DumpToc0; + private static uint _nkLoadO32Word0; + private static uint _nkLoadO32Fp; + private static bool _nkLoadO32Bit200; + private static bool _nkLoadO32Entered; + private static bool _nkLoadO32Skip200; + private static bool _nkLoadO32Thunk; + private static bool _nkLoadO32Ret; + private static int _nkLoadO32Steps; + private static bool _curMSecDisasmLogged; + private const int LoadE32AfterMax = 8; + private static readonly uint[] _afterRa = new uint[LoadE32AfterMax]; + private static readonly string[] _afterName = new string[LoadE32AfterMax]; + private static readonly uint[] _afterA0 = new uint[LoadE32AfterMax]; + private static readonly uint[] _afterA1 = new uint[LoadE32AfterMax]; + private static readonly uint[] _afterA2 = new uint[LoadE32AfterMax]; + private static readonly uint[] _afterWord = new uint[LoadE32AfterMax]; + private static readonly string[] _afterNeed = new string[LoadE32AfterMax]; + private static int _afterN; + private static string _afterRets; + private static string _afterDisasm; + + private static string _lastRomAttachKey; + + private static void LogRomAttach(string result, string source, string kind, int index, + string name, int type, uint dest, uint real, uint comp, string why) + { + string key = (result ?? "") + "|" + (source ?? "") + "|" + (kind ?? "") + "|" + (name ?? ""); + if (key == _lastRomAttachKey) + return; + _lastRomAttachKey = key; + BootLog.Rom(result, source, kind, index, name, type, dest, real, comp, why); + } + + public static void NotePendingRomFile(string path) + { + if (string.IsNullOrEmpty(path)) + return; + int slash = path.LastIndexOf('\\'); + if (slash < 0) + slash = path.LastIndexOf('/'); + _pendingRomFile = slash >= 0 ? path.Substring(slash + 1) : path; + } public static bool TryContinueRomModule(MipsBus bus, uint path, out uint attr, out uint tocEntry) + { + return TryContinueRomModule(bus, path, out attr, out tocEntry, out _); + } + + public static bool TryContinueRomModule(MipsBus bus, uint path, out uint attr, out uint tocEntry, out byte attachType) { attr = 0; tocEntry = 0; + attachType = TocAttachType; if (bus == null || path == 0) return false; - string baseName = Basename(bus, path); - if (string.IsNullOrEmpty(baseName)) + string baseName = Basename(bus, path); + if (string.IsNullOrEmpty(baseName) && !string.IsNullOrEmpty(_pendingRomFile)) + baseName = _pendingRomFile; + if (string.IsNullOrEmpty(baseName)) + return false; + // FILE type-8 first so FILE[11] mscorlib / FILE[25] + // tv2clientce / FILE[26] tv2clientcorece stay type-8 + // dest/cache. Do not turn those names into TOC type-7. + // ExtraROM TOC type-7 attach is any dump ROMHDR TOC + // name (ddi_nop/mscoree/ole32 plus bcmuart/ndis/sipcfg + // /iptvhal_*/iptvdriver and the rest). Do not skip + // those as "not ExtraROM FILE". Names not in ExtraROM + // TOC or FILE skip. Display stays ddi_nop.dll. + // wait53: CreateFile \Windows\tv2clientce.exe is + // INVALID_HANDLE. ExtraROM FILE[25] is that name + // (5120/2421 at 0x81050DCC), not a TOC module and + // not the 90-byte root stub. Same attach as TOC + // (object+0=entry, +4=7). Image bytes are already + // in ExtraROM RAM. wait54: live FILE table at + // 0x8134xxxx is zeros by Launch56 (ExtraROM tail + // RAM reuse). Restore the cached FILESentry first. + // Do not invent 0x81360000. Do not host CreateProcess. + if (IsTv2ClientCe(baseName)) + { + TryRestoreExtraRomFileIfClobbered(bus); + uint real = 0; + uint comp = 0; + uint load = 0; + if (_tv2FileEntry != 0 && _tv2FileWords != null) + { + tocEntry = _tv2FileEntry; + // Real FILE attr 0x807 (COMPRESSED). Do not set + // 0x2000: that is ROMMODULE and LoadE32 reads + // entry+0x14 as e32 (wait55 193). + attr = _tv2FileWords[0]; + real = _tv2FileReal; + comp = _tv2FileComp; + load = _tv2FileLoad; + } + else if (!TryFindExtraRomFile(bus, "tv2clientce.exe", out tocEntry, out attr, + out real, out comp, out load)) + { + LogRomAttach("fail", "ExtraROM", "FILE", 25, "tv2clientce.exe", 8, 0, 0, 0, + "CreateFileFail; FILESentry miss; do not invent 0x81360000"); + return false; + } + _romFileAttach = false; + attachType = FileAttachType; + System.Console.WriteLine("[Hive] FILE-attach ExtraROM tv2clientce.exe entry=0x" + + tocEntry.ToString("X8") + + " type=8 attr=0x" + attr.ToString("X8") + + " real=" + real + + " comp=" + comp + + " load=0x" + load.ToString("X8") + + " (FILESentry; firmware SetFilePointer/ReadFile; not a dump 0x81360000 map)"); + LogRomAttach("ok", "ExtraROM", "FILE", 25, "tv2clientce.exe", 8, load, real, comp, + "CreateFileFail type-8 FILESentry; firmware SetFilePointer/ReadFile; not a dump 0x81360000 map"); + _pendingRomFile = null; + return true; + } + // mscoree OpenFile after FILE[25]+TOC[46] is + // ExtraROM FILE mscorlib.dll then + // tv2clientcorece.dll. Same type-8 as FILE[25]: + // object+0=entry, +4=8, dump attr 0x807. + // dest/cache sized for that file's real/comp. + // Do not invent FILE[26] bytes or 0x81360000. + // Do not set ROMMODULE. Do not attach TOC + // type-7 names. leftover dest-live stays parked. + if (IsExtraRomOpenFile(baseName)) + { + string want = ExtraRomOpenFileName(baseName); + TryRestoreExtraRomOpenFileIfClobbered(bus, want); + uint real = 0; + uint comp = 0; + uint load = 0; + if (!TrySelectExtraRomOpenFile(want, out tocEntry, out attr, + out real, out comp, out load) + && !TryFindExtraRomFile(bus, want, out tocEntry, out attr, + out real, out comp, out load)) + { + LogRomAttach("fail", "ExtraROM", "FILE", -1, want, 8, 0, 0, 0, + "OpenFile type-8 FILESentry miss; do not invent bytes or 0x81360000"); + return false; + } + ExtraRomOpenFile fileSlot = FindExtraRomOpenFile(want); + int fileIndex = fileSlot != null ? fileSlot.Index : -1; + _romFileAttach = true; + attachType = FileAttachType; + System.Console.WriteLine("[Hive] FILE-attach ExtraROM " + want + + " entry=0x" + tocEntry.ToString("X8") + + " type=8 attr=0x" + attr.ToString("X8") + + " real=" + real + + " comp=" + comp + + " load=0x" + load.ToString("X8") + + " (FILESentry; firmware SetFilePointer/ReadFile; not a dump 0x81360000 map)"); + LogRomAttach("ok", "ExtraROM", "FILE", fileIndex, want, 8, load, real, comp, + "CreateFileFail/OpenFile type-8 FILESentry; firmware SetFilePointer/ReadFile; not a dump 0x81360000 map"); + _pendingRomFile = null; + return true; + } + if (TryFindTocModule(bus, 0, 80, baseName, out tocEntry, out attr)) + { + LogRomAttach("ok", "NK", "TOC", -1, baseName, 7, 0, 0, 0, + "CreateFileFail NK ROMHDR attach type-7"); + return true; + } + int tocIndex; + uint dest; + uint e32; + if (TrySelectExtraRomToc(bus, baseName, out tocEntry, out attr, out tocIndex, out dest, out e32)) + { + attachType = TocAttachType; + string why = "CreateFileFail/OpenFile type-7; ExtraROM TOC[" + tocIndex + + "]; e32=0x" + e32.ToString("X8") + + "; do not invent 0x81360000"; + if (BootLog.IsGuestIoName(baseName)) + why = "CreateFileFail/OpenFile type-7; ExtraROM TOC[" + tocIndex + + "]; firmware probe; do not invent a NIC or UART"; + System.Console.WriteLine("[Hive] TOC-attach ExtraROM " + baseName + + " entry=0x" + tocEntry.ToString("X8") + + " type=7 attr=0x" + attr.ToString("X8") + + " e32=0x" + e32.ToString("X8") + + " (TOC[" + tocIndex + "]; not a FILE; do not invent 0x81360000)"); + LogRomAttach("ok", "ExtraROM", "TOC", tocIndex, baseName, 7, dest, 0, 0, why); + TryMarkExtraRomO32Compressed(bus, tocEntry); + NoteLoadE32(baseName, tocIndex); + _pendingRomFile = null; + return true; + } + uint nkReal = 0; + uint nkComp = 0; + uint nkLoad = 0; + if (TryFindNkFile(bus, baseName, out tocEntry, out attr, out nkReal, out nkComp, out nkLoad)) + { + _romFileAttach = false; + attachType = FileAttachType; + LogRomAttach("ok", "NK", "FILE", -1, baseName, 8, nkLoad, nkReal, nkComp, + "CreateFileFail NK ROMHDR FILE type-8; do not invent ExtraROM copy"); + _pendingRomFile = null; + return true; + } + LogRomAttach("skip", "ExtraROM", "", -1, baseName, 0, 0, 0, 0, + BootLog.IsGuestIoName(baseName) + ? "CreateFileFail/OpenFile; guest IO name; not ExtraROM FILE type-8 or TOC attach; do not invent a NIC or UART" + : "CreateFileFail/OpenFile; not ExtraROM FILE type-8 or TOC attach name; do not invent"); + return false; + } + + // LoadDriver does not CreateFile. OpenExe 0x8001D6F0 calls + // this walk at 0x8001DA58 for a bare name. NK modules hit + // because they sit on *(0x80342B10). ExtraROM 0x8134DA84 + // is mapped but never linked. Host attach is a workaround + // because the chain is unlinked. Do not invent a + // ROMChain_t. Write the same object the hit path at + // 0x80016B9C writes and return 0 so 0x800196E4 can + // decompress/map. + public static bool TryAttachExtraRomTocWalk(MipsBus bus, uint path, uint obj) + { + if (bus == null || path == 0 || obj == 0) + return false; + string baseName = Basename(bus, path); + if (string.IsNullOrEmpty(baseName) && !string.IsNullOrEmpty(_pendingRomFile)) + baseName = _pendingRomFile; + if (string.IsNullOrEmpty(baseName)) + return false; + if (IsTv2ClientCe(baseName) || IsExtraRomOpenFile(baseName)) + return false; + uint tocEntry; + uint attr; + int tocIndex; + uint dest; + uint e32; + if (!TrySelectExtraRomToc(bus, baseName, out tocEntry, out attr, out tocIndex, out dest, out e32)) + { + uint toc = ExtraRomToc(bus); + uint nmods = 0; + try + { + if (toc != 0) + nmods = bus.Read32(toc + RomHdrNumMods); + } + catch + { + } + System.Console.WriteLine("[Hive] TOC-walk ExtraROM " + baseName + " miss toc=0x" + + toc.ToString("X8") + " nmods=" + nmods + + " cached-hdr=0x" + _extraRomHdr.ToString("X8") + + " (do not invent 0x81360000)"); + TryLogRomHdrListWalk(bus, "TOC-walk miss " + baseName); + LogRomAttach("fail", "ExtraROM", "TOC", -1, baseName, 7, 0, 0, 0, + "TOC-walk miss toc=0x" + toc.ToString("X8") + + " nmods=" + nmods + "; " + NameChainMiss()); + return false; + } + try + { + bus.Write32(obj, tocEntry); + bus.Write8(obj + 4, TocAttachType); + } + catch + { + return false; + } + TryLogRomHdrListWalk(bus, "TOC-walk host-attach " + baseName); + System.Console.WriteLine("[Hive] TOC-walk ExtraROM " + baseName + " entry=0x" + + tocEntry.ToString("X8") + + " (TOC[" + tocIndex + "]; type-7 host attach; chain unlinked; do not invent a ROMChain_t; do not invent a FILE)"); + LogRomAttach("ok", "ExtraROM", "TOC", tocIndex, baseName, 7, dest, 0, 0, + "TOC-walk type-7 host attach; TOC[" + tocIndex + "]; " + NameChainMiss()); + TryMarkExtraRomO32Compressed(bus, tocEntry); + NoteLoadE32(baseName, tocIndex); + return true; + } + + // ExtraROM o32[0] first word B501743A / psize 16) + return; + for (uint s = 0; s < objcnt; s++) + { + uint src = o32 + s * O32RomSize; + uint vsize = bus.Read32(src); + uint psize = bus.Read32(src + 8); + uint dataptr = bus.Read32(src + 0xC); + uint real = bus.Read32(src + 0x10); + uint flags = bus.Read32(src + 0x14); + ExtraRomTocMod marked = cached; + if (marked != null && marked.O32Words != null && marked.O32Words.Length >= 3 + && marked.O32Words[2] == 0) + continue; + if (!LooksCompressed(bus, dataptr, vsize, psize)) + continue; + uint next = flags | O32Compressed; + if (next == flags) + continue; + bus.Write32(src + 0x14, next); + System.Console.WriteLine("[Hive] ExtraROM o32[" + s + + "] flags 0x" + flags.ToString("X8") + + " -> 0x" + next.ToString("X8") + + " dataptr=0x" + dataptr.ToString("X8") + + " real=0x" + real.ToString("X8") + + " (keep 0x2000 for CopyO32 align; MapO32 clears it)"); + } + } + catch + { + } + } + + private static bool LooksCompressed(MipsBus bus, uint dataptr, uint vsize, uint psize) + { + if (bus == null || dataptr == 0 || vsize == 0 || psize == 0 || psize >= vsize) + return false; + try + { + uint first = bus.Read32(dataptr); + uint declared = first & 0x00FFFFFFu; + uint sig = first >> 24; + return declared == vsize + || sig == 0xB5 || sig == 0xB4 || sig == 0x11 || sig == 0x0C; + } + catch + { + return psize < vsize; + } + } + + // Slot-1 o32.real 0x03981000 is the ExtraROM vbase. VALLOC + // only MEM_COMMITs and the current process has no reservation + // there (last-error 14). Use the same slot offset in slot 0 + // (0x01981000) so firmware can RESERVE|COMMIT, then + // 0x80028844 writes those pages. Alias 0x0398xxxx to that + // dest after VALLOC. Do not host-alias src XIP. + public static void TrySteerExtraRomMapO32(MipsBus bus, uint o32Lite) + { + if (bus == null || o32Lite == 0) + return; + try + { + uint dest = bus.Read32(o32Lite + 8); + uint dataptr = bus.Read32(o32Lite + 0x18); + // ExtraROM type-7 destDump (o32.real) is what + // firmware VirtualAllocs. Do not rewrite to dest0. + // ddi_nop OpenFile dest stays the working Display. + if (!IsExtraRomDdiNopDest(dest) && !IsExtraRomDdiNopData(dataptr)) + return; + uint slot = dest & SlotMask; + if (slot == dest) + return; + bus.Write32(o32Lite + 8, slot); + System.Console.WriteLine("[Hive] ExtraROM MapO32 dest 0x" + + dest.ToString("X8") + " -> 0x" + slot.ToString("X8") + + " (ddi_nop Display dest; do not steer ExtraROM type-7 destDump)"); + } + catch + { + } + } + + // wait63: dest 0x014B1000 dest-word=0. 0x8001AC9C + // ands flags with 0x80002000; 0x60006020 leaves + // 0x2000 so jal 0x80028844 is skipped. AD50 then + // returns at 0x8001AE4C when object+6<2 and flags + // lack 0x08000000 (type-7 never stores those). + // ddi_nop keeps 0x2000 and VALLOCs because LoadDriver + // set object+6>=2. Do not force that VALLOC. + // CopyO32 already passed; clear O32RomXip on the + // lite only so 0x8001AC9C falls through. a3!=0 + // still hits 0x8001ACB0 and skips the jal: leave + // flags alone. Do not invent dest bytes. + public static void TryClearO32RomXipForMscoree(MipsBus bus, uint[] regs) + { + // 0x8001AC9C is flags bnez, not jal 0x80028844. + // Do not rewrite o32_lite flags. ExtraROM type-7 + // destDump is firmware VirtualAlloc of o32.real. + } + + // 0x80028844 is a0=dest a1=dataptr a2=vsize. + // Do not jal 0x8004DBF8 or rewrite a0/a1/a2/a3. + // 6c001d9 stole sipcfg/shell dest 0x00011000 and + // looped. Firmware MapO32/OpenFile/VALLOC owns this. + public static bool TryRedirectExtraRomMapO32Decompress( + MipsBus bus, uint[] regs, ref uint programCounter) + { + return false; + } + + public static void TryLogMscoreeMapO32Ret(MipsBus bus, uint[] regs) + { + if (bus == null || regs == null || regs.Length <= 20) + return; + uint dest = regs[20]; + if (dest == 0 || (!IsExtraRomMscoreeDest(dest) && !IsExtraRomOle32Dest(dest))) + return; + uint word = 0; + uint word4 = 0; + bool mapped = false; + try + { + word = bus.Read32(dest); + word4 = bus.Read32(dest + 4); + mapped = true; + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM MapO32 ret dest=0x" + + dest.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " dest+4=0x" + word4.ToString("X8") + + (mapped && (word != 0 || word4 != 0) + ? " (firmware dest after MapO32)" + : " (dest still empty)")); + // wait90: RI dest-word 0x603E984F at RVA 0x7DA8. + // o32[0] dest 0x014B1000 is RVA 0x1000. Peek the + // same CEDecompressROM dest at RVA 0x7D7C / 0x7DA8 + // / startip 0x9D98. Do not write dest. Do not + // alias that dest a second time. + if (mapped && IsExtraRomMscoreeDest(dest) + && (dest & SlotMask) == 0x014B1000u) + { + uint jal = 0; + uint ri = 0; + uint startip = 0; + TryPeekWord(bus, dest + 0x6D7Cu, out jal); + TryPeekWord(bus, dest + 0x6DA8u, out ri); + TryPeekWord(bus, dest + 0x8D98u, out startip); + System.Console.WriteLine("[Hive] ExtraROM MapO32 mscoree o32[0] dest=0x" + + dest.ToString("X8") + + " rva7D7C=0x" + jal.ToString("X8") + + " rva7DA8=0x" + ri.ToString("X8") + + " rva9D98=0x" + startip.ToString("X8") + + " (peek only; same CEDecompressROM dest as startip; do not invent dest bytes; not a second alias)"); + } + } + + // kseg0 scratch for an aligned copy of ExtraROM compressed + // o32. 0x80028844 xors dest^src and requires the page + // offsets to match; dataptr 0x80764CE0 is off 0xCE0. + // This is not ExtraROM and not 0x81360000. + public const uint AlignedCompSrc = 0x8F000000; + public const uint AlignedCompStride = 0x10000; + // VALLOC dest is useg. CEDecompress lbu/sb that VA + // before the first store, so DestReadable is false and + // lookbacks TLB-miss. Host-back the already-VALLOC'd + // pages at kseg0 (zeros only). Not ExtraROM XIP and + // not 0x81360000. + public const uint ExtraRomDestKseg0 = 0x8F100000; + public const uint ExtraRomDestKseg1 = 0x8F180000; + // wait62: TOC[46] slot-0 view of dump o32.real + // 0x034B1000 / 0x034Cxxxx. Not 0x81360000. + public const uint ExtraRomDestKsegMscoree = 0x8F1A0000; + public const uint ExtraRomDestKsegMscoree1 = 0x8F1C0000; + // wait65: TOC[34] slot-0 view of dump o32.real + // 0x03941000 / 0x03972000. Not 0x81360000. + // 0x8F080000 is ole32 aligned-src slot 8 + // (0x8F000000 + 8*0x10000). HostCommit of dest + // 0x01941000 at that kseg zeroed psize 0x17BDC + // and CEDecompressROM page 3 was v0=4. + public const uint ExtraRomDestKsegOle32 = 0x8F0C0000; + // Firmware VirtualAlloc(NULL) useg must not alias kseg0 + // 0x80000000|va: 0x000E1700 would be NK at 0x800E1700. + // Dedicated unused kseg0, same class as ExtraROM dest. + public const uint VallocHostKseg = 0x8F200000; + public const uint VallocHostKsegLim = 0x8F400000; + // ExtraROM TOC/e32/o32 live at 0x8134xxxx / 0x80E99Cxx. + // Firmware reuses that tail as RAM. Host dump e32+o32 + // so LoadE32 type-7 can take the ROM success path + // (v0=0 at 0x80019990). Dest word 0 after that is + // CopyO32/CEDecompressROM not running, not LoadE32 + // fail. NK TOC attach works because NK + // ROMHDR e32_rom stays in XIP. Copy dump TOC+e32+o32 + // next to FILE[25] dest 0x8F140000 (CEDecompressROM + // tv2clientce already uses that kseg0 window). After + // FILE[25] 5120/0x2000. Not 0x81360000, not FILE dest, + // not VallocHostKseg 0x8F200000. + public const uint ExtraRomE32Host = 0x8F148000; + public const uint ExtraRomE32HostLim = 0x8F168000; + // Dump ExtraROM TOC o32 dataptr backing (not a0). + // a0 is dump o32 dataptr (bcmuart 0x80B62B98). + // Do not rewrite a0 to ExtraRomTocSrc. a2 is firmware + // dest (o32.real 0x02F21000 / VALLOC). Do not rewrite + // a2 to ExtraRomTocDestHost. Dump vbase/vsize only. + // Not 0x81360000. + public const uint ExtraRomTocSrc = 0x8E000000; + public const uint ExtraRomTocSrcLim = 0x8E800000; + public const uint ExtraRomTocDestHost = 0x8E800000; + public const uint ExtraRomTocDestHostLim = 0x8F000000; + public const uint CeAllocGranularity = 0x10000; + + public static bool TryReserveExtraRomValloc(uint[] regs) + { + if (regs == null || regs.Length <= 6) + return false; + uint dest = regs[4]; + ExtraRomTocMod type7 = FindCachedTocByDest(dest); + if (type7 == null && (dest & 0xF0000000u) == 0x60000000u + && !string.IsNullOrEmpty(_loadE32OkName)) + type7 = FindCachedExtraRomToc(_loadE32OkName); + if (type7 != null && type7.Dest != 0 + && !NamesMatchRom(type7.Name, "ddi_nop.dll")) + return TryReserveExtraRomType7DestDump(regs, type7); + // ddi_nop Display dest stays the working OpenFile path. + return TryReserveExtraRomVallocDdiNopTail(regs, dest); + } + + // Live eaeb634: MEM_COMMIT of ExtraROM type-7 destDump + // (nleddrvr 0x02F81000 / bcmuart 0x02F21000 / mscoree + // 0x034B1000) returned 0. last-error 14. Wrapper v0=0xE + // is that OOM. Same miss as ddi_nop slot-1 0x03981000: + // current process has no reservation. destDump is the + // VA (o32.real). dest0 is only destDump&SlotMask. + // Live 0x800283FC one-liner a0=0x60002020 is o32 flags + // sampled at jal 0x8001AD50; dump jal a0=s4=destDump + // a2=0x1000 a3=0x40. Do not treat flags as the address. + // Add MEM_RESERVE so firmware COMMIT can succeed. + // Host-back zeros only. Do not invent dest bytes. + // Do not host-CEDecompressROM slot-0. ddi_nop stays + // on the OpenFile path below. + private static bool TryReserveExtraRomType7DestDump(uint[] regs, ExtraRomTocMod type7) + { + if (regs == null || regs.Length <= 6 || type7 == null) + return false; + uint destDump = type7.Dest; + if (destDump == 0 || destDump >= 0x80000000u) + return false; + if (NamesMatchRom(type7.Name, "ddi_nop.dll") + || IsExtraRomDdiNopDest(destDump) + || IsExtraRomDdiNopDest(type7.Dest & SlotMask)) + return false; + + uint a0 = regs[4]; + uint size = regs[5]; + uint type = regs[6]; + uint dest0 = destDump & SlotMask; + + if (a0 != destDump) + regs[4] = destDump; + + if (size == 0 || size == 1 || size > 0x01000000u) + { + uint vsize = type7.O32Words != null && type7.O32Words.Length > 0 + ? type7.O32Words[0] : 0; + if (vsize == 0 || vsize > 0x01000000u) + vsize = 0x1000; + size = (vsize + 0xFFFu) & ~0xFFFu; + regs[5] = size; + } + + if (type == 0 || type == 1 || (type & 0xF0000000u) == 0x60000000u) + type = 0x1000u; + if ((type & MemReserve) == 0) + type |= MemReserve; + regs[6] = type; + + if (MapVallocHostVa(destDump) == destDump) + TryHostBackValloc(destDump, destDump, size, type, false); + + BootLog.Write( + "[Hive] TOC[" + type7.Index + "] " + type7.Name + + " destDump reserve destDump=0x" + destDump.ToString("X8") + + " dest0=0x" + dest0.ToString("X8") + + " a0was=0x" + a0.ToString("X8") + + " size=0x" + size.ToString("X") + + " type=0x" + type.ToString("X") + + " slot-" + (destDump >> 25) + + " MEM_RESERVE+COMMIT. no dest bytes."); + return true; + } + + private static bool TryReserveExtraRomVallocDdiNopTail(uint[] regs, uint dest) + { + if (!IsExtraRomDdiNopDest(dest)) + return false; + // o32[0].real is vbase+0x1000. BindImp reads IMP + // at vbase+NameRVA. VALLOC of dest alone leaves + // the header page unmapped. Pull dest down one + // page. Do not invent a PE header. + uint slot = dest & SlotMask; + uint header = 0; + if (IsExtraRomHeaderDestPage(slot & 0xFFFFF000u)) + { + header = 0x1000; + dest -= header; + regs[4] = dest; + } + uint type = regs[6]; + bool needReserve = (type & MemReserve) == 0; + if (needReserve) + regs[6] = type | MemReserve; + // CEDecompress step 0x1000 can lbu the next dest page + // (section 2 vsize 0xB04 read 0x019A9000 and took + // 0x80000180). Commit one extra page. Not ExtraROM XIP. + if (regs.Length > 5) + { + uint size = regs[5] + header; + uint pages = (size + 0xFFFu) & ~0xFFFu; + if (pages < size + 0x1000) + pages += 0x1000; + if (pages > regs[5]) + regs[5] = pages; + } + // Live 330f08b: dest0 back 0x01980000 size 0x1A000 + // then CEDecompressROM dest=0x01981000 dest-word=0. + // ExtraRomDestKseg0 / TryHostBackValloc remapped + // dest0 to a kseg alias firmware does not write. + // dest0 stays useg. MapFirmwareSlotVa walks + // firmware PTE (0x80040278) so stores land on + // the VALLOC page. Do not copy destDump onto + // dest0. Do not invent dest. + uint dest0Base = dest & SlotMask; + _ddiNopDestOn = true; + _ddiNopSlot0 = dest0Base != 0 ? dest0Base : (DdiNopVbase & SlotMask); + BootLog.Write("[Hive] ExtraROM ddi_nop dest0 useg dest0=0x" + + dest0Base.ToString("X8") + + " (firmware PTE walk; not ExtraRomDestKseg0)"); + if (!needReserve && header == 0) + return true; + System.Console.WriteLine("[Hive] ExtraROM VALLOC a0=0x" + + dest.ToString("X8") + " type 0x" + type.ToString("X") + + " -> 0x" + regs[6].ToString("X") + + " size 0x" + (regs.Length > 5 ? regs[5].ToString("X") : "0") + + (header != 0 ? " (vbase header page + extra; do not invent 0x81360000)" + : " (MEM_RESERVE|COMMIT + extra page; do not invent 0x81360000)")); + return true; + } + + // 0x80026F50 returns how many NEW pages it committed. + // VALLOC already committed ExtraROM dest, so that is 0. + // 0x800289F8 bne v0, s4 then last-error 87. s4 is the + // page count (dest+vsize). Keep the VALLOC pages. + public static bool TryAcceptExtraRomDestCommit(uint[] regs) + { + if (regs == null || regs.Length <= 30) + return false; + uint dest = regs[30]; + if (!IsExtraRomCompressedDest(dest)) + return false; + uint v0 = regs[2]; + uint pages = regs[20]; + if (v0 != 0 || pages == 0 || pages > 0x100) + return false; + regs[2] = pages; + System.Console.WriteLine("[Hive] ExtraROM 0x80026F50 v0=0 pages=" + + pages + " dest=0x" + dest.ToString("X8") + + " (VALLOC already committed; do not invent 0x81360000)"); + return true; + } + + public static void NoteExtraRomVallocRet(uint dest, uint v0) + { + ExtraRomTocMod slot = FindCachedTocByDest(dest); + if (slot != null) + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " 0x800283FC-ret v0=0x" + v0.ToString("X") + + " destDump=0x" + slot.Dest.ToString("X8") + + " a0=0x" + dest.ToString("X8") + + (v0 == 0 + ? " slot-" + (dest >> 25) + " destDump COMMIT no reserve last-error 14" + : "")); + if (!IsExtraRomCompressedDest(dest)) + return; + System.Console.WriteLine("[Hive] ExtraROM VALLOC dest=0x" + + dest.ToString("X8") + " v0=0x" + v0.ToString("X8") + + (v0 == 0 ? " (firmware miss)" : " (slot-0 dest ready)")); + if (v0 != 0) + { + if (IsExtraRomDdiNopDest(dest)) + { + _ddiNopDestOn = true; + _ddiNopSlot0 = DdiNopVbase & SlotMask; + } + if (IsExtraRomMscoreeDest(dest)) + { + _mscoreeDestOn = true; + if (_mscoreeVbase != 0) + _mscoreeSlot0 = _mscoreeVbase & SlotMask; + } + if (IsExtraRomOle32Dest(dest)) + { + _ole32DestOn = true; + if (_ole32Vbase != 0) + _ole32Slot0 = _ole32Vbase & SlotMask; + } + } + } + + // Do not jal 0x8004DBF8 from VirtualCopy. 6c001d9 + // treated dest 0x00011000 (sipcfg/shell TOC) as + // ddi_nop and looped 3012 hits. Firmware owns + // OpenFile/VALLOC/CopyO32. Leave a0/a1/a2/a3. + // dest 0x01981000 first nonzero is noted at the + // firmware 0x8004DBF8 return, once. + private static uint _ddiNopDecompRa; + private static uint _ddiNopDecompSrc; + private static uint _ddiNopDecompCb; + private static uint _ddiNopDecompDest; + private static uint _ddiNopDecompVsize; + private static uint _ddiNopDecompHdr; + private static bool _ddiNopInnerCap; + private static int _ddiNopInnerPages; + private static bool _ddiNopDestWordLogged; + private static bool _ddiNopObserve; + + public static bool TryRedirectExtraRomVirtualCopyToDecompress( + MipsBus bus, uint[] regs, ref uint programCounter) + { + return false; + } + + // Firmware already at 0x8004DBF8. Leave registers + // and PC. sipcfg/shell dest 0x00011000 is not + // ddi_nop. Remember RA only for VALLOC dest + // 0x01981000 so the first nonzero dest word logs + // once. + public static void TryNoteExtraRomDecompressEntry(MipsBus bus, uint[] regs) + { + if (regs == null || regs.Length <= 7) + return; + uint dest = regs[6]; + if (dest != 0x01981000u || _ddiNopDestWordLogged) + return; + uint src = regs[4]; + uint cb = regs[5]; + uint vsize = regs[7]; + _ddiNopObserve = true; + _ddiNopDecompRa = regs.Length > 31 ? regs[31] : 0; + _ddiNopDecompSrc = src; + _ddiNopDecompCb = cb; + _ddiNopDecompDest = dest; + _ddiNopDecompVsize = vsize; + _ddiNopDecompHdr = 0; + try + { + if (bus != null && src != 0) + _ddiNopDecompHdr = bus.Read32(src); + } + catch + { + } + // Live c710c07: dest-word 0 at dest0/dest6; + // dest10 word 0x806F0000 is a kseg pointer, not MZ. + // Count host stores from this jal until ret. + if (bus == null) + return; + BeginDdiNopDecompStoreWatch(bus); + TryHuntDdiNopModuleFromRegs(bus, regs); + } + + public static bool TryNoteExtraRomInnerDest(MipsBus bus, uint[] regs) + { + if (_ddiNopObserve + || (_ddiNopDecompRa == 0 && _tv2FileDecompRa == 0 && _romFileDecompRa == 0) + || bus == null || regs == null || regs.Length <= 7) + return false; + try + { + uint src = regs[4]; + uint slen = regs[5]; + uint dest = regs[6]; + uint work = regs[7]; + uint leftover = 0; + uint src0 = 0; + if (work != 0) + leftover = bus.Read32(work); + if (src != 0) + src0 = bus.Read32(src); + if (!_ddiNopInnerCap) + { + _ddiNopInnerCap = true; + System.Console.WriteLine("[Hive] ExtraROM CEDecompressROM inner src=0x" + + src.ToString("X8") + " slen=0x" + slen.ToString("X") + + " dest=0x" + dest.ToString("X8") + + " leftover=0x" + leftover.ToString("X") + + " src0=0x" + src0.ToString("X8") + + " (LZX window/vsize header; do not cap leftover)"); + } + } + catch + { + } + return false; + } + + public static bool TryNoteExtraRomInnerRet(uint[] regs) + { + if (_ddiNopObserve + || (_ddiNopDecompRa == 0 && _tv2FileDecompRa == 0 && _romFileDecompRa == 0) + || regs == null || regs.Length <= 2) + return false; + // TOC[34] o32[0] vsize 0x2E705 is 47 pages. + if (_ddiNopInnerPages >= 48) + return false; + _ddiNopInnerPages++; + uint v0 = regs[2]; + uint page = regs.Length > 23 ? regs[23] : 0; + uint total = regs.Length > 21 ? regs[21] : 0; + System.Console.WriteLine("[Hive] ExtraROM CEDecompressROM inner v0=0x" + + v0.ToString("X8") + " page=" + page + + " total=0x" + total.ToString("X") + + (v0 == 0 ? " (LZX page ok)" : + v0 == 3 ? " (window/leftover miss)" : + v0 == 4 ? " (bad LZX window)" : + (int)v0 < 0 ? " (ROM inner fail)" : " (ROM inner status)")); + return false; + } + + public static bool TryNoteExtraRomDecompressRet(MipsBus bus, uint[] regs, uint pc) + { + if (_ddiNopDecompRa == 0 || pc != _ddiNopDecompRa) + return false; + uint dest = _ddiNopDecompDest; + uint vsize = _ddiNopDecompVsize; + uint src = _ddiNopDecompSrc; + uint cb = _ddiNopDecompCb; + uint hdr = _ddiNopDecompHdr; + LogDdiNopDecompStores(); + _ddiNopDecompWatch = false; + _ddiNopDecompRa = 0; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint a2 = regs != null && regs.Length > 6 ? regs[6] : 0; + uint a3 = regs != null && regs.Length > 7 ? regs[7] : 0; + uint word = 0; + uint entry = 0; + bool mapped = false; + bool entryMapped = false; + try + { + if (bus != null && dest != 0) + { + // dest0 useg: do not remap to pfn6 before + // dest6/dest10/dest0/destDump compare. + if (dest == 0x01981000u) + word = PeekDestWordRaw(bus, dest, out _); + else + word = bus.Read32(dest); + mapped = true; + } + } + catch + { + } + if (dest == 0x01981000u && bus != null && regs != null) + { + TryMeasureDdiNopDestAfterDecomp(bus, hdr, v0); + TryServeDdiNopAtDecompRet(bus, regs); + } + try + { + // entryrva 0x18014 is dest+0x17014 (o32[0] rva 0x1000). + if (bus != null && dest != 0 && vsize > 0x17014) + { + entry = bus.Read32(dest + 0x17014); + entryMapped = true; + } + } + catch + { + } + string imp = ""; + if (bus != null && dest != 0 && vsize > 0x17370) + { + try + { + uint lookup = bus.Read32(dest + 0x17350); + uint nameRva = bus.Read32(dest + 0x1735C); + string dll = ""; + if (nameRva >= 0x1000 && nameRva < 0x1843Au) + dll = ReadAscii(bus, dest + (nameRva - 0x1000)); + imp = " imp0=0x" + lookup.ToString("X8") + + " nameRVA=0x" + nameRva.ToString("X") + + (dll.Length > 0 ? " \"" + dll + "\"" : ""); + } + catch + { + } + } + string note; + if (v0 == 0xFFFFFFFFu) + note = " (firmware CEDecompressROM miss)"; + else if (vsize != 0 && v0 == vsize) + note = " (firmware expanded vsize)"; + else if (v0 == 0) + note = " (firmware returned 0)"; + else + note = ""; + if (mapped && word != 0 && hdr != 0 && word == hdr) + note += " (dest is src header; not expanded)"; + string decompName = !string.IsNullOrEmpty(_pendingLoadE32Name) + ? _pendingLoadE32Name : ""; + string decompWhy = v0 == 0xFFFFFFFFu + ? "firmware CEDecompressROM miss" + : (vsize != 0 && v0 == vsize) + ? "firmware expanded vsize; dest word=0x" + word.ToString("X8") + + "; a0=0x" + src.ToString("X8") + + " a1=0x" + cb.ToString("X8") + + " a2=0x" + dest.ToString("X8") + : (v0 == 0 ? "firmware returned 0" : "firmware CEDecompressROM"); + BootLog.DecompressRom(decompName, dest, v0, decompWhy); + bool header = mapped && word != 0 && hdr != 0 && word == hdr; + bool expanded = mapped && word != 0 && !header && v0 != 0xFFFFFFFFu; + if (expanded) + MarkExtraRomTocDecompressed(dest); + // 0x8004DBF8 is not ddi_nop on every hit. sipcfg/shell + // dest 0x00011000 stays firmware. One line when + // VALLOC dest 0x01981000 first becomes nonzero. + if ((dest == 0x01981000u || dest == _ddiNopDest0Pte) + && mapped && word != 0 && !header + && !_ddiNopDestWordLogged) + { + _ddiNopDestWordLogged = true; + string first = "[Hive] ExtraROM ddi_nop dest 0x01981000 first nonzero word=0x" + + word.ToString("X8") + + (_ddiNopDest0Pte != 0 + ? " pteDest=0x" + _ddiNopDest0Pte.ToString("X8") : "") + + " a0=0x" + src.ToString("X8") + + " a1=0x" + cb.ToString("X8") + + " a2=0x" + dest.ToString("X8") + + " a3=0x" + vsize.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " live-a0=0x" + a0.ToString("X8") + + " live-a1=0x" + a1.ToString("X8") + + " live-a2=0x" + a2.ToString("X8") + + " live-a3=0x" + a3.ToString("X8") + + (entryMapped ? " entry=0x" + entry.ToString("X8") : "") + + imp + + note + + " (firmware OpenFile/VALLOC/CopyO32 dest; not sipcfg 0x00011000; not host a2 rewrite)"; + System.Console.WriteLine(first); + BootLog.Write(first); + } + _ddiNopObserve = false; + _tocDecompSlot = null; + return false; + } + + // DllMain TLB epc 0x03981520 is dest+0x520 (rva 0x1520). + // 0x000E1970 is not an o32 RVA (e32 vsize 0x2B000) and not + // sec1 BSS (0x01F57xxx / leftover after 0xAB28). nk TOC[7] + // gwes.exe e32 vbase 0x00010000 vsize 0xBB000 ends + // 0x000CB000 (o32[3] real 0x000C6000+0x42C4). ExtraROM + // has no module or B000FF record in 0x000E0000-0x000F0000. + // 0x000E1970 / 0x000E1700 are not LE words in nk.bin or + // etc.bin. Observe the store. Do not invent 0x000E0000. + private static void DumpDdiNopTextSites(MipsBus bus, uint dest) + { + uint[] off = { 0x520, 0x1D50, 0x1DD4, 0x5FA8, 0x70C4, 0x70E4, 0x17014, 0x170F0 }; + for (int i = 0; i < off.Length; i++) + { + try + { + uint va = dest + off[i]; + uint w0 = bus.Read32(va); + uint w1 = bus.Read32(va + 4); + uint w2 = bus.Read32(va + 8); + System.Console.WriteLine("[Hive] ExtraROM ddi_nop dest+0x" + + off[i].ToString("X") + " @0x" + va.ToString("X8") + + " " + w0.ToString("X8") + " " + w1.ToString("X8") + + " " + w2.ToString("X8")); + } + catch + { + } + } + } + + private static bool _ddiNopBindHdr; + private static bool _ddiNopBindName; + private static bool _ddiNopBindLib; + private static bool _ddiNopBindLibRet; + + public static bool TryNoteExtraRomBindImp(MipsBus bus, uint[] regs, uint pc) + { + if (regs == null || regs.Length <= 30) + return false; + if (pc == BindImpHdr && !_ddiNopBindHdr) + { + _ddiNopBindHdr = true; + uint hdr = regs[20]; + uint vbase = regs[22]; + uint e32 = regs[23]; + uint impRva = 0; + uint impSize = 0; + uint w0 = 0; + uint nameRva = 0; + try + { + if (e32 != 0) + { + impRva = bus != null ? bus.Read32(e32 + 0x24) : 0; + impSize = bus != null ? bus.Read32(e32 + 0x28) : 0; + } + if (bus != null && hdr != 0) + { + w0 = bus.Read32(hdr); + nameRva = bus.Read32(hdr + 12); + } + } + catch + { + } + string dll = ""; + try + { + if (bus != null && nameRva != 0) + dll = ReadAscii(bus, vbase + nameRva); + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM BindImp hdr=0x" + + hdr.ToString("X8") + " vbase=0x" + vbase.ToString("X8") + + " e32IMP=0x" + impRva.ToString("X") + "/0x" + impSize.ToString("X") + + " word0=0x" + w0.ToString("X8") + + " nameRVA=0x" + nameRva.ToString("X") + + (dll.Length > 0 ? " \"" + dll + "\"" : " (name unread)") + + " (do not invent 0x81360000)"); + BootLog.Write("[Hive] ExtraROM BindImp vbase=0x" + + vbase.ToString("X8") + + " hdr=0x" + hdr.ToString("X8") + + " e32=0x" + e32.ToString("X8") + + (dll.Length > 0 ? " \"" + dll + "\"" : " (name unread)")); + NoteDdiNopWalkSeeds(regs); + if (_ddiNopLandedBySig) + TrySetDdiNopRamStartip(bus, 0, regs); + return false; + } + if (pc == BindImpDllName && !_ddiNopBindName) + { + _ddiNopBindName = true; + uint nameVa = regs[3]; + string dll = ""; + try + { + if (bus != null && nameVa != 0) + dll = ReadAscii(bus, nameVa); + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM BindImp nameVA=0x" + + nameVa.ToString("X8") + + (dll.Length > 0 ? " \"" + dll + "\"" : " (empty or unmapped)") + + " (LoadLibrary of this import; 126 is this miss)"); + return false; + } + if (pc == BindImpLoadLib && _ddiNopBindHdr && !_ddiNopBindLib) + { + _ddiNopBindLib = true; + uint a0 = regs[4]; + string dll = ""; + try + { + if (bus != null && a0 != 0) + dll = ReadUtf16Name(bus, a0); + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM BindImp LoadLibrary \"" + + (dll.Length > 0 ? dll : "(empty)") + + "\" a0=0x" + a0.ToString("X8")); + _ddiNopBindLibName = dll; + LogRomAttach("ok", "ExtraROM", "", -1, dll.Length > 0 ? dll : "(empty)", 0, 0, 0, 0, + "BindImp LoadLibrary; do not invent the DLL"); + return false; + } + if (pc == BindImpLoadLibRet && _ddiNopBindLib && !_ddiNopBindLibRet) + { + _ddiNopBindLibRet = true; + uint v0 = regs[2]; + System.Console.WriteLine("[Hive] ExtraROM BindImp LoadLibrary ret v0=0x" + + v0.ToString("X8") + + (v0 == 0 ? " (import miss; last-error 126)" : " (import loaded)")); + LogRomAttach(v0 == 0 ? "miss" : "ok", "ExtraROM", "", -1, "", 0, 0, 0, 0, + v0 == 0 + ? "BindImp LoadLibrary ret v0=0 import miss; last-error 126; do not invent the DLL" + : "BindImp LoadLibrary ret v0=0x" + v0.ToString("X8")); + // Live 9183b83: serve dest6 + entry-word + // 0x27BDFFD8; FindInFlight returned 0 + // (heap TOC-attach openexe, not obj-96). + // Walk the MODULE list from live v0 / $fp. + _ddiNopBindLibV0 = v0; + if (v0 != 0 && NamesMatchRom(_ddiNopBindLibName, "coredll.dll")) + { + _coredllModule = v0; + TryKeepCoredllImageBasePtr(bus, v0); + } + NoteDdiNopWalkSeeds(regs); + if (_ddiNopLandedBySig) + TrySetDdiNopRamStartip(bus, 0, regs); + if (_ddiNopModule == 0) + LogDdiNopBindWalkOnce(bus); + else if (_ddiNopLandedBySig) + { + // Live c231655: NK/filesys CallDLL during + // early boot set saw=true. Reset so this + // load's poll is a fresh window. + _ddiNopAwaitCallDll = true; + _ddiNopSawCallDllPc = false; + _ddiNopCallDllMissPoll = 0; + // Live b4b6454: BindImp vbase is VALLOC + // 0x01980000; IAT FT is .data RVA 0x19000. + // Only .text was CEDecompress'd. Observe + // the IAT page and serve the TOC .data + // o32 dest if it was never mapped. Do + // not force CallDLL here. + TryServeDdiNopDataO32(bus); + TryLogDdiNopIatPage(bus); + _ddiNopIatWatch = true; + } + return false; + } + TryNoteDdiNopOrdGetProc(bus, regs, pc); + return false; + } + + // Live 404d06b: stall at 0x8001F7D0 lw MODULE+0x50. + // Rate-limit first + every 256th, max 5. Peek only. + // Do not invent BasePtr / export dir / GetProc VA. + public static void TryNoteDdiNopOrdGetProc(MipsBus bus, uint[] regs, uint pc) + { + if (!_ddiNopAwaitCallDll || regs == null || regs.Length <= 5) + return; + if (pc == BindImpOrdBaseLw && regs.Length > 4) + TryKeepCoredllImageBasePtr(bus, regs[4]); + TryFixBindImpIatSlot(bus, regs, pc); + TryNoteBindImpAfterGoodV0(bus, pc); + TryNoteBindImpIatWindow(bus, regs, pc); + TryNoteBindImpExnSave(bus, regs, pc); + TryNoteDdiNopProcessInfo(bus, regs); + TryNoteDdiNopDllMain(bus, regs, pc); + TryNoteDdiNopAfterDllMain(bus, regs, pc); + if (pc == BindImpOrdJalRet) + { + uint v0 = regs[2]; + uint a1 = regs[5]; + if (v0 != 0 && _ddiNopOrdGoodV0 == 0) + { + _ddiNopOrdGoodV0 = v0; + _ddiNopOrdAfterN = 0; + TryArmUserKPageAlias(bus); + TryFixBindImpIatSlot(bus, regs, pc); + } + if (a1 == _ddiNopOrdRetLastA1 || _ddiNopOrdRetLog >= BindImpObserveMax) + return; + _ddiNopOrdRetLastA1 = a1; + _ddiNopOrdRetLog++; + uint iat = 0; + uint dest6 = 0; + PeekDdiNopIatWord(bus, out iat, out dest6); + uint fp = regs.Length > 30 ? regs[30] : 0; + uint fp1c = 0; + TryPeekWord(bus, fp + BindImpFpIatOff, out fp1c); + BootLog.Write("[Hive] ExtraROM BindImp-ord ret v0=0x" + + v0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " iat=0x" + iat.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " fp1c=0x" + fp1c.ToString("X8") + + " v1=0x" + regs[3].ToString("X8") + + (v0 == 0 ? " (unresolved)" : "")); + return; + } + if (pc != BindImpOrdBaseLw) + return; + uint a0 = regs[4]; + uint a1o = regs[5]; + if (a1o == _ddiNopOrdLastA1 || _ddiNopOrdLog >= BindImpObserveMax) + return; + _ddiNopOrdLastA1 = a1o; + _ddiNopOrdLog++; + uint ra = regs.Length > 31 ? regs[31] : 0; + uint p50 = 0; + uint exp = 0; + uint end = 0; + bool p50ok = a0 != 0 && TryPeekWord(bus, a0 + ProcModule, out p50); + bool expok = a0 != 0 && TryPeekWord(bus, a0 + ModuleExpRva, out exp); + TryPeekWord(bus, a0 + ModuleExpEnd, out end); + uint fp0 = regs.Length > 30 ? regs[30] : 0; + uint fp1c0 = 0; + TryPeekWord(bus, fp0 + BindImpFpIatOff, out fp1c0); + uint kdata0 = 0; + bool kOk0 = TryPeekWord(bus, UserKPage, out kdata0); + BootLog.Write("[Hive] ExtraROM BindImp-ord a0=0x" + + a0.ToString("X8") + + " a1=0x" + a1o.ToString("X8") + + " p50=0x" + p50.ToString("X8") + + (p50ok ? "" : " unmapped") + + " exp=0x" + exp.ToString("X") + + (expok ? "" : " unread") + + " +90=0x" + end.ToString("X") + + " fp1c=0x" + fp1c0.ToString("X8") + + (kOk0 + ? " FFFF5800=0x" + kdata0.ToString("X8") + : " FFFF5800-unmapped") + + " ra=0x" + ra.ToString("X8") + + (_ddiNopIatStoreLogged ? " after-slot0" : "")); + if (_ddiNopOrdExpLogged || !p50ok || !expok || p50 == 0 || exp == 0) + return; + uint expVa = p50 + exp; + uint w0 = 0; + uint w1 = 0; + uint w2 = 0; + uint w3 = 0; + if (!TryPeekWord(bus, expVa, out w0) + || !TryPeekWord(bus, expVa + 4, out w1) + || !TryPeekWord(bus, expVa + 8, out w2) + || !TryPeekWord(bus, expVa + 12, out w3)) + return; + _ddiNopOrdExpLogged = true; + BootLog.Write("[Hive] ExtraROM BindImp-ord expVA=0x" + + expVa.ToString("X8") + + " w0=0x" + w0.ToString("X8") + + " w1=0x" + w1.ToString("X8") + + " w2=0x" + w2.ToString("X8") + + " w3=0x" + w3.ToString("X8")); + } + + private static void HostCommitExtraRomDest(MipsBus bus, uint dest, uint vsize) + { + if (bus == null || dest == 0 || vsize == 0) + return; + uint kseg = 0; + uint off = 0; + if (dest >= 0x01980000u && dest < 0x019B0000u) + { + kseg = ExtraRomDestKseg0; + off = dest - 0x01980000u; + } + else if (dest >= 0x01F57000u && dest < 0x01F67000u) + { + kseg = ExtraRomDestKseg1; + off = dest - 0x01F57000u; + } + else if (dest >= 0x014B0000u && dest < 0x014D0000u) + { + kseg = ExtraRomDestKsegMscoree; + off = dest - 0x014B0000u; + } + else if (dest >= 0x01F32000u && dest < 0x01F33000u) + { + kseg = ExtraRomDestKsegMscoree1; + off = dest - 0x01F32000u; + } + else if (dest >= 0x01940000u && dest < 0x01980000u) + { + kseg = ExtraRomDestKsegOle32; + off = dest - 0x01940000u; + } + if (kseg == 0) + { + ExtraRomTocMod slot = FindCachedTocByDest(dest); + if (slot != null) + { + HostMapFirmwareTocDest(bus, slot, dest, vsize); + slot.DecompDest = dest; + } + return; + } + try + { + uint n = (vsize + 0x1FFFu) & ~0xFFFu; + for (uint i = 0; i < n; i += 4) + bus.Write32(kseg + off + i, 0); + } + catch + { + } + } + + private static uint CopyExtraRomSrcPageAligned(MipsBus bus, uint src, uint psize) + { + if (bus == null || src == 0 || psize == 0 || psize > 0x20000) + return 0; + if ((src & 0xFFF) == 0) + return src; + int slot = -1; + uint[][] cache = null; + int baseSlot = 0; + if (_mscoreeDataPtr != null) + { + for (int s = 0; s < _mscoreeDataPtr.Length; s++) + { + if (_mscoreeDataPtr[s] == src) + { + slot = s; + cache = _mscoreeData; + baseSlot = 4; + break; + } + } + } + if (slot < 0 && _ole32DataPtr != null) + { + for (int s = 0; s < _ole32DataPtr.Length; s++) + { + if (_ole32DataPtr[s] == src) + { + slot = s; + cache = _ole32Data; + baseSlot = 8; + break; + } + } + } + if (slot < 0 && _ddiNopDataPtr != null) + { + for (int s = 0; s < _ddiNopDataPtr.Length; s++) + { + if (_ddiNopDataPtr[s] == src) + { + slot = s; + cache = _ddiNopData; + break; + } + } + } + if (slot < 0) + slot = 0; + uint dest = AlignedCompSrc + (uint)(baseSlot + slot) * AlignedCompStride; + try + { + uint[] blob = null; + if (cache != null && slot < cache.Length) + blob = cache[slot]; + uint n = (psize + 3) / 4; + if (blob != null && blob.Length < n) + n = (uint)blob.Length; + for (uint w = 0; w < n; w++) + { + uint word = blob != null && w < blob.Length + ? blob[w] + : bus.Read32(src + w * 4); + bus.Write32(dest + w * 4, word); + } + return dest; + } + catch + { + return 0; + } + } + + private static uint ExtraRomO32Access(MipsBus bus, uint[] regs) + { + uint o32 = regs != null && regs.Length > 23 ? regs[23] : 0; + uint access = 0; + uint flags = 0; + try + { + if (bus != null && o32 != 0) + { + access = bus.Read32(o32 + 0xC); + flags = bus.Read32(o32 + 0x10); + } + } + catch + { + } + uint page = access & 0xFF; + if (page == 1 || page == 2 || page == 4 || page == 8 + || page == 0x10 || page == 0x20 || page == 0x40 || page == 0x80) + return page; + if ((flags & 0x80000000u) != 0) + return 0x40; + return 0x20; + } + + private static bool DestReadable(MipsBus bus, uint dest) + { + if (bus == null || dest == 0) + return false; + try + { + bus.Read32(dest); + return true; + } + catch + { + return false; + } + } + + private static bool IsExtraRomDdiNopDest(uint dest) + { + uint slot = dest & SlotMask; + return (dest >= DdiNopVbase && dest < 0x039B0000u) + || (slot >= 0x01980000u && slot < 0x019B0000u) + || (dest >= 0x01F57000u && dest < 0x01F66000u); + } + + private static bool IsExtraRomDdiNopData(uint dataptr) + { + // ole32 o32[0] dataptr 0x807752F4 sits past ddi_nop + // o32[2]. Do not treat that dump blob as ddi_nop. + if (IsExtraRomOle32Data(dataptr)) + return false; + return dataptr >= 0x80764CE0u && dataptr < 0x807752F4u; + } + + // wait62: TOC[46] dump o32.real / dataptr. Not invented. + private static bool IsExtraRomMscoreeDest(uint dest) + { + if (dest == 0 || _mscoreeO32Words == null) + return false; + uint slot = dest & SlotMask; + for (int s = 0; s + 5 < _mscoreeO32Words.Length; s += 6) + { + uint vsize = _mscoreeO32Words[s]; + uint rva = _mscoreeO32Words[s + 1]; + uint real = _mscoreeO32Words[s + 4]; + if (real == 0) + continue; + uint span = vsize == 0 ? 0x1000u : ((vsize + 0xFFFu) & ~0xFFFu); + if (span < 0x1000) + span = 0x1000; + uint loSlot = real & SlotMask; + if ((dest >= real && dest < real + span) + || (slot >= loSlot && slot < loSlot + span)) + return true; + if (rva == 0x1000 && real >= 0x1000) + { + uint vbase = real - 0x1000; + uint vbaseSlot = vbase & SlotMask; + if (dest == vbase || dest == vbaseSlot || slot == vbaseSlot) + return true; + } + } + return false; + } + + private static bool IsExtraRomMscoreeData(uint dataptr) + { + if (dataptr == 0 || _mscoreeDataPtr == null) + return false; + for (int s = 0; s < _mscoreeDataPtr.Length; s++) + { + uint p = _mscoreeDataPtr[s]; + if (p == 0) + continue; + if (dataptr == p) + return true; + uint n = _mscoreeDataLen != null && s < _mscoreeDataLen.Length + ? _mscoreeDataLen[s] : 0; + if (n != 0 && dataptr > p && dataptr < p + n) + return true; + } + return false; + } + + // wait65: TOC[34] dump o32.real / dataptr. Not invented. + private static bool IsExtraRomOle32Dest(uint dest) + { + if (dest == 0 || _ole32O32Words == null) + return false; + uint slot = dest & SlotMask; + for (int s = 0; s + 5 < _ole32O32Words.Length; s += 6) + { + uint vsize = _ole32O32Words[s]; + uint rva = _ole32O32Words[s + 1]; + uint real = _ole32O32Words[s + 4]; + if (real == 0) + continue; + uint span = vsize == 0 ? 0x1000u : ((vsize + 0xFFFu) & ~0xFFFu); + if (span < 0x1000) + span = 0x1000; + uint loSlot = real & SlotMask; + if ((dest >= real && dest < real + span) + || (slot >= loSlot && slot < loSlot + span)) + return true; + if (rva == 0x1000 && real >= 0x1000) + { + uint vbase = real - 0x1000; + uint vbaseSlot = vbase & SlotMask; + if (dest == vbase || dest == vbaseSlot || slot == vbaseSlot) + return true; + } + } + return false; + } + + private static bool IsExtraRomOle32Data(uint dataptr) + { + if (dataptr == 0 || _ole32DataPtr == null) + return false; + for (int s = 0; s < _ole32DataPtr.Length; s++) + { + uint p = _ole32DataPtr[s]; + if (p == 0) + continue; + if (dataptr == p) + return true; + uint n = _ole32DataLen != null && s < _ole32DataLen.Length + ? _ole32DataLen[s] : 0; + if (n != 0 && dataptr > p && dataptr < p + n) + return true; + } + return false; + } + + private static bool IsExtraRomCompressedDest(uint dest) + { + if (IsExtraRomDdiNopDest(dest) || IsExtraRomMscoreeDest(dest) + || IsExtraRomOle32Dest(dest)) + return true; + return false; + } + + private static ExtraRomTocMod FindCachedTocByDest(uint dest) + { + if (_romTocMods == null || dest == 0) + return null; + if (dest >= ExtraRomTocDestHost && dest < ExtraRomTocDestHostLim) + return null; + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod slot = _romTocMods[i]; + if (slot == null || slot.Dest == 0) + continue; + uint vsize = slot.O32Words != null && slot.O32Words.Length > 0 + ? slot.O32Words[0] : 0; + if (vsize == 0) + vsize = 0x1000; + uint dump = slot.Dest; + uint slot0 = dump & SlotMask; + if (dest >= dump && dest < dump + vsize) + return slot; + if (dest >= slot0 && dest < slot0 + vsize) + return slot; + } + return null; + } + + private static ExtraRomTocMod FindCachedTocByDataptr(uint dataptr) + { + if (_romTocMods == null || dataptr == 0) + return null; + if (IsExtraRomDdiNopData(dataptr)) + return FindCachedExtraRomToc("ddi_nop.dll"); + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod slot = _romTocMods[i]; + if (slot == null) + continue; + if (slot.DataPtr != null) + { + for (int s = 0; s < slot.DataPtr.Length; s++) + { + if (slot.DataPtr[s] != 0 && slot.DataPtr[s] == dataptr) + return slot; + } + } + if (slot.O32Words == null) + continue; + int nsec = slot.O32Words.Length / 6; + for (int s = 0; s < nsec; s++) + { + if (slot.O32Words[s * 6 + 3] == dataptr) + return slot; + } + } + return null; + } + + // MapO32 0x8001AC30 a0=obj a1=o32_lite; dest at +8, + // dataptr at +0x18. 0x80028844 a0=dest a1=dataptr + // a2=vsize. 0x8004DBF8 a0=src a2=dest. ddi_nop + // VALLOC dest 0x01981000 and dataptr 0x80764CE0 + // are dump-real (c1c0bc4). Do not invent dest. + private static ExtraRomTocMod FindExtraRomMapSlot(MipsBus bus, uint[] regs, uint pc) + { + if (regs == null || regs.Length <= 4) + return null; + ExtraRomTocMod slot = null; + uint a0 = regs[4]; + uint a1 = regs.Length > 5 ? regs[5] : 0; + uint a2 = regs.Length > 6 ? regs[6] : 0; + if (pc == MapO32Rom || pc == MapO32FlagsBnez) + { + try + { + if (bus != null && a0 != 0 && bus.Read8(a0 + 4) == TocAttachType) + slot = FindCachedTocByEntry(bus.Read32(a0)); + } + catch + { + } + uint dest = 0; + uint dataptr = 0; + if (bus != null && a1 != 0) + { + dest = PeekDestWord(bus, a1 + 8); + dataptr = PeekDestWord(bus, a1 + 0x18); + } + if (slot == null && dest == 0x01981000u) + slot = FindCachedExtraRomToc("ddi_nop.dll"); + if (slot == null) + slot = FindCachedTocByDest(dest); + if (slot == null) + slot = FindCachedTocByDataptr(dataptr); + } + else if (pc == MapO32InnerJal || pc == MapO32Decompress || pc == MapO32VallocJal) + { + if (a0 == 0x01981000u || a1 == 0x01981000u) + slot = FindCachedExtraRomToc("ddi_nop.dll"); + if (slot == null) + slot = FindCachedTocByDest(a0); + if (slot == null) + slot = FindCachedTocByDataptr(a1); + } + else if (pc == BinaryDecompressRom) + { + if (a2 == 0x01981000u) + slot = FindCachedExtraRomToc("ddi_nop.dll"); + if (slot == null) + slot = FindCachedTocByDest(a2); + if (slot == null) + slot = FindCachedTocByDataptr(a0); + } + else + { + try + { + if (bus != null && a0 != 0 && bus.Read8(a0 + 4) == TocAttachType) + slot = FindCachedTocByEntry(bus.Read32(a0)); + } + catch + { + } + } + return slot; + } + + private static bool IsCompareExtraRom(ExtraRomTocMod slot) + { + return slot != null && (NamesMatchRom(slot.Name, "bcmuart.dll") + || NamesMatchRom(slot.Name, "ddi_nop.dll")); + } + + private static bool WatchMatchesExtraRom(MipsBus bus, uint[] regs, uint pc) + { + if (string.IsNullOrEmpty(_loadE32OkName)) + return false; + uint obj = regs != null && regs.Length > 4 ? regs[4] : 0; + if (_loadE32OkObj != 0 && obj == _loadE32OkObj) + return true; + ExtraRomTocMod hit = FindExtraRomMapSlot(bus, regs, pc); + return hit != null && NamesMatchRom(hit.Name, _loadE32OkName); + } + + private static bool IsExtraRomCompressedData(uint dataptr) + { + if (IsExtraRomDdiNopData(dataptr) || IsExtraRomMscoreeData(dataptr) + || IsExtraRomOle32Data(dataptr)) + return true; + if (_romTocMods == null) + return false; + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod slot = _romTocMods[i]; + if (slot == null || slot.DataPtr == null) + continue; + for (int s = 0; s < slot.DataPtr.Length; s++) + { + if (slot.DataPtr[s] != 0 && slot.DataPtr[s] == dataptr) + return true; + } + } + return false; + } + + private static bool IsExtraRomHeaderDestPage(uint slotPage) + { + if (slotPage == 0x01981000u || slotPage == 0x01941000u) + return true; + if (_mscoreeO32Words == null || _mscoreeO32Words.Length < 6) + return false; + uint rva = _mscoreeO32Words[1]; + uint real = _mscoreeO32Words[4]; + if (rva != 0x1000 || real == 0) + return false; + return (real & SlotMask & 0xFFFFF000u) == slotPage; + } + + public static bool IsDdiNopTocObject(MipsBus bus, uint obj) + { + if (bus == null || obj == 0) + return false; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return false; + uint toc = bus.Read32(obj); + if (_ddiNopTocEntry != 0 && toc == _ddiNopTocEntry) + return true; + ExtraRomTocMod slot = FindCachedTocByEntry(toc); + return slot != null && NamesMatchRom(slot.Name, "ddi_nop.dll"); + } + catch + { + return false; + } + } + + public static uint DdiNopTocEntry + { + get { return _ddiNopTocEntry; } + } + + public static bool IsMscoreeTocObject(MipsBus bus, uint obj) + { + if (bus == null || obj == 0) + return false; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return false; + uint toc = bus.Read32(obj); + if (_mscoreeTocEntry != 0 && toc == _mscoreeTocEntry) + return true; + ExtraRomTocMod slot = FindCachedTocByEntry(toc); + return slot != null && IsMscoreeDll(slot.Name); + } + catch + { + return false; + } + } + + public static uint MscoreeTocEntry + { + get { return _mscoreeTocEntry; } + } + + public static uint MscoreeE32 + { + get { return _mscoreeE32; } + } + + public static bool IsOle32TocObject(MipsBus bus, uint obj) + { + if (bus == null || obj == 0) + return false; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return false; + uint toc = bus.Read32(obj); + if (_ole32TocEntry != 0 && toc == _ole32TocEntry) + return true; + ExtraRomTocMod slot = FindCachedTocByEntry(toc); + return slot != null && IsOle32Dll(slot.Name); + } + catch + { + return false; + } + } + + public static uint Ole32TocEntry + { + get { return _ole32TocEntry; } + } + + public static uint Ole32E32 + { + get { return _ole32E32; } + } + + public static bool TryDescribeExtraRomTocObject(MipsBus bus, uint obj, + out string name, out int index, out uint tocEntry, out uint e32) + { + name = ""; + index = -1; + tocEntry = 0; + e32 = 0; + if (bus == null || obj == 0) + return false; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return false; + tocEntry = bus.Read32(obj); + } + catch + { + return false; + } + ExtraRomTocMod slot = FindCachedTocByEntry(tocEntry); + if (slot != null) + { + name = slot.Name; + index = slot.Index; + e32 = slot.LiveE32 != 0 ? slot.LiveE32 : slot.E32; + return true; + } + if (tocEntry == _ddiNopTocEntry && tocEntry != 0) + { + name = "ddi_nop.dll"; + index = 33; + return true; + } + if (tocEntry == _mscoreeTocEntry && tocEntry != 0) + { + name = "mscoree.dll"; + index = 46; + e32 = _mscoreeE32; + return true; + } + if (tocEntry == _ole32TocEntry && tocEntry != 0) + { + name = "ole32.dll"; + index = 34; + e32 = _ole32E32; + return true; + } + return false; + } + + public static void NoteLoadE32(string name, int index) + { + _pendingLoadE32Name = name; + _pendingLoadE32Index = index; + } + + public static bool TryPeekLoadE32(out string name, out int index) + { + name = _pendingLoadE32Name ?? ""; + index = _pendingLoadE32Index; + return name.Length != 0; + } + + public static bool TryGetCachedExtraRomToc(string name, out int index, out uint tocEntry, out uint dest) + { + ExtraRomTocMod slot = FindCachedExtraRomToc(name); + if (slot == null) + { + index = -1; + tocEntry = 0; + dest = 0; + return false; + } + index = slot.Index; + tocEntry = slot.Entry; + dest = slot.Dest; + return true; + } + + public static void LogExtraRomTocAttachCache() + { + BootLog.Write("[NkBinLoader] ExtraROM TOC type-7 attach cache count=" + _romTocCount + + " FILE type-8 cache count=" + _romFileCount); + string[] probe = + { + "bcmuart.dll", "NDIS.Dll", "ndisuio.dll", "sipcfg.exe", + "timesvc.dll", "waveapi.dll", "AFD.Dll", "cfgrdr.dll", + "credsvc.dll", "ehci.dll", "nleddrvr.dll", "ohci2.dll", + "PPP.Dll", "uspce.dll", "serial.dll", "iptvdriver.dll", + "ddi_nop.dll", "mscoree.dll", "ole32.dll", "RunOnce.exe", + "mscorlib.dll", "tv2clientce.exe", "com16550.dll", + "keybddr.dll", "ddcore.dll", "EVENTLOG.DLL", "LMemDebug.DLL" + }; + for (int i = 0; i < probe.Length; i++) + { + string n = probe[i]; + int index; + uint entry; + uint dest; + if (TryGetCachedExtraRomToc(n, out index, out entry, out dest)) + { + BootLog.Rom("ok", "ExtraROM", "TOC", index, n, 7, dest, 0, 0, "cached"); + continue; + } + ExtraRomOpenFile file = FindExtraRomOpenFile(n); + if (file != null || IsTv2ClientCe(n)) + { + int fi = file != null ? file.Index : 25; + BootLog.Rom("ok", "ExtraROM", "FILE", fi, n, 8, 0, 0, 0, + "FILE type-8 dest/cache; not ExtraROM TOC type-7"); + continue; + } + BootLog.Rom("miss", "ExtraROM", "", -1, n, 0, 0, 0, 0, + "not in ExtraROM TOC/FILE; honest miss; do not invent"); + } + LogCachedExtraRomFragment("iptvhal"); + } + + // ExtraROM has iptvhal_* TOC names, not a bare iptvhal.dll. + // Log the dump names so CreateFile/LoadLibrary can attach + // them type-7. Do not invent iptvhal.dll or a Display REG_SZ. + private static void LogCachedExtraRomFragment(string fragment) + { + if (string.IsNullOrEmpty(fragment)) + return; + int hits = 0; + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod m = _romTocMods[i]; + if (m == null || string.IsNullOrEmpty(m.Name) + || m.Name.IndexOf(fragment, System.StringComparison.OrdinalIgnoreCase) < 0) + continue; + hits++; + BootLog.Rom("ok", "ExtraROM", "TOC", m.Index, m.Name, 7, m.Dest, 0, 0, + "cached iptvhal_* for CreateFileFail/OpenFile/LoadLibrary type-7; Display stays ddi_nop.dll"); + } + for (int i = 0; i < _romFileCount; i++) + { + ExtraRomOpenFile f = _romFiles[i]; + if (f == null || string.IsNullOrEmpty(f.Label) + || f.Label.IndexOf(fragment, System.StringComparison.OrdinalIgnoreCase) < 0) + continue; + hits++; + BootLog.Rom("ok", "ExtraROM", "FILE", f.Index, f.Label, 8, f.Load, 0, 0, + "FILE type-8 dest/cache; not ExtraROM TOC type-7"); + } + if (hits == 0) + BootLog.Rom("miss", "ExtraROM", "", -1, fragment, 0, 0, 0, 0, + "no ExtraROM TOC/FILE *" + fragment + "* ; honest miss; do not invent iptvhal.dll or a Display REG_SZ"); + } + + public static void NoteExtraRom(uint imageStart) + { + _extraRomStart = imageStart; + _extraRomHdr = 0; + _romHdrChainLogged = false; + _romHdrListWalkLogged = false; + _obj6ShLogged = false; + _romHdrLinkEnterCount = 0; + _romHdrLinkPublishCount = 0; + _romHdrLinkSpliceCount = 0; + _romHdrLinkJalLogged = false; + _romHdrLinkContinueLogged = false; + _pendingRomFile = null; + _lastRomAttachKey = null; + _ddiNopTocEntry = 0; + _ddiNopAttr = 0; + _ddiNopTocWords = null; + _ddiNopE32 = 0; + _ddiNopE32Words = null; + _ddiNopO32 = 0; + _ddiNopO32Words = null; + _ddiNopDataPtr = null; + _ddiNopDataLen = null; + _ddiNopData = null; + _ddiNopDestOn = false; + _ddiNopSlot0 = 0; + _ddiNopDest0PteLogged = false; + _ddiNopDest0Pte = 0; + _ddiNopDestPeekRaw = false; + _ddiNopDestPteMeasured = false; + _ddiNopLandedDest = 0; + _ddiNopLandedWord = 0; + _ddiNopLandedBySig = false; + _ddiNopModule = 0; + ResetDdiNopModuleHunt(); + _mscoreeDestOn = false; + _mscoreeSlot0 = 0; + _mscoreeVbase = 0; + _ole32DestOn = false; + _ole32Slot0 = 0; + _ole32Vbase = 0; + _ddiNopDecompRa = 0; + _ddiNopDecompSrc = 0; + _ddiNopDecompCb = 0; + _ddiNopDecompDest = 0; + _ddiNopDecompVsize = 0; + _ddiNopDecompHdr = 0; + ResetDdiNopDecompStores(); + _ddiNopDestWordLogged = false; + _ddiNopObserve = false; + _ddiNopInnerCap = false; + _ddiNopInnerPages = 0; + _ddiNopBindHdr = false; + _ddiNopBindName = false; + _ddiNopBindLib = false; + _ddiNopBindLibRet = false; + ResetDdiNopModuleHunt(); + _tv2FileEntry = 0; + _tv2FileWords = null; + _tv2FileName = 0; + _tv2FileNameWords = null; + _tv2FileReal = 0; + _tv2FileComp = 0; + _tv2FileLoad = 0; + _tv2FileData = null; + _tv2FileDecompRa = 0; + _tv2FileSavedSp = 0; + _tv2FilePos = 0; + _tv2FileDestOn = false; + _tv2FileIoLogged = false; + _romFiles = null; + _romFileCount = 0; + _romFile = null; + _romFileDecompRa = 0; + _romFileSavedSp = 0; + _romFilePos = 0; + _romFileDestOn = false; + _romFileIoLogged = false; + _romFileAttach = false; + _tv2PeImageVa = 0; + _tv2PeImageBytes = 0; + _tv2PeVallocRa = 0; + _tv2BindLogged = false; + _tv2PeEntryRva = 0; + _tv2PeImageBase = 0; + _tv2PeComRva = 0; + _tv2Proc = 0; + _tv2Startip = 0; + _tv2Thread = 0; + _tv2FetchLogged = false; + _tv2ContinueLogged = false; + _tv2ExnHelperLogged = false; + _tv2PostFetchExnLogged = false; + _tv2ImplAdelLogged = false; + _tv2AfterExnContLogged = false; + _pteMapBusy = false; + _pteMapLogged = false; + _slot2MapLogged = false; + _slot0InfoMapLogged = false; + _slot0FetchMapLogged = false; + _tv2CoredllLogged = false; + _tv2CoredllContLogged = false; + _coredllLiveSec = 0; + _coredllLiveLogged = false; + _coredllMapLogged = false; + _coredllHighLogged = false; + _coredllZeroLogged = false; + _tv2ZeroContLogged = false; + _tv2HighContLogged = false; + _tv2ImplRa = 0; + _tv2ImplResume = 0; + _tv2ImplEpc = 0; + _tv2ImplK1Before = 0; + _tv2ImplContLogged = false; + _tv2ImplPastLogged = false; + _tv2UserSrLogged = false; + _tv2DispatchCtxLogged = false; + _tv2UserSpLogged = false; + _tv2UserRaLogged = false; + _tv2StoreSp = 0; + _tv2StoreContLogged = false; + _tv2LeftoverStoreFrame = false; + _tv2StoreFrameLogged = false; + _tv2LeftoverLiveLogged = false; + _tv2LeftoverPastLogged = false; + _tv2LeftoverCae8Logged = false; + _tv2LeftoverSkipLogged = false; + _tv2LeftoverCaf0Logged = false; + _tv2LeftoverCaf0Peeked = false; + _tv2LeftoverCaf0Word = 0; + _tv2LeftoverCae8V0Set = false; + _tv2LeftoverCae8V0 = 0; + _tv2LeftoverCae8S6Set = false; + _tv2LeftoverCae8S6 = 0; + _tv2LeftoverS6Logged = false; + _tv2LeftoverCaf4Peeked = false; + _tv2LeftoverCaf4Word = 0; + _tv2LeftoverCafcPeeked = false; + _tv2LeftoverCafcWord = 0; + _tv2LeftoverAfterCaf0Logged = false; + _tv2LeftoverPastAfterLogged = false; + _tv2LeftoverPastCb0cLogged = false; + _tv2LeftoverCb14Peeked = false; + _tv2LeftoverCb14Word = 0; + _tv2LeftoverAfterCb10Logged = false; + _tv2LeftoverPastCb14Logged = false; + _tv2LeftoverCb34Peeked = false; + _tv2LeftoverCb34Word = 0; + _tv2LeftoverAfterCb14Logged = false; + _tv2LeftoverPastCb34Logged = false; + _tv2LeftoverCb38Peeked = false; + _tv2LeftoverCb38Word = 0; + _tv2LeftoverAfterCb34Logged = false; + _tv2LeftoverPastCb38Logged = false; + _tv2LeftoverCb3cPeeked = false; + _tv2LeftoverCb3cWord = 0; + _tv2LeftoverAfterCb38Logged = false; + _tv2LeftoverPastCb3cLogged = false; + _tv2LeftoverCb40Peeked = false; + _tv2LeftoverCb40Word = 0; + _tv2LeftoverAfterCb3cLogged = false; + _tv2LeftoverPastCb40Logged = false; + _tv2LeftoverCb44Peeked = false; + _tv2LeftoverCb44Word = 0; + _tv2LeftoverAfterCb40Logged = false; + _tv2LeftoverPastCb44Logged = false; + _tv2LeftoverCb48Peeked = false; + _tv2LeftoverCb48Word = 0; + _tv2LeftoverAfterCb44Logged = false; + _tv2LeftoverPastCb48Logged = false; + _tv2LeftoverCb4cPeeked = false; + _tv2LeftoverCb4cWord = 0; + _tv2LeftoverAfterCb48Logged = false; + _tv2LeftoverPastCb4cLogged = false; + _tv2LeftoverAfterCb4cLogged = false; + _tv2LeftoverPastJrRaLogged = false; + _tv2LeftoverJrRaDest = 0; + _tv2LeftoverBeqRaV0Set = false; + _tv2LeftoverBeqRaV0 = 0; + _tv2LeftoverBeqRaFtPeeked = false; + _tv2LeftoverBeqRaFtWord = 0; + _tv2LeftoverBeqRaTkPeeked = false; + _tv2LeftoverBeqRaTkWord = 0; + _tv2LeftoverAfterJrRaLogged = false; + _tv2LeftoverPastBeqRaFtLogged = false; + _tv2LeftoverPastBeqRaTkLogged = false; + _tv2LeftoverBPlus2DelayPeeked = false; + _tv2LeftoverBPlus2DelayWord = 0; + _tv2LeftoverBPlus2TakenPeeked = false; + _tv2LeftoverBPlus2TakenWord = 0; + _tv2LeftoverAfterBPlus2Logged = false; + _tv2LeftoverPastBPlus2DelayLogged = false; + _tv2LeftoverPastBPlus2TakenLogged = false; + _tv2LeftoverBPlus2NextPeeked = false; + _tv2LeftoverBPlus2NextWord = 0; + _tv2LeftoverAfterBPlus2TakenLogged = false; + _tv2LeftoverPastBPlus2NextLogged = false; + _tv2LeftoverFpNextPeeked = false; + _tv2LeftoverFpNextWord = 0; + _tv2LeftoverAfterFpLogged = false; + _tv2LeftoverPastFpNextLogged = false; + _tv2LeftoverS7NextPeeked = false; + _tv2LeftoverS7NextWord = 0; + _tv2LeftoverAfterS7Logged = false; + _tv2LeftoverPastS7NextLogged = false; + _tv2LeftoverS6NextPeeked = false; + _tv2LeftoverS6NextWord = 0; + _tv2LeftoverAfterS6Logged = false; + _tv2LeftoverPastS6NextLogged = false; + _tv2LeftoverS5NextPeeked = false; + _tv2LeftoverS5NextWord = 0; + _tv2LeftoverAfterS5Logged = false; + _tv2LeftoverPastS5NextLogged = false; + _tv2LeftoverS4NextPeeked = false; + _tv2LeftoverS4NextWord = 0; + _tv2LeftoverAfterS4Logged = false; + _tv2LeftoverPastS4NextLogged = false; + _tv2LeftoverEpiloguePeeked = false; + _tv2LeftoverEpilogueWord = 0; + _tv2LeftoverPastEpilogueLogged = false; + _tv2LeftoverPastEpilogueDelayLogged = false; + _tv2LeftoverDestLiveNext = 0; + _tv2LeftoverUserRaSet = false; + _tv2LeftoverUserRa = 0; + _tv2LeftoverEretLogged = false; + _tv2LeftoverDropLogged = false; + _tv2LeftoverDestLiveEretLogged = false; + _tv2LeftoverDispatchLogged = false; + _tv2GwesFetchLogged = false; + _tv2GwesContLogged = false; + _tv2MscoreeSlotLogged = false; + _coredllMapBusy = false; + _tv2ProcSwitchLogged = false; + _tv2CurThreadLogged = false; + _tv2RestoreLogged = false; + _tv2SwitchForced = false; + _tv2SwitchStoreLogged = false; + _mscoreeTocEntry = 0; + _mscoreeAttr = 0; + _mscoreeTocWords = null; + _mscoreeE32 = 0; + _mscoreeE32Words = null; + _mscoreeO32 = 0; + _mscoreeO32Words = null; + _mscoreeDataPtr = null; + _mscoreeDataLen = null; + _mscoreeData = null; + _ole32TocEntry = 0; + _ole32Attr = 0; + _ole32TocWords = null; + _ole32E32 = 0; + _ole32E32Words = null; + _ole32O32 = 0; + _ole32O32Words = null; + _ole32DataPtr = null; + _ole32DataLen = null; + _ole32Data = null; + _romTocMods = null; + _romTocCount = 0; + _pendingLoadE32Name = null; + _pendingLoadE32Index = -1; + _e32HostPool = ExtraRomE32Host; + _e32HostCommitted = false; + _tocDestHostPool = ExtraRomTocDestHost; + _tocDestSlot0 = null; + _tocDestDump = null; + _tocDestVsize = null; + _tocDestKseg = null; + _tocDestReady = null; + _tocDestN = 0; + _tocSrcPool = ExtraRomTocSrc; + _tocSrcPtr = null; + _tocSrcLen = null; + _tocSrcKseg = null; + _tocSrcN = 0; + _tocDecompSlot = null; + _loadE32Obj = 0; + ClearLoadE32Watch(); + ClearNkLoadE32Watch(); + ClearNkLoadO32Watch(); + _nkLoadE32Logged = 0; + _nkLoadE32Ok = null; + _curMSecDisasmLogged = false; + ClearAfterLoadE32(); + _afterDisasm = null; + ClearLoadE32OkWatch(); + } + + public static void NoteExtraRomModule(uint romhdr, uint tocEntry, uint attr) + { + if (romhdr != 0) + _extraRomHdr = romhdr; + if (tocEntry != 0) + { + _ddiNopTocEntry = tocEntry; + _ddiNopAttr = attr; + } + } + + public static void CacheExtraRomDdiNop(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint tocEntry) + { + if (memory == null || tocEntry == 0) + return; + try + { + var toc = new uint[8]; + for (int i = 0; i < 8; i++) + toc[i] = memory.ReadMemory32(tocEntry + (uint)(i * 4)); + uint e32 = toc[5]; + uint o32 = toc[6]; + if (e32 == 0 || o32 == 0) + return; + uint objcnt = memory.ReadMemory32(e32) & 0xFFFF; + if (objcnt == 0 || objcnt > 16) + return; + var e32Words = new uint[32]; + for (int i = 0; i < e32Words.Length; i++) + e32Words[i] = memory.ReadMemory32(e32 + (uint)(i * 4)); + var o32Words = new uint[objcnt * 6]; + for (int i = 0; i < o32Words.Length; i++) + o32Words[i] = memory.ReadMemory32(o32 + (uint)(i * 4)); + var dataPtr = new uint[objcnt]; + var dataLen = new uint[objcnt]; + var data = new uint[objcnt][]; + for (uint s = 0; s < objcnt; s++) + { + uint psize = o32Words[s * 6 + 2]; + uint dataptr = o32Words[s * 6 + 3]; + if (dataptr == 0 || psize == 0 || psize > 0x20000) + continue; + uint n = (psize + 3) / 4; + var blob = new uint[n]; + for (uint w = 0; w < n; w++) + blob[w] = memory.ReadMemory32(dataptr + w * 4); + dataPtr[s] = dataptr; + dataLen[s] = psize; + data[s] = blob; + } + _ddiNopTocWords = toc; + _ddiNopE32 = e32; + _ddiNopE32Words = e32Words; + _ddiNopO32 = o32; + _ddiNopO32Words = o32Words; + _ddiNopDataPtr = dataPtr; + _ddiNopDataLen = dataLen; + _ddiNopData = data; + System.Console.WriteLine("[NkBinLoader] ExtraROM TOC[33] cached e32=0x" + + e32.ToString("X8") + " o32=0x" + o32.ToString("X8") + + " (restore if firmware RAM reuses ExtraROM tail)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[NkBinLoader] ExtraROM TOC[33] cache skipped: " + ex.Message); + } + } + + // wait54: FILE[25] FILESentry is 28 bytes at 0x8134E794 + // plus name at +0x14 and compressed bytes at load. + // Same ExtraROM-tail reuse that zeros TOC[33]. + public static void CacheExtraRomOpenFile(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint filesEntry, string label) + { + CacheExtraRomOpenFile(memory, filesEntry, label, -1); + } + + public static void CacheExtraRomOpenFile(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint filesEntry, string label, int index) + { + if (memory == null || filesEntry == 0 || string.IsNullOrEmpty(label)) + return; + if (IsTv2ClientCe(label)) + return; + try + { + var words = new uint[7]; + for (int i = 0; i < words.Length; i++) + words[i] = memory.ReadMemory32(filesEntry + (uint)(i * 4)); + uint real = words[3]; + uint comp = words[4]; + uint name = words[5]; + uint load = words[6]; + if (real == 0 || name == 0 || load == 0) + return; + uint[] nameWords = null; + if (name != 0) + { + nameWords = new uint[16]; + for (int i = 0; i < nameWords.Length; i++) + nameWords[i] = memory.ReadMemory32(name + (uint)(i * 4)); + } + uint[] blob = null; + if (comp > 0 && comp <= ExtraRomFileCacheMax) + { + uint n = (comp + 3) / 4; + blob = new uint[n]; + for (uint w = 0; w < n; w++) + blob[w] = memory.ReadMemory32(load + w * 4); + } + ExtraRomOpenFile slot = FindExtraRomOpenFile(label); + if (slot == null) + { + if (_romFileCount >= ExtraRomFileMax) + return; + if (_romFiles == null) + _romFiles = new ExtraRomOpenFile[ExtraRomFileMax]; + slot = new ExtraRomOpenFile(); + _romFiles[_romFileCount] = slot; + _romFileCount++; + } + slot.Index = index; + slot.Entry = filesEntry; + slot.Words = words; + slot.Name = name; + slot.NameWords = nameWords; + slot.Real = real; + slot.Comp = comp; + slot.Load = load; + slot.Data = blob; + slot.Label = label; + BootLog.Write("[NkBinLoader] ExtraROM FILE" + + (index >= 0 ? "[" + index + "]" : "") + + " cached " + slot.Label + + " entry=0x" + filesEntry.ToString("X8") + + " real=" + real + + " comp=" + comp + + " load=0x" + load.ToString("X8") + + (blob != null ? "" : " (FILESentry only; dump LZX stays at load)") + + " (restore if firmware RAM reuses ExtraROM tail; do not invent 0x81360000)"); + } + catch (System.Exception ex) + { + BootLog.Write("[NkBinLoader] ExtraROM FILE cache skipped " + label + + ": " + ex.Message); + } + } + + public static void CacheExtraRomTv2File(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint filesEntry) + { + if (memory == null || filesEntry == 0) + return; + try + { + var words = new uint[7]; + for (int i = 0; i < words.Length; i++) + words[i] = memory.ReadMemory32(filesEntry + (uint)(i * 4)); + uint real = words[3]; + uint comp = words[4]; + uint name = words[5]; + uint load = words[6]; + if (real == 0 || name == 0 || load == 0) + return; + uint[] nameWords = null; + if (name != 0) + { + nameWords = new uint[8]; + for (int i = 0; i < nameWords.Length; i++) + nameWords[i] = memory.ReadMemory32(name + (uint)(i * 4)); + } + uint[] blob = null; + if (comp > 0 && comp <= 0x10000) + { + uint n = (comp + 3) / 4; + blob = new uint[n]; + for (uint w = 0; w < n; w++) + blob[w] = memory.ReadMemory32(load + w * 4); + } + _tv2FileEntry = filesEntry; + _tv2FileWords = words; + _tv2FileName = name; + _tv2FileNameWords = nameWords; + _tv2FileReal = real; + _tv2FileComp = comp; + _tv2FileLoad = load; + _tv2FileData = blob; + BootLog.Write("[NkBinLoader] ExtraROM FILE[25] cached entry=0x" + + filesEntry.ToString("X8") + + " real=" + real + + " comp=" + comp + + " load=0x" + load.ToString("X8") + + " (restore if firmware RAM reuses ExtraROM tail)"); + } + catch (System.Exception ex) + { + BootLog.Write("[NkBinLoader] ExtraROM FILE[25] cache skipped: " + ex.Message); + } + } + + public static void CacheExtraRomMscoree(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint tocEntry) + { + if (memory == null || tocEntry == 0) + return; + try + { + var toc = new uint[8]; + for (int i = 0; i < 8; i++) + toc[i] = memory.ReadMemory32(tocEntry + (uint)(i * 4)); + uint e32 = toc[5]; + uint o32 = toc[6]; + if (e32 == 0 || o32 == 0) + return; + uint objcnt = memory.ReadMemory32(e32) & 0xFFFF; + if (objcnt == 0 || objcnt > 16) + return; + var e32Words = new uint[32]; + for (int i = 0; i < e32Words.Length; i++) + e32Words[i] = memory.ReadMemory32(e32 + (uint)(i * 4)); + var o32Words = new uint[objcnt * 6]; + for (int i = 0; i < o32Words.Length; i++) + o32Words[i] = memory.ReadMemory32(o32 + (uint)(i * 4)); + var dataPtr = new uint[objcnt]; + var dataLen = new uint[objcnt]; + var data = new uint[objcnt][]; + for (uint s = 0; s < objcnt; s++) + { + uint psize = o32Words[s * 6 + 2]; + uint dataptr = o32Words[s * 6 + 3]; + if (dataptr == 0 || psize == 0 || psize > 0x20000) + continue; + uint n = (psize + 3) / 4; + var blob = new uint[n]; + for (uint w = 0; w < n; w++) + blob[w] = memory.ReadMemory32(dataptr + w * 4); + dataPtr[s] = dataptr; + dataLen[s] = psize; + data[s] = blob; + } + _mscoreeTocEntry = tocEntry; + _mscoreeAttr = toc[0]; + _mscoreeTocWords = toc; + _mscoreeE32 = e32; + _mscoreeE32Words = e32Words; + _mscoreeO32 = o32; + _mscoreeO32Words = o32Words; + _mscoreeDataPtr = dataPtr; + _mscoreeDataLen = dataLen; + _mscoreeData = data; + _mscoreeVbase = 0; + if (o32Words.Length >= 6 && o32Words[1] == 0x1000 && o32Words[4] >= 0x1000) + _mscoreeVbase = o32Words[4] - o32Words[1]; + System.Console.WriteLine("[NkBinLoader] ExtraROM TOC[46] cached e32=0x" + + e32.ToString("X8") + " o32=0x" + o32.ToString("X8") + + " vbase=0x" + _mscoreeVbase.ToString("X8") + + " (restore if firmware RAM reuses ExtraROM tail; not a FILE)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[NkBinLoader] ExtraROM TOC[46] cache skipped: " + ex.Message); + } + } + + public static void CacheExtraRomOle32(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint tocEntry) + { + if (memory == null || tocEntry == 0) + return; + try + { + var toc = new uint[8]; + for (int i = 0; i < 8; i++) + toc[i] = memory.ReadMemory32(tocEntry + (uint)(i * 4)); + uint e32 = toc[5]; + uint o32 = toc[6]; + if (e32 == 0 || o32 == 0) + return; + uint objcnt = memory.ReadMemory32(e32) & 0xFFFF; + if (objcnt == 0 || objcnt > 16) + return; + var e32Words = new uint[32]; + for (int i = 0; i < e32Words.Length; i++) + e32Words[i] = memory.ReadMemory32(e32 + (uint)(i * 4)); + var o32Words = new uint[objcnt * 6]; + for (int i = 0; i < o32Words.Length; i++) + o32Words[i] = memory.ReadMemory32(o32 + (uint)(i * 4)); + var dataPtr = new uint[objcnt]; + var dataLen = new uint[objcnt]; + var data = new uint[objcnt][]; + for (uint s = 0; s < objcnt; s++) + { + uint psize = o32Words[s * 6 + 2]; + uint dataptr = o32Words[s * 6 + 3]; + if (dataptr == 0 || psize == 0 || psize > 0x20000) + continue; + uint n = (psize + 3) / 4; + var blob = new uint[n]; + for (uint w = 0; w < n; w++) + blob[w] = memory.ReadMemory32(dataptr + w * 4); + dataPtr[s] = dataptr; + dataLen[s] = psize; + data[s] = blob; + } + _ole32TocEntry = tocEntry; + _ole32Attr = toc[0]; + _ole32TocWords = toc; + _ole32E32 = e32; + _ole32E32Words = e32Words; + _ole32O32 = o32; + _ole32O32Words = o32Words; + _ole32DataPtr = dataPtr; + _ole32DataLen = dataLen; + _ole32Data = data; + _ole32Vbase = 0; + if (o32Words.Length >= 6 && o32Words[1] == 0x1000 && o32Words[4] >= 0x1000) + _ole32Vbase = o32Words[4] - o32Words[1]; + System.Console.WriteLine("[NkBinLoader] ExtraROM TOC[34] cached e32=0x" + + e32.ToString("X8") + " o32=0x" + o32.ToString("X8") + + " vbase=0x" + _ole32Vbase.ToString("X8") + + " (restore if firmware RAM reuses ExtraROM tail; not a FILE)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[NkBinLoader] ExtraROM TOC[34] cache skipped: " + ex.Message); + } + } + + public static void CacheExtraRomTocModule( + ProcessorEmulator.Core.Emulation.IMemoryManager memory, + uint romhdr, uint tocEntry, int index, string name) + { + if (memory == null || tocEntry == 0 || string.IsNullOrEmpty(name)) + return; + if (IsTv2ClientCe(name) || IsExtraRomOpenFile(name)) + return; + try + { + if (romhdr != 0) + _extraRomHdr = romhdr; + var toc = new uint[8]; + for (int i = 0; i < 8; i++) + toc[i] = memory.ReadMemory32(tocEntry + (uint)(i * 4)); + uint e32 = toc[5]; + uint o32 = toc[6]; + uint dest = 0; + uint[] e32Words = null; + uint[] o32Words = null; + if (e32 != 0) + { + e32Words = new uint[32]; + for (int i = 0; i < e32Words.Length; i++) + e32Words[i] = memory.ReadMemory32(e32 + (uint)(i * 4)); + uint objcnt = e32Words[0] & 0xFFFF; + if (o32 != 0 && objcnt > 0 && objcnt <= 16) + { + o32Words = new uint[objcnt * 6]; + for (int i = 0; i < o32Words.Length; i++) + o32Words[i] = memory.ReadMemory32(o32 + (uint)(i * 4)); + if (o32Words.Length >= 5) + dest = o32Words[4]; + } + } + ExtraRomTocMod slot = FindCachedTocByEntry(tocEntry); + if (slot == null) + slot = FindCachedExtraRomToc(name); + if (slot == null) + { + if (_romTocCount >= 128) + return; + if (_romTocMods == null) + _romTocMods = new ExtraRomTocMod[128]; + slot = new ExtraRomTocMod(); + _romTocMods[_romTocCount] = slot; + _romTocCount++; + } + slot.Index = index; + slot.Name = name; + slot.Entry = tocEntry; + slot.Attr = toc[0]; + slot.LoadVa = toc.Length > 7 ? toc[7] : 0; + slot.Dest = dest; + slot.E32 = e32; + slot.O32 = o32; + slot.TocWords = toc; + slot.E32Words = e32Words; + slot.O32Words = o32Words; + slot.Vbase = e32Words != null && e32Words.Length > 2 ? e32Words[2] : 0; + slot.Decompressed = false; + slot.DecompDest = 0; + slot.LoadE32Ok = false; + if (o32Words != null && o32Words.Length >= 6) + { + int nsec = o32Words.Length / 6; + slot.DataPtr = new uint[nsec]; + slot.DataLen = new uint[nsec]; + slot.Data = new uint[nsec][]; + for (int s = 0; s < nsec; s++) + { + uint psize = o32Words[s * 6 + 2]; + uint dataptr = o32Words[s * 6 + 3]; + if (dataptr == 0 || psize == 0 || psize > 0x40000) + continue; + uint n = (psize + 3) / 4; + var blob = new uint[n]; + for (uint w = 0; w < n; w++) + blob[w] = memory.ReadMemory32(dataptr + w * 4); + slot.DataPtr[s] = dataptr; + slot.DataLen[s] = psize; + slot.Data[s] = blob; + } + } + } + catch (System.Exception ex) + { + BootLog.Write("[NkBinLoader] ExtraROM TOC[" + index + "] " + name + + " cache skipped: " + ex.Message); + } + } + + private static void TryRestoreExtraRomIfClobbered(MipsBus bus, uint tocEntry) + { + if (bus == null || tocEntry == 0 || _ddiNopTocWords == null) + return; + uint liveE32 = 0; + uint liveO32 = 0; + uint liveObjcnt = 0; + uint liveVsize = 0; + try + { + liveE32 = bus.Read32(tocEntry + 0x14); + liveO32 = bus.Read32(tocEntry + 0x18); + if (liveE32 != 0) + liveObjcnt = bus.Read32(liveE32) & 0xFFFF; + if (liveO32 != 0) + liveVsize = bus.Read32(liveO32); + } + catch + { + } + if (liveE32 == _ddiNopE32 && liveE32 != 0 && liveObjcnt != 0 && liveVsize != 0) + return; + try + { + for (int i = 0; i < _ddiNopTocWords.Length; i++) + bus.Write32(tocEntry + (uint)(i * 4), _ddiNopTocWords[i]); + if (_ddiNopE32 != 0 && _ddiNopE32Words != null) + { + for (int i = 0; i < _ddiNopE32Words.Length; i++) + bus.Write32(_ddiNopE32 + (uint)(i * 4), _ddiNopE32Words[i]); + } + if (_ddiNopO32 != 0 && _ddiNopO32Words != null) + { + for (int i = 0; i < _ddiNopO32Words.Length; i++) + bus.Write32(_ddiNopO32 + (uint)(i * 4), _ddiNopO32Words[i]); + } + if (_ddiNopData != null) + { + for (int s = 0; s < _ddiNopData.Length; s++) + { + uint[] blob = _ddiNopData[s]; + if (blob == null || _ddiNopDataPtr[s] == 0) + continue; + for (int w = 0; w < blob.Length; w++) + bus.Write32(_ddiNopDataPtr[s] + (uint)(w * 4), blob[w]); + } + } + System.Console.WriteLine("[Hive] ExtraROM TOC[33] restored e32=0x" + + _ddiNopE32.ToString("X8") + " o32=0x" + _ddiNopO32.ToString("X8") + + " (was 0x" + liveE32.ToString("X8") + + "; firmware RAM reused ExtraROM tail; do not invent 0x81360000)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC[33] restore-fail " + ex.Message); + } + } + + private static void TryRestoreExtraRomMscoreeIfClobbered(MipsBus bus) + { + if (bus == null || _mscoreeTocEntry == 0 || _mscoreeTocWords == null) + return; + uint liveE32 = 0; + uint liveO32 = 0; + uint liveObjcnt = 0; + uint liveVsize = 0; + try + { + liveE32 = bus.Read32(_mscoreeTocEntry + 0x14); + liveO32 = bus.Read32(_mscoreeTocEntry + 0x18); + if (liveE32 != 0) + liveObjcnt = bus.Read32(liveE32) & 0xFFFF; + if (liveO32 != 0) + liveVsize = bus.Read32(liveO32); + } + catch + { + } + if (liveE32 == _mscoreeE32 && liveE32 != 0 && liveObjcnt != 0 && liveVsize != 0) + return; + try + { + for (int i = 0; i < _mscoreeTocWords.Length; i++) + bus.Write32(_mscoreeTocEntry + (uint)(i * 4), _mscoreeTocWords[i]); + if (_mscoreeE32 != 0 && _mscoreeE32Words != null) + { + for (int i = 0; i < _mscoreeE32Words.Length; i++) + bus.Write32(_mscoreeE32 + (uint)(i * 4), _mscoreeE32Words[i]); + } + if (_mscoreeO32 != 0 && _mscoreeO32Words != null) + { + for (int i = 0; i < _mscoreeO32Words.Length; i++) + bus.Write32(_mscoreeO32 + (uint)(i * 4), _mscoreeO32Words[i]); + } + if (_mscoreeData != null) + { + for (int s = 0; s < _mscoreeData.Length; s++) + { + uint[] blob = _mscoreeData[s]; + if (blob == null || _mscoreeDataPtr[s] == 0) + continue; + for (int w = 0; w < blob.Length; w++) + bus.Write32(_mscoreeDataPtr[s] + (uint)(w * 4), blob[w]); + } + } + System.Console.WriteLine("[Hive] ExtraROM TOC[46] restored e32=0x" + + _mscoreeE32.ToString("X8") + " o32=0x" + _mscoreeO32.ToString("X8") + + " (was 0x" + liveE32.ToString("X8") + + "; firmware RAM reused ExtraROM tail; do not invent a FILE)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC[46] restore-fail " + ex.Message); + } + } + + private static void TryRestoreExtraRomOle32IfClobbered(MipsBus bus) + { + if (bus == null || _ole32TocEntry == 0 || _ole32TocWords == null) + return; + uint liveE32 = 0; + uint liveO32 = 0; + uint liveObjcnt = 0; + uint liveVsize = 0; + try + { + liveE32 = bus.Read32(_ole32TocEntry + 0x14); + liveO32 = bus.Read32(_ole32TocEntry + 0x18); + if (liveE32 != 0) + liveObjcnt = bus.Read32(liveE32) & 0xFFFF; + if (liveO32 != 0) + liveVsize = bus.Read32(liveO32); + } + catch + { + } + if (liveE32 == _ole32E32 && liveE32 != 0 && liveObjcnt != 0 && liveVsize != 0) + return; + try + { + for (int i = 0; i < _ole32TocWords.Length; i++) + bus.Write32(_ole32TocEntry + (uint)(i * 4), _ole32TocWords[i]); + if (_ole32E32 != 0 && _ole32E32Words != null) + { + for (int i = 0; i < _ole32E32Words.Length; i++) + bus.Write32(_ole32E32 + (uint)(i * 4), _ole32E32Words[i]); + } + if (_ole32O32 != 0 && _ole32O32Words != null) + { + for (int i = 0; i < _ole32O32Words.Length; i++) + bus.Write32(_ole32O32 + (uint)(i * 4), _ole32O32Words[i]); + } + if (_ole32Data != null) + { + for (int s = 0; s < _ole32Data.Length; s++) + { + uint[] blob = _ole32Data[s]; + if (blob == null || _ole32DataPtr[s] == 0) + continue; + for (int w = 0; w < blob.Length; w++) + bus.Write32(_ole32DataPtr[s] + (uint)(w * 4), blob[w]); + } + } + System.Console.WriteLine("[Hive] ExtraROM TOC[34] restored e32=0x" + + _ole32E32.ToString("X8") + " o32=0x" + _ole32O32.ToString("X8") + + " (was 0x" + liveE32.ToString("X8") + + "; firmware RAM reused ExtraROM tail; do not invent a FILE)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC[34] restore-fail " + ex.Message); + } + } + + private static void TryRestoreExtraRomFileIfClobbered(MipsBus bus) + { + if (bus == null || _tv2FileEntry == 0 || _tv2FileWords == null) + return; + uint liveAttr = 0; + uint liveName = 0; + uint liveReal = 0; + uint liveComp = 0; + uint liveLoad = 0; + try + { + liveAttr = bus.Read32(_tv2FileEntry); + liveName = bus.Read32(_tv2FileEntry + FilesNameOff); + liveReal = bus.Read32(_tv2FileEntry + FilesRealSize); + liveComp = bus.Read32(_tv2FileEntry + FilesCompSize); + liveLoad = bus.Read32(_tv2FileEntry + FilesLoadOff); + } + catch + { + } + if (liveAttr == _tv2FileWords[0] && liveName == _tv2FileName + && liveReal == _tv2FileReal && liveComp == _tv2FileComp + && liveLoad == _tv2FileLoad && liveReal != 0) + return; + try + { + for (int i = 0; i < _tv2FileWords.Length; i++) + bus.Write32(_tv2FileEntry + (uint)(i * 4), _tv2FileWords[i]); + if (_tv2FileName != 0 && _tv2FileNameWords != null) + { + for (int i = 0; i < _tv2FileNameWords.Length; i++) + bus.Write32(_tv2FileName + (uint)(i * 4), _tv2FileNameWords[i]); + } + uint liveLoad0 = 0; + try + { + if (_tv2FileLoad != 0) + liveLoad0 = bus.Read32(_tv2FileLoad); + } + catch + { + } + if (_tv2FileData != null && _tv2FileLoad != 0 && liveLoad0 == 0) + { + for (int w = 0; w < _tv2FileData.Length; w++) + bus.Write32(_tv2FileLoad + (uint)(w * 4), _tv2FileData[w]); + } + System.Console.WriteLine("[Hive] ExtraROM FILE[25] restored entry=0x" + + _tv2FileEntry.ToString("X8") + + " real=" + _tv2FileReal + + " load=0x" + _tv2FileLoad.ToString("X8") + + " (was attr=0x" + liveAttr.ToString("X8") + + " real=" + liveReal + + "; firmware RAM reused ExtraROM tail; do not invent 0x81360000)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM FILE[25] restore-fail " + ex.Message); + } + } + + private static ExtraRomOpenFile FindExtraRomOpenFile(string want) + { + if (_romFiles == null || string.IsNullOrEmpty(want)) + return null; + string look = RomLookupName(want); + for (int i = 0; i < _romFileCount; i++) + { + ExtraRomOpenFile slot = _romFiles[i]; + if (slot == null || string.IsNullOrEmpty(slot.Label)) + continue; + if (NamesMatchRom(want, slot.Label) || NamesMatchRom(look, slot.Label)) + return slot; + } + return null; + } + + private static bool TrySelectExtraRomOpenFile(string want, out uint filesEntry, + out uint attr, out uint real, out uint comp, out uint load) + { + filesEntry = 0; + attr = 0; + real = 0; + comp = 0; + load = 0; + ExtraRomOpenFile slot = FindExtraRomOpenFile(want); + if (slot == null || slot.Entry == 0 || slot.Words == null) + return false; + _romFile = slot; + _romFilePos = 0; + _romFileDestOn = false; + _romFileIoLogged = false; + filesEntry = slot.Entry; + attr = slot.Words[0]; + real = slot.Real; + comp = slot.Comp; + load = slot.Load; + return true; + } + + private static void TryRestoreExtraRomOpenFileIfClobbered(MipsBus bus, string want) + { + ExtraRomOpenFile slot = FindExtraRomOpenFile(want); + if (bus == null || slot == null || slot.Entry == 0 || slot.Words == null) + return; + uint liveAttr = 0; + uint liveName = 0; + uint liveReal = 0; + uint liveComp = 0; + uint liveLoad = 0; + try + { + liveAttr = bus.Read32(slot.Entry); + liveName = bus.Read32(slot.Entry + FilesNameOff); + liveReal = bus.Read32(slot.Entry + FilesRealSize); + liveComp = bus.Read32(slot.Entry + FilesCompSize); + liveLoad = bus.Read32(slot.Entry + FilesLoadOff); + } + catch + { + } + if (liveAttr == slot.Words[0] && liveName == slot.Name + && liveReal == slot.Real && liveComp == slot.Comp + && liveLoad == slot.Load && liveReal != 0) + return; + try + { + for (int i = 0; i < slot.Words.Length; i++) + bus.Write32(slot.Entry + (uint)(i * 4), slot.Words[i]); + if (slot.Name != 0 && slot.NameWords != null) + { + for (int i = 0; i < slot.NameWords.Length; i++) + bus.Write32(slot.Name + (uint)(i * 4), slot.NameWords[i]); + } + uint liveLoad0 = 0; + try + { + if (slot.Load != 0) + liveLoad0 = bus.Read32(slot.Load); + } + catch + { + } + if (slot.Data != null && slot.Load != 0 && liveLoad0 == 0) + { + for (int w = 0; w < slot.Data.Length; w++) + bus.Write32(slot.Load + (uint)(w * 4), slot.Data[w]); + } + System.Console.WriteLine("[Hive] ExtraROM FILE restored " + slot.Label + + " entry=0x" + slot.Entry.ToString("X8") + + " real=" + slot.Real + + " load=0x" + slot.Load.ToString("X8") + + " (was attr=0x" + liveAttr.ToString("X8") + + " real=" + liveReal + + "; firmware RAM reused ExtraROM tail; do not invent 0x81360000)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM FILE restore-fail " + + (slot.Label ?? want) + " " + ex.Message); + } + } + + // wait55: type 7 made LoadE32 read FILE+0x14 (name). Firmware + // loads a compressed FILE like runonce.exe via CreateFile + // type 8, then CEDecompressROM of the dump record, then + // SetFilePointer/ReadFile. Do not invent e32/o32. + public static bool TryStartTv2FileDecompress(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (bus == null || regs == null || regs.Length <= 31) + return false; + if (_romFileAttach) + return TryStartExtraRomOpenFileDecompress(bus, regs, ref programCounter); + if (_tv2FileEntry == 0 || _tv2FileReal == 0 || _tv2FileComp == 0) + return false; + uint src = Tv2FileSrcAlign; + uint dest = Tv2FileDest; + try + { + uint n = (_tv2FileComp + 3) / 4; + uint[] blob = _tv2FileData; + for (uint w = 0; w < n; w++) + { + uint word = blob != null && w < blob.Length + ? blob[w] + : bus.Read32(_tv2FileLoad + w * 4); + bus.Write32(src + w * 4, word); + } + uint pages = (_tv2FileReal + 0x1FFFu) & ~0xFFFu; + for (uint i = 0; i < pages; i += 4) + bus.Write32(dest + i, 0); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] FILE[25] dest-prep fail " + ex.Message + + " (do not invent 0x81360000)"); + return false; + } + regs[4] = src; + regs[5] = _tv2FileComp; + regs[6] = dest; + regs[7] = _tv2FileReal; + _tv2FileSavedSp = regs[29]; + regs[29] = _tv2FileSavedSp - 32; + try + { + bus.Write32(regs[29] + 16, 0); + bus.Write32(regs[29] + 20, 1); + bus.Write32(regs[29] + 24, 0x1000); + } + catch + { + } + _tv2FileDecompRa = NameCopyContinue; + _tv2FilePos = 0; + _tv2FileDestOn = true; + regs[31] = NameCopyContinue; + programCounter = BinaryDecompressRom; + uint src0 = 0; + try + { + src0 = bus.Read32(src); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] CEDecompressROM dest=0x" + + dest.ToString("X8") + " src=0x" + src.ToString("X8") + + " real=" + _tv2FileReal + + " comp=" + _tv2FileComp + + " src0=0x" + src0.ToString("X8") + + " (firmware BinaryDecompressROM; dump FILE record; do not invent e32)"); + return true; + } + + private static bool TryStartExtraRomOpenFileDecompress(MipsBus bus, uint[] regs, ref uint programCounter) + { + ExtraRomOpenFile slot = _romFile; + if (!_romFileAttach || slot == null || slot.Entry == 0 || slot.Real == 0 || slot.Comp == 0) + return false; + _romFileAttach = false; + if (slot.Real > ExtraRomFileDestMax || slot.Comp > ExtraRomFileCacheMax) + return false; + uint src = ExtraRomFileSrc; + uint dest = ExtraRomFileDest; + try + { + uint n = (slot.Comp + 3) / 4; + uint[] blob = slot.Data; + for (uint w = 0; w < n; w++) + { + uint word = blob != null && w < blob.Length + ? blob[w] + : bus.Read32(slot.Load + w * 4); + bus.Write32(src + w * 4, word); + } + uint pages = (slot.Real + 0x1FFFu) & ~0xFFFu; + if (pages > ExtraRomFileDestMax) + pages = ExtraRomFileDestMax; + for (uint i = 0; i < pages; i += 4) + bus.Write32(dest + i, 0); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM FILE dest-prep fail " + + slot.Label + " " + ex.Message + + " (do not invent 0x81360000)"); + return false; + } + regs[4] = src; + regs[5] = slot.Comp; + regs[6] = dest; + regs[7] = slot.Real; + _romFileSavedSp = regs[29]; + regs[29] = _romFileSavedSp - 32; + try + { + bus.Write32(regs[29] + 16, 0); + bus.Write32(regs[29] + 20, 1); + bus.Write32(regs[29] + 24, 0x1000); + } + catch + { + } + _romFileDecompRa = NameCopyContinue; + _romFilePos = 0; + _romFileDestOn = true; + regs[31] = NameCopyContinue; + programCounter = BinaryDecompressRom; + uint src0 = 0; + try + { + src0 = bus.Read32(src); + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM FILE CEDecompressROM " + slot.Label + + " dest=0x" + dest.ToString("X8") + " src=0x" + src.ToString("X8") + + " real=" + slot.Real + + " comp=" + slot.Comp + + " src0=0x" + src0.ToString("X8") + + " (firmware BinaryDecompressROM; dump FILE record; do not invent e32)"); + return true; + } + + private static bool TryFinishExtraRomOpenFileDecompress(MipsBus bus, uint[] regs, uint pc) + { + if (_romFileDecompRa == 0 || pc != _romFileDecompRa) + return false; + _romFileDecompRa = 0; + if (regs != null && regs.Length > 29 && _romFileSavedSp != 0) + regs[29] = _romFileSavedSp; + _romFileSavedSp = 0; + uint ret = regs != null && regs.Length > 2 ? regs[2] : 0; + uint dest0 = 0; + ExtraRomOpenFile slot = _romFile; + try + { + if (bus != null) + dest0 = bus.Read32(ExtraRomFileDest); + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM FILE CEDecompressROM ret " + + (slot != null ? slot.Label : "") + + " v0=0x" + ret.ToString("X8") + + " dest=0x" + ExtraRomFileDest.ToString("X8") + + " word=0x" + dest0.ToString("X8") + + (slot != null && ret == slot.Real ? " (firmware expanded FILE real)" : "") + + " (do not invent e32; FILE[26] tv2clientcorece.dll is 6398464)"); + BootLog.DecompressRom(slot != null ? slot.Label : "", ExtraRomFileDest, ret, + slot != null && ret == slot.Real + ? "firmware expanded FILE real; dest 0x8F400000 class" + : "FILE type-8 CEDecompressROM; dest 0x8F400000 class"); + return true; + } + + public static bool TryFinishTv2FileDecompress(MipsBus bus, uint[] regs, uint pc) + { + if (TryFinishExtraRomOpenFileDecompress(bus, regs, pc)) + return false; + if (_tv2FileDecompRa == 0 || pc != _tv2FileDecompRa) + return false; + _tv2FileDecompRa = 0; + if (regs != null && regs.Length > 29 && _tv2FileSavedSp != 0) + regs[29] = _tv2FileSavedSp; + _tv2FileSavedSp = 0; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint word = 0; + uint pe = 0; + uint lfanew = 0; + bool mz = false; + try + { + if (bus != null) + { + word = bus.Read32(Tv2FileDest); + mz = (word & 0xFFFF) == 0x5A4D; + if (mz) + { + lfanew = bus.Read32(Tv2FileDest + 0x3C); + if (lfanew + 4 <= _tv2FileReal) + pe = bus.Read32(Tv2FileDest + lfanew); + if (pe == 0x00004550u && lfanew + 56 <= _tv2FileReal) + { + _tv2PeEntryRva = bus.Read32(Tv2FileDest + lfanew + 40); + _tv2PeImageBase = bus.Read32(Tv2FileDest + lfanew + 52); + if (lfanew + 24 + 96 + 14 * 8 + 4 <= _tv2FileReal) + _tv2PeComRva = bus.Read32(Tv2FileDest + lfanew + 24 + 96 + 14 * 8); + } + } + } + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] CEDecompressROM ret v0=0x" + + v0.ToString("X8") + " dest=0x" + Tv2FileDest.ToString("X8") + + " word=0x" + word.ToString("X8") + + (mz ? " MZ e_lfanew=0x" + lfanew.ToString("X") + + " pe=0x" + pe.ToString("X8") : " (not MZ)") + + (_tv2PeEntryRva != 0 || _tv2PeImageBase != 0 + ? " entryrva=0x" + _tv2PeEntryRva.ToString("X") + + " imagebase=0x" + _tv2PeImageBase.ToString("X8") + + " comrva=0x" + _tv2PeComRva.ToString("X") + : "") + + (v0 == _tv2FileReal ? " (firmware expanded FILE real)" : "") + + " (do not invent e32; FILE[26] tv2clientcorece.dll is 6398464)"); + BootLog.DecompressRom("tv2clientce.exe", Tv2FileDest, v0, + v0 == _tv2FileReal + ? "firmware expanded FILE real; FILE[25] dest 0x8F140000" + : "FILE[25] type-8 CEDecompressROM; dest 0x8F140000"); + return false; + } + + public static bool IsTv2FileHandle(uint handle) + { + return _tv2FileDestOn && _tv2FileEntry != 0 && handle == _tv2FileEntry; + } + + public static bool IsExtraRomOpenFileHandle(uint handle) + { + return _romFileDestOn && _romFile != null && _romFile.Entry != 0 + && handle == _romFile.Entry; + } + + public static bool TryServeTv2SetFilePointer(uint[] regs, uint jalrTarget, ref uint target) + { + if (jalrTarget != Win32SetFilePointer || regs == null || regs.Length <= 7) + return false; + if (IsExtraRomOpenFileHandle(regs[4])) + return ServeExtraRomOpenFilePointer(regs, ref target); + if (!IsTv2FileHandle(regs[4])) + return false; + uint dist = regs[5]; + uint method = regs[7]; + uint pos = _tv2FilePos; + if (method == 0) + pos = dist; + else if (method == 1) + pos = _tv2FilePos + dist; + else if (method == 2) + pos = _tv2FileReal + dist; + if (pos > _tv2FileReal) + pos = _tv2FileReal; + _tv2FilePos = pos; + regs[2] = pos; + target = regs.Length > 31 ? regs[31] : target; + if (!_tv2FileIoLogged) + { + _tv2FileIoLogged = true; + System.Console.WriteLine("[Hive] FILE[25] SetFilePointer pos=0x" + + pos.ToString("X") + " method=" + method + + " (dump FILE bytes; do not invent e32)"); + } + else if (method == 0 && dist < _tv2FileReal) + { + System.Console.WriteLine("[Hive] FILE[25] MapO32 SetFilePointer pos=0x" + + pos.ToString("X") + " (PE raw; firmware 0x8001AECC)"); + } + return true; + } + + public static bool TryServeTv2FileRead(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (bus == null || regs == null || regs.Length <= 31) + return false; + if (IsExtraRomOpenFileHandle(regs[4])) + return ServeExtraRomOpenFileRead(bus, regs, ref programCounter); + if (!IsTv2FileHandle(regs[4])) + return false; + uint dest = regs[5]; + uint count = regs[6]; + uint outN = regs[7]; + if (dest == 0 || count == 0 || count > 0x10000) + return false; + if (IsTv2DumpPeDest(dest) && !DestReadable(bus, dest)) + TryHostBackTv2PeDest(dest, count); + uint left = _tv2FileReal > _tv2FilePos ? _tv2FileReal - _tv2FilePos : 0; + if (count > left) + count = left; + uint srcPos = _tv2FilePos; + try + { + for (uint i = 0; i < count; i += 4) + { + uint word = bus.Read32(Tv2FileDest + _tv2FilePos + i); + if (i + 4 <= count) + bus.Write32((dest + i) & ~3u, word); + else + { + for (uint b = 0; b < count - i; b++) + { + uint src = Tv2FileDest + _tv2FilePos + i + b; + uint w = bus.Read32(src & ~3u); + uint ch = (w >> (8 * (int)(src & 3))) & 0xFF; + uint d = dest + i + b; + uint dw = bus.Read32(d & ~3u); + int sh = 8 * (int)(d & 3); + dw = (dw & ~(0xFFu << sh)) | (ch << sh); + bus.Write32(d & ~3u, dw); + } + } + } + if (outN != 0) + bus.Write32(outN, count); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] FILE[25] ReadFile fail " + ex.Message); + return false; + } + _tv2FilePos += count; + regs[2] = 1; + programCounter = regs[31]; + if (IsTv2DumpPeDest(dest) && count != 0) + { + uint destWord = 0; + uint fileWord = 0; + try + { + destWord = bus.Read32(dest); + fileWord = bus.Read32(Tv2FileDest + srcPos); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] MapO32 ReadFile dest=0x" + + dest.ToString("X8") + " pos=0x" + srcPos.ToString("X") + + " n=0x" + count.ToString("X") + + " dest-word=0x" + destWord.ToString("X8") + + " file-word=0x" + fileWord.ToString("X8") + + (destWord == fileWord && destWord != 0 + ? " (firmware copied dump PE)" + : " (copy miss)") + + " (Tv2FileDest+raw; do not invent section bytes)"); + } + return true; + } + + // wait58: v0=Tv2FileDest made CreateFile think the FILE was + // mapped. Firmware then skips sh object+6=3 (0x8001D4F0) + // and MapO32 lhu +6 < 2 returns success without ReadFile + // (BindImp word=0). Mapping miss is the real FILE path: + // object+6=3, then 0x8001AECC SetFilePointer(dataptr raw) + // + ReadFile onto the VALLOC dest from Tv2FileDest+pos. + public static bool TryServeTv2FileMap(uint[] regs, ref uint programCounter) + { + if (regs == null || regs.Length <= 31) + return false; + if (IsExtraRomOpenFileHandle(regs[4])) + { + regs[2] = 0; + programCounter = regs[31]; + ExtraRomOpenFile mapped = _romFile; + System.Console.WriteLine("[Hive] ExtraROM FILE CreateFileMapping v0=0 " + + (mapped != null ? mapped.Label : "") + + " (firmware object+6=3; MapO32 ReadFile of dump PE; do not invent e32)"); + return true; + } + if (!IsTv2FileHandle(regs[4])) + return false; + regs[2] = 0; + programCounter = regs[31]; + System.Console.WriteLine("[Hive] FILE[25] CreateFileMapping v0=0" + + " (firmware object+6=3; MapO32 ReadFile of dump PE; do not invent e32)"); + return true; + } + + private static bool ServeExtraRomOpenFilePointer(uint[] regs, ref uint target) + { + ExtraRomOpenFile slot = _romFile; + if (slot == null || regs == null || regs.Length <= 7) + return false; + uint dist = regs[5]; + uint method = regs[7]; + uint pos = _romFilePos; + if (method == 0) + pos = dist; + else if (method == 1) + pos = _romFilePos + dist; + else if (method == 2) + pos = slot.Real + dist; + if (pos > slot.Real) + pos = slot.Real; + _romFilePos = pos; + regs[2] = pos; + target = regs.Length > 31 ? regs[31] : target; + if (!_romFileIoLogged) + { + _romFileIoLogged = true; + System.Console.WriteLine("[Hive] ExtraROM FILE SetFilePointer " + slot.Label + + " pos=0x" + pos.ToString("X") + " method=" + method + + " (dump FILE bytes; do not invent e32)"); + } + return true; + } + + private static bool ServeExtraRomOpenFileRead(MipsBus bus, uint[] regs, ref uint programCounter) + { + ExtraRomOpenFile slot = _romFile; + if (bus == null || slot == null || regs == null || regs.Length <= 31) + return false; + uint dest = regs[5]; + uint count = regs[6]; + uint outN = regs[7]; + if (dest == 0 || count == 0 || count > ExtraRomFileDestMax) + return false; + uint left = slot.Real > _romFilePos ? slot.Real - _romFilePos : 0; + if (count > left) + count = left; + uint srcPos = _romFilePos; + try + { + for (uint i = 0; i < count; i += 4) + { + uint word = bus.Read32(ExtraRomFileDest + _romFilePos + i); + if (i + 4 <= count) + bus.Write32((dest + i) & ~3u, word); + else + { + for (uint b = 0; b < count - i; b++) + { + uint src = ExtraRomFileDest + _romFilePos + i + b; + uint w = bus.Read32(src & ~3u); + uint ch = (w >> (8 * (int)(src & 3))) & 0xFF; + uint d = dest + i + b; + uint dw = bus.Read32(d & ~3u); + int sh = 8 * (int)(d & 3); + dw = (dw & ~(0xFFu << sh)) | (ch << sh); + bus.Write32(d & ~3u, dw); + } + } + } + if (outN != 0) + bus.Write32(outN, count); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM FILE ReadFile fail " + + slot.Label + " " + ex.Message); + return false; + } + _romFilePos += count; + regs[2] = 1; + programCounter = regs[31]; + if (count != 0 && srcPos == 0) + { + uint destWord = 0; + uint fileWord = 0; + try + { + destWord = bus.Read32(dest); + fileWord = bus.Read32(ExtraRomFileDest + srcPos); + } + catch + { + } + System.Console.WriteLine("[Hive] ExtraROM FILE ReadFile " + slot.Label + + " dest=0x" + dest.ToString("X8") + " pos=0x" + srcPos.ToString("X") + + " n=0x" + count.ToString("X") + + " dest-word=0x" + destWord.ToString("X8") + + " file-word=0x" + fileWord.ToString("X8") + + " (ExtraRomFileDest+raw; do not invent section bytes)"); + } + return true; + } + + public static bool IsTv2FileExpanded() + { + return _tv2FileDestOn && _tv2FileReal != 0; + } + + public static bool IsTv2DumpPeDest(uint dest) + { + if (!_tv2FileDestOn || dest == 0 || dest == 0x000E0000u) + return false; + if (dest >= 0x80000000u) + return false; + // wait67: filesys I-fetches 0x00017F54 / 0x00017000. + // VALLOC 0x00010000/0x8000 covers that useg. Those + // pages are not MapO32 dests. Do not invent them. + if (dest >= 0x00017000u && dest < 0x00018000u) + return false; + if (_tv2PeImageVa != 0 && _tv2PeImageBytes != 0) + return dest >= _tv2PeImageVa && dest < _tv2PeImageVa + _tv2PeImageBytes; + return dest >= ExeVbase && dest < ExeVbase + 0x8000u; + } + + // wait56: MEM_IMAGE VALLOC of this dump PE. Capture even + // when the shared VALLOC-ret slot is overwritten. + public static bool NoteTv2PeImageValloc(uint dest, uint size, uint type, uint ra) + { + if (!_tv2FileDestOn || dest != ExeVbase) + return false; + if ((type & 0x01000000u) == 0) + return false; + if (size < 0x4000u || size > 0x10000u) + return false; + _tv2PeImageVa = dest; + _tv2PeImageBytes = size; + _tv2PeVallocRa = ra; + System.Console.WriteLine("[Hive] FILE[25] VALLOC image a0=0x" + + dest.ToString("X8") + " a1=0x" + size.ToString("X8") + + " a2=0x" + type.ToString("X8") + + " (dump PE MEM_IMAGE; dests host-backed at MapO32 only)"); + return true; + } + + public static bool TryFinishTv2PeImageValloc(uint pc, uint v0) + { + if (_tv2PeVallocRa == 0 || pc != _tv2PeVallocRa) + return false; + _tv2PeVallocRa = 0; + if (v0 != 0) + { + _tv2PeImageVa = v0; + if (_tv2PeImageBytes == 0) + _tv2PeImageBytes = 0x8000; + } + System.Console.WriteLine("[Hive] FILE[25] VALLOC image ret v0=0x" + + v0.ToString("X8") + + (v0 == 0 ? " (firmware miss)" : " (dump PE dest range)") + + " (do not invent 0x81360000; do not host-back 0x000E0000)"); + if (v0 != 0) + TryHostBackTv2PeVallocGapPage(); + return true; + } + + // wait59: I-fetch 0x00013628 is page 0x00013000. That page + // sits inside firmware VALLOC 0x00010000/0x8000, past + // dest+vsize 0x8C4 (MapO32 host-back ends at 0x00013000). + // Host-back this one page only. Not a MapO32 dest. Not + // 0x000E0000. Do not invent section bytes. + private static void TryHostBackTv2PeVallocGapPage() + { + const uint page = 0x00013000u; + if (!_tv2FileDestOn || _tv2PeImageVa == 0 || _tv2PeImageBytes == 0) + return; + if (page < _tv2PeImageVa || page + 0x1000u > _tv2PeImageVa + _tv2PeImageBytes) + return; + TryHostBackTv2PeDest(page, 0x1000); + } + + // wait57: type 8 MapO32 does not jal 0x80028844 or VirtualCopy. + // object+4 bit2 is 0, so 0x8001AECC SetFilePointer(dataptr, + // FILE_BEGIN) then ReadFile(dest, min(vsize,psize)). dataptr + // must stay PE raw. wait57 rewrote it to Tv2FileDest+raw; + // jalr -8210 then v0!=dataptr and skipped the copy (BindImp + // word=0). Host-back dest only; firmware ReadFile copies + // from Tv2FileDest+_tv2FilePos. Do not invent section bytes. + public static void TryMapTv2DumpPeO32(MipsBus bus, uint o32Lite) + { + if (!_tv2FileDestOn || bus == null || o32Lite == 0 || _tv2FileReal == 0) + return; + try + { + uint vsize = bus.Read32(o32Lite); + uint dest = bus.Read32(o32Lite + 8); + uint dataptr = bus.Read32(o32Lite + 0x18); + if (!IsTv2DumpPeDest(dest)) + return; + if (dataptr >= _tv2FileReal) + return; + uint raw = dataptr; + if (!DestReadable(bus, dest)) + TryHostBackTv2PeDest(dest, vsize); + uint fileWord = 0; + try + { + fileWord = bus.Read32(Tv2FileDest + raw); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] MapO32 dest=0x" + + dest.ToString("X8") + " dataptr raw=0x" + raw.ToString("X") + + " vsize=0x" + vsize.ToString("X") + + " file-word=0x" + fileWord.ToString("X8") + + " dest-" + (DestReadable(bus, dest) ? "mapped" : "unmapped") + + " (SetFilePointer+ReadFile of dump PE; do not rewrite dataptr)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] FILE[25] MapO32 fail " + ex.Message + + " (do not invent 0x81360000)"); + } + } + + public static void TryNoteTv2BindImp(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2FileDestOn || _tv2BindLogged || regs == null) + return; + if (pc != BindImpHdr) + return; + _tv2BindLogged = true; + uint hdr = regs.Length > 20 ? regs[20] : 0; + uint vbase = regs.Length > 22 ? regs[22] : 0; + uint destWord = 0; + bool destOk = false; + try + { + if (bus != null && hdr != 0) + { + destWord = bus.Read32(hdr); + destOk = true; + } + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] BindImp hdr=0x" + + hdr.ToString("X8") + " vbase=0x" + vbase.ToString("X8") + + " word=0x" + destWord.ToString("X8") + + " dest-" + (destOk ? "mapped" : "unmapped") + + " (dump PE dest; do not invent 0x81360000)"); + } + + private static void TryHostBackTv2PeDest(uint dest, uint vsize) + { + if (dest == 0 || dest == 0x000E0000u || dest >= 0x80000000u) + return; + if (!IsTv2DumpPeDest(dest)) + return; + uint baseVa = dest & ~0xFFFu; + uint size = vsize == 0 ? 0x1000u : vsize; + uint end = (dest + size + 0xFFFu) & ~0xFFFu; + if (end <= baseVa) + return; + if (end > 0x000E0000u && baseVa < 0x000E0000u) + end = 0x000E0000u; + if (_tv2PeImageVa != 0 && _tv2PeImageBytes != 0) + { + uint imageEnd = _tv2PeImageVa + _tv2PeImageBytes; + if (end > imageEnd) + end = imageEnd; + } + else if (end > ExeVbase + 0x8000u) + end = ExeVbase + 0x8000u; + if (end <= baseVa) + return; + if (MapVallocHostVa(baseVa) != baseVa) + return; + uint span = end - baseVa; + if (_vallocHostN >= _vallocHostLo.Length) + return; + uint kseg = _vallocHostPool; + if (kseg < VallocHostKseg || kseg + span > VallocHostKsegLim) + return; + _vallocHostLo[_vallocHostN] = baseVa; + _vallocHostHi[_vallocHostN] = end; + _vallocHostKseg[_vallocHostN] = kseg; + _vallocHostN++; + _vallocHostPool += span; + string why = baseVa == 0x00013000u + ? " (firmware VALLOC image page; not a MapO32 dest; do not invent 0x000E0000)" + : " (firmware MapO32 of dump PE; do not invent 0x000E0000)"; + System.Console.WriteLine("[Hive] FILE[25] dest host-back 0x" + + baseVa.ToString("X8") + "-0x" + end.ToString("X8") + + " -> 0x" + kseg.ToString("X8") + why); + } + + private static bool TrySelectExtraRomToc(MipsBus bus, string baseName, + out uint tocEntry, out uint attr, out int index, out uint dest, out uint e32) + { + tocEntry = 0; + attr = 0; + index = -1; + dest = 0; + e32 = 0; + if (string.IsNullOrEmpty(baseName)) + return false; + if (IsTv2ClientCe(baseName) || IsExtraRomOpenFile(baseName)) + return false; + + if (IsMscoreeDll(baseName)) + TryRestoreExtraRomMscoreeIfClobbered(bus); + else if (IsOle32Dll(baseName)) + TryRestoreExtraRomOle32IfClobbered(bus); + else if (NamesMatchRom(baseName, "ddi_nop.dll")) + TryRestoreExtraRomIfClobbered(bus, _ddiNopTocEntry); + + ExtraRomTocMod slot = FindCachedExtraRomToc(baseName); + if (slot != null) + { + if (!IsMscoreeDll(baseName) && !IsOle32Dll(baseName) + && !NamesMatchRom(baseName, "ddi_nop.dll")) + TryRestoreExtraRomTocModIfClobbered(bus, slot); + TryHostExtraRomE32O32(bus, slot); + tocEntry = slot.LiveEntry != 0 ? slot.LiveEntry : slot.Entry; + attr = (slot.Attr & 0xFFFFEFFFu) | 0x2040u; + if (IsMscoreeDll(baseName) && _mscoreeAttr != 0) + attr = _mscoreeAttr; + else if (IsOle32Dll(baseName) && _ole32Attr != 0) + attr = _ole32Attr; + index = slot.Index; + dest = slot.Dest; + e32 = slot.LiveE32 != 0 ? slot.LiveE32 : slot.E32; + if (IsMscoreeDll(baseName) && _mscoreeE32 != 0 && slot.LiveE32 == 0) + e32 = _mscoreeE32; + else if (IsOle32Dll(baseName) && _ole32E32 != 0 && slot.LiveE32 == 0) + e32 = _ole32E32; + return tocEntry != 0; + } + + string look = RomLookupName(baseName); + if (bus != null + && TryFindTocModule(bus, ExtraRomToc(bus), 128, look, out tocEntry, out attr)) + { + ExtraRomTocMod live = FindCachedTocByEntry(tocEntry); + index = live != null ? live.Index : ExtraRomTocIndex(tocEntry); + dest = live != null ? live.Dest : 0; + try + { + e32 = bus.Read32(tocEntry + 0x14); + } + catch + { + } + return true; + } + + if (IsMscoreeDll(baseName) && _mscoreeTocEntry != 0) + { + tocEntry = _mscoreeTocEntry; + attr = _mscoreeAttr != 0 ? _mscoreeAttr + : (_mscoreeTocWords != null ? _mscoreeTocWords[0] : 0); + index = 46; + e32 = _mscoreeE32; + return true; + } + if (IsOle32Dll(baseName) && _ole32TocEntry != 0) + { + tocEntry = _ole32TocEntry; + attr = _ole32Attr != 0 ? _ole32Attr + : (_ole32TocWords != null ? _ole32TocWords[0] : 0); + index = 34; + e32 = _ole32E32; + return true; + } + if (NamesMatchRom(baseName, "ddi_nop.dll") && _ddiNopTocEntry != 0) + { + tocEntry = _ddiNopTocEntry; + attr = (_ddiNopAttr & 0xFFFFEFFFu) | 0x2040u; + index = 33; + return true; + } + return false; + } + + private static ExtraRomTocMod FindCachedExtraRomToc(string name) + { + if (_romTocMods == null || string.IsNullOrEmpty(name)) + return null; + string look = RomLookupName(name); + ExtraRomTocMod family = null; + int familyHits = 0; + bool wantIptvHal = IsIptvHalAsk(name) || IsIptvHalAsk(look); + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod slot = _romTocMods[i]; + if (slot == null || string.IsNullOrEmpty(slot.Name)) + continue; + if (NamesMatchRom(name, slot.Name) || NamesMatchRom(look, slot.Name)) + return slot; + if (wantIptvHal && IsIptvHalAsk(slot.Name)) + { + familyHits++; + if (family == null) + family = slot; + } + } + // CE may say iptvhal.dll while ExtraROM only has + // iptvhal_*. Attach the one dump name. Two hits stay + // a miss so we do not pick a module CE did not name. + if (familyHits == 1) + return family; + return null; + } + + private static ExtraRomTocMod FindCachedTocByEntry(uint tocEntry) + { + if (_romTocMods == null || tocEntry == 0) + return null; + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod slot = _romTocMods[i]; + if (slot != null && (slot.Entry == tocEntry || slot.LiveEntry == tocEntry)) + return slot; + } + return null; + } + + private static int ExtraRomTocIndex(uint tocEntry) + { + ExtraRomTocMod slot = FindCachedTocByEntry(tocEntry); + if (slot != null) + return slot.Index; + if (tocEntry == _ddiNopTocEntry) + return 33; + if (tocEntry == _mscoreeTocEntry) + return 46; + if (tocEntry == _ole32TocEntry) + return 34; + if (_extraRomHdr != 0 && tocEntry >= _extraRomHdr + TocFirst) + { + uint off = tocEntry - (_extraRomHdr + TocFirst); + if ((off % TocEntrySize) == 0) + return (int)(off / TocEntrySize); + } + return -1; + } + + private static string ExtraRomTocTag(uint tocEntry, ExtraRomTocMod? cached) + { + int index = cached != null ? cached.Index : ExtraRomTocIndex(tocEntry); + if (index >= 0) + return "TOC[" + index + "]"; + return "TOC"; + } + + private static void TryRestoreExtraRomTocModIfClobbered(MipsBus bus, ExtraRomTocMod slot) + { + if (bus == null || slot == null || slot.Entry == 0 || slot.TocWords == null) + return; + uint liveE32 = 0; + uint liveO32 = 0; + uint liveObjcnt = 0; + uint liveVsize = 0; + try + { + liveE32 = bus.Read32(slot.Entry + 0x14); + liveO32 = bus.Read32(slot.Entry + 0x18); + if (liveE32 != 0) + liveObjcnt = bus.Read32(liveE32) & 0xFFFF; + if (liveO32 != 0) + liveVsize = bus.Read32(liveO32); + } + catch + { + } + if (liveE32 == slot.E32 && liveE32 != 0 && liveObjcnt != 0 && liveVsize != 0) + return; + try + { + for (int i = 0; i < slot.TocWords.Length; i++) + bus.Write32(slot.Entry + (uint)(i * 4), slot.TocWords[i]); + if (slot.E32 != 0 && slot.E32Words != null) + { + for (int i = 0; i < slot.E32Words.Length; i++) + bus.Write32(slot.E32 + (uint)(i * 4), slot.E32Words[i]); + } + if (slot.O32 != 0 && slot.O32Words != null) + { + for (int i = 0; i < slot.O32Words.Length; i++) + bus.Write32(slot.O32 + (uint)(i * 4), slot.O32Words[i]); + } + System.Console.WriteLine("[Hive] ExtraROM TOC[" + slot.Index + "] " + + slot.Name + " restored e32=0x" + slot.E32.ToString("X8") + + " o32=0x" + slot.O32.ToString("X8") + + " (was 0x" + liveE32.ToString("X8") + + "; firmware RAM reused ExtraROM tail; do not invent 0x81360000)"); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC[" + slot.Index + "] " + + slot.Name + " restore-fail " + ex.Message); + } + } + + // NK LoadE32 copies e32_rom at TOC+0x14 and o32 at +0x18 + // because those VAs stay in NK XIP. ExtraROM tail does + // not. Write dump-cached TOC/e32/o32 to ExtraRomE32Host + // and point object+0 at that copy. Do not invent e32 + // bytes or 0x81360000. + public static bool TryServeExtraRomLoadE32(MipsBus bus, uint obj) + { + if (bus == null || obj == 0) + return false; + ExtraRomTocMod slot; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return false; + uint tocEntry = bus.Read32(obj); + slot = FindCachedTocByEntry(tocEntry); + } + catch + { + return false; + } + if (slot == null || slot.E32Words == null) + return false; + TryRestoreExtraRomTocModIfClobbered(bus, slot); + if (!TryHostExtraRomE32O32(bus, slot) || slot.LiveEntry == 0) + return false; + try + { + bus.Write32(obj, slot.LiveEntry); + } + catch + { + return false; + } + _loadE32Obj = obj; + TryMarkExtraRomO32Compressed(bus, slot.LiveEntry); + NoteLoadE32(slot.Name, slot.Index); + return true; + } + + private static bool TryHostExtraRomE32O32(MipsBus bus, ExtraRomTocMod slot) + { + if (bus == null || slot == null || slot.TocWords == null || slot.E32Words == null) + return false; + uint e32Bytes = ExtraRomHostE32Bytes(slot); + uint o32Bytes = slot.O32Words != null ? (uint)slot.O32Words.Length * 4 : 0; + string name = slot.Name ?? ""; + uint nameBytes = ((uint)name.Length + 4) & ~3u; + uint tocBytes = 32; + uint span = (tocBytes + e32Bytes + o32Bytes + nameBytes + 0xF) & ~0xFu; + bool first = slot.LiveEntry == 0; + if (first) + { + if (_e32HostPool < ExtraRomE32Host + || _e32HostPool + span > ExtraRomE32HostLim) + return false; + slot.LiveEntry = _e32HostPool; + _e32HostPool += span; + } + slot.LiveE32 = slot.LiveEntry + tocBytes; + slot.LiveO32 = o32Bytes != 0 ? slot.LiveE32 + e32Bytes : 0; + slot.LiveName = (o32Bytes != 0 ? slot.LiveO32 + o32Bytes : slot.LiveE32 + e32Bytes); + CommitExtraRomE32Host(bus); + if (!WriteHostExtraRomE32O32(bus, slot, name)) + return false; + if (!first) + return true; + uint o32Real = slot.O32Words != null && slot.O32Words.Length > 4 ? slot.O32Words[4] : 0; + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " e32_rom v0= dest-word=0 destDump=0x" + slot.Dest.ToString("X8") + + " dest0=0x" + (slot.Dest & SlotMask).ToString("X8") + + " object+6=0 0x80028844=False o32.real=0x" + o32Real.ToString("X8")); + return true; + } + + // FILE[25] dest 0x8F140000 is kseg0 RAM because + // CEDecompressROM Write32 commits those pages. Do the + // same for ExtraRomE32Host (next to that dest). Do not + // invent a third B000FF at 0x81360000. + private static void CommitExtraRomE32Host(MipsBus bus) + { + if (bus == null || _e32HostCommitted) + return; + try + { + for (uint i = ExtraRomE32Host; i < ExtraRomE32HostLim; i += 4) + bus.Write32(i, 0); + _e32HostCommitted = true; + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM e32-host commit-fail " + ex.Message + + " (0x8F148000 next to FILE dest 0x8F140000; do not invent 0x81360000)"); + } + } + + public static void TryLogExtraRomLoadE32(MipsBus bus, uint[] regs, bool isRet, uint lastError) + { + if (bus == null || regs == null || regs.Length <= 4) + return; + uint obj = regs[4]; + if (obj == 0 || (isRet && _loadE32Obj != 0)) + obj = _loadE32Obj != 0 ? _loadE32Obj : obj; + if (obj == 0) + return; + uint entry = 0; + uint type = 0; + uint obj6 = 0; + try + { + type = bus.Read8(obj + 4); + entry = bus.Read32(obj); + obj6 = (uint)(bus.Read8(obj + 6) | (bus.Read8(obj + 7) << 8)); + } + catch + { + return; + } + if (type != TocAttachType) + return; + ExtraRomTocMod slot = FindCachedTocByEntry(entry); + if (slot == null || string.IsNullOrEmpty(slot.Name) || slot.Index < 0) + return; + uint v0 = isRet && regs.Length > 2 ? regs[2] : 0; + uint dest0 = slot.Dest & SlotMask; + uint destWord = PeekDestWord(bus, dest0); + string line = "[Hive] TOC[" + slot.Index + "] " + slot.Name + + (isRet ? " LoadE32-ret" : " LoadE32") + + " v0=0x" + v0.ToString("X") + + " dest-word=0x" + destWord.ToString("X") + + " dest0=0x" + dest0.ToString("X8") + + " object+6=" + obj6 + + " 0x80028844=" + slot.FwMapO32; + if (!isRet) + { + BeginLoadE32Watch(slot, regs, lastError); + _loadE32RomBit = type & LoadE32RomBit; + if (NamesMatchRom(slot.Name, "ddi_nop.dll")) + LatchDdiNopFileObj(obj); + } + else + { + if (IsLoadE32Success(v0, _loadE32RetPc)) + { + slot.LoadE32Ok = true; + BeginLoadE32OkWatch(slot, _loadE32WatchA0); + } + _loadE32Obj = 0; + ClearLoadE32Watch(); + } + BootLog.Write(line); + } + + // NK TOC type-7 LoadE32 also returns v0=0 on success + // (0x80019990 / 0x800199A4). Log ret-pc so ExtraROM + // can match. Fail is v0=0xC1 / 0x47E only. CurMSec + // leftover a1 is not o32. NK e32 bytes are not in-repo. + public static void TryBeginNkLoadE32(MipsBus bus, uint[] regs) + { + if (_loadE32Watch || _nkLoadE32Watch || bus == null || regs == null || regs.Length <= 4) + return; + uint obj = regs[4]; + if (obj == 0) + return; + uint toc = 0; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return; + toc = bus.Read32(obj); + } + catch + { + return; + } + if (toc == 0 || FindCachedTocByEntry(toc) != null) + return; + uint e32 = 0; + uint o32 = 0; + string name = ""; + try + { + e32 = bus.Read32(toc + 0x14); + o32 = bus.Read32(toc + 0x18); + uint np = bus.Read32(toc + 0x10); + name = ReadAscii(bus, np); + } + catch + { + return; + } + if (string.IsNullOrEmpty(name)) + return; + TryNoteLeftoverWait99O32NkAfterLoad(bus, name); + TryNoteLeftoverWait99O32NkChainLoad(bus, name); + if (!WantNkLoadE32Log(name) && _nkLoadE32Logged >= 8) + return; + uint o32v = PeekLoadE32Word(bus, o32); + uint o32p = PeekLoadE32Word(bus, o32 != 0 ? o32 + 0xC : 0); + uint dumpToc0 = PeekDestWord(bus, toc); + _nkLoadE32Watch = true; + _nkLoadE32Name = name; + _nkLoadE32E32 = e32; + _nkLoadE32O32 = o32; + _nkLoadE32O32Vsize = o32v; + _nkLoadE32O32Ptr = o32p; + _nkLoadE32Obj = obj; + _nkLoadE32Toc = toc; + _nkLoadE32DumpToc0 = dumpToc0; + _nkChkRa = 0; + _nkChkA0 = 0; + _nkChkA1 = 0; + _nkChkA2 = 0; + _nkChkWord = 0; + _nkChkV0 = 0xFFFFFFFFu; + _nkChkSpan = null; + _nkChkSeen = false; + _nkRomBit = LoadE32RomBit; + _nkCmpPc = 0; + _nkCmpOp = null; + _nkCmpLhs = 0; + _nkCmpRhs = 0; + _nkCmpFirstPc = 0; + _nkCmpFirstOp = null; + _nkCmpFirstLhs = 0; + _nkCmpFirstRhs = 0; + _nkRetPc = 0; + } + + public static void TryFinishNkLoadE32(MipsBus bus, uint[] regs) + { + if (!_nkLoadE32Watch) + return; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint destWord = PeekDestWord(bus, _nkLoadE32Toc); + uint obj6 = PeekObj6(bus, _nkLoadE32Obj); + BootLog.Write("[Hive] NK " + _nkLoadE32Name + + " LoadE32-ret v0=0x" + v0.ToString("X") + + " dest-word=0x" + destWord.ToString("X") + + " dest0=0x" + _nkLoadE32Toc.ToString("X8") + + " object+6=" + obj6 + + " 0x80028844=False"); + if (IsLoadE32Success(v0, _nkRetPc)) + { + _nkLoadE32Ok = _nkLoadE32Name + + " success=LoadE32 ret-pc=0x" + _nkRetPc.ToString("X8") + + " v0=0 rombit=" + _nkRomBit + + " dumpToc0=0x" + _nkLoadE32DumpToc0.ToString("X8") + + " dumpToc0&0x200=" + (_nkLoadE32DumpToc0 & LoadO32VallocBit).ToString("X"); + if (WantNkLoadO32Log(_nkLoadE32Name)) + BeginNkLoadO32Watch(); + if (NamesMatchRom(_nkLoadE32Name, "coredll.dll") + && _coredllModule != 0) + TryPlantCoredllStartip(bus, _coredllModule); + } + _nkLoadE32Logged++; + ClearNkLoadE32Watch(); + } + + private static bool WantNkLoadE32Log(string name) + { + if (string.IsNullOrEmpty(name)) + return false; + return NamesMatchRom(name, "fsdmgr.dll") + || NamesMatchRom(name, "coredll.dll") + || NamesMatchRom(name, "ceddk.dll") + || NamesMatchRom(name, "nk.exe") + || NamesMatchRom(name, "filesys.exe") + || NamesMatchRom(name, "filesys.dll") + || NamesMatchRom(name, "osaxst0.dll"); + } + + private static bool WantNkLoadO32Log(string name) + { + if (string.IsNullOrEmpty(name)) + return false; + return NamesMatchRom(name, "fsdmgr.dll") + || NamesMatchRom(name, "coredll.dll") + || NamesMatchRom(name, "ceddk.dll") + || NamesMatchRom(name, "osaxst0.dll"); + } + + private static void BeginNkLoadO32Watch() + { + _nkLoadO32Watch = true; + _nkLoadO32Name = _nkLoadE32Name; + _nkLoadO32Obj = _nkLoadE32Obj; + _nkLoadO32Toc = _nkLoadE32Toc; + _nkLoadO32DumpToc0 = _nkLoadE32DumpToc0; + _nkLoadO32Word0 = 0; + _nkLoadO32Fp = 0; + _nkLoadO32Bit200 = false; + _nkLoadO32Entered = false; + _nkLoadO32Skip200 = false; + _nkLoadO32Thunk = false; + _nkLoadO32Ret = false; + _nkLoadO32Steps = 0; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " LoadO32-watch v0= dest-word=0 dest0=0x" + + _nkLoadO32Toc.ToString("X8") + + " object+6=0 0x80028844=False"); + } + + private static void ClearNkLoadO32Watch() + { + _nkLoadO32Watch = false; + _nkLoadO32Name = null; + _nkLoadO32Obj = 0; + _nkLoadO32Toc = 0; + _nkLoadO32DumpToc0 = 0; + _nkLoadO32Word0 = 0; + _nkLoadO32Fp = 0; + _nkLoadO32Bit200 = false; + _nkLoadO32Entered = false; + _nkLoadO32Skip200 = false; + _nkLoadO32Thunk = false; + _nkLoadO32Ret = false; + _nkLoadO32Steps = 0; + } + + private static void NoteAfterNkLoadO32(MipsBus bus, uint[] regs, uint pc) + { + if (!_nkLoadO32Watch) + return; + _nkLoadO32Steps++; + if (pc == LoadLibSyscallRet || _nkLoadO32Steps > 200000) + { + if (!_nkLoadO32Entered) + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " LoadO32-not-entered v0= dest-word=0 dest0=0x" + + _nkLoadO32Toc.ToString("X8") + + " object+6=0 0x80028844=False"); + ClearNkLoadO32Watch(); + return; + } + if (pc == LoadO32Rom && !_nkLoadO32Entered) + { + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + if (_nkLoadO32Obj != 0 && a0 != 0 && a0 != _nkLoadO32Obj) + return; + _nkLoadO32Entered = true; + uint toc = PeekDestWord(bus, a0 != 0 ? a0 : _nkLoadO32Obj); + uint fp = toc != 0 ? PeekDestWord(bus, toc) : 0; + uint live0 = _nkLoadO32Toc != 0 + ? PeekDestWord(bus, _nkLoadO32Toc) : fp; + _nkLoadO32Fp = fp; + _nkLoadO32Word0 = live0; + _nkLoadO32Bit200 = (fp & LoadO32VallocBit) != 0; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " LoadO32 v0= dest-word=0x" + live0.ToString("X") + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " object+6=" + PeekObj6(bus, _nkLoadO32Obj) + + " 0x80028844=False"); + return; + } + if (pc == LoadO32SkipValloc && _nkLoadO32Entered && !_nkLoadO32Skip200) + { + _nkLoadO32Skip200 = true; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " LoadO32-skip200 v0= dest-word=0x" + _nkLoadO32Word0.ToString("X") + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " object+6=" + PeekObj6(bus, _nkLoadO32Obj) + + " 0x80028844=False"); + return; + } + if (pc == LoadO32VallocOpen && _nkLoadO32Entered && !_nkLoadO32Thunk) + { + _nkLoadO32Thunk = true; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " thunk-enter v0= dest-word=0x" + _nkLoadO32Word0.ToString("X") + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " object+6=" + PeekObj6(bus, _nkLoadO32Obj) + + " 0x80028844=False"); + return; + } + if (pc == LoadO32RomRet && _nkLoadO32Entered && !_nkLoadO32Ret) + { + _nkLoadO32Ret = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint live0 = _nkLoadO32Toc != 0 + ? PeekDestWord(bus, _nkLoadO32Toc) : _nkLoadO32Word0; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " LoadO32-ret v0=0x" + v0.ToString("X") + + " dest-word=0x" + live0.ToString("X") + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " object+6=" + PeekObj6(bus, _nkLoadO32Obj) + + " 0x80028844=False"); + if (NamesMatchRom(_nkLoadO32Name, "coredll.dll")) + { + uint mod = PeekCoredllCallDllModule(bus, regs); + if (mod == 0) + mod = _coredllModule; + if (mod != 0) + { + if (_coredllModule == 0) + _coredllModule = mod; + TryPlantCoredllStartip(bus, mod); + } + } + ClearNkLoadO32Watch(); + return; + } + if (!_nkLoadO32Entered || bus == null || regs == null) + return; + uint instr = 0; + try + { + instr = bus.Read32(pc); + } + catch + { + return; + } + uint op = instr >> 26; + if (!_nkLoadO32Bit200 && op == 0xC && (instr & 0xFFFF) == LoadO32VallocBit) + { + uint rs = (instr >> 21) & 31; + uint lhs = regs.Length > (int)rs ? regs[(int)rs] : 0; + _nkLoadO32Fp = lhs; + _nkLoadO32Bit200 = (lhs & LoadO32VallocBit) != 0; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " andi-0x200 v0= dest-word=0x" + _nkLoadO32Word0.ToString("X") + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " object+6=" + PeekObj6(bus, _nkLoadO32Obj) + + " 0x80028844=False"); + } + uint target = 0; + if (op == 3) + target = (pc & 0xF0000000u) | ((instr & 0x3FFFFFFu) << 2); + if (target == LoadO32VallocOpen && !_nkLoadO32Thunk) + { + _nkLoadO32Thunk = true; + uint a0 = regs.Length > 4 ? regs[4] : 0; + BootLog.Write("[Hive] NK " + _nkLoadO32Name + + " jal-pred v0= dest-word=0x" + _nkLoadO32Word0.ToString("X") + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " object+6=" + PeekObj6(bus, _nkLoadO32Obj) + + " 0x80028844=False"); + } + } + + private static void NoteNkLoadE32FieldJal(MipsBus bus, uint[] regs, uint pc) + { + _nkChkSeen = true; + _nkChkRa = pc + 8; + _nkChkA0 = regs != null && regs.Length > 4 ? regs[4] : 0; + _nkChkA1 = regs != null && regs.Length > 5 ? regs[5] : 0; + _nkChkA2 = regs != null && regs.Length > 6 ? regs[6] : 0; + _nkChkWord = PeekLoadE32Word(bus, _nkChkA1); + _nkChkSpan = FormatO32RomPeek(bus, _nkChkA1); + TryLogCurMSecDecompile(bus); + } + + // Observe firmware LoadE32 ExtraROM only. Poll last-error + // and jal targets. Do not jal. Do not rewrite registers. + // Do not force v0=1. Do not emit BinaryDecompressROM hex + // (watchdog LOOP_KILL false-positive on that substring). + public static void TryWatchExtraRomLoadE32(MipsBus bus, uint[] regs, uint pc) + { + TryLeftoverWait99O32NkObserve(bus, regs, pc); + TryWatchExtraRomFwMap(bus, regs, pc); + if (pc == RomHdrLinkJal) + TryLogRomHdrLinkJal(bus, regs); + if (pc == RomHdrLink) + TryLogRomHdrLinkEnter(bus, regs); + if (pc == RomHdrLinkPublish) + TryLogRomHdrLinkSw(bus, regs, "0x80017308 publish-head"); + if (pc == RomHdrLinkSplice) + TryLogRomHdrLinkSw(bus, regs, "0x8001731C splice-front"); + if (pc == RomHdrWalk || pc == RomHdrListLoad0 || pc == RomHdrListLoad1 + || pc == RomHdrListLoad2 || pc == RomHdrListLoad3 + || pc == RomHdrListLoad4 || pc == RomHdrListLoad5) + TryLogRomHdrListWalk(bus, "live pc=0x" + pc.ToString("X8")); + if (pc == CreateFileMappingObj6 && !_obj6ShLogged) + { + _obj6ShLogged = true; + uint fp = regs != null && regs.Length > 30 ? regs[30] : 0; + uint s5 = PeekS5(regs); + uint obj6 = PeekObj6(bus, fp); + BootLog.Write("[Hive] 0x8001D4F0 object+6=" + obj6 + + " s5=0x" + s5.ToString("X") + + " dest-word= dest0=0x" + fp.ToString("X8") + + " 0x80028844=False"); + } + if (_loadE32OkWatch) + NoteAfterLoadE32Ok(bus, regs, pc); + if (_nkLoadO32Watch) + NoteAfterNkLoadO32(bus, regs, pc); + if ((!_loadE32Watch && !_nkLoadE32Watch) || bus == null) + return; + NoteLoadE32RetPc(regs, pc); + _loadE32WatchSteps++; + if (_loadE32WatchSteps > 200000) + { + ClearLoadE32Watch(); + return; + } + uint err = ReadThreadLastError(bus); + if (regs != null && _loadE32CopyRa != 0 && pc == _loadE32CopyRa) + { + _loadE32CopyV0 = regs.Length > 2 ? regs[2] : 0; + _loadE32CopyRa = 0; + } + if (regs != null && _nkChkRa != 0 && pc == _nkChkRa) + { + _nkChkV0 = regs.Length > 2 ? regs[2] : 0; + _nkChkRa = 0; + } + if (regs != null && _loadE32ChkRa != 0 && pc == _loadE32ChkRa) + { + _loadE32ChkV0 = regs.Length > 2 ? regs[2] : 0; + _loadE32ChkRa = 0; + } + if (regs != null) + FinishLoadE32AfterJal(regs, pc); + if (_loadE32Watch && err != _loadE32WatchErrNow && _loadE32WatchErrHits < 4) + { + _loadE32WatchErrNow = err; + if (_loadE32WatchErrHits == 0) + { + _loadE32WatchErrPc = pc; + _loadE32WatchErrNew = err; + } + _loadE32WatchErrHits++; + } + if (regs == null) + return; + uint instr = 0; + try + { + instr = bus.Read32(pc); + } + catch + { + return; + } + uint target = 0; + uint op = instr >> 26; + if (op == 3) + target = (pc & 0xF0000000u) | ((instr & 0x3FFFFFFu) << 2); + else if (op == 0 && (instr & 0x3Fu) == 9 && regs.Length > ((int)((instr >> 21) & 0x1F))) + target = regs[(int)((instr >> 21) & 0x1F)]; + NoteLoadE32BodyCmp(bus, regs, pc, instr); + if (target == 0) + return; + if (_nkLoadE32Watch && target == OemCurMSec && !_nkChkSeen) + NoteNkLoadE32FieldJal(bus, regs, pc); + if (!_loadE32Watch) + return; + if (target == LoadE32UnitCopy || target == OemCurMSec) + NoteLoadE32FieldJal(bus, regs, pc, target); + if (IsLoadE32OemTickJal(target)) + NoteLoadE32AfterJal(bus, regs, pc, target); + string name = NameLoadE32Jal(target); + if (string.IsNullOrEmpty(name)) + return; + bool named = name.Length > 0 && name[0] != '0'; + if (!named && _loadE32WatchJalN >= 8) + return; + if (!string.IsNullOrEmpty(_loadE32WatchJal) + && _loadE32WatchJal.IndexOf(name, System.StringComparison.Ordinal) >= 0) + return; + if (!named) + _loadE32WatchJalN++; + if (!string.IsNullOrEmpty(_loadE32WatchJal)) + _loadE32WatchJal += ","; + _loadE32WatchJal += name; + } + + private static void BeginLoadE32Watch(ExtraRomTocMod slot, uint[] regs, uint err) + { + ClearAfterLoadE32(); + _loadE32Watch = true; + _loadE32WatchName = slot != null ? slot.Name : ""; + _loadE32WatchIndex = slot != null ? slot.Index : -1; + _loadE32WatchA0 = regs != null && regs.Length > 4 ? regs[4] : 0; + _loadE32WatchA1 = regs != null && regs.Length > 5 ? regs[5] : 0; + _loadE32WatchA2 = regs != null && regs.Length > 6 ? regs[6] : 0; + _loadE32WatchA3 = regs != null && regs.Length > 7 ? regs[7] : 0; + if (NamesMatchRom(_loadE32WatchName, "ddi_nop.dll")) + LatchDdiNopFileObj(_loadE32WatchA0); + _loadE32WatchErr0 = err; + _loadE32WatchErrNow = err; + _loadE32WatchErrPc = 0; + _loadE32WatchErrNew = err; + _loadE32WatchErrHits = 0; + _loadE32WatchJalN = 0; + _loadE32WatchJal = ""; + _loadE32WatchSteps = 0; + _loadE32CopyRa = 0; + _loadE32CopyV0 = 0xFFFFFFFFu; + _loadE32CopyA0 = 0; + _loadE32CopyA1 = 0; + _loadE32CopyA2 = 0; + _loadE32CopyWord = 0; + _loadE32ChkRa = 0; + _loadE32ChkV0 = 0xFFFFFFFFu; + _loadE32ChkA0 = 0; + _loadE32ChkA1 = 0; + _loadE32ChkA2 = 0; + _loadE32ChkWord = 0; + _loadE32ChkOff = 0; + _loadE32ChkSpan = null; + _loadE32CopySeen = false; + _loadE32ChkSeen = false; + ClearLoadE32Cmp(); + } + + private static void ClearNkLoadE32Watch() + { + _nkLoadE32Watch = false; + _nkLoadE32Name = null; + _nkLoadE32E32 = 0; + _nkLoadE32O32 = 0; + _nkLoadE32O32Vsize = 0; + _nkLoadE32O32Ptr = 0; + _nkLoadE32Obj = 0; + _nkLoadE32Toc = 0; + _nkLoadE32DumpToc0 = 0; + _nkChkRa = 0; + _nkChkA0 = 0; + _nkChkA1 = 0; + _nkChkA2 = 0; + _nkChkWord = 0; + _nkChkV0 = 0xFFFFFFFFu; + _nkChkSpan = null; + _nkChkSeen = false; + _nkRomBit = 0; + _nkCmpPc = 0; + _nkCmpOp = null; + _nkCmpLhs = 0; + _nkCmpRhs = 0; + _nkCmpFirstPc = 0; + _nkCmpFirstOp = null; + _nkCmpFirstLhs = 0; + _nkCmpFirstRhs = 0; + _nkRetPc = 0; + } + + private static void ClearLoadE32Watch() + { + ClearAfterLoadE32(); + _loadE32Watch = false; + _loadE32WatchName = null; + _loadE32WatchIndex = -1; + _loadE32WatchA0 = 0; + _loadE32WatchA1 = 0; + _loadE32WatchA2 = 0; + _loadE32WatchA3 = 0; + _loadE32WatchErr0 = 0; + _loadE32WatchErrNow = 0; + _loadE32WatchErrPc = 0; + _loadE32WatchErrNew = 0; + _loadE32WatchErrHits = 0; + _loadE32WatchJalN = 0; + _loadE32WatchJal = null; + _loadE32WatchSteps = 0; + _loadE32CopyRa = 0; + _loadE32CopyV0 = 0xFFFFFFFFu; + _loadE32CopyA0 = 0; + _loadE32CopyA1 = 0; + _loadE32CopyA2 = 0; + _loadE32CopyWord = 0; + _loadE32ChkRa = 0; + _loadE32ChkV0 = 0xFFFFFFFFu; + _loadE32ChkA0 = 0; + _loadE32ChkA1 = 0; + _loadE32ChkA2 = 0; + _loadE32ChkWord = 0; + _loadE32ChkOff = 0; + _loadE32ChkSpan = null; + _loadE32CopySeen = false; + _loadE32ChkSeen = false; + ClearLoadE32Cmp(); + } + + private static void ClearLoadE32Cmp() + { + _loadE32RomBit = 0; + _loadE32CmpPc = 0; + _loadE32CmpOp = null; + _loadE32CmpLhs = 0; + _loadE32CmpRhs = 0; + _loadE32CmpFirstPc = 0; + _loadE32CmpFirstOp = null; + _loadE32CmpFirstLhs = 0; + _loadE32CmpFirstRhs = 0; + _loadE32CmpAfterPc = 0; + _loadE32CmpAfterOp = null; + _loadE32CmpAfterLhs = 0; + _loadE32CmpAfterRhs = 0; + _loadE32CmpN = 0; + _loadE32CmpLog = null; + _loadE32RetPc = 0; + _loadE32RetV0 = 0; + _loadE32RetLogged = false; + } + + private static void BeginLoadE32OkWatch(ExtraRomTocMod slot, uint obj) + { + _loadE32OkWatch = true; + _loadE32OkName = slot != null ? slot.Name : ""; + _loadE32OkIndex = slot != null ? slot.Index : -1; + _loadE32OkObj = obj; + if (NamesMatchRom(_loadE32OkName, "ddi_nop.dll")) + LatchDdiNopFileObj(obj); + _loadE32OkDest = slot != null ? slot.Dest : 0; + _loadE32OkDest0 = _loadE32OkDest & SlotMask; + _loadE32OkLiveEntry = slot != null ? slot.LiveEntry : 0; + _loadE32OkLiveE32 = slot != null ? slot.LiveE32 : 0; + _loadE32OkDumpToc0 = DumpTocWord0(slot); + _loadE32OkLoadVa = SlotLoadVa(slot); + _loadE32OkObj6 = 0; + _loadE32OkWrapPc = LoadE32RomRet; + _loadE32OkLoadO32 = false; + _loadE32OkCopyO32 = false; + _loadE32OkPred = false; + _loadE32OkPredFail = false; + _loadE32OkLoadO32Ret = false; + _loadE32OkWrapFail = false; + _loadE32OkWrapAfter = false; + _loadE32OkMapO32 = false; + _loadE32OkMapInner = false; + _loadE32OkMap28844 = false; + _loadE32OkMapValloc = false; + _loadE32OkMapVallocV0 = 0xFFFFFFFFu; + _loadE32OkMapVallocA0 = 0; + _loadE32OkMapVallocA2 = 0; + _loadE32OkMapVallocA3 = 0; + _loadE32OkWrapValloc = false; + _loadE32OkO32Walk = false; + _loadE32OkS5Hi = false; + _loadE32OkFlagsChk = false; + _loadE32OkC1 = false; + _loadE32OkS5 = 0; + _loadE32OkSp24 = 0; + _loadE32OkDestAfter = 0; + _loadE32OkBindImp = false; + _loadE32OkCallDll = false; + _loadE32OkDecomp = false; + _skipDisasmLogged = false; + _wrapAfterDisasmLogged = false; + _loadE32OkPredRa = 0; + _loadE32OkPredV0 = 0xFFFFFFFFu; + _loadE32OkFp = 0; + _loadE32OkBit200 = false; + _loadE32OkBit200Seen = false; + _loadE32OkSkip200 = false; + _loadE32OkValloc = false; + _loadE32OkVallocRa = 0; + _loadE32OkVallocV0 = 0xFFFFFFFFu; + _loadE32OkSteps = 0; + } + + private static void ClearLoadE32OkWatch() + { + _loadE32OkWatch = false; + _loadE32OkName = null; + _loadE32OkIndex = -1; + _loadE32OkObj = 0; + _loadE32OkDest = 0; + _loadE32OkDest0 = 0; + _loadE32OkWrapPc = 0; + _loadE32OkLiveEntry = 0; + _loadE32OkLiveE32 = 0; + _loadE32OkDumpToc0 = 0; + _loadE32OkLoadVa = 0; + _loadE32OkObj6 = 0; + _loadE32OkLoadO32 = false; + _loadE32OkCopyO32 = false; + _loadE32OkPred = false; + _loadE32OkPredFail = false; + _loadE32OkLoadO32Ret = false; + _loadE32OkWrapFail = false; + _loadE32OkWrapAfter = false; + _loadE32OkMapO32 = false; + _loadE32OkMapInner = false; + _loadE32OkMap28844 = false; + _loadE32OkMapValloc = false; + _loadE32OkMapVallocV0 = 0xFFFFFFFFu; + _loadE32OkMapVallocA0 = 0; + _loadE32OkMapVallocA2 = 0; + _loadE32OkMapVallocA3 = 0; + _loadE32OkWrapValloc = false; + _loadE32OkO32Walk = false; + _loadE32OkS5Hi = false; + _loadE32OkFlagsChk = false; + _loadE32OkC1 = false; + _loadE32OkS5 = 0; + _loadE32OkSp24 = 0; + _loadE32OkDestAfter = 0; + _loadE32OkBindImp = false; + _loadE32OkCallDll = false; + _loadE32OkDecomp = false; + _skipDisasmLogged = false; + _wrapAfterDisasmLogged = false; + _loadE32OkPredRa = 0; + _loadE32OkPredV0 = 0xFFFFFFFFu; + _loadE32OkFp = 0; + _loadE32OkBit200 = false; + _loadE32OkBit200Seen = false; + _loadE32OkSkip200 = false; + _loadE32OkValloc = false; + _loadE32OkVallocRa = 0; + _loadE32OkVallocV0 = 0xFFFFFFFFu; + _loadE32OkSteps = 0; + } + + private static uint ReadThreadLastError(MipsBus bus) + { + if (bus == null) + return 0xFFFFFFFF; + try + { + uint thr = bus.Read32(ThreadPtr); + if (thr != 0 && thr != 0xDEADBEEFu) + return bus.Read32(thr + ThreadLastErr); + } + catch + { + } + return 0xFFFFFFFF; + } + + private static string FormatLastError(uint err) + { + if (err == 0xFFFFFFFF) + return "unmapped"; + string name = err == 2 ? " FILE_NOT_FOUND" + : err == 3 ? " PATH_NOT_FOUND" + : err == 8 ? " NOT_ENOUGH_MEMORY" + : err == 14 ? " OUTOFMEMORY" + : err == 87 ? " INVALID_PARAMETER" + : err == 126 ? " MOD_NOT_FOUND" + : err == 193 ? " BAD_EXE_FORMAT" + : err == LoadE32Err47E ? " LoadE32-0x47E" + : err == 1114 ? " DLL_INIT_FAILED" + : ""; + return err + name; + } + + private static bool IsLoadE32Success(uint v0, uint retPc) + { + if (v0 == LoadE32BadExe || v0 == LoadE32Err47E) + return false; + if (retPc == LoadE32FailBadExe || retPc == LoadE32Fail47E) + return false; + if (retPc == LoadE32Ok || retPc == LoadE32Epilogue) + return v0 == 0; + return v0 == 0; + } + + private static string NameLoadE32Ret(uint retPc, uint v0) + { + if (retPc == LoadE32FailBadExe || v0 == LoadE32BadExe) + return "fail=ERROR_BAD_EXE_FORMAT v0=0xC1"; + if (retPc == LoadE32Fail47E || v0 == LoadE32Err47E) + return "fail=0x47E"; + if ((retPc == LoadE32Ok || retPc == LoadE32Epilogue || retPc == 0) && v0 == 0) + return "success=LoadE32"; + if (v0 == 0) + return "success=LoadE32"; + return "fail=LoadE32 v0=0x" + v0.ToString("X8"); + } + + public static string NameLoadE32RetPublic(uint v0) + { + return NameLoadE32Ret(0, v0); + } + + // Dump nk.exe: v0=0 at 0x80019990 / 0x800199A4 is + // success. Dest word 0 after that is CopyO32 miss. + private static string DescribeLoadE32Ret(MipsBus bus, ExtraRomTocMod slot, + uint v0, uint err, bool liveMapped, uint live0, uint dump0) + { + string lite = DescribeE32Lite(bus, _loadE32WatchA1, slot); + string jal = !string.IsNullOrEmpty(_loadE32WatchJal) + ? " jal=" + _loadE32WatchJal : " jal=none"; + if (!string.IsNullOrEmpty(_afterRets)) + jal += " after=" + _afterRets; + string errAt = _loadE32WatchErrHits > 0 + ? " last-error-set " + FormatLastError(_loadE32WatchErrNew) + + " at pc=0x" + _loadE32WatchErrPc.ToString("X8") + : (err == _loadE32WatchErr0 + ? (err == 2 + ? " last-error stale FILE_NOT_FOUND (CreateFileFail leftover; LoadE32 did not SetLastError)" + : " last-error unchanged") + : " last-error-set " + FormatLastError(err)); + string copy = !liveMapped ? " LiveE32-unmapped" + : (live0 == dump0 && dump0 != 0 ? " e32_rom dump-real" : " e32_rom mismatch"); + string dest = DescribeLoadE32Dest(bus, slot); + string named = NameLoadE32Ret(_loadE32RetPc, v0); + string retpc = " ret-pc=0x" + _loadE32RetPc.ToString("X8"); + string body; + if (IsLoadE32Success(v0, _loadE32RetPc)) + body = " " + named + retpc + + " rombit=(obj+4)&2=" + _loadE32RomBit + + " " + NameLoadE32BodyNote(slot) + dest + + " (type-7 ROM path; memcpy then move v0,0; dest word 0 is CopyO32/CEDecompressROM/VALLOC not yet; not LoadE32 fail)"; + else if (lite.IndexOf("empty", System.StringComparison.Ordinal) >= 0) + body = " " + named + retpc + + " fail=before-e32_rom-copy rombit=(obj+4)&2=" + _loadE32RomBit + + " first-cmp " + + FormatLoadE32Cmp(_loadE32CmpFirstPc, _loadE32CmpFirstOp, + _loadE32CmpFirstLhs, _loadE32CmpFirstRhs); + else + body = " " + named + retpc + " " + NameLoadE32BodyNote(slot) + dest; + return lite + copy + jal + body + " " + errAt; + } + + private static string DescribeLoadE32Dest(MipsBus bus, ExtraRomTocMod slot) + { + if (slot == null) + return ""; + uint destDump = slot.Dest; + uint dest0 = destDump & SlotMask; + uint word0 = PeekDestWord(bus, dest0); + uint wordDump = destDump != dest0 ? PeekDestWord(bus, destDump) : word0; + return " dest0=0x" + dest0.ToString("X8") + + " dest-word=0x" + word0.ToString("X8") + + " destDump=0x" + destDump.ToString("X8") + + " dump-word=0x" + wordDump.ToString("X8"); + } + + private static string DescribeE32Lite(MipsBus bus, uint lite, ExtraRomTocMod slot) + { + if (lite == 0) + return " e32_lite=a1-0"; + uint w0 = 0; + uint w1 = 0; + uint w2 = 0; + uint w3 = 0; + bool mapped = false; + try + { + if (bus != null) + { + w0 = bus.Read32(lite); + w1 = bus.Read32(lite + 4); + w2 = bus.Read32(lite + 8); + w3 = bus.Read32(lite + 12); + mapped = true; + } + } + catch + { + } + if (!mapped) + return " e32_lite=0x" + lite.ToString("X8") + "-unmapped"; + uint dumpVbase = slot != null && slot.E32Words != null && slot.E32Words.Length > 2 + ? slot.E32Words[2] : 0; + uint dumpVsize = slot != null && slot.E32Words != null && slot.E32Words.Length > 5 + ? slot.E32Words[5] : 0; + uint dump0 = slot != null && slot.E32Words != null && slot.E32Words.Length > 0 + ? slot.E32Words[0] : 0; + bool empty = w0 == 0 && w1 == 0 && w2 == 0 && w3 == 0; + bool hasVbase = dumpVbase != 0 && (w0 == dumpVbase || w1 == dumpVbase + || w2 == dumpVbase || w3 == dumpVbase); + bool hasVsize = dumpVsize != 0 && (w0 == dumpVsize || w1 == dumpVsize + || w2 == dumpVsize || w3 == dumpVsize); + bool hasObjcnt = dump0 != 0 && ((w0 & 0xFFFF) == (dump0 & 0xFFFF)); + string which = empty ? "empty" + : ((hasObjcnt ? "objcnt" : "objcnt-miss") + + (hasVbase ? "+vbase" : "+vbase-miss") + + (hasVsize ? "+vsize" : "+vsize-miss")); + return " e32_lite=0x" + lite.ToString("X8") + + " w0=0x" + w0.ToString("X8") + + " w1=0x" + w1.ToString("X8") + + " w2=0x" + w2.ToString("X8") + + " w3=0x" + w3.ToString("X8") + + " " + which; + } + + private static string NameLoadE32Jal(uint target) + { + if (target == 0) + return ""; + if (target == BinaryDecompressRom || target == BinaryDecompressInner) + return "BinaryDecompressROM"; + if (target == CreateFileFail) + return "CreateFileFail"; + if (target == KernelReadFile) + return "ReadFile"; + if (target == KernelCreateFileMapping) + return "CreateFileMapping"; + if (target == 0x8001D3A0u) + return "CreateFile"; + if (target == 0x800283FCu) + return "VALLOC"; + if (target == MapO32VirtualCopy) + return "VirtualCopy"; + if (target == MapO32Decompress) + return "MapO32Decompress"; + if (target == LoadE32Rom) + return ""; + if (target == LoadE32UnitCopy) + return "e32_unit_copy"; + if (target == OemCurMSec) + return "CurMSec"; + if (target == OemReadCount) + return "ReadCount"; + if (target == OemTickDelta) + return "TickDelta"; + if (target == OemCountStall) + return "CountStall"; + if (target == OemReadCompare) + return "ReadCompare"; + if (target == OemWriteCompare) + return "WriteCompare"; + if (target == NkMoveV0A0) + return "MoveV0A0"; + return "0x" + target.ToString("X8"); + } + + private static bool IsLoadE32OemTickJal(uint target) + { + return target == OemReadCount + || target == OemTickDelta + || target == OemCountStall + || target == OemReadCompare + || target == OemWriteCompare + || target == NkMoveV0A0; + } + + private static string NameLoadE32AfterNeed(uint target, uint a0, uint a1, uint word) + { + if (target == OemReadCount) + return "mfc0 Count leftover; not a LoadE32 compare"; + if (target == OemReadCompare) + return "mfc0 Compare leftover; not a LoadE32 compare"; + if (target == OemWriteCompare) + return "mtc0 Compare leftover; not a LoadE32 compare"; + if (target == OemTickDelta) + return "tick vs 0x80338F70 leftover; later MMIO 0xB04007D4; not OalLoadE32Arg dest"; + if (target == OemCountStall) + return "Count+Compare stall leftover; not a LoadE32 compare"; + if (target == NkMoveV0A0) + return "move v0,a0 leftover; not a LoadE32 compare"; + return "OEM tick leftover a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " word=0x" + word.ToString("X8") + + "; not a LoadE32 compare"; + } + + private static void NoteLoadE32AfterJal(MipsBus bus, uint[] regs, uint pc, uint target) + { + if (_afterN >= LoadE32AfterMax) + return; + int i = _afterN; + _afterN++; + _afterRa[i] = pc + 8; + _afterName[i] = NameLoadE32Jal(target); + _afterA0[i] = regs != null && regs.Length > 4 ? regs[4] : 0; + _afterA1[i] = regs != null && regs.Length > 5 ? regs[5] : 0; + _afterA2[i] = regs != null && regs.Length > 6 ? regs[6] : 0; + _afterWord[i] = PeekLoadE32Word(bus, _afterA1[i] != 0 ? _afterA1[i] : _afterA0[i]); + _afterNeed[i] = NameLoadE32AfterNeed(target, _afterA0[i], _afterA1[i], _afterWord[i]); + TryLogLoadE32JalDecompile(bus, target, _afterName[i]); + } + + private static void FinishLoadE32AfterJal(uint[] regs, uint pc) + { + for (int i = 0; i < _afterN; i++) + { + if (_afterRa[i] == 0 || pc != _afterRa[i]) + continue; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + _afterRa[i] = 0; + string ret = _afterName[i] + " v0=0x" + v0.ToString("X8") + + " a0=0x" + _afterA0[i].ToString("X8") + + " a1=0x" + _afterA1[i].ToString("X8") + + " a2=0x" + _afterA2[i].ToString("X8") + + " word=0x" + _afterWord[i].ToString("X8"); + if (string.IsNullOrEmpty(_afterRets)) + _afterRets = ret; + else + _afterRets += "; " + ret; + } + } + + private static void ClearAfterLoadE32() + { + for (int i = 0; i < LoadE32AfterMax; i++) + { + _afterRa[i] = 0; + _afterName[i] = null; + _afterA0[i] = 0; + _afterA1[i] = 0; + _afterA2[i] = 0; + _afterWord[i] = 0; + _afterNeed[i] = null; + } + _afterN = 0; + _afterRets = null; + } + + private static void NoteLoadE32FieldJal(MipsBus bus, uint[] regs, uint pc, uint target) + { + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint a2 = regs != null && regs.Length > 6 ? regs[6] : 0; + uint word = PeekLoadE32Word(bus, a1 != 0 ? a1 : a0); + uint ra = pc + 8; + if (target == LoadE32UnitCopy && !_loadE32CopySeen) + { + _loadE32CopySeen = true; + _loadE32CopyRa = ra; + _loadE32CopyA0 = a0; + _loadE32CopyA1 = a1; + _loadE32CopyA2 = a2; + _loadE32CopyWord = word; + return; + } + if (target != OemCurMSec || _loadE32ChkSeen) + return; + _loadE32ChkSeen = true; + _loadE32ChkRa = ra; + _loadE32ChkA0 = a0; + _loadE32ChkA1 = a1; + _loadE32ChkA2 = a2; + _loadE32ChkWord = word; + _loadE32ChkOff = 0; + _loadE32ChkSpan = FormatO32RomPeek(bus, a1); + ExtraRomTocMod slot = FindCachedExtraRomToc(_loadE32WatchName); + uint live = slot != null ? slot.LiveE32 : 0; + if (a1 != 0 && live != 0 && a1 >= live && a1 < live + 0x80) + _loadE32ChkOff = a1 - live; + TryLogCurMSecDecompile(bus); + } + + private static uint PeekLoadE32Word(MipsBus bus, uint va) + { + if (bus == null || va == 0) + return 0; + try + { + return bus.Read32(va); + } + catch + { + return 0; + } + } + + private static string FormatLoadE32Cmp(uint pc, string op, uint lhs, uint rhs) + { + if (string.IsNullOrEmpty(op) || pc == 0) + return "none"; + return "pc=0x" + pc.ToString("X8") + " " + op + + " lhs=0x" + lhs.ToString("X8") + + " rhs=0x" + rhs.ToString("X8"); + } + + private static bool TryDecodeLoadE32Cmp(uint[] regs, uint instr, + out string op, out uint lhs, out uint rhs) + { + op = null; + lhs = 0; + rhs = 0; + uint opcode = instr >> 26; + uint rs = (instr >> 21) & 31; + uint rt = (instr >> 16) & 31; + uint fn = instr & 0x3F; + int simm = (short)(instr & 0xFFFF); + uint rsV = regs != null && regs.Length > (int)rs ? regs[(int)rs] : 0; + uint rtV = regs != null && regs.Length > (int)rt ? regs[(int)rt] : 0; + if (opcode == 4) + { + op = "beq"; + lhs = rsV; + rhs = rtV; + return true; + } + if (opcode == 5) + { + op = "bne"; + lhs = rsV; + rhs = rtV; + return true; + } + if (opcode == 6) + { + op = "blez"; + lhs = rsV; + rhs = 0; + return true; + } + if (opcode == 7) + { + op = "bgtz"; + lhs = rsV; + rhs = 0; + return true; + } + if (opcode == 0xA) + { + op = "slti"; + lhs = rsV; + rhs = (uint)simm; + return true; + } + if (opcode == 0xB) + { + op = "sltiu"; + lhs = rsV; + rhs = (uint)simm; + return true; + } + if (opcode == 0 && fn == 0x2A) + { + op = "slt"; + lhs = rsV; + rhs = rtV; + return true; + } + if (opcode == 0 && fn == 0x2B) + { + op = "sltu"; + lhs = rsV; + rhs = rtV; + return true; + } + if (opcode == 0xC && (instr & 0xFFFF) == LoadE32RomBit) + { + op = "andi-rombit"; + lhs = rsV; + rhs = LoadE32RomBit; + return true; + } + return false; + } + + private static void NoteLoadE32BodyCmp(MipsBus bus, uint[] regs, uint pc, uint instr) + { + if (pc < LoadE32Rom || pc >= LoadE32BodyLim) + return; + string op; + uint lhs; + uint rhs; + if (!TryDecodeLoadE32Cmp(regs, instr, out op, out lhs, out rhs)) + return; + if (_nkLoadE32Watch) + { + if (string.IsNullOrEmpty(_nkCmpFirstOp)) + { + _nkCmpFirstPc = pc; + _nkCmpFirstOp = op; + _nkCmpFirstLhs = lhs; + _nkCmpFirstRhs = rhs; + } + _nkCmpPc = pc; + _nkCmpOp = op; + _nkCmpLhs = lhs; + _nkCmpRhs = rhs; + } + if (!_loadE32Watch) + return; + if (string.IsNullOrEmpty(_loadE32CmpFirstOp)) + { + _loadE32CmpFirstPc = pc; + _loadE32CmpFirstOp = op; + _loadE32CmpFirstLhs = lhs; + _loadE32CmpFirstRhs = rhs; + } + _loadE32CmpPc = pc; + _loadE32CmpOp = op; + _loadE32CmpLhs = lhs; + _loadE32CmpRhs = rhs; + bool afterCopy = _loadE32CopySeen && _loadE32CopyRa == 0; + if (!afterCopy) + return; + _loadE32CmpAfterPc = pc; + _loadE32CmpAfterOp = op; + _loadE32CmpAfterLhs = lhs; + _loadE32CmpAfterRhs = rhs; + string key = "0x" + pc.ToString("X8"); + if (!string.IsNullOrEmpty(_loadE32CmpLog) + && _loadE32CmpLog.IndexOf(key, System.StringComparison.Ordinal) >= 0) + return; + if (_loadE32CmpN >= 8) + return; + if (string.IsNullOrEmpty(_loadE32CmpLog)) + _loadE32CmpLog = key; + else + _loadE32CmpLog += "," + key; + _loadE32CmpN++; + if (pc == LoadE32Ok || pc == LoadE32Fail47E + || pc == LoadE32FailBadExe || pc == LoadE32Epilogue) + return; + } + + private static string FormatO32RomPeek(MipsBus bus, uint va) + { + if (va == 0) + return "va=0"; + uint vsize = PeekLoadE32Word(bus, va); + uint rva = PeekLoadE32Word(bus, va + 4); + uint psize = PeekLoadE32Word(bus, va + 8); + uint dataptr = PeekLoadE32Word(bus, va + 0xC); + uint real = PeekLoadE32Word(bus, va + 0x10); + uint flags = PeekLoadE32Word(bus, va + 0x14); + return "va=0x" + va.ToString("X8") + + " vsize=0x" + vsize.ToString("X") + + " rva=0x" + rva.ToString("X") + + " psize=0x" + psize.ToString("X") + + " dataptr=0x" + dataptr.ToString("X8") + + " real=0x" + real.ToString("X8") + + " flags=0x" + flags.ToString("X"); + } + + private static string FormatDumpO32(ExtraRomTocMod? slot) + { + if (slot == null || slot.O32Words == null || slot.O32Words.Length < 4) + return ""; + return " psize=0x" + slot.O32Words[2].ToString("X") + + " dataptr=0x" + slot.O32Words[3].ToString("X8"); + } + + private static uint PeekSpWord(MipsBus bus, uint[] regs, uint off) + { + if (bus == null || regs == null || regs.Length <= 29) + return 0; + uint sp = regs[29]; + if (sp == 0) + return 0; + return PeekDestWord(bus, sp + off); + } + + private static uint PeekS5(uint[] regs) + { + if (regs == null || regs.Length <= 21) + return 0; + return regs[21]; + } + + private static string FormatWrapBits(uint s5, uint sp24) + { + return " s5=0x" + s5.ToString("X8") + + " s5&2=" + (s5 & WrapS5Bit2).ToString("X") + + " s5&0x8000=" + (s5 & WrapS5CallDll).ToString("X") + + " 0x24(sp)=0x" + sp24.ToString("X8") + + " 0x24(sp)&0x2000=" + (sp24 & E32ImageDllBit).ToString("X") + + " (0x24(sp) is LoadE32 e32_imageflags; ExtraROM 0x212E0003 has 0x2000 DLL; do not invent 0x2000)"; + } + + private static string FormatSkipVsDdiNop() + { + return FormatSkipVsDdiNop(_loadE32OkName); + } + + private static string FormatSkipVsDdiNop(string name) + { + bool bcm = name != null && NamesMatchRom(name, "bcmuart.dll"); + bool ddi = name != null && NamesMatchRom(name, "ddi_nop.dll"); + if (bcm) + return " vs ddi_nop OpenFile/LoadDriver object+6>=2 c1c0bc4 dest 0x01981000; BuiltIn bcmuart LoadLibrary skip dest 0"; + if (ddi) + return " vs BuiltIn bcmuart LoadLibrary LoadO32 skip dest 0; this is OpenFile/LoadDriver MapO32/CEDecompressROM"; + return " vs ddi_nop OpenFile/LoadDriver (object+6>=2) vs BuiltIn LoadLibrary skip"; + } + + private static string FormatSkipWatchBits() + { + return " object+6=" + _loadE32OkObj6 + + " 0x8001AC9c=" + _loadE32OkMapInner + + " 0x80028844=" + _loadE32OkMap28844 + + " 0x800283fc=" + _loadE32OkWrapValloc + + " 0x8001AF20=" + _loadE32OkO32Walk + + " 0x8001E45c=" + _loadE32OkS5Hi + + " 0x8001E4a8=" + _loadE32OkFlagsChk + + " C1=" + _loadE32OkC1 + + " dest-after-0x80016848=0x" + _loadE32OkDestAfter.ToString("X8") + + FormatWrapBits(_loadE32OkS5, _loadE32OkSp24); + } + + private static void MarkFwMapO32() + { + ExtraRomTocMod slot = FindCachedExtraRomToc(_loadE32OkName); + if (slot != null) + slot.FwMapO32 = true; + } + + private static void MarkBuiltInSkip() + { + ExtraRomTocMod slot = FindCachedExtraRomToc(_loadE32OkName); + if (slot != null) + slot.BuiltInSkip = true; + } + + private static void PersistSkipCompare(MipsBus bus) + { + if (string.IsNullOrEmpty(_loadE32OkName)) + return; + string snap = _loadE32OkName + FormatSkipWatchBits() + FormatSkipVsDdiNop(); + bool bcm = NamesMatchRom(_loadE32OkName, "bcmuart.dll"); + bool ddi = NamesMatchRom(_loadE32OkName, "ddi_nop.dll"); + if (bcm) + _bcmSkipSnap = snap; + if (ddi) + _ddiSkipSnap = snap; + if (!bcm && !ddi) + return; + HiveWatch(bus, "skip-compare", 0); + } + + private static void PersistOpenFileMap(ExtraRomTocMod slot, uint obj6, uint dest, uint destWord) + { + if (slot == null || !IsCompareExtraRom(slot)) + return; + string snap = slot.Name + + " OpenFile/LoadDriver object+6=" + obj6 + + " 0x8001AC9c=" + slot.LoggedFwMapInner + + " 0x80028844=" + slot.LoggedFwMap28844 + + " MapO32=" + slot.LoggedFwMapO32 + + " dest=0x" + dest.ToString("X8") + + " dest-word=0x" + destWord.ToString("X8") + + " " + FormatDumpO32(slot) + + FormatLoadVaPhys(slot.Name, SlotLoadVa(slot)) + + " (firmware MapO32/CEDecompressROM; serve dest on this path; do not invent dest; do not invent a map at 0x8178C000)"; + bool ddi = NamesMatchRom(slot.Name, "ddi_nop.dll"); + if (ddi) + _ddiSkipSnap = snap; + else + _bcmMapSnap = snap; + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " openfile-map v0= dest-word=0x" + destWord.ToString("X") + + " dest0=0x" + dest.ToString("X8") + + " object+6=" + obj6 + + " 0x80028844=" + slot.LoggedFwMap28844); + } + + // ddi_nop dest is OpenFile/LoadDriver MapO32, not the + // ExtraROM BuiltIn LoadE32-ok watch. Log the same + // compare bits so Boot can set _ddiSkipSnap without + // attributing that MapO32 to bcmuart skip. + private static void TryWatchExtraRomFwMap(MipsBus bus, uint[] regs, uint pc) + { + if (bus == null || regs == null) + return; + if (pc != MapO32Rom && pc != MapO32InnerJal && pc != MapO32Decompress + && pc != BinaryDecompressRom) + return; + ExtraRomTocMod slot = FindExtraRomMapSlot(bus, regs, pc); + if (!IsCompareExtraRom(slot)) + return; + bool first = false; + if (pc == MapO32Rom && !slot.LoggedFwMapO32) + { + slot.LoggedFwMapO32 = true; + first = true; + } + else if (pc == MapO32InnerJal && !slot.LoggedFwMapInner) + { + slot.LoggedFwMapInner = true; + first = true; + } + else if (pc == MapO32Decompress && !slot.LoggedFwMap28844) + { + slot.LoggedFwMap28844 = true; + first = true; + } + else if (pc == BinaryDecompressRom && !slot.FwMapO32) + first = true; + if (!first) + return; + slot.FwMapO32 = true; + uint obj = regs.Length > 4 ? regs[4] : 0; + uint obj6 = PeekObj6(bus, obj); + uint dest = 0; + uint destWord = 0; + if (pc == MapO32Decompress) + dest = regs[4]; + else if (pc == BinaryDecompressRom) + dest = regs.Length > 6 ? regs[6] : 0; + else if (regs.Length > 5 && regs[5] != 0) + dest = PeekDestWord(bus, regs[5] + 8); + if (dest == 0) + dest = slot.DecompDest != 0 ? slot.DecompDest : (slot.Dest & SlotMask); + destWord = PeekDestWord(bus, dest); + PersistOpenFileMap(slot, obj6, dest, destWord); + string ev = pc == MapO32InnerJal ? "0x8001ACC4" + : pc == MapO32Decompress ? "0x80028844" + : pc == BinaryDecompressRom ? "CEDecompressROM" + : "MapO32"; + uint destDump = slot.Dest; + uint wordDump = destDump != 0 ? PeekDestWord(bus, destDump) : destWord; + string miss = (pc == MapO32Decompress || pc == MapO32Rom || pc == MapO32InnerJal) + && destWord == 0 && wordDump == 0 + ? " destDump-word=0; 0x800283FC(o32.real) not memcpy" + : ""; + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " " + ev + + " v0= dest-word=0x" + destWord.ToString("X") + + " dest0=0x" + dest.ToString("X8") + + " object+6=" + obj6 + + " 0x80028844=" + slot.LoggedFwMap28844 + + miss); + } + + // Dump nk.exe: CurMSec jal ReadCount then 0x803392B0 / + // 0x80342C60. Guest bytes are not in-repo; later Boot + // fills this. Incoming a1 is leftover LoadE32, not o32. + private static void TryLogCurMSecDecompile(MipsBus bus) + { + _curMSecDisasmLogged = true; + } + + // Guest NK/OAL bytes are not in-repo. Read them from the + // live bus on the later Boot (no dump folder I/O). + private static void TryLogLoadE32JalDecompile(MipsBus bus, uint va, string name) + { + } + + private static bool IsMipsJrRa(uint instr) + { + return (instr >> 26) == 0 && (instr & 0x3Fu) == 8 && ((instr >> 21) & 0x1Fu) == 31; + } + + private static readonly string[] MipsRegName = { + "0", "at", "v0", "v1", "a0", "a1", "a2", "a3", + "t0", "t1", "t2", "t3", "t4", "t5", "t6", "t7", + "s0", "s1", "s2", "s3", "s4", "s5", "s6", "s7", + "t8", "t9", "k0", "k1", "gp", "sp", "fp", "ra" + }; + + private static string MipsRn(uint r) + { + return MipsRegName[r & 31]; + } + + private static string FormatMipsOp(uint pc, uint instr) + { + uint op = instr >> 26; + uint rs = (instr >> 21) & 31; + uint rt = (instr >> 16) & 31; + uint rd = (instr >> 11) & 31; + uint sh = (instr >> 6) & 31; + uint fn = instr & 0x3F; + int simm = (short)(instr & 0xFFFF); + uint uimm = instr & 0xFFFF; + if (op == 0) + { + if (instr == 0) + return "nop"; + if (fn == 0) + return "sll " + MipsRn(rd) + "," + MipsRn(rt) + "," + sh; + if (fn == 2) + return "srl " + MipsRn(rd) + "," + MipsRn(rt) + "," + sh; + if (fn == 3) + return "sra " + MipsRn(rd) + "," + MipsRn(rt) + "," + sh; + if (fn == 8) + return "jr " + MipsRn(rs); + if (fn == 9) + return "jalr " + MipsRn(rd) + "," + MipsRn(rs); + if (fn == 0x0A) + return "movz " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x0B) + return "movn " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x0D) + return "break"; + if (fn == 0x0F) + return "sync"; + if (fn == 0x16) + return "spec fn=0x16 " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x21) + return "addu " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x23) + return "subu " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x24) + return "and " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x25) + return "or " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x27) + return "nor " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x2A) + return "slt " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x2B) + return "sltu " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x1A) + return "div " + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x1B) + return "divu " + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x10) + return "mfhi " + MipsRn(rd); + if (fn == 0x12) + return "mflo " + MipsRn(rd); + return "spec fn=0x" + fn.ToString("X"); + } + if (op == 0x10) + { + if (rs == 0) + return "mfc0 " + MipsRn(rt) + "," + rd; + if (rs == 4) + return "mtc0 " + MipsRn(rt) + "," + rd; + } + if (op == 2 || op == 3) + { + uint t = (pc & 0xF0000000u) | ((instr & 0x3FFFFFFu) << 2); + return (op == 2 ? "j " : "jal ") + "0x" + t.ToString("X8"); + } + if (op == 4) + return "beq " + MipsRn(rs) + "," + MipsRn(rt) + "," + simm; + if (op == 5) + return "bne " + MipsRn(rs) + "," + MipsRn(rt) + "," + simm; + if (op == 6) + return "blez " + MipsRn(rs) + "," + simm; + if (op == 7) + return "bgtz " + MipsRn(rs) + "," + simm; + if (op == 8) + return "addi " + MipsRn(rt) + "," + MipsRn(rs) + "," + simm; + if (op == 9) + return "addiu " + MipsRn(rt) + "," + MipsRn(rs) + "," + simm; + if (op == 0xA) + return "slti " + MipsRn(rt) + "," + MipsRn(rs) + "," + simm; + if (op == 0xB) + return "sltiu " + MipsRn(rt) + "," + MipsRn(rs) + "," + simm; + if (op == 0xC) + return "andi " + MipsRn(rt) + "," + MipsRn(rs) + ",0x" + uimm.ToString("X"); + if (op == 0xD) + return "ori " + MipsRn(rt) + "," + MipsRn(rs) + ",0x" + uimm.ToString("X"); + if (op == 0xE) + return "xori " + MipsRn(rt) + "," + MipsRn(rs) + ",0x" + uimm.ToString("X"); + if (op == 0xF) + return "lui " + MipsRn(rt) + ",0x" + uimm.ToString("X"); + if (op == 0x20) + return "lb " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x23) + return "lw " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x24) + return "lbu " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x25) + return "lhu " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x28) + return "sb " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x2B) + return "sw " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x2F) + return "cache " + rt + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x30) + return "ll " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x33) + return "pref " + rt + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x38) + return "sc " + MipsRn(rt) + "," + simm + "(" + MipsRn(rs) + ")"; + if (op == 0x1C) + { + if (fn == 0x02) + return "mul " + MipsRn(rd) + "," + MipsRn(rs) + "," + MipsRn(rt); + if (fn == 0x20) + return "clz " + MipsRn(rd) + "," + MipsRn(rs); + return "spec2 fn=0x" + fn.ToString("X"); + } + return "op" + op.ToString("X") + "=0x" + instr.ToString("X8"); + } + + // Body notes only. v0=0 is success, not fail=LoadE32Cmp. + private static string NameLoadE32BodyNote(ExtraRomTocMod slot) + { + uint live = slot != null ? slot.LiveE32 : 0; + uint liveO32 = slot != null ? slot.LiveO32 : 0; + string copy = _loadE32CopySeen + ? " e32_unit_copy v0=0x" + _loadE32CopyV0.ToString("X8") + + " dest=0x" + _loadE32CopyA0.ToString("X8") + + " src=0x" + _loadE32CopyA1.ToString("X8") + + " a2=0x" + _loadE32CopyA2.ToString("X8") + : " e32_unit_copy missed"; + string first = " first-cmp " + + FormatLoadE32Cmp(_loadE32CmpFirstPc, _loadE32CmpFirstOp, + _loadE32CmpFirstLhs, _loadE32CmpFirstRhs); + string lastAfter = !string.IsNullOrEmpty(_loadE32CmpAfterOp) + ? " last-cmp " + + FormatLoadE32Cmp(_loadE32CmpAfterPc, _loadE32CmpAfterOp, + _loadE32CmpAfterLhs, _loadE32CmpAfterRhs) + : " last-cmp " + + FormatLoadE32Cmp(_loadE32CmpPc, _loadE32CmpOp, + _loadE32CmpLhs, _loadE32CmpRhs); + string leftover = _loadE32ChkSeen + ? " CurMSec leftover a1=0x" + _loadE32ChkA1.ToString("X8") + + " tick-v0=0x" + _loadE32ChkV0.ToString("X8") + + " (not o32 ABI; not the fail)" + : " CurMSec not observed"; + string dumpO32 = FormatDumpO32(slot); + string nk = !string.IsNullOrEmpty(_nkLoadE32Ok) + ? " NK-ok " + _nkLoadE32Ok + : " NK-ok pending fsdmgr/coredll/ceddk (NK e32 not in-repo)"; + return lastAfter + + first + copy + leftover + + " liveE32=0x" + live.ToString("X8") + + " LiveO32=0x" + liveO32.ToString("X8") + + " " + dumpO32 + + " (dump e32 then dump o32 after; do not invent +0x5C;" + + nk + "; memcpy is 0x80058B24; do not force v0=1)"; + } + + private static void NoteLoadE32RetPc(uint[] regs, uint pc) + { + if (pc != LoadE32Ok && pc != LoadE32Fail47E + && pc != LoadE32FailBadExe && pc != LoadE32Epilogue) + return; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + if (pc == LoadE32Ok || pc == LoadE32Fail47E || pc == LoadE32FailBadExe) + { + if (_loadE32Watch) + _loadE32RetPc = pc; + if (_nkLoadE32Watch) + _nkRetPc = pc; + } + else if (pc == LoadE32Epilogue) + { + if (_loadE32Watch && _loadE32RetPc == 0) + _loadE32RetPc = pc; + if (_nkLoadE32Watch && _nkRetPc == 0) + _nkRetPc = pc; + } + if (_loadE32Watch) + _loadE32RetV0 = v0; + if (!_loadE32Watch || _loadE32RetLogged) + return; + _loadE32RetLogged = true; + } + + private static string FormatLoadE32OkDest(MipsBus bus) + { + uint word0 = PeekDestWord(bus, _loadE32OkDest0); + uint wordDump = _loadE32OkDest != 0 && _loadE32OkDest != _loadE32OkDest0 + ? PeekDestWord(bus, _loadE32OkDest) : word0; + return " dest0=0x" + _loadE32OkDest0.ToString("X8") + + " dest-word=0x" + word0.ToString("X8") + + " destDump=0x" + _loadE32OkDest.ToString("X8") + + " dump-word=0x" + wordDump.ToString("X8"); + } + + private static uint DumpTocWord0(ExtraRomTocMod slot) + { + if (slot == null) + return 0; + if (slot.TocWords != null && slot.TocWords.Length > 0) + return slot.TocWords[0]; + return slot.Attr; + } + + private static string FormatDumpLiveEntry0(uint dumpToc0, uint live0) + { + bool dumpReal = dumpToc0 != 0 && live0 == dumpToc0; + return " dumpToc0=0x" + dumpToc0.ToString("X8") + + " LiveEntry0=0x" + live0.ToString("X8") + + (dumpReal ? " dump-real" : " LiveEntry0!=dumpToc0") + + " dumpToc0&0x200=" + (dumpToc0 & LoadO32VallocBit).ToString("X") + + " LiveEntry0&0x200=" + (live0 & LoadO32VallocBit).ToString("X"); + } + + // Extract: ExtraROM BuiltIn 0x807 and ddi_nop 0x807 + // both lack 0x200. ddi_nop dest was OpenFile/LoadDriver + // MapO32/CEDecompressROM (object+6>=2), not the + // LoadO32 thunk. BuiltIn LoadLibrary hits LoadE32 + // success then LoadO32 skip, so firmware never + // VirtualCopys ExtraROM BuiltIn o32. Serve dest only + // on the path firmware actually takes. Do not set + // 0x200. Do not copy NK 0x1007. Do not invent dest. + private static string NameBuiltInMiss() + { + return "dest-word 0; serve dest only if firmware wrote it"; + } + + // Dump-real: linker 0x8001728C has ONE caller, + // 0x80014420 (early kernel, before mtc0 Status at + // 0x8001442C). One-shot. nk.exe .text only + // 0x800172B8 addiu/lw of 0x29c8, no sw; ExtraROM + // extracted PEs: zero lui 0x8034 + imm 0x29c8. + // If *0x803429C8 is 0 at 0x80014420, firmware never + // links 0x8134DA84. Do not invent a ROMChain_t + // before that jal. Do not host-write 0x803429C8. + // Host attach is a workaround because ExtraROM is + // unlinked. 86e51ea linker enter/sw logs stay. + private static string NameChainMiss() + { + return "host attach; ExtraROM unlinked; dest only if firmware wrote it"; + } + + public static void LogExtraRomHdrAtMap(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint romhdr) + { + if (memory == null) + return; + if (romhdr != 0) + _extraRomHdr = romhdr; + uint hdr = romhdr != 0 ? romhdr : ExtraRomDumpHdr; + uint copy = 0; + uint ext = 0; + uint physfirst = 0; + uint physlast = 0; + uint nmods = 0; + bool dumpHdr = false; + try + { + copy = memory.ReadMemory32(hdr + RomHdrCopyEntries); + ext = memory.ReadMemory32(hdr + RomHdrExtensions); + physfirst = memory.ReadMemory32(hdr + 8); + physlast = memory.ReadMemory32(hdr + 0xC); + nmods = memory.ReadMemory32(hdr + RomHdrNumMods); + dumpHdr = true; + } + catch + { + } + if (!dumpHdr && hdr != ExtraRomDumpHdr) + { + try + { + hdr = ExtraRomDumpHdr; + copy = memory.ReadMemory32(hdr + RomHdrCopyEntries); + ext = memory.ReadMemory32(hdr + RomHdrExtensions); + physfirst = memory.ReadMemory32(hdr + 8); + physlast = memory.ReadMemory32(hdr + 0xC); + nmods = memory.ReadMemory32(hdr + RomHdrNumMods); + dumpHdr = true; + } + catch + { + } + } + if (!_romHdrChainLogged) + { + _romHdrChainLogged = true; + uint head = 0; + try { head = memory.ReadMemory32(RomHdrListPtr); } + catch { } + BootLog.Write("[Hive] ROMHDR at-map ExtraROM-hdr=0x" + hdr.ToString("X8") + + " *0x80342B10=0x" + head.ToString("X") + + " nmods=" + nmods); + } + } + + private static string FormatRomHdrListFromMemory(ProcessorEmulator.Core.Emulation.IMemoryManager memory, uint extraHdr) + { + if (memory == null) + return "list-walk skipped"; + try + { + uint head = memory.ReadMemory32(RomHdrListPtr); + return FormatRomHdrListWalk(va => memory.ReadMemory32(va), head, extraHdr); + } + catch + { + return "*(0x80342B10) unmapped (NK list not readable at ExtraROM map)"; + } + } + + public static void TryLogRomHdrListWalk(MipsBus bus, string when) + { + if (bus == null) + return; + uint extraHdr = _extraRomHdr != 0 ? _extraRomHdr : ExtraRomDumpHdr; + uint head = PeekDestWord(bus, RomHdrListPtr); + if (_romHdrListWalkLogged && when != null && when.IndexOf("host-attach", System.StringComparison.Ordinal) < 0) + return; + _romHdrListWalkLogged = true; + BootLog.Write("[Hive] ROMHDR list ExtraROM-hdr=0x" + extraHdr.ToString("X8") + + " *0x80342B10=0x" + head.ToString("X")); + } + + // Observe 0x80014420 jal of 0x8001728C only. Peek + // *0x803429C8 and ExtraROM hdr mapped. Cite dump: + // one caller, no sw of 0x803429C8 in nk or ExtraROM + // PEs. Do not invent a ROMChain_t before that jal. + // Do not host-write 0x803429C8. 86e51ea enter/sw stay. + private static void TryLogRomHdrLinkJal(MipsBus bus, uint[] regs) + { + if (bus == null || _romHdrLinkJalLogged) + return; + _romHdrLinkJalLogged = true; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint a2 = regs != null && regs.Length > 6 ? regs[6] : 0; + uint a3 = regs != null && regs.Length > 7 ? regs[7] : 0; + uint srcHead; + TryRead32(va => bus.Read32(va), RomHdrSrcChain, out srcHead); + uint word = 0; + bool hdrMapped = TryRead32(va => bus.Read32(va), ExtraRomDumpHdr, out word); + BootLog.Write("[Hive] ROMHDR jal 0x80014420 *0x803429C8=0x" + srcHead.ToString("X") + + " ExtraROM-hdr=" + (hdrMapped ? "mapped" : "unmapped") + + " a0=0x" + a0.ToString("X") + + " a1=0x" + a1.ToString("X") + + " a2=0x" + a2.ToString("X") + + " a3=0x" + a3.ToString("X")); + } + + private static string FormatExtraRomHdrMapped(MipsBus bus) + { + uint word = 0; + bool mapped = bus != null + && TryRead32(va => bus.Read32(va), ExtraRomDumpHdr, out word); + string host = _extraRomHdr != 0 + ? " host-NkBinLoader-hdr=0x" + _extraRomHdr.ToString("X8") + : " host-NkBinLoader-hdr-not-yet"; + if (!mapped) + return "ExtraROM-hdr-0x8134DA84-unmapped" + host; + return "ExtraROM-hdr-0x8134DA84-mapped word0=0x" + word.ToString("X8") + host; + } + + // Observe 0x8001728C only. Peek *0x803429C8 and walk + // node+4 vs ExtraROM 0x8134DA84 / NK 0x802808B4. + // Do not host-write 0x803429C8 or 0x80342B10. + private static void TryLogRomHdrLinkEnter(MipsBus bus, uint[] regs) + { + if (bus == null || _romHdrLinkEnterCount >= RomHdrLinkLogMax) + return; + _romHdrLinkEnterCount++; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint a2 = regs != null && regs.Length > 6 ? regs[6] : 0; + uint a3 = regs != null && regs.Length > 7 ? regs[7] : 0; + uint srcHead = PeekDestWord(bus, RomHdrSrcChain); + uint listHead = PeekDestWord(bus, RomHdrListPtr); + BootLog.Write("[Hive] ROMHDR enter 0x8001728C *0x803429C8=0x" + srcHead.ToString("X") + + " *0x80342B10=0x" + listHead.ToString("X") + + " a1=0x" + a1.ToString("X") + + " a2=0x" + a2.ToString("X") + + " a3=0x" + a3.ToString("X")); + } + + private static void TryLogRomHdrLinkSw(MipsBus bus, uint[] regs, string which) + { + if (bus == null || string.IsNullOrEmpty(which)) + return; + bool publish = which.IndexOf("0x80017308", System.StringComparison.Ordinal) >= 0; + if (publish) + { + if (_romHdrLinkPublishCount >= RomHdrLinkLogMax) + return; + _romHdrLinkPublishCount++; + } + else + { + if (_romHdrLinkSpliceCount >= RomHdrLinkLogMax) + return; + _romHdrLinkSpliceCount++; + } + uint a3 = regs != null && regs.Length > 7 ? regs[7] : 0; + uint srcHead = PeekDestWord(bus, RomHdrSrcChain); + uint oldHead = PeekDestWord(bus, RomHdrListPtr); + BootLog.Write("[Hive] ROMHDR sw " + which + + " *0x803429C8=0x" + srcHead.ToString("X") + + " *0x80342B10=0x" + oldHead.ToString("X") + + " a3=0x" + a3.ToString("X")); + } + + // Boot 75fab53 hung at ROMHDR enter + // 0x8001728C (3 Hive lines). First + // work is addiu $sp,-248 then + // sw $ra,244($sp). Unbacked $sp + // dest-miss TLBS and never reaches + // empty-chain beq 0x8001730C. + // Dump-true: exec addiu; skip + // prologue sw; peek *0x803429C8 + // (0 → empty); honor beq → + // 0x8001732C jal 0x80041AC4. + // Do not invent a ROMChain_t. + // Do not host-write 0x803429C8 + // or 0x80342B10. + public static bool TryTakeDumpMemRomHdrLinkContinue(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (pc != RomHdrLink) + return false; + if (inDelay) + return false; + if (_romHdrLinkContinueLogged) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(RomHdrSrcChainLw) + || IsDumpMemRefuseVa(RomHdrLinkJalNext)) + return false; + uint addiu = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out addiu) || addiu == 0) + addiu = RomHdrLinkAddiuDump; + if (addiu != RomHdrLinkAddiuDump) + return false; + if (insn != 0 && insn != addiu && !IsDumpMemAluInsn(insn) + && !IsMipsStore(insn)) + return false; + if (!TryExecDumpMemAlu(regs, addiu)) + return false; + uint srcHead = 0; + if (bus != null) + TryPeekWord(bus, RomHdrSrcChain, out srcHead); + uint next = RomHdrSrcChainLw; + string how = "prologue"; + if (srcHead == 0) + { + uint luiV0 = 0x3C028034; + uint addiuA2 = 0x244629C8; + uint luiV1 = 0x3C038034; + uint addiuA1 = 0x24652B10; + uint luiS6 = 0x3C038001; + uint orA0 = 0x00002025; + uint orV0 = 0x00E01025; + uint addiuS6 = 0x2476101C; + TryPeekLeftoverWait99DumpOnly(RomHdrSrcChainLw, out luiV0); + if (luiV0 == 0) + luiV0 = 0x3C028034; + TryPeekLeftoverWait99DumpOnly(RomHdrSrcChainLw + 4, out addiuA2); + if (addiuA2 == 0) + addiuA2 = 0x244629C8; + TryPeekLeftoverWait99DumpOnly(RomHdrSrcChainLw + 8, out luiV1); + if (luiV1 == 0) + luiV1 = 0x3C038034; + TryPeekLeftoverWait99DumpOnly(0x800172C8u, out addiuA1); + if (addiuA1 == 0) + addiuA1 = 0x24652B10; + TryPeekLeftoverWait99DumpOnly(0x800172CCu, out luiS6); + if (luiS6 == 0) + luiS6 = 0x3C038001; + TryPeekLeftoverWait99DumpOnly(0x800172D0u, out orA0); + if (orA0 == 0) + orA0 = 0x00002025; + TryPeekLeftoverWait99DumpOnly(0x800172D4u, out orV0); + if (orV0 == 0) + orV0 = 0x00E01025; + TryPeekLeftoverWait99DumpOnly(0x800172DCu, out addiuS6); + if (addiuS6 == 0) + addiuS6 = 0x2476101C; + if (!IsDumpMemAluInsn(luiV0) || !IsDumpMemAluInsn(addiuA2) + || !IsDumpMemAluInsn(luiV1) || !IsDumpMemAluInsn(addiuA1) + || !IsDumpMemAluInsn(luiS6) || !IsDumpMemAluInsn(orA0) + || !IsDumpMemAluInsn(orV0) || !IsDumpMemAluInsn(addiuS6)) + return false; + if (!TryExecDumpMemAlu(regs, luiV0) + || !TryExecDumpMemAlu(regs, addiuA2) + || !TryExecDumpMemAlu(regs, luiV1) + || !TryExecDumpMemAlu(regs, addiuA1) + || !TryExecDumpMemAlu(regs, luiS6) + || !TryExecDumpMemAlu(regs, orA0)) + return false; + PokeGpr(regs, 7, 0); + if (!TryExecDumpMemAlu(regs, orV0) + || !TryExecDumpMemAlu(regs, addiuS6)) + return false; + next = RomHdrLinkJalNext; + how = "empty-chain"; + } + if (next == 0 || (next & 3) != 0 || IsDumpMemRefuseVa(next) + || IsLeftoverDestVa(next) || IsWrapDestSize(next) + || IsWrapDestFp50Va(next)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = next; + _romHdrLinkContinueLogged = true; + uint sp = PeekGpr(regs, 29); + uint ra = PeekGpr(regs, 31); + uint listHead = 0; + if (bus != null) + TryPeekWord(bus, RomHdrListPtr, out listHead); + BootLog.Write("[Hive] ROMHDR continue 0x8001728C next=0x" + + next.ToString("X") + + " *0x803429C8=0x" + srcHead.ToString("X") + + " *0x80342B10=0x" + listHead.ToString("X") + + " how=" + how + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " via=dump-mem-romhdr-link" + + " (dump addiu $sp,-248; skip unbacked prologue sw;" + + " empty *0x803429C8 honor beq 0x8001730C → 0x8001732C;" + + " no invent ROMChain / 0x803429C8 / 0x80342B10 / 0x9A / 0x9F)"); + return true; + } + + // Walk *0x803429C8. Each node+4 vs ExtraROM 0x8134DA84 + // and NK 0x802808B4 / live *0x8001101C. Peek only. + private static string FormatSrcChainWalk(System.Func read32) + { + uint src; + if (!TryRead32(read32, RomHdrSrcChain, out src)) + return "live-*(0x803429C8)-unmapped"; + uint nkWord; + bool gotNk = TryRead32(read32, NkRomHdrPtr, out nkWord); + string nkCite = " *0x8001101C=" + + (gotNk ? "0x" + nkWord.ToString("X8") : "unmapped") + + (gotNk && nkWord == NkDumpHdr + ? " dump-NK-romhdr-0x802808B4" + : gotNk && nkWord != 0 + ? " !=dump-0x802808B4" + : ""); + if (src == 0) + return "live-*(0x803429C8)=0 OEM-never-published-ExtraROM-onto-source-chain ExtraROM-hdr-unlinked" + + nkCite; + var sb = new System.Text.StringBuilder(); + sb.Append("live-*(0x803429C8)=0x").Append(src.ToString("X8")).Append(nkCite); + bool extra = false; + bool matchNkWord = false; + uint node = src; + for (int i = 0; i < 16 && node != 0; i++) + { + uint next; + uint hdr; + if (!TryRead32(read32, node, out next) || !TryRead32(read32, node + 4, out hdr)) + { + sb.Append(" [").Append(i).Append("] node=0x").Append(node.ToString("X8")) + .Append(" unmapped"); + break; + } + string vs = hdr == ExtraRomDumpHdr + ? " ExtraROM-hdr-0x8134DA84" + : hdr == NkDumpHdr + ? " NK-hdr-0x802808B4" + : " !=ExtraROM/NK"; + if (gotNk && hdr != 0 && hdr == nkWord) + { + vs += " ==*0x8001101C"; + matchNkWord = true; + } + sb.Append(" [").Append(i).Append("] node=0x").Append(node.ToString("X8")) + .Append(" node+4=0x").Append(hdr.ToString("X8")).Append(vs); + if (hdr == ExtraRomDumpHdr) + extra = true; + if (next == 0 || next == node) + break; + node = next; + } + sb.Append(extra ? " ExtraROM-on-source-chain" : " ExtraROM-not-on-source-chain"); + sb.Append(matchNkWord ? " would-0x80017308-publish" : " source-walk-miss"); + sb.Append(" (do not invent a ROMChain_t; do not host-write 0x803429C8 or 0x80342B10)"); + return sb.ToString(); + } + + // Dump-named NK copy[0] vs live *(0x80342B10) and + // source chain *(0x803429C8). List head is dst+0x22B10 + // (BSS tail past copy_len) until 0x8001728C sw. Peek + // only; do not host-write. Do not invent a ROMChain_t. + private static string FormatNkCopyVsList(System.Func read32) + { + string nkCopy = "NK-copy[0]-dump src=0x" + + NkCopy0Src.ToString("X8") + + " dst=0x" + + NkCopy0Dst.ToString("X8") + + " copy_len=0x" + + NkCopy0CopyLen.ToString("X") + + " dest_len=0x" + + NkCopy0DestLen.ToString("X") + + " list=dst+0x" + + RomHdrListBssOff.ToString("X"); + uint nkHdr; + if (!TryRead32(read32, EcecTocPtr, out nkHdr)) + { + nkCopy += " live-NK-hdr-unmapped"; + } + else if (nkHdr == 0) + { + nkCopy += " live-NK-hdr=0"; + } + else + { + uint nkEntries; + uint nkCopyOff; + bool gotEntries = TryRead32(read32, nkHdr + RomHdrCopyEntries, out nkEntries); + bool gotOff = TryRead32(read32, nkHdr + RomHdrCopyOffset, out nkCopyOff); + nkCopy += " live-NK-hdr=0x" + nkHdr.ToString("X8"); + if (gotEntries) + nkCopy += " ulCopyEntries=0x" + nkEntries.ToString("X"); + if (gotOff) + nkCopy += " ulCopyOffset=0x" + nkCopyOff.ToString("X8"); + if (gotEntries && gotOff && nkEntries != 0 && nkCopyOff != 0) + { + uint liveSrc; + uint liveDst; + uint liveCopyLen; + uint liveDestLen; + if (TryRead32(read32, nkCopyOff, out liveSrc) + && TryRead32(read32, nkCopyOff + 4, out liveDst) + && TryRead32(read32, nkCopyOff + 8, out liveCopyLen) + && TryRead32(read32, nkCopyOff + 12, out liveDestLen)) + { + nkCopy += " live-copy[0] src=0x" + + liveSrc.ToString("X8") + + " dst=0x" + + liveDst.ToString("X8") + + " copy_len=0x" + + liveCopyLen.ToString("X") + + " dest_len=0x" + + liveDestLen.ToString("X"); + } + } + } + + uint extraCopy; + string extraTable = TryRead32(read32, ExtraRomDumpHdr + RomHdrCopyEntries, out extraCopy) + ? (extraCopy == 0 + ? " ExtraROM-copy_table-empty" + : " ExtraROM-ulCopyEntries=0x" + extraCopy.ToString("X")) + : " ExtraROM-copy_table-unmapped"; + + uint[] pExt = new uint[8]; + bool pExtMapped = true; + bool pExtZeros = true; + for (int i = 0; i < 8; i++) + { + if (!TryRead32(read32, NkPExtensions + (uint)(i * 4), out pExt[i])) + { + pExtMapped = false; + break; + } + if (pExt[i] != 0) + pExtZeros = false; + } + string pExtLive; + if (!pExtMapped) + pExtLive = "pExtensions-0x80011020-dump-.text-32-zeros pExtensions-0x80011020-unmapped"; + else if (pExtZeros) + pExtLive = "pExtensions-0x80011020-dump-.text-32-zeros pExtensions-0x80011020-live-32-zeros"; + else + { + var sb = new System.Text.StringBuilder(); + sb.Append("pExtensions-0x80011020-dump-.text-32-zeros pExtensions-0x80011020-live="); + for (int i = 0; i < 8; i++) + { + if (i != 0) + sb.Append(','); + sb.Append("0x").Append(pExt[i].ToString("X8")); + } + pExtLive = sb.ToString(); + } + + uint listWord; + string list; + if (!TryRead32(read32, RomHdrListPtr, out listWord)) + { + list = "live-*(0x80342B10)-unmapped"; + } + else if (listWord == 0) + { + list = "live-*(0x80342B10)=0 empty-after-NK-copy-BSS-tail-until-0x8001728C ExtraROM-no-dump-node"; + } + else + { + uint nodeHdr; + list = "live-*(0x80342B10)=0x" + listWord.ToString("X8"); + if (TryRead32(read32, listWord + 4, out nodeHdr)) + list += " node+4=0x" + nodeHdr.ToString("X8"); + else + list += " node+4-unmapped"; + } + + return nkCopy + extraTable + " " + pExtLive + " " + FormatSrcChainWalk(read32) + " " + list; + } + + private static bool TryRead32(System.Func read32, uint va, out uint value) + { + value = 0; + if (read32 == null) + return false; + try + { + value = read32(va); + return true; + } + catch + { + return false; + } + } + + private static string FormatRomHdrListWalk(System.Func read32, uint head, uint extraHdr) + { + if (read32 == null) + return "list-walk skipped"; + if (head == 0) + return "*(0x80342B10)=0 BSS-tail-past-copy_len ExtraROM-no-dump-node; do not invent a ROMChain_t"; + var sb = new System.Text.StringBuilder(); + sb.Append("*(0x80342B10)=0x").Append(head.ToString("X8")); + bool linked = false; + uint node = head; + for (int i = 0; i < 16 && node != 0; i++) + { + uint next = 0; + uint hdr = 0; + try + { + next = read32(node); + hdr = read32(node + 4); + } + catch + { + sb.Append(" [").Append(i).Append("] node=0x").Append(node.ToString("X8")) + .Append(" unmapped"); + break; + } + sb.Append(" [").Append(i).Append("] node=0x").Append(node.ToString("X8")) + .Append(" hdr=0x").Append(hdr.ToString("X8")); + if (hdr != 0 && (hdr == extraHdr || hdr == ExtraRomDumpHdr)) + linked = true; + if (next == 0 || next == node) + break; + node = next; + } + sb.Append(linked + ? " ExtraROM-hdr-on-list" + : " ExtraROM-no-dump-node"); + sb.Append(" (do not invent a ROMChain_t)"); + return sb.ToString(); + } + + private static string NameLoadO32Path(uint dumpToc0, uint live0, bool destFilled) + { + bool has200 = ((live0 != 0 ? live0 : dumpToc0) & LoadO32VallocBit) != 0; + if (destFilled) + return "dest filled; serve dest only if firmware wrote it"; + if (!has200) + return NameBuiltInMiss(); + return "dest-word 0; serve dest only if firmware wrote it"; + } + + private static uint SlotLoadVa(ExtraRomTocMod slot) + { + if (slot != null && slot.LoadVa != 0) + return slot.LoadVa; + if (slot != null && slot.TocWords != null && slot.TocWords.Length > 7 + && slot.TocWords[7] != 0) + return slot.TocWords[7]; + return ExtractLoadVa(slot != null ? slot.Name : null); + } + + private static uint ExtractLoadVa(string name) + { + if (NamesMatchRom(name, "bcmuart.dll")) + return BcmuartLoadVa; + if (NamesMatchRom(name, "ddi_nop.dll")) + return DdiNopLoadVa; + return 0; + } + + private static string FormatLoadVaPhys(string name, uint loadVa) + { + uint va = loadVa != 0 ? loadVa : ExtractLoadVa(name); + return va == 0 ? "" : " load_va=0x" + va.ToString("X8"); + } + + private static uint PeekObj6(MipsBus bus, uint obj) + { + if (bus == null || obj == 0) + return 0; + try + { + return (uint)(bus.Read8(obj + 6) | (bus.Read8(obj + 7) << 8)); + } + catch + { + return 0; + } + } + + private static void TryLogNkRangeDecompile(MipsBus bus, uint va, string name, uint words, string why) + { + } + + private static string FormatLoadO32Fp(MipsBus bus, uint obj) + { + uint toc = PeekDestWord(bus, obj); + uint fp = toc != 0 ? PeekDestWord(bus, toc) : 0; + uint live0 = _loadE32OkLiveEntry != 0 + ? PeekDestWord(bus, _loadE32OkLiveEntry) : 0; + uint e32live0 = _loadE32OkLiveE32 != 0 + ? PeekDestWord(bus, _loadE32OkLiveE32) : 0; + uint dumpToc0 = _loadE32OkDumpToc0; + _loadE32OkFp = fp; + _loadE32OkBit200 = (fp & LoadO32VallocBit) != 0; + bool alias = toc != 0 && toc == _loadE32OkLiveE32; + string aliasName = alias + ? " fp-aliases-e32" + : " fp=LiveEntry-first-word not e32 live0"; + return " *obj=0x" + toc.ToString("X8") + + " fp=**(obj)=0x" + fp.ToString("X8") + + " LiveEntry=0x" + _loadE32OkLiveEntry.ToString("X8") + + FormatDumpLiveEntry0(dumpToc0, live0) + + " LiveE32=0x" + _loadE32OkLiveE32.ToString("X8") + + " e32-live0=0x" + e32live0.ToString("X8") + + " fp&0x200=" + (fp & LoadO32VallocBit).ToString("X") + + " fp&0x400=" + (fp & LoadO32LockBit).ToString("X") + + " e32&0x200=" + (e32live0 & LoadO32VallocBit).ToString("X") + + " e32&0x400=" + (e32live0 & LoadO32LockBit).ToString("X") + + aliasName; + } + + // destDump is o32.real (nleddrvr 0x02F81000 / mscoree + // 0x034B1000, CE slot 1). dest0 is destDump&0x01FFFFFF. + // Live bfa911a: both words 0 after MapO32. jal + // 0x800283FC a0=destDump a2=0x1000 (MEM_COMMIT). + // Current process has no reservation on that slot-1 + // VA (same last-error 14 as ddi_nop slot-1 0x03981000). + // MapO32 memcpy/decomp never run. Serve destDump only + // if firmware wrote dump-word. Do not invent dest. + private static void HiveWatch(MipsBus bus, string ev, uint v0) + { + uint destDump = _loadE32OkDest; + uint dest0 = _loadE32OkDest0; + uint wordDump = PeekDestWord(bus, destDump); + uint word0 = PeekDestWord(bus, dest0); + uint slot = destDump >> 25; + string miss = ""; + if (_loadE32OkMapValloc && _loadE32OkMapVallocV0 == 0 && wordDump == 0 && word0 == 0) + miss = " slot-" + slot + " destDump COMMIT no reserve last-error 14"; + else if (v0 == 0xE && ev != null && ev.IndexOf("wrapper", System.StringComparison.Ordinal) >= 0 + && word0 == 0) + miss = " MapO32 v0=0xE after slot-" + slot + " COMMIT no reserve; LoadO32 was 0"; + else if ((_loadE32OkMap28844 || _loadE32OkMapO32) && wordDump == 0 && word0 == 0) + miss = " destDump-word=0 dest0-word=0; slot-" + slot + " COMMIT miss"; + else if (wordDump == 0 && word0 != 0) + miss = " dest0-word set; firmware dest is dest0"; + BootLog.Write("[Hive] TOC[" + _loadE32OkIndex + "] " + _loadE32OkName + + " " + ev + + " v0=0x" + v0.ToString("X") + + " destDump=0x" + destDump.ToString("X8") + + " dump-word=0x" + wordDump.ToString("X") + + " dest0=0x" + dest0.ToString("X8") + + " dest0-word=0x" + word0.ToString("X") + + " object+6=" + _loadE32OkObj6 + + " 0x80028844=" + _loadE32OkMap28844 + + miss); + } + + private static void NoteAfterLoadE32Ok(MipsBus bus, uint[] regs, uint pc) + { + if (!_loadE32OkWatch) + return; + _loadE32OkSteps++; + bool ddiOk = NamesMatchRom(_loadE32OkName, "ddi_nop.dll") || _ddiNopFileObj != 0; + if (ddiOk && (pc == BinaryDecompressRom || (_loadE32OkSteps & 0xFFF) == 0)) + TryHuntDdiNopModuleFromRegs(bus, regs); + if (pc == LoadLibSyscallRet || _loadE32OkSteps > 200000) + { + // Live e29762a: 200k cap cleared the watch + // during CEDecompressROM, so startip saw + // obj=0. Keep ddi_nop until one startip + // attempt after the .text sig serve. + if (ddiOk && pc != LoadLibSyscallRet + && (!_ddiNopLandedBySig || !_ddiNopStartipAttempted)) + return; + if (!_loadE32OkLoadO32) + HiveWatch(bus, "LoadO32-not-entered", 0); + else if (!_loadE32OkMapInner && !_loadE32OkMap28844 && !_loadE32OkMapO32 && !_loadE32OkDecomp) + HiveWatch(bus, "LoadO32-skip-no-MapO32", 0); + PersistSkipCompare(bus); + ClearLoadE32OkWatch(); + return; + } + if (pc == LoadE32WrapFail && !_loadE32OkWrapFail) + { + _loadE32OkWrapFail = true; + _loadE32OkWrapPc = pc; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + HiveWatch(bus, "wrapper-0x8001E538", v0); + return; + } + if (pc == LoadO32Rom && !_loadE32OkLoadO32) + { + uint a0chk = regs != null && regs.Length > 4 ? regs[4] : 0; + if (_loadE32OkObj != 0 && a0chk != 0 && a0chk != _loadE32OkObj) + return; + _loadE32OkLoadO32 = true; + uint a0 = a0chk; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint a2 = regs != null && regs.Length > 6 ? regs[6] : 0; + uint a3 = regs != null && regs.Length > 7 ? regs[7] : 0; + uint type = 0; + try + { + if (bus != null && a0 != 0) + type = bus.Read8(a0 + 4); + } + catch + { + } + uint obj = a0 != 0 ? a0 : _loadE32OkObj; + _loadE32OkObj6 = PeekObj6(bus, obj); + HiveWatch(bus, "LoadO32", 0); + return; + } + if (pc == LoadO32PredFail && !_loadE32OkPredFail) + { + _loadE32OkPredFail = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + HiveWatch(bus, "LoadO32-pred-fail", v0); + return; + } + if (pc == LoadO32SkipValloc && _loadE32OkLoadO32 && !_loadE32OkSkip200) + { + _loadE32OkSkip200 = true; + MarkBuiltInSkip(); + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + uint sp20 = PeekSpWord(bus, regs, 0x20); + if (!_skipDisasmLogged) + { + _skipDisasmLogged = true; + TryLogNkRangeDecompile(bus, LoadO32SkipValloc, "LoadO32-skip 0x80016830", 8, + "dump nk.exe: lw v0,0x20(sp); beqz 0x80016848; not MapO32; dest out only if thunk filled 0x20(sp); observe only; do not set 0x200"); + } + HiveWatch(bus, "LoadO32-skip200", 0); + return; + } + if (pc == LoadO32OkRet && _loadE32OkLoadO32 && !_loadE32OkLoadO32Ret) + { + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint word0 = PeekDestWord(bus, _loadE32OkDest0); + _loadE32OkDestAfter = word0; + HiveWatch(bus, "LoadO32-ok", v0); + } + if (regs != null && _loadE32OkPredRa != 0 && pc == _loadE32OkPredRa) + { + _loadE32OkPredV0 = regs.Length > 2 ? regs[2] : 0; + _loadE32OkPredRa = 0; + HiveWatch(bus, "LoadO32-pred", _loadE32OkPredV0); + return; + } + if (regs != null && _loadE32OkVallocRa != 0 && pc == _loadE32OkVallocRa) + { + _loadE32OkVallocV0 = regs.Length > 2 ? regs[2] : 0; + _loadE32OkVallocRa = 0; + HiveWatch(bus, "LoadO32-thunk", _loadE32OkVallocV0); + return; + } + if (pc == LoadO32RomRet && _loadE32OkLoadO32 && !_loadE32OkLoadO32Ret) + { + _loadE32OkLoadO32Ret = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint word0 = PeekDestWord(bus, _loadE32OkDest0); + uint live0 = _loadE32OkLiveEntry != 0 + ? PeekDestWord(bus, _loadE32OkLiveEntry) : _loadE32OkFp; + string destWhy = word0 != 0 + ? NameLoadO32Path(_loadE32OkDumpToc0, live0, true) + : (_loadE32OkValloc + ? "dest word 0 after kmode thunk 0x8003E660 v0=0x" + _loadE32OkVallocV0.ToString("X8") + : NameLoadO32Path(_loadE32OkDumpToc0, live0, false)); + HiveWatch(bus, "LoadO32-ret", v0); + return; + } + if (pc == LoadO32WrapAfter && _loadE32OkLoadO32 && !_loadE32OkWrapAfter) + { + _loadE32OkWrapAfter = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint word0 = PeekDestWord(bus, _loadE32OkDest0); + if (_loadE32OkDestAfter == 0) + _loadE32OkDestAfter = word0; + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + _loadE32OkS5 = PeekS5(regs); + _loadE32OkSp24 = PeekSpWord(bus, regs, 0x24); + if (!_wrapAfterDisasmLogged) + { + _wrapAfterDisasmLogged = true; + TryLogNkRangeDecompile(bus, LoadO32WrapAfter, "LoadO32-wrap-after 0x8001E428", 16, + "dump nk.exe: andi v0,s5,2 beqz 0x8001E45c; bit2 jal 0x800283fc $ra=0x8001E44c then sw v0,80(fp) CopyO32 0x8001E6E0; o32walk 0x8001AF20 is bit2-clear; observe only; do not jal; do not invent dest; do not invent 0x2000"); + } + HiveWatch(bus, "wrap-after", v0); + return; + } + if (pc == LoadO32WrapValloc && _loadE32OkLoadO32 && !_loadE32OkWrapValloc) + { + uint ra = PeekGpr(regs, 31); + if (ra != LoadO32WrapVallocRa) + return; + _loadE32OkWrapValloc = true; + _loadE32OkS5 = PeekS5(regs); + _loadE32OkSp24 = PeekSpWord(bus, regs, 0x24); + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a2 = regs != null && regs.Length > 6 ? regs[6] : 0; + HiveWatch(bus, "wrap-valloc", 0); + return; + } + if (pc == LoadO32WrapS5Hi && _loadE32OkLoadO32 && !_loadE32OkS5Hi) + { + _loadE32OkS5Hi = true; + _loadE32OkS5 = PeekS5(regs); + _loadE32OkSp24 = PeekSpWord(bus, regs, 0x24); + HiveWatch(bus, "wrap-s5", 0); + return; + } + if (pc == LoadO32WrapO32Walk && _loadE32OkLoadO32 && !_loadE32OkO32Walk) + { + _loadE32OkO32Walk = true; + _loadE32OkS5 = PeekS5(regs); + _loadE32OkSp24 = PeekSpWord(bus, regs, 0x24); + HiveWatch(bus, "wrap-o32walk", 0); + return; + } + if (pc == LoadO32WrapFlagsChk && _loadE32OkLoadO32 && !_loadE32OkFlagsChk) + { + _loadE32OkFlagsChk = true; + _loadE32OkS5 = PeekS5(regs); + _loadE32OkSp24 = PeekSpWord(bus, regs, 0x24); + HiveWatch(bus, "wrap-flags", 0); + return; + } + if (pc == LoadO32WrapC1 && _loadE32OkLoadO32 && !_loadE32OkC1) + { + _loadE32OkC1 = true; + _loadE32OkS5 = PeekS5(regs); + _loadE32OkSp24 = PeekSpWord(bus, regs, 0x24); + HiveWatch(bus, "wrap-C1", 0); + return; + } + if ((pc == CopyO32Rom || pc == LoadO32WrapCopy) + && !_loadE32OkCopyO32 && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkCopyO32 = true; + HiveWatch(bus, pc == LoadO32WrapCopy + ? "wrap-copy 0x8001E6E0" : "CopyO32", 0); + return; + } + if (pc == MapO32Rom && _loadE32OkLoadO32 && !_loadE32OkMapO32 + && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkMapO32 = true; + MarkFwMapO32(); + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + HiveWatch(bus, "MapO32-0x8001AC30", 0); + return; + } + if (pc == MapO32InnerJal && _loadE32OkLoadO32 && !_loadE32OkMapInner + && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkMapInner = true; + MarkFwMapO32(); + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + HiveWatch(bus, "MapO32-inner", 0); + return; + } + if (pc == MapO32Decompress && _loadE32OkLoadO32 && !_loadE32OkMap28844 + && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkMap28844 = true; + MarkFwMapO32(); + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + HiveWatch(bus, "0x80028844", 0); + return; + } + if (_loadE32OkMapO32 && !_loadE32OkMapValloc + && (pc == MapO32VallocJal + || (pc == LoadO32WrapValloc + && regs != null && regs.Length > 4 + && (regs[4] == _loadE32OkDest || regs[4] == _loadE32OkDest0)))) + { + _loadE32OkMapValloc = true; + _loadE32OkMapVallocA0 = regs != null && regs.Length > 4 ? regs[4] : 0; + _loadE32OkMapVallocA2 = regs != null && regs.Length > 6 ? regs[6] : 0; + _loadE32OkMapVallocA3 = regs != null && regs.Length > 7 ? regs[7] : 0; + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + uint a0log = _loadE32OkMapVallocA0; + if ((a0log & 0xF0000000u) == 0x60000000u && _loadE32OkDest != 0) + a0log = _loadE32OkDest; + HiveWatch(bus, "0x800283FC a0=0x" + a0log.ToString("X8") + + ((_loadE32OkMapVallocA0 & 0xF0000000u) == 0x60000000u + ? " (flags; destDump)" : "") + + " a2=0x" + _loadE32OkMapVallocA2.ToString("X") + + " a3=0x" + _loadE32OkMapVallocA3.ToString("X"), 0); + return; + } + if (pc == MapO32VallocRet && _loadE32OkMapValloc && _loadE32OkMapVallocV0 == 0xFFFFFFFFu) + { + _loadE32OkMapVallocV0 = regs != null && regs.Length > 2 ? regs[2] : 0; + _loadE32OkObj6 = PeekObj6(bus, _loadE32OkObj); + HiveWatch(bus, "0x8001AE08", _loadE32OkMapVallocV0); + return; + } + if (pc == BindImpHdr && _loadE32OkLoadO32 && !_loadE32OkBindImp + && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkBindImp = true; + uint word0 = PeekDestWord(bus, _loadE32OkDest0); + HiveWatch(bus, "BindImp", 0); + return; + } + if (pc == CallDllStartip && _loadE32OkLoadO32 && !_loadE32OkCallDll + && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkCallDll = true; + uint word0 = PeekDestWord(bus, _loadE32OkDest0); + HiveWatch(bus, "CallDLL", 0); + return; + } + if (pc == BinaryDecompressRom && _loadE32OkLoadO32 && !_loadE32OkDecomp + && WatchMatchesExtraRom(bus, regs, pc)) + { + _loadE32OkDecomp = true; + MarkFwMapO32(); + HiveWatch(bus, "CEDecompressROM", 0); + if (NamesMatchRom(_loadE32OkName, "ddi_nop.dll") || _ddiNopFileObj != 0) + TryHuntDdiNopModuleFromRegs(bus, regs); + return; + } + if (bus == null || regs == null) + return; + uint instr = 0; + try + { + instr = bus.Read32(pc); + } + catch + { + return; + } + uint op = instr >> 26; + if (_loadE32OkLoadO32 && !_loadE32OkBit200Seen && op == 0xC + && (instr & 0xFFFF) == LoadO32VallocBit) + { + _loadE32OkBit200Seen = true; + uint rs = (instr >> 21) & 31; + uint lhs = regs.Length > (int)rs ? regs[(int)rs] : 0; + _loadE32OkFp = lhs; + _loadE32OkBit200 = (lhs & LoadO32VallocBit) != 0; + HiveWatch(bus, _loadE32OkBit200 ? "andi-0x200-taken" : "andi-0x200-skip", 0); + } + uint target = 0; + if (op == 3) + target = (pc & 0xF0000000u) | ((instr & 0x3FFFFFFu) << 2); + if (target == LoadO32Pred && !_loadE32OkPred) + { + _loadE32OkPred = true; + _loadE32OkPredRa = pc + 8; + uint a0 = regs.Length > 4 ? regs[4] : 0; + HiveWatch(bus, "jal-pred", 0); + } + if (target == LoadO32VallocOpen && _loadE32OkLoadO32 && !_loadE32OkValloc) + { + _loadE32OkValloc = true; + _loadE32OkVallocRa = pc + 8; + uint a0 = regs.Length > 4 ? regs[4] : 0; + HiveWatch(bus, "thunk-enter", 0); + } + } + + // Same 0x8004DBF8 path gwes uses for ddi_nop after + // LoadE32=0. Dump o32 dest/vsize/psize/dataptr only. + // Do not invent e32 bytes. ddi_nop/mscoree/ole32 keep + // their existing VALLOC+VirtualCopy redirect. + // CreateFileFail a0/a1/a2/a3 are not CEDecompressROM + // (src,cb,dest,vsize). Booted 2c926c7: a0=0x86F46220 + // (heap object) a1=1 a2=0 a3=0xFFFFFFFE. Leave + // firmware registers. Type-7 attach still CreateFileOk. + // BuiltIn LoadDriver uses OpenFile/VALLOC/CopyO32 like + // ddi_nop. Do not jal 0x8004DBF8 from this PC. + public static bool TryStartExtraRomTocDecompress(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (regs == null || regs.Length <= 7) + return false; + ExtraRomTocMod slot = null; + try + { + uint obj = regs.Length > 30 ? regs[30] : 0; + if (obj != 0 && bus != null && bus.Read8(obj + 4) == TocAttachType) + slot = FindCachedTocByEntry(bus.Read32(obj)); + } + catch + { + } + if (slot == null && !string.IsNullOrEmpty(_pendingLoadE32Name)) + slot = FindCachedExtraRomToc(_pendingLoadE32Name); + if (slot == null || string.IsNullOrEmpty(slot.Name) || slot.Index < 0) + return false; + if (NamesMatchRom(slot.Name, "ddi_nop.dll") || IsMscoreeDll(slot.Name) + || IsOle32Dll(slot.Name)) + return false; + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " CreateFileFail v0= dest-word= dest0=0 object+6=0 0x80028844=False"); + return false; + } + + // Firmware sh s5,6(fp) at 0x8001D4F0 only when + // CreateFileMapping 0x8003DA64 returns 0. BuiltIn + // LoadLibrary never takes that jal. Do not host-write + // object+6 to match LoadDriver. Observe only. + public static void TryPrepareExtraRomBuiltInLikeDdiNop(MipsBus bus, uint obj) + { + if (bus == null || obj == 0) + return; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return; + ExtraRomTocMod slot = FindCachedTocByEntry(bus.Read32(obj)); + // NK attach names hit CreateFileFail type-7 with + // no ExtraROM o32. destDump=0 dataptr=0 is not + // ExtraROM TOC[-1]. Do not log those as o32. + if (slot == null || string.IsNullOrEmpty(slot.Name) || slot.Index < 0) + return; + uint obj6 = (uint)(bus.Read8(obj + 6) | (bus.Read8(obj + 7) << 8)); + uint dest = slot != null ? slot.Dest : 0; + uint slot0 = dest & SlotMask; + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " CreateFileFail v0= dest-word=0 destDump=0x" + dest.ToString("X8") + + " dest0=0x" + slot0.ToString("X8") + + " object+6=" + obj6 + + " 0x80028844=False"); + } + catch + { + } + } + + private static bool IsFirmwareDecompressDest(uint dest, uint real) + { + if (dest == 0) + return false; + if (dest >= ExtraRomTocDestHost && dest < ExtraRomTocDestHostLim) + return false; + if (dest >= ExtraRomTocSrc && dest < ExtraRomTocSrcLim) + return false; + if (real != 0 && (dest == real || dest == (real & SlotMask))) + return true; + if (dest >= 0x01400000u && dest < 0x02000000u) + return true; + return false; + } + + // Dump o32 dataptr bytes stay at dump dataptr VA. Backing + // is ExtraRomTocSrc pool. a0 stays dump dataptr. + private static bool HostSrcExtraRomToc(MipsBus bus, ExtraRomTocMod slot, + uint dataptr, uint psize) + { + if (bus == null || dataptr == 0 || psize == 0) + return false; + uint pages = (psize + 0x1FFFu) & ~0xFFFu; + if (_tocSrcPool + pages > ExtraRomTocSrcLim) + return false; + uint kseg = _tocSrcPool; + try + { + uint[] blob = slot.Data != null && slot.Data.Length > 0 ? slot.Data[0] : null; + uint n = (psize + 3) / 4; + for (uint w = 0; w < n; w++) + { + uint word = blob != null && w < blob.Length ? blob[w] : 0; + bus.Write32(kseg + w * 4, word); + } + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC[" + slot.Index + "] " + + slot.Name + " src-host fail " + ex.Message + + " (do not invent 0x81360000)"); + return false; + } + if (_tocSrcPtr == null) + { + _tocSrcPtr = new uint[32]; + _tocSrcLen = new uint[32]; + _tocSrcKseg = new uint[32]; + } + if (_tocSrcN >= _tocSrcPtr.Length) + return false; + _tocSrcPtr[_tocSrcN] = dataptr; + _tocSrcLen[_tocSrcN] = psize; + _tocSrcKseg[_tocSrcN] = kseg; + _tocSrcN++; + _tocSrcPool += pages; + return true; + } + + // Map firmware dest (o32.real 0x02F21000 / VALLOC) onto + // ExtraRomTocDestHost backing. a2 stays firmware dest. + private static bool HostMapFirmwareTocDest(MipsBus bus, ExtraRomTocMod slot, + uint fwDest, uint vsize) + { + if (bus == null || fwDest == 0 || vsize == 0) + return false; + uint slot0 = fwDest & SlotMask; + uint pages = (vsize + 0x1FFFu) & ~0xFFFu; + if (_tocDestHostPool + pages > ExtraRomTocDestHostLim) + return false; + uint kseg = _tocDestHostPool; + try + { + for (uint i = 0; i < pages; i += 4) + bus.Write32(kseg + i, 0); + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC dest-host fail " + + slot.Name + " " + ex.Message + + " (do not invent 0x81360000)"); + return false; + } + if (_tocDestSlot0 == null) + { + _tocDestSlot0 = new uint[32]; + _tocDestDump = new uint[32]; + _tocDestVsize = new uint[32]; + _tocDestKseg = new uint[32]; + _tocDestReady = new bool[32]; + } + if (_tocDestN >= _tocDestSlot0.Length) + return false; + _tocDestSlot0[_tocDestN] = slot0; + _tocDestDump[_tocDestN] = slot.Dest != 0 ? slot.Dest : fwDest; + _tocDestVsize[_tocDestN] = pages; + _tocDestKseg[_tocDestN] = kseg; + _tocDestReady[_tocDestN] = true; + _tocDestN++; + _tocDestHostPool += pages; + return true; + } + + public static uint MapExtraRomE32HostVa(uint va) + { + if (va >= ExtraRomE32Host && va < ExtraRomE32HostLim) + return va; + return va; + } + + public static uint MapExtraRomTocSrcVa(uint va) + { + for (int i = 0; i < _tocSrcN; i++) + { + uint ptr = _tocSrcPtr[i]; + uint len = _tocSrcLen[i]; + uint kseg = _tocSrcKseg[i]; + if (ptr == 0 || len == 0 || kseg == 0) + continue; + if (va >= ptr && va < ptr + len) + return kseg + (va - ptr); + uint slot0 = ptr & SlotMask; + uint off = va & SlotMask; + if ((va >> 25) == (ptr >> 25) + && off >= slot0 && off < slot0 + len) + return kseg + (off - slot0); + } + return va; + } + + public static uint MapExtraRomTocDestVa(uint va) + { + for (int i = 0; i < _tocDestN; i++) + { + uint slot0 = _tocDestSlot0[i]; + uint dump = _tocDestDump[i]; + uint vsize = _tocDestVsize[i]; + uint kseg = _tocDestKseg[i]; + if (kseg == 0 || vsize == 0) + continue; + if (va >= kseg && va < kseg + vsize) + return va; + if (_tocDestReady == null || !_tocDestReady[i]) + continue; + uint off = va & SlotMask; + uint base0 = slot0 & SlotMask; + if (slot0 != 0 && off >= base0 && off < base0 + vsize) + return kseg + (off - base0); + if (dump != 0) + { + uint dumpOff = dump & SlotMask; + if ((va & ~SlotMask) == (dump & ~SlotMask) + && off >= dumpOff && off < dumpOff + vsize) + return kseg + (off - dumpOff); + } + } + return va; + } + + private static void MarkExtraRomTocDecompressed(uint dest) + { + if (_tocDecompSlot != null + && (_tocDecompSlot.DecompDest == dest || dest == 0)) + _tocDecompSlot.Decompressed = true; + if (_romTocMods != null && dest != 0) + { + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod s = _romTocMods[i]; + if (s != null && s.DecompDest != 0 && s.DecompDest == dest) + s.Decompressed = true; + } + } + if (_tocDestReady == null || dest == 0) + return; + for (int i = 0; i < _tocDestN; i++) + { + if (_tocDestKseg[i] == dest) + _tocDestReady[i] = true; + } + } + + private static string FileBaseName(string path) + { + if (string.IsNullOrEmpty(path)) + return path; + int slash = path.LastIndexOf('\\'); + if (slash < 0) + slash = path.LastIndexOf('/'); + return slash >= 0 ? path.Substring(slash + 1) : path; + } + + private static uint PeekDestWord(MipsBus bus, uint va) + { + if (bus == null || va == 0) + return 0; + // Live 822671a: do not rewrite dest0 useg to pfn6 + // before comparing dest6/dest10/dest0/destDump. + try + { + return bus.Read32(va); + } + catch + { + return 0; + } + } + + // Dump wrapper dest-out is a byte at fp+0xCE + // (unaligned). dest-word=2 is that sb, not dest. + private static uint PeekDestByte(MipsBus bus, uint va) + { + if (bus == null || va == 0) + return 0; + try + { + return bus.Read8(va); + } + catch + { + return 0; + } + } + + // dest0 useg / destDump peek must not go through + // MapFirmwareSlotVa pfn6 remap (that hid dest0-useg). + private static uint PeekDestWordRaw(MipsBus bus, uint va, out bool threw) + { + threw = false; + if (bus == null || va == 0) + return 0; + _ddiNopDestPeekRaw = true; + try + { + return bus.Read32(va); + } + catch + { + threw = true; + return 0; + } + finally + { + _ddiNopDestPeekRaw = false; + } + } + + // Live ccb9552: VALLOC vbase 0x01980000, CEDecompressROM + // dest 0x01981000 (o32 rva 0x1000). MZ is at vbase, not + // the section first word. dest6 0x86F1C000 took 1038 + // stores; pfn6-word at section base stayed 0. + private const uint DdiNopVbasePage = 0x01980000u; + private const uint DdiNopDest0Page = 0x01981000u; + private const uint DdiNopDestDumpPage = 0x03981000u; + private const uint DdiNopDestKseg0Page = 0x81981000u; + private const uint DdiNopDest6Live = 0x86F1C000u; + private const uint DdiNopDest10Live = 0x806F1000u; + // ExtraROM extract ddi_nop.dll .text RVA 0x2000 + // (file ptr 0x1200). Live 021a2eb dest+0x1000 + // 0x86F1D000 word. TOC cache is compressed o32, + // not PE bytes. Do not invent this word. + private const uint DdiNopTextSigRva2000 = 0x8C481B78u; + private const uint DdiNopTextVsize = 0x1743Au; + // ExtraROM extract ddi_nop.dll AddressOfEntryPoint. + // Prefer slot e32[1] (e32_entryrva). Do not invent e32. + private const uint DdiNopEntryRvaExtract = 0x18014u; + // Extract IAT FirstThunk / .data VA. VALLOC IAT is + // vbase+this. Do not invent dest10. + private const uint DdiNopIatRva = 0x19000u; + // Live 68b9567: data-TLBL 0x0199B050 after coredll- + // page. o32[.data] dest 0x01999000 + vsz covers + // past the IAT page. dest0 walk stopped at + // 0x019B0000. Demand-map remaining VALLOC .data + // via firmware PTE. Do not invent dest. + private const uint DdiNopVallocLo = 0x01980000u; + private const uint DdiNopVallocHi = 0x019B0000u; + private const int DdiNopDataPageCap = 32; + + private static void ResetDdiNopDecompStores() + { + _ddiNopDecompWatch = false; + _ddiNopWatchDest6 = DdiNopDest6Live; + _ddiNopWatchDest10 = DdiNopDest10Live; + _ddiNopWatchVbase6 = 0; + _ddiNopStoreN0 = 0; + _ddiNopStoreN6 = 0; + _ddiNopStoreNV6 = 0; + _ddiNopStoreN10 = 0; + _ddiNopStoreND = 0; + _ddiNopStoreNK = 0; + _ddiNopStoreFirstVa = 0; + _ddiNopStoreFirstVal = 0; + _ddiNopStoreLastVa = 0; + _ddiNopStoreLastVal = 0; + _ddiNopStoreThrew0 = false; + _ddiNopStoreThrew6 = false; + _ddiNopStoreThrewV = false; + _ddiNopStoreThrew10 = false; + _ddiNopStoreThrewD = false; + _ddiNopStoreThrewK = false; + } + + // Live l2 only. Do not invent dest6 / dest10 / l2. + private static bool WalkDdiNopPteDests(MipsBus bus, uint va, + out uint l2, out uint dest6, out uint dest10) + { + l2 = 0; + dest6 = 0; + dest10 = 0; + if (bus == null || va == 0) + return false; + uint sec = PeekSection(bus, 0); + if (sec == 0 || sec == 1) + return false; + uint l1Ptr = sec + (((va >> 16) & 0x1FFu) * 4); + uint l1; + if (!TryPeekWord(bus, l1Ptr, out l1) || l1 == 0 || l1 == 1) + return false; + uint l2Ptr = l1 + ((((va >> 12) & 0xFu) + 3) * 4); + if (!TryPeekWord(bus, l2Ptr, out l2) || l2 == 0 || (l2 & 2) == 0) + return false; + dest6 = 0x80000000u | ((((l2 >> 6) << 12) & 0x1FFFFFFFu)); + dest6 |= va & 0xFFFu; + dest10 = 0x80000000u | ((((l2 >> 10) << 12) & 0x1FFFFFFFu)); + dest10 |= va & 0xFFFu; + return dest6 != 0 || dest10 != 0; + } + + private static void WalkDdiNopWatchDests(MipsBus bus) + { + _ddiNopWatchDest6 = DdiNopDest6Live; + _ddiNopWatchDest10 = DdiNopDest10Live; + _ddiNopWatchVbase6 = 0; + if (bus == null) + return; + uint dest6; + uint dest10; + uint v6; + uint unused; + if (WalkDdiNopPteDests(bus, DdiNopDest0Page, out unused, out dest6, out dest10)) + { + if (dest6 != 0) + _ddiNopWatchDest6 = dest6; + if (dest10 != 0) + _ddiNopWatchDest10 = dest10; + } + if (WalkDdiNopPteDests(bus, DdiNopVbasePage, out unused, out v6, out dest10) + && v6 != 0) + _ddiNopWatchVbase6 = v6; + } + + private static void BeginDdiNopDecompStoreWatch(MipsBus bus) + { + ResetDdiNopDecompStores(); + WalkDdiNopWatchDests(bus); + _ddiNopDecompWatch = true; + } + + private static int DdiNopDecompStoreSlot(uint mappedVa) + { + uint page = mappedVa & ~0xFFFu; + if (page == DdiNopDest0Page) + return 0; + if (page == (_ddiNopWatchDest6 & ~0xFFFu)) + return 1; + if (_ddiNopWatchVbase6 != 0 + && page == (_ddiNopWatchVbase6 & ~0xFFFu)) + return 5; + if (page == (_ddiNopWatchDest10 & ~0xFFFu)) + return 2; + if (page == DdiNopDestDumpPage) + return 3; + if (page == DdiNopDestKseg0Page) + return 4; + return -1; + } + + // Count after Map* so dest0 remapped to dest6 counts + // as dest6. Do not invent dest. + public static bool TryNoteDdiNopDecompStore(uint mappedVa, uint value) + { + if (!_ddiNopDecompWatch) + return false; + int slot = DdiNopDecompStoreSlot(mappedVa); + if (slot < 0) + return false; + if (slot == 0) + _ddiNopStoreN0++; + else if (slot == 1) + _ddiNopStoreN6++; + else if (slot == 5) + _ddiNopStoreNV6++; + else if (slot == 2) + _ddiNopStoreN10++; + else if (slot == 3) + _ddiNopStoreND++; + else + _ddiNopStoreNK++; + if (_ddiNopStoreFirstVa == 0) + { + _ddiNopStoreFirstVa = mappedVa; + _ddiNopStoreFirstVal = value; + } + _ddiNopStoreLastVa = mappedVa; + _ddiNopStoreLastVal = value; + return true; + } + + public static void TryNoteDdiNopDecompStoreThrow(uint mappedVa) + { + if (!_ddiNopDecompWatch) + return; + int slot = DdiNopDecompStoreSlot(mappedVa); + if (slot == 0) + _ddiNopStoreThrew0 = true; + else if (slot == 1) + _ddiNopStoreThrew6 = true; + else if (slot == 5) + _ddiNopStoreThrewV = true; + else if (slot == 2) + _ddiNopStoreThrew10 = true; + else if (slot == 3) + _ddiNopStoreThrewD = true; + else if (slot == 4) + _ddiNopStoreThrewK = true; + } + + private static void LogDdiNopDecompStores() + { + BootLog.Write("[Hive] ExtraROM ddi_nop dest stores dest0=" + + _ddiNopStoreN0 + + " dest6=" + _ddiNopStoreN6 + + " vbase6=" + _ddiNopStoreNV6 + + " dest10=" + _ddiNopStoreN10 + + " dump=" + _ddiNopStoreND + + " kseg0=" + _ddiNopStoreNK + + " first=0x" + _ddiNopStoreFirstVa.ToString("X8") + + ":0x" + _ddiNopStoreFirstVal.ToString("X8") + + " last=0x" + _ddiNopStoreLastVa.ToString("X8") + + ":0x" + _ddiNopStoreLastVal.ToString("X8") + + " threw=" + (_ddiNopStoreThrew6 ? "6" : "") + + (_ddiNopStoreThrewV ? "V" : "") + + (_ddiNopStoreThrew10 ? "A" : "") + + (_ddiNopStoreThrew0 ? "0" : "") + + (_ddiNopStoreThrewD ? "D" : "") + + (_ddiNopStoreThrewK ? "K" : "")); + } + + // Live ccb9552 dest10 pfn10-word 0x806F0000 is a + // kseg0 page pointer, not MZ. Serve only MZ at vbase. + private static bool IsMzWord(uint word) + { + return (word & 0xFFFFu) == 0x5A4D; + } + + // TOC[33] ExtraROM extract ddi_nop.dll .text RVA 0x2000. + // Cached o32 Data[] is compressed; not PE bytes. + private static uint DdiNopTextSigExpected() + { + uint[] blob = null; + if (_ddiNopData != null && _ddiNopData.Length > 0) + blob = _ddiNopData[0]; + if (blob == null) + { + ExtraRomTocMod slot = FindCachedExtraRomToc("ddi_nop.dll"); + if (slot != null && slot.Data != null && slot.Data.Length > 0) + blob = slot.Data[0]; + } + // File ptr 0x1200 / 4 = word 0x480. Only if + // cached blob is an expanded PE (MZ). + if (blob != null && blob.Length > 0x480 + && (blob[0] & 0xFFFFu) == 0x5A4D) + return blob[0x480]; + return DdiNopTextSigRva2000; + } + + private static bool DdiNopDestStoresAllowServe() + { + return _ddiNopStoreN0 != 0 + || _ddiNopStoreN6 != 0 + || _ddiNopStoreNV6 != 0; + } + + // Live ccb9552: section dest6 0x86F1C000 took 1038 + // stores; pfn6-word at 0x86F1C000 stayed 0. MZ for a + // CE TOC module is at VALLOC vbase 0x01980000 + // (dest - 0x1000), not the o32 section page. + private static void TryMeasureDdiNopDestAfterDecomp(MipsBus bus, uint hdr, uint expanded) + { + if (_ddiNopDestPteMeasured || bus == null) + return; + _ddiNopDestPteMeasured = true; + uint vbase = DdiNopVbasePage; + uint dest0 = DdiNopDest0Page; + uint vl2 = 0; + uint sl2 = 0; + uint vbase6 = 0; + uint vbase10 = 0; + uint dest6 = 0; + uint dest10 = 0; + WalkDdiNopPteDests(bus, vbase, out vl2, out vbase6, out vbase10); + WalkDdiNopPteDests(bus, dest0, out sl2, out dest6, out dest10); + bool tv6 = false; + bool tv10 = false; + bool ts6 = false; + bool ts10 = false; + uint vw6 = vbase6 != 0 ? PeekDestWordRaw(bus, vbase6, out tv6) : 0; + uint vw10 = vbase10 != 0 ? PeekDestWordRaw(bus, vbase10, out tv10) : 0; + uint dw6 = dest6 != 0 ? PeekDestWordRaw(bus, dest6, out ts6) : 0; + uint dw10 = dest10 != 0 ? PeekDestWordRaw(bus, dest10, out ts10) : 0; + bool tsig = false; + uint sig = 0; + if (dest6 != 0) + sig = PeekDestWordRaw(bus, dest6 + 0x1000u, out tsig); + bool tv0 = false; + uint vw0 = PeekDestWordRaw(bus, vbase, out tv0); + BootLog.Write("[Hive] ExtraROM ddi_nop dest vbase PTE vbase6=0x" + + vbase6.ToString("X8") + + " vw6=0x" + vw6.ToString("X8") + + " vw10=0x" + vw10.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " dw6=0x" + dw6.ToString("X8") + + " sig=0x" + sig.ToString("X8") + + " dw10=0x" + dw10.ToString("X8") + + " threw=" + (tv6 ? "V" : "") + (ts6 ? "6" : "") + + (tv10 ? "A" : "") + (ts10 ? "S" : "") + + (tsig ? "G" : "") + (tv0 ? "0" : "")); + uint span = expanded != 0 && expanded != 0xFFFFFFFFu + ? expanded : _ddiNopDecompVsize; + uint end = vbase + 0x1000u + span; + if (end <= vbase) + end = vbase + 0x1000u; + uint last = (end - 1u) & ~0xFFFu; + uint mzVa = 0; + uint mz6 = 0; + uint mzW = 0; + uint nzVa = 0; + uint nz6 = 0; + uint nzW = 0; + int n = 0; + for (uint va = vbase; va <= last && n < 32; va += 0x1000u, n++) + { + uint l2; + uint page6; + uint page10; + if (!WalkDdiNopPteDests(bus, va, out l2, out page6, out page10) + || page6 == 0) + continue; + bool threw; + uint w = PeekDestWordRaw(bus, page6, out threw); + if (threw || w == 0) + continue; + if (nzVa == 0) + { + nzVa = va; + nz6 = page6; + nzW = w; + } + if (mzVa == 0 && IsMzWord(w)) + { + mzVa = va; + mz6 = page6; + mzW = w; + } + } + BootLog.Write("[Hive] ExtraROM ddi_nop dest MZ page mz=0x" + + mzVa.ToString("X8") + "->0x" + mz6.ToString("X8") + + " w=0x" + mzW.ToString("X8") + + " nz=0x" + nzVa.ToString("X8") + "->0x" + nz6.ToString("X8") + + " w=0x" + nzW.ToString("X8")); + _ddiNopLandedDest = 0; + _ddiNopLandedWord = 0; + _ddiNopLandedBySig = false; + // Live 021a2eb: dest-word 0 at dest6 is honest + // (.text starts 0). dest+0x1000 word 0x8C481B78 + // matches extract .text RVA 0x2000. dest10 + // 0x806F0000 is not MZ. Do not invent dest. + if (!DdiNopDestStoresAllowServe()) + return; + uint expect = DdiNopTextSigExpected(); + bool sizeOk = expanded != 0 && expanded != 0xFFFFFFFFu + && (expanded == _ddiNopDecompVsize || expanded == DdiNopTextVsize); + if (sizeOk && dest6 != 0 && !tsig && sig == expect + && (dest6 & ~0xFFFu) != DdiNopDest10Live) + { + _ddiNopLandedDest = dest6; + _ddiNopLandedWord = sig; + _ddiNopLandedBySig = true; + return; + } + if (vbase6 != 0 && IsMzWord(vw6)) + { + _ddiNopLandedDest = vbase6; + _ddiNopLandedWord = vw6; + } + else if (IsMzWord(vw0)) + { + _ddiNopLandedDest = vbase; + _ddiNopLandedWord = vw0; + } + } + + // Live 37c4995: sig matched but LoadLibrary v0!=0 + // (firmware already MapO32'd; BindImp COREDLL). Serve + // dest6 here, not on a LoadLibrary miss that will not + // come. Do not serve dest10. + private static void TryServeDdiNopAtDecompRet(MipsBus bus, uint[] regs) + { + if (!_ddiNopLandedBySig || _ddiNopLandedDest == 0) + return; + if ((_ddiNopLandedDest & ~0xFFFu) == DdiNopDest10Live) + return; + ExtraRomTocMod slot = FindCachedExtraRomToc("ddi_nop.dll"); + if (slot == null) + return; + uint dest6 = _ddiNopLandedDest; + uint vbase = DdiNopVbasePage; + slot.DecompDest = dest6; + slot.Vbase = vbase; + slot.Decompressed = true; + MarkExtraRomTocDecompressed(dest6); + TrySetDdiNopRamStartip(bus, 0, regs); + BootLog.Write("[Hive] TOC[" + slot.Index + "] ddi_nop.dll serve dest6=0x" + + dest6.ToString("X8") + + " sig=0x" + _ddiNopLandedWord.ToString("X8") + + " vbase=0x" + vbase.ToString("X8") + + " (CEDecompressROM .text sig; not LoadLibrary miss)"); + BootLog.Rom("ok", "ExtraROM", "TOC", slot.Index, slot.Name, 7, + dest6, _ddiNopLandedWord, vbase, + "CEDecompressROM .text sig; serve dest6"); + } + + private static uint DdiNopEntryRvaFromSlot(ExtraRomTocMod slot) + { + if (slot != null && slot.E32Words != null + && slot.E32Words.Length > 1 && slot.E32Words[1] != 0) + return slot.E32Words[1]; + return DdiNopEntryRvaExtract; + } + + // Live 9183b83: heap TOC-attach openexe, so + // obj-96 is not a MODULE. Find the real in-flight + // MODULE via pointer oe or a pmodNext walk from + // live seeds. Do not invent a module. + private static void TrySetDdiNopRamStartip(MipsBus bus, uint hintModule) + { + TrySetDdiNopRamStartip(bus, hintModule, null); + } + + private static void TrySetDdiNopRamStartip(MipsBus bus, uint hintModule, uint[] regs) + { + if (regs != null) + NoteDdiNopWalkSeeds(regs); + ExtraRomTocMod slot = FindCachedExtraRomToc("ddi_nop.dll"); + uint entryrva = DdiNopEntryRvaFromSlot(slot); + TrySetDdiNopModuleStartip(bus, DdiNopVbasePage, entryrva, hintModule); + } + + private static void TrySetDdiNopModuleStartip(MipsBus bus, uint vbase, uint entryrva) + { + TrySetDdiNopModuleStartip(bus, vbase, entryrva, 0); + } + + private static void TrySetDdiNopModuleStartip(MipsBus bus, uint vbase, uint entryrva, uint hintModule) + { + if (bus == null) + return; + if (vbase == 0) + vbase = DdiNopVbasePage; + if (entryrva == 0) + entryrva = DdiNopEntryRvaExtract; + uint want = vbase + entryrva; + uint dumpXip = DdiNopVbase + entryrva; + uint module = 0; + uint p50 = 0; + uint before = 0; + string why; + try + { + _ddiNopStartipAttempted = true; + module = FindInFlightDdiNopModule(bus, hintModule); + if (module == 0) + { + why = "skip-no-mod"; + LogDdiNopNoModOnce(bus); + } + else + { + TryPeekWord(bus, module + ProcModule, out p50); + TryPeekWord(bus, module + ModuleStartip, out before); + if (before == 0) + { + bus.Write32(module + ModuleStartip, want); + why = "set-zero"; + } + else if (before == dumpXip && _ddiNopLandedBySig) + { + bus.Write32(module + ModuleStartip, want); + why = "set-dump-xip"; + } + else if (before == want) + why = "keep"; + else + why = "skip-have"; + TrySetDdiNopVallocBasePtr(bus, module); + } + } + catch + { + why = "skip-throw"; + } + uint entryWord = PeekDdiNopRamEntryWord(bus); + BootLog.Write("[Hive] ExtraROM ddi_nop startip module=0x" + + module.ToString("X8") + + " mod+0x50=0x" + p50.ToString("X8") + + " startip=0x" + before.ToString("X8") + + " " + why + + " startip=0x" + want.ToString("X8") + + " entry-word=0x" + entryWord.ToString("X8")); + } + + // Live e8489d0: module+0x50 stayed dump XIP + // 0x03980000 while serve/startip used VALLOC + // 0x01980000. BindImp then walked dump IAT. + // Only this field, only ddi_nop, only dump XIP. + private static void TrySetDdiNopVallocBasePtr(MipsBus bus, uint module) + { + if (!_ddiNopLandedBySig || bus == null || module == 0) + return; + if (!IsDdiNopModule(bus, module)) + return; + uint p50; + if (!TryPeekWord(bus, module + ProcModule, out p50)) + return; + if (p50 != DdiNopVbase) + return; + bus.Write32(module + ProcModule, DdiNopVbasePage); + BootLog.Write("[Hive] ExtraROM ddi_nop baseptr module=0x" + + module.ToString("X8") + + " was=0x" + p50.ToString("X8") + + " set-valloc=0x" + DdiNopVbasePage.ToString("X8")); + } + + // Live 5166cf2: set-xip 0x800B2000 made F7BC treat + // MIPS prologues as the export dir (expVA words + // 0xAFAA0014…). 94038eb GetProc was correct with + // ImageBase 0x03F50000 → v0=0x03F57EB4. Keep that + // BasePtr. Undo leftover XIP. Do not invent a + // new BasePtr. Do not serve PE into 0x800B2000. + private static void TryKeepCoredllImageBasePtr(MipsBus bus, uint module) + { + if (bus == null || module == 0) + return; + if (IsDdiNopModule(bus, module)) + return; + uint p50; + if (!TryPeekWord(bus, module + ProcModule, out p50)) + return; + bool coredll = module == _coredllModule + || p50 == CoredllSharedLo + || (p50 >= 0x80000000u + && NamesMatchRom(_ddiNopBindLibName, "coredll.dll") + && module == _ddiNopBindLibV0); + if (!coredll) + return; + if (p50 >= 0x80000000u) + { + bus.Write32(module + ProcModule, CoredllSharedLo); + BootLog.Write("[Hive] ExtraROM coredll baseptr module=0x" + + module.ToString("X8") + + " was=0x" + p50.ToString("X8") + + " undo-xip=0x" + CoredllSharedLo.ToString("X8")); + TryPlantCoredllStartip(bus, module); + return; + } + if (p50 != CoredllSharedLo) + return; + TryPlantCoredllStartip(bus, module); + if (_coredllBasePtrLogged) + return; + _coredllBasePtrLogged = true; + BootLog.Write("[Hive] ExtraROM coredll baseptr keep-imagebase=0x" + + CoredllSharedLo.ToString("X8") + + " (XIP+exp was code, not export dir)"); + } + + private static void PeekDdiNopIatWord(MipsBus bus, out uint word, out uint dest6) + { + word = 0; + dest6 = _ddiNopIatDest6; + uint va = DdiNopVbasePage + DdiNopIatRva; + uint l2 = 0; + uint dest10 = 0; + if (dest6 == 0) + WalkDdiNopPteDests(bus, va, out l2, out dest6, out dest10); + if (dest6 != 0 && !IsDdiNopDest10Page(dest6)) + { + bool threw; + word = PeekDestWordRaw(bus, dest6, out threw); + if (!threw) + return; + } + TryPeekWord(bus, va, out word); + } + + // Live 5166cf2: after a good GetProc v0 the IAT + // stayed 0. Observe whether BindImp stores into + // 0x01999000 / dest6. Log the next BindImp PCs + // if it does not. Do not invent IAT fills. + private static void TryNoteBindImpAfterGoodV0(MipsBus bus, uint pc) + { + if (_ddiNopOrdGoodV0 == 0 || _ddiNopOrdAfterDone) + return; + if (pc == BindImpOrdJalRet) + return; + if (pc >= 0x80000000u && pc < 0x80000400u) + return; + if (pc == _ddiNopOrdAfterLast) + return; + uint iat = 0; + uint dest6 = 0; + PeekDdiNopIatWord(bus, out iat, out dest6); + uint va = DdiNopVbasePage + DdiNopIatRva; + if (_ddiNopIatStoreLogged || iat == _ddiNopOrdGoodV0) + { + _ddiNopOrdAfterDone = true; + BootLog.Write("[Hive] ExtraROM BindImp-after pc=0x" + + pc.ToString("X8") + + " iat=0x" + iat.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " va=0x" + va.ToString("X8") + + " (store)"); + return; + } + if (iat != 0) + { + _ddiNopOrdAfterDone = true; + BootLog.Write("[Hive] ExtraROM BindImp-after pc=0x" + + pc.ToString("X8") + + " iat=0x" + iat.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " va=0x" + va.ToString("X8") + + " (iat-has)"); + return; + } + _ddiNopOrdAfterLast = pc; + _ddiNopOrdAfterN++; + if (_ddiNopOrdAfterN <= 6) + { + BootLog.Write("[Hive] ExtraROM BindImp-after pc=0x" + + pc.ToString("X8") + + " iat=0x00000000 dest6=0x" + dest6.ToString("X8") + + " va=0x" + va.ToString("X8") + + " (no-store)"); + } + // Back at GetProc without an IAT write is the + // drop. Do not conclude after four sequential + // BindImp instructions — the store may be later. + bool backGetProc = pc == BindImpOrdBaseLw + || pc == BindImpOrdLookup; + if (!backGetProc && _ddiNopOrdAfterN < 16) + return; + _ddiNopOrdAfterDone = true; + BootLog.Write("[Hive] ExtraROM BindImp-ord drop-v0=0x" + + _ddiNopOrdGoodV0.ToString("X8") + + " no-IAT last=0x" + pc.ToString("X8") + + (backGetProc ? " (back-GetProc)" : "")); + TryNoteBindImpIatSwSkipped(); + } + + // Live d79cd40: BindImp touches 0xFFFF5800 before + // sw $v0,0($v1) at 0x80019124. UserKData addiu + // sign-extends; kernel KData is already live at + // 0xFFFFD800 (nest/CurProc/ThreadPtr). Alias the + // user page onto that KData. Do not invent bytes. + public static uint MapUserKDataVa(uint va) + { + if (!_userKPageAlias) + return va; + if ((va & ~0xFFFu) != (UserKPage & ~0xFFFu)) + return va; + return (KDataBase & ~0xFFFu) | (va & 0xFFFu); + } + + // Live 674d704: lh at 0xFFFFFCE1 (base=1 + + // sign_extend 0xFCE0). Same discipline as + // MapUserKDataVa: rewrite onto live firmware + // backing only. Peek 0xFFFFF000 or TLB PFN + // (kseg0). Do not alias KData. Do not + // zero-fill SharedUserData. Do not rewrite + // GPR23. + public static uint MapFfffF000Va(MipsBus bus, uint va) + { + if (_ffffF000Busy) + return va; + if (!IsFfffF000Armed()) + return va; + if ((va & ~0xFFFu) != FfffF000Page) + return va; + if (_ffffF000Kseg == FfffF000Page) + _ffffF000Kseg = 0; + if (_ffffF000Kseg != 0) + return _ffffF000Kseg | (va & 0xFFFu); + TryResolveFfffF000(bus, va); + if (_ffffF000Kseg == FfffF000Page) + _ffffF000Kseg = 0; + if (_ffffF000Kseg != 0) + return _ffffF000Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsFfffF000Armed() + { + if (_leftoverWait99O32NkCoredllSawEntry) + return true; + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ffffFce1Logged || _ffffF000Demand; + } + + private static void TryResolveFfffF000(MipsBus bus, uint va) + { + if (bus == null || _ffffF000Busy || _ffffF000Done) + return; + if ((va & ~0xFFFu) != FfffF000Page) + return; + try + { + _ffffF000Busy = true; + _ffffF000Demand = true; + uint word = 0; + // Live 221208f: peek of 0xFFFFFE54 hit + // sud-beq0-skip return 0 and identity- + // mapped F000->F000. That is not + // backing. Refuse. Only kseg0 TLB PFN. + uint pfn = 0; + bool valid = false; + bool tlbHit = bus.TryFindTlbPfn(FfffF000Page, out pfn, out valid); + if (tlbHit && valid) + { + uint dest = 0x80000000u | ((pfn << 12) & 0x1FFFFFFFu); + if ((dest & 0x1FFFFFFFu) >= 0x00010000u + && (TryPeekWord(bus, dest | (va & 0xFFFu), out word) + || TryPeekWord(bus, dest, out word))) + { + RememberFfffF000Kseg(bus, dest, va, word, "tlb-pfn"); + return; + } + } + if (!_ffffF000Logged) + { + _ffffF000Logged = true; + _ffffF000Done = true; + uint kd = 0; + bool kdOk = TryPeekWord(bus, KDataBase, out kd); + string tlbWhy = "none"; + if (tlbHit) + tlbWhy = valid + ? "pfn=0x" + pfn.ToString("X") + "-unmapped" + : "inv-pfn=0x" + pfn.ToString("X"); + BootLog.Write("[Hive] ExtraROM ddi_nop ffff-f000 map va=0x" + + FfffF000Page.ToString("X8") + + " pte-miss tlb=" + tlbWhy + + (kdOk ? " FFFFD800=0x" + kd.ToString("X8") : " FFFFD800-unmapped") + + " (SharedUserData; no dump page; not UserK/KData alias; do not invent dest)"); + } + } + finally + { + _ffffF000Busy = false; + } + } + + private static void RememberFfffF000Kseg(MipsBus bus, uint kseg, + uint va, uint word, string via) + { + kseg &= ~0xFFFu; + if (kseg == 0 || kseg == FfffF000Page) + { + if (!_ffffF000Logged) + { + _ffffF000Logged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-f000 refuse identity" + + " via=" + (via ?? "live-peek") + + " dest-word=0x" + word.ToString("X8") + + " (F000->F000 is not backing; do not invent dest)"); + } + return; + } + _ffffF000Kseg = kseg; + if (_ffffF000Logged) + return; + _ffffF000Logged = true; + _ffffF000Done = true; + if (via == null) + via = "firmware"; + BootLog.Write("[Hive] ExtraROM ddi_nop ffff-f000 map va=0x" + + FfffF000Page.ToString("X8") + + " -> 0x" + _ffffF000Kseg.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " via=" + via + + " (SharedUserData; firmware backing; do not invent dest)"); + } + + // Live 734b895: kdata-tlb pfn=0x345-v. + // No E000 PFN (do not invent pfn+1). + // sb-zero continue when l2=0 / v0=0. + // Same discipline as MapFfffF000Va: live + // peek, TLB PFN, or sec0 firmware PTE + // dest. Do not alias KData / UserK / + // SharedUserData. Do not invent dest. + // Do not leftover-hop. + public static uint MapFfffE000Va(MipsBus bus, uint va) + { + if (_ffffE000Busy) + return va; + if (!IsFfffE000Armed()) + return va; + if ((va & ~0xFFFu) != FfffE000Page) + return va; + if (_ffffE000Kseg != 0) + return _ffffE000Kseg | (va & 0xFFFu); + TryResolveFfffE000(bus, va); + if (_ffffE000Kseg != 0) + return _ffffE000Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsFfffE000Armed() + { + return _leftoverWait99O32NkCoredllSawEntry || _ffffE000Demand; + } + + private static void TryResolveFfffE000(MipsBus bus, uint va) + { + if (bus == null || _ffffE000Busy || _ffffE000Done) + return; + if ((va & ~0xFFFu) != FfffE000Page) + return; + try + { + _ffffE000Busy = true; + _ffffE000Demand = true; + uint word = 0; + if (TryPeekWord(bus, FfffE000Page | (va & 0xFFFu), out word) + || TryPeekWord(bus, CoredllDllMainKdataStore, out word) + || TryPeekWord(bus, FfffE000Page, out word)) + { + RememberFfffE000Kseg(bus, FfffE000Page, va, word, "live-peek"); + return; + } + uint pfn = 0; + bool valid = false; + bool tlbHit = bus.TryFindTlbPfn(FfffE000Page, out pfn, out valid); + if (tlbHit && valid) + { + uint dest = 0x80000000u | ((pfn << 12) & 0x1FFFFFFFu); + if ((dest & 0x1FFFFFFFu) >= 0x00010000u + && (TryPeekWord(bus, dest | (va & 0xFFFu), out word) + || TryPeekWord(bus, dest, out word))) + { + RememberFfffE000Kseg(bus, dest, va, word, "tlb-pfn"); + return; + } + } + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfnWord = 0; + uint kseg = 0; + bool pte = sec != 0 + && WalkFirmwarePte(bus, sec, FfffE000Page | (va & 0xFFFu), + out l1, out l2, out pfnWord, out kseg); + if (pte && kseg != 0 + && TryPeekWord(bus, kseg | (va & 0xFFFu), out word)) + { + RememberFfffE000Kseg(bus, kseg, va, word, "fw-pte"); + return; + } + if (!_ffffE000Logged) + { + _ffffE000Logged = true; + _ffffE000Done = true; + uint kd = 0; + bool kdOk = TryPeekWord(bus, KDataBase, out kd); + uint kdL1 = 0; + uint kdL2 = 0; + uint kdPfn = 0; + uint kdKseg = 0; + bool kdPte = sec != 0 + && WalkFirmwarePte(bus, sec, KDataBase, + out kdL1, out kdL2, out kdPfn, out kdKseg); + uint kdTlbPfn = 0; + bool kdTlbValid = false; + bool kdTlb = bus.TryFindTlbPfn(KDataBase & ~0xFFFu, + out kdTlbPfn, out kdTlbValid); + uint insn = 0; + bool insnOk = TryPeekWord(bus, CoredllDllMainKdataEpc, out insn); + string tlbWhy = "none"; + if (tlbHit) + tlbWhy = valid + ? "pfn=0x" + pfn.ToString("X") + "-unmapped" + : "inv-pfn=0x" + pfn.ToString("X"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 map va=0x" + + FfffE000Page.ToString("X8") + + " pte-miss tlb=" + tlbWhy + + " sec0=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + (kdPte + ? " kdata-pte=0x" + kdKseg.ToString("X8") + : " kdata-l2=0x" + kdL2.ToString("X8")) + + (kdOk ? " FFFFD800=0x" + kd.ToString("X8") : " FFFFD800-unmapped")); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 why l2=0x" + + l2.ToString("X") + + " pair=0xFFFFE000/F000" + + " kdata-pair=0xFFFFC000/D000" + + (kdTlb + ? " kdata-tlb=pfn=0x" + kdTlbPfn.ToString("X") + + (kdTlbValid ? "-v" : "-inv") + : " kdata-tlb=none") + + (insnOk + ? " insn=0x" + insn.ToString("X8") + + " " + FormatMipsOp(CoredllDllMainKdataEpc, insn) + : "") + + " (NK wired KData pair; never created E000 L2/TLB; sb $v0,0xE380($0) zero-byte; do not invent dest)"); + } + } + finally + { + _ffffE000Busy = false; + } + } + + private static void RememberFfffE000Kseg(MipsBus bus, uint kseg, + uint va, uint word, string via) + { + _ffffE000Kseg = kseg & ~0xFFFu; + if (_ffffE000Logged) + return; + _ffffE000Logged = true; + _ffffE000Done = true; + if (via == null) + via = "firmware"; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 map va=0x" + + FfffE000Page.ToString("X8") + + " -> 0x" + _ffffE000Kseg.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " via=" + via + + " (KData+0xB80 page; firmware backing; not UserK/SharedUserData/KData alias; do not invent dest)"); + } + + // Live 734b895: firmware l2=0, no E000 PFN + // (do not invent kdata pfn+1). sb $v0,0xE380($0) + // with v0=0 is a zero-byte to a never-wired + // pair. Swallow that store only so NK + // continues at addiu 0x2442FE54; leave + // ra=0x8002F124. Do not leftover-hop. + // Later loads still TLBL (no zero page). + public static bool TrySkipFfffE000SbZero(MipsBus bus, uint va, uint value) + { + if ((va & ~0xFFFu) != FfffE000Page) + return false; + if ((value & 0xFFu) != 0) + return false; + if (!IsFfffE000Armed()) + return false; + if (_ffffE000Kseg != 0) + return false; + TryResolveFfffE000(bus, va); + if (_ffffE000Kseg != 0) + return false; + if (!_ffffE000Done) + return false; + if (!_ffffE000SkipLogged) + { + _ffffE000SkipLogged = true; + uint epc = va == CoredllDllMainKdataStore + ? CoredllDllMainKdataEpc + : 0; + if (epc == 0) + epc = CoredllDllMainKdataEpc; + uint next = 0; + if (!TryPeekWord(bus, epc + 4, out next) || next == 0) + next = CoredllDllMainKdataNext; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 sb-zero-skip" + + " epc=0x" + epc.ToString("X") + + " next=0x" + next.ToString("X") + + " ra=0x" + CoredllDllMainKdataRa.ToString("X") + + " v0=0 l2=0" + + " (zero-byte to never-wired E000/F000 pair; continue addiu; honor ra; do not invent dest)"); + } + return true; + } + + private static bool IsJalrV0(uint insn) + { + return (insn >> 26) == 0 + && (insn & 63) == 9 + && ((insn >> 21) & 31) == 2; + } + + // Live ab4c991: sb $v0,0xE428($0) with + // v0=0x80341A74 then jalr $v0. Nonzero + // store to never-wired E000. Do not use + // sb-zero-skip. No pfn+1. Swallow this + // dump-true sb so NK jalr's peekable + // kseg dest. Do not leftover-hop. + public static bool TrySkipFfffE428SbJalr(MipsBus bus, uint va, uint value) + { + if (va != CoredllDllMainKdataStore2) + return false; + if ((value & 0xFFu) == 0) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry) + return false; + if (_ffffE000Busy) + return false; + if (_ffffE000Kseg != 0) + return false; + TryResolveFfffE000(bus, va); + if (_ffffE000Kseg != 0) + return false; + uint insn = 0; + if (!TryPeekWord(bus, CoredllDllMainKdataEpc2, out insn) || insn == 0) + insn = CoredllDllMainKdataInsn2; + if (insn != CoredllDllMainKdataInsn2) + return false; + uint next = 0; + if (!TryPeekWord(bus, CoredllDllMainKdataEpc2 + 4, out next) || next == 0) + next = CoredllDllMainKdataNext2; + if (!IsJalrV0(next)) + return false; + if (!_ffffE428SkipLogged) + { + _ffffE428SkipLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 sb-jalr-skip" + + " epc=0x" + CoredllDllMainKdataEpc2.ToString("X") + + " bad=0x" + CoredllDllMainKdataStore2.ToString("X") + + " word=0x" + insn.ToString("X") + + " dis=" + FormatMipsOp(CoredllDllMainKdataEpc2, insn) + + " next=0x" + next.ToString("X") + + " byte=0x" + (value & 0xFFu).ToString("X") + + " ra=0x" + CoredllDllMainKdataRa.ToString("X") + + " (nonzero sb then jalr $v0; never-wired E000; no page; do not invent dest)"); + } + return true; + } + + // Live c4c77e1: sb $v1,-5496($0) at + // 0x8003F888 dest 0xFFFFEA88. + // Nonzero $v1 — not sb-zero-skip. + // Never-wired E000/F000. Swallow + // this dump-overlay sb so dump- + // true continues. Do not invent + // E000 / F000 / SUD / pfn+1. + public static bool TrySkipFfffEa88Sb(MipsBus bus, uint va, uint value) + { + if (va != CoredllDllMainKdataStoreEa88) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (_ffffE000Busy) + return false; + if (_ffffE000Kseg != 0) + return false; + TryResolveFfffE000(bus, va); + if (_ffffE000Kseg != 0) + return false; + if (!_ffffEa88SkipLogged) + { + _ffffEa88SkipLogged = true; + uint ea88Dump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainKdataEpcEa88, out ea88Dump) + || ea88Dump == 0) + ea88Dump = CoredllDllMainKdataDumpEa88; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 sb-ea88-skip" + + " epc=0x" + CoredllDllMainKdataEpcEa88.ToString("X") + + " bad=0x" + CoredllDllMainKdataStoreEa88.ToString("X") + + " word=0x" + CoredllDllMainKdataInsnEa88.ToString("X") + + " dump=0x" + ea88Dump.ToString("X") + + " byte=0x" + (value & 0xFFu).ToString("X") + + " (nonzero sb $v1,-5496($0); never-wired E000/F000;" + + " dest-miss skip; continue dump-true; no invent dest / SUD)"); + } + return true; + } + + // Dump nk.exe at 0x8002F218: + // lw $v0,36($sp); lw $t9,0($v0); + // or $v0,$t9; jalr $v0. Live sb-jalr + // left $v0=0x80341A74 (table) and + // $t9=*table=0x80057EB8 (NK func: + // addiu $sp,-40; OemCurMSec-scale + // sibling at 0x80342C60 / CurMSec + // 0xFFFFD894). jalr $v0 I-fetched + // the table (RI 0x03C18016). Retarget + // to $t9 only when *table==$t9 and t9 + // peeks. Do not leftover-hop refuse + // dests. Do not invent tick. Do not + // MUL. Do not ri-nop. + public static bool TryFixJalrTableDest(MipsBus bus, uint[] regs, ref uint target) + { + if (bus == null || regs == null) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry || !_ffffE428SkipLogged) + return false; + if (target != CoredllDllMainJalrDest) + return false; + uint t9 = PeekGpr(regs, 25); + if (t9 != CoredllDllMainKdataT9_2) + return false; + if (t9 == LeftoverWait99O32RefuseRa + || t9 == LeftoverWait99GetProcDest + || t9 == LeftoverWait99O32RefuseDump + || IsLeftoverDestVa(t9) + || IsWrapDestSize(t9) || IsWrapDestFp50Va(t9) + || IsHdDllImageBase(t9) || t9 == WrapDestE32SizeLive) + return false; + uint word = 0; + if (!TryPeekWord(bus, target, out word) || word != t9) + return false; + uint t9w = 0; + if (!TryPeekWord(bus, t9, out t9w) || t9w == 0) + return false; + target = t9; + regs[2] = t9; + if (!_jalrTableFixLogged) + { + _jalrTableFixLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-table" + + " dest=0x" + CoredllDllMainJalrDest.ToString("X") + + " -> 0x" + t9.ToString("X") + + " *table=0x" + word.ToString("X") + + " t9w=0x" + t9w.ToString("X") + + " via=t9 (dump lw $t9,0($v0); or $v0,$t9; jalr $v0; do not I-fetch table)"); + } + return true; + } + + // Dump nk.exe: $t9 body is OemCurMSec + // sibling (scale 0x80342C60, CurMSec + // 0xFFFFD894, last Count 0x80339B24). + // Observe peeks only. Do not invent + // tick. Do not leftover-hop. + private static void TryNoteJalrT9MsecScale(MipsBus bus, uint[] regs, + uint pc) + { + if (_jalrT9MsecLogged) + return; + if (!_leftoverWait99O32NkCoredllSawEntry || !_ffffE428SkipLogged) + return; + if (pc != CoredllDllMainKdataT9_2) + return; + _jalrT9MsecLogged = true; + uint a0 = PeekGpr(regs, 4); + uint scale0 = 0; + uint scale20 = 0; + uint k94 = 0; + uint last = 0; + bool scaleOk = TryPeekWord(bus, CoredllDllMainT9Scale, out scale0); + bool scale20Ok = TryPeekWord(bus, CoredllDllMainT9Scale + 20, out scale20); + bool k94Ok = TryPeekWord(bus, CoredllDllMainT9CurMSec, out k94); + bool lastOk = TryPeekWord(bus, CoredllDllMainT9LastCount, out last); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-t9" + + " pc=0x" + CoredllDllMainKdataT9_2.ToString("X") + + " a0=0x" + a0.ToString("X") + + " scale=0x" + CoredllDllMainT9Scale.ToString("X") + + (scaleOk ? " *scale=0x" + scale0.ToString("X") : " *scale-miss") + + (scale20Ok ? " +20=0x" + scale20.ToString("X") : " +20-miss") + + " k94=0x" + CoredllDllMainT9CurMSec.ToString("X") + + (k94Ok ? " *k94=0x" + k94.ToString("X") : " *k94-miss") + + " last=0x" + CoredllDllMainT9LastCount.ToString("X") + + (lastOk ? " *last=0x" + last.ToString("X") : " *last-miss") + + " via=msec-scale (dump OemCurMSec sibling; ReadCount-delta;" + + " do not invent tick)"); + } + + // Live 07670a8: sb $v0,0xE478($0) at + // dump jr $ra. After jalr-t9 only. + // Rewrite fetch to dump jr. Honor $ra + // when it peeks and is not a refuse + // dest. Do not invent E000. Do not + // leftover-hop. + public static bool TryFixE478SbAsDumpJr(MipsBus bus, uint[] regs, + uint pc, ref uint insn) + { + if (pc != CoredllDllMainKdataEpc3) + return false; + if (insn != CoredllDllMainKdataInsn3) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry || !_ffffE428SkipLogged + || !_jalrT9MsecLogged) + return false; + uint prev = 0; + uint next = 0; + if (!TryPeekWord(bus, CoredllDllMainKdataEpc3 - 4, out prev) + || prev != CoredllDllMainKdataPrev3) + return false; + if (!TryPeekWord(bus, CoredllDllMainKdataEpc3 + 4, out next) + || next != CoredllDllMainKdataNext3) + return false; + uint ra = PeekGpr(regs, 31); + if (ra == 0 || (ra & 3) != 0) + return false; + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || ra == LeftoverWait99O32RefuseDump + || ra == CoredllDllMainKdataWrapRefuse + || IsLeftoverDestVa(ra) + || IsWrapDestSize(ra) || IsWrapDestFp50Va(ra) + || IsHdDllImageBase(ra) || ra == WrapDestE32SizeLive + || ra == WrapDestFp50FillLive) + return false; + uint raw = 0; + if (!TryPeekWord(bus, ra, out raw) || raw == 0) + return false; + insn = CoredllDllMainKdataDumpJr; + TryHealDumpInsn(bus, pc, CoredllDllMainKdataInsn3, + CoredllDllMainKdataDumpJr); + if (!_jalrE478JrLogged) + { + _jalrE478JrLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 sb-jr" + + " epc=0x" + CoredllDllMainKdataEpc3.ToString("X") + + " bad=0x" + CoredllDllMainKdataStore3.ToString("X") + + " word=0x" + CoredllDllMainKdataInsn3.ToString("X") + + " dump=0x" + CoredllDllMainKdataDumpJr.ToString("X") + + " ra=0x" + ra.ToString("X") + + " ra-word=0x" + raw.ToString("X") + + " via=dump-jr (live sb overwrote dump jr $ra;" + + " never-wired E000; honor ra; do not invent dest)"); + } + return true; + } + + // Live 8553edf: sb $a0,0x2470($0) at + // dump sw $a2,8($sp). After sb-jr only. + // Rewrite fetch to dump sw. Live $sp is + // KData 0xFFFFD768. Do not invent page + // 0x2000. Log once. Do not leftover-hop. + public static bool TryFixStk2470SbAsDumpSw(MipsBus bus, uint[] regs, + uint pc, ref uint insn) + { + if (pc != CoredllDllMainStk2470Epc) + return false; + if (insn != CoredllDllMainStk2470Live) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry || !_jalrE478JrLogged) + return false; + uint prev = 0; + uint next = 0; + if (!TryPeekWord(bus, CoredllDllMainStk2470Epc - 4, out prev) + || prev != CoredllDllMainStk2470Prev) + return false; + if (!TryPeekWord(bus, CoredllDllMainStk2470Epc + 4, out next) + || next != CoredllDllMainStk2470Next) + return false; + uint ra = PeekGpr(regs, 31); + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || ra == LeftoverWait99O32RefuseDump + || ra == CoredllDllMainKdataWrapRefuse + || IsLeftoverDestVa(ra) + || IsWrapDestSize(ra) || IsWrapDestFp50Va(ra) + || IsHdDllImageBase(ra) || ra == WrapDestE32SizeLive + || ra == WrapDestFp50FillLive) + return false; + insn = CoredllDllMainStk2470Insn; + TryHealDumpInsn(bus, pc, CoredllDllMainStk2470Live, + CoredllDllMainStk2470Insn); + _stk2470Done = true; + if (!_stk2470SwLogged) + { + _stk2470SwLogged = true; + uint sp = PeekGpr(regs, 29); + uint a0 = PeekGpr(regs, 4); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk stk-2470 sb-sw" + + " epc=0x" + CoredllDllMainStk2470Epc.ToString("X") + + " bad=0x" + CoredllDllMainStk2470Bad.ToString("X") + + " word=0x" + CoredllDllMainStk2470Live.ToString("X") + + " dump=0x" + CoredllDllMainStk2470Insn.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " a0=0x" + a0.ToString("X") + + " via=dump-sw (live sb $a0,0x2470($0) overwrote dump" + + " sw $a2,8($sp); KData $sp; do not invent dest)"); + } + return true; + } + + // Live 9eea658: sb $a0,0x1670($0) at + // dump sb $a3,443($v0). After dump-sw + // only. Rewrite fetch to dump sb when + // $v0 peeks on the 0x86FB THREAD class. + // Do not invent page 0x1000. Log once. + // Do not leftover-hop. + public static bool TryFixNest1670SbAsDumpSb(MipsBus bus, uint[] regs, + uint pc, ref uint insn) + { + if (pc != CoredllDllMainStk1670Epc) + return false; + if (insn != CoredllDllMainStk1670Live) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry || !_stk2470SwLogged) + return false; + uint prev = 0; + uint next = 0; + if (!TryPeekWord(bus, CoredllDllMainStk1670Epc - 4, out prev) + || prev != CoredllDllMainStk1670Prev) + return false; + if (!TryPeekWord(bus, CoredllDllMainStk1670Epc + 4, out next) + || next != CoredllDllMainStk1670Next) + return false; + uint v0 = PeekGpr(regs, 2); + if (v0 == 0 || (v0 & 3) != 0) + return false; + if ((v0 & 0xFFFF0000u) != CoredllDllMainStk1670ThrPage) + return false; + if (v0 == LeftoverWait99O32RefuseRa + || v0 == LeftoverWait99GetProcDest + || v0 == LeftoverWait99O32RefuseDump + || v0 == CoredllDllMainKdataWrapRefuse + || IsLeftoverDestVa(v0) + || IsWrapDestSize(v0) || IsWrapDestFp50Va(v0) + || IsHdDllImageBase(v0) || v0 == WrapDestE32SizeLive + || v0 == WrapDestFp50FillLive) + return false; + uint thr = 0; + if (!TryPeekWord(bus, v0, out thr) || thr == 0) + return false; + uint ra = PeekGpr(regs, 31); + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || ra == LeftoverWait99O32RefuseDump + || ra == CoredllDllMainKdataWrapRefuse + || IsLeftoverDestVa(ra) + || IsWrapDestSize(ra) || IsWrapDestFp50Va(ra) + || IsHdDllImageBase(ra) || ra == WrapDestE32SizeLive + || ra == WrapDestFp50FillLive) + return false; + insn = CoredllDllMainStk1670Insn; + TryHealDumpInsn(bus, pc, CoredllDllMainStk1670Live, + CoredllDllMainStk1670Insn); + _stk1670Logged = true; + if (!_stk1670SbLogged) + { + _stk1670SbLogged = true; + uint a0 = PeekGpr(regs, 4); + uint a3 = PeekGpr(regs, 7); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk nest-1670 sb-sb" + + " epc=0x" + CoredllDllMainStk1670Epc.ToString("X") + + " bad=0x" + CoredllDllMainStk1670Bad.ToString("X") + + " word=0x" + CoredllDllMainStk1670Live.ToString("X") + + " dump=0x" + CoredllDllMainStk1670Insn.ToString("X") + + " ra=0x" + ra.ToString("X") + + " v0=0x" + v0.ToString("X") + + " *v0=0x" + thr.ToString("X") + + " a0=0x" + a0.ToString("X") + + " a3=0x" + a3.ToString("X") + + " via=dump-sb (live sb $a0,0x1670($0) overwrote dump" + + " sb $a3,443($v0); THREAD $v0; do not invent dest)"); + } + return true; + } + + // After dump-sb: live I-fetch abs store + // rs=0 overwrote dump load/store + // (rs!=0) or dump J/JAL/JR/JALR + // (J-type rs field is 0). Peek + // dump-only nk.bin (fallback known + // EPCs). Rewrite and write dump + // word back at EPC (self-heal) + // so the next I-fetch is dump- + // true. Healed jal/memop falls + // through — no dump-mem-skip. + // Live 296037e: nest dump-sb then + // dump-mem fallthrough at the SAME + // 0x80042470 stalled jal vs 0cb3d43. + // Do not double-handle dump-jr / + // dump-sw / dump-sb sites. Fallthrough + // only at dump-mem EPCs (1828/6670/ + // 15C28). Skip-log only when an abs + // store cannot rewrite. Log once + // per EPC. Do not invent low useg. + // Do not leftover-hop. + public static bool TryFixLiveAbsStoreAsDumpMem(MipsBus bus, uint[] regs, + uint pc, ref uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_stk1670SbLogged) + return false; + if ((pc & 3) != 0 || pc < 0x80010000u || pc >= 0x80400000u) + return false; + // Already dump-jr / dump-sw / dump-sb. + // Live 296037e nest site must not + // consume dump-mem fallthrough. + if (IsDumpMemPriorHandledPc(pc)) + return false; + // Live 93085c2: after heal=1 at + // 0x80057470, word is already + // dump jal 0x0C010C9B. Do not + // dump-mem-skip / stall — let + // normal I-fetch execute. + if (IsDumpMemAlreadyTrue(insn)) + { + // Live 4577e0a: after dump-mem-jal, + // fallthrough at 57470/42628 logged + // stale $ra=0x80057448 and undid PC. + // Once jal applied, skip those sites. + if (IsDumpMemFallthroughPc(pc) && !IsDumpMemJalHoldPc(pc)) + TryLogDumpMemFallthrough(pc, insn, regs); + return false; + } + if (!IsMipsAbsRs0Store(insn) || (insn & 0x8000u) != 0) + return false; + bool site6670 = (insn & 0xFFFF) == CoredllDllMainAbs6670Bad + || pc == CoredllDllMainAbs6670Epc; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + { + if (pc == CoredllDllMainAbs1828Epc) + dump = CoredllDllMainAbs1828Dump; + else if (pc == CoredllDllMainAbs6670Epc) + dump = CoredllDllMainAbs6670Dump; + else if (pc == CoredllDllMainExn15C28Epc) + dump = CoredllDllMainExn15C28Dump; + else + { + TryLogDumpMemSkip(pc, insn, 0, regs, "dump-miss", site6670); + return false; + } + } + if (dump == insn) + { + TryLogDumpMemSkip(pc, insn, dump, regs, + "dump-already-matches", site6670); + return false; + } + bool dumpJump = IsMipsJumpOrJr(dump); + bool dumpMem = (IsMipsLoad(dump) || IsMipsStore(dump)) + && ((dump >> 21) & 31) != 0; + if (!dumpJump && !dumpMem) + { + string why = IsMipsAbsRs0Store(dump) + ? "dump-abs-store" + : "dump-not-memop-or-jump"; + TryLogDumpMemSkip(pc, insn, dump, regs, why, site6670); + return false; + } + if (dumpJump) + { + uint dest = 0; + uint op = dump >> 26; + if (op == 2 || op == 3) + dest = (pc & 0xF0000000u) | ((dump & 0x03FFFFFFu) << 2); + else + dest = PeekGpr(regs, (int)((dump >> 21) & 31)); + if (dest == 0 || (dest & 3) != 0 || IsDumpMemRefuseVa(dest)) + { + TryLogDumpMemSkip(pc, insn, dump, regs, + "dump-jump-refuse", site6670); + return false; + } + } + uint ra = PeekGpr(regs, 31); + if (IsDumpMemRefuseVa(ra)) + { + TryLogDumpMemSkip(pc, insn, dump, regs, "ra-refuse", site6670); + return false; + } + uint live = insn; + insn = dump; + bool heal = TryHealDumpInsn(bus, pc, live, dump); + if (dumpJump && pc == CoredllDllMainAbs6670Epc) + { + TryHealDumpMemJalDelay(bus, pc); + TryClearDumpMemExn(bus, pc); + } + if (TryNoteDumpMemLogPc(pc)) + { + uint v0 = PeekGpr(regs, 2); + uint fp = PeekGpr(regs, 30); + uint rt = (live >> 16) & 31; + uint imm = live & 0xFFFF; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-store sb-mem" + + " epc=0x" + pc.ToString("X") + + " bad=0x" + imm.ToString("X") + + " word=0x" + live.ToString("X") + + " dump=0x" + dump.ToString("X") + + " dis=" + FormatMipsOp(pc, live) + + " dump-dis=" + FormatMipsOp(pc, dump) + + " rs=0 rt=" + rt.ToString() + + " v0=0x" + v0.ToString("X") + + " fp=0x" + fp.ToString("X") + + " ra=0x" + ra.ToString("X") + + (heal ? " heal=1" : " heal=0") + + " via=dump-mem (live abs store rs=0; dump memop/jump;" + + " self-heal EPC; do not invent dest)"); + } + return true; + } + + public static uint MapStk2470Va(MipsBus bus, uint va) + { + if (_stk2470Busy) + return va; + if (!_leftoverWait99O32NkCoredllSawEntry || !_jalrE478JrLogged) + return va; + if ((va & ~0xFFFu) != CoredllDllMainStk2470Page) + return va; + if (_stk2470SwLogged) + return va; + if (_stk2470Kseg != 0) + return _stk2470Kseg | (va & 0xFFFu); + if (_stk2470Done) + return va; + TryResolveStk2470(bus, va); + if (_stk2470Kseg != 0) + return _stk2470Kseg | (va & 0xFFFu); + return va; + } + + public static uint MapC0000088Va(MipsBus bus, uint va) + { + if (_c000Busy) + return va; + if (!_leftoverWait99O32NkCoredllSawEntry || !_stk1670SbLogged) + return va; + if (!IsC000StoreSkipVa(va)) + return va; + if (_c000Kseg != 0) + return _c000Kseg | (va & 0xFFFu); + if (_c000Done) + return va; + TryResolveC0000088(bus, va, null); + if (_c000Kseg != 0) + return _c000Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsC000StoreSkipVa(uint va) + { + uint page = va & ~0xFFFu; + if (page == 0) + return false; + if (page == FfffF000Page || va >= FfffF000Page) + return false; + if (page == FfffE000Page) + return false; + if (va >= CoredllDllMainC000Page && va <= CoredllDllMainCksegHi) + return true; + // Live f48c2dc: a1=0xFFFF0288 + // above FFFEFFFF, KData-class, + // not SUD / not E000. + return va >= CoredllDllMainFfffKdataLo + && va <= CoredllDllMainFfffKdataHi; + } + + private static bool CanPeekC000StoreDest(MipsBus bus, uint va) + { + uint peek = 0; + return TryPeekWord(bus, va, out peek); + } + + // Live 7ad9ab2: c000-0088 tlb-none + // and v0-kseg0-miss (v0=*a0= + // 0xBFFFF288). Firmware PTE L1 + // index is page 0 — refuse. + // Live 98276c7: skip 0xC0000088 + // then sibling a1=0xC0001070. + // Live faf00f3: skip ×4 then + // a1=0xC1000070 (not 0xC000xxxx). + // Live e7f0f37: skip 0088…0E88 + // then a1=0xD0000028 (kseg2). + // Live 71fd3f6: skip ×16 then + // a1=0xE0000688 (kseg3-low). + // Live e9baf25: skip ×24 then + // a1=0xF0000288 (kseg3). + // Live f48c2dc: skip ×32 then + // a1=0xFFFF0288 (KData-class). + // Swallow dest-miss sw $v0,0($a1) + // in C0000000–FFFEFFFF and + // FFFF0000–FFFFDFFF when dest + // cannot peek so next + // sw $a1,0($a0) / jr $ra can run. + // Do not invent those pages / + // page 0 / SUD 0xFFFFF000 / + // 0xFFFFE000. + // Boot 0e9d76d: leftover chain / + // coredll-page maps hit list-insert + // 0x800151D0 a1=0xC0002BC8 TLBS + // before nest-1670. Arm dest-miss + // skip from leftover entry or that + // EPC. Do not invent 0xC0002000. + private static bool IsDumpMemListInsertStoreSkipArmed(MipsBus bus) + { + if (_leftoverWait99O32NkCoredllSawEntry) + return true; + if (bus == null) + return false; + uint epc = bus.PeekEpc(); + return epc == CoredllDllMainC000Epc + || epc == CoredllDllMainC000NextPc; + } + + public static bool TrySkipC0000088Store(MipsBus bus, uint va, uint value) + { + if (!IsDumpMemListInsertStoreSkipArmed(bus)) + return false; + if (!IsC000StoreSkipVa(va)) + return false; + if (_c000Kseg != 0 || _c000Busy) + return false; + if (CanPeekC000StoreDest(bus, va)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000Epc, out dump) + || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + // Boot a654026: 40 unique C000 dests + // was climb, then useg. Log the + // class once — skip still runs. + if (_c000SkipN < 1 && _c000SkipLast != va) + { + _c000SkipLast = va; + _c000SkipN++; + _c000SkipLogged = true; + uint next = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000NextPc, out next) + || next == 0) + next = CoredllDllMainC000Next; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk c000-0088 store-skip" + + " epc=0x" + CoredllDllMainC000Epc.ToString("X") + + " bad=0x" + va.ToString("X") + + " word=0x" + dump.ToString("X") + + " next=0x" + next.ToString("X") + + " next-pc=0x" + CoredllDllMainC000NextPc.ToString("X") + + " val=0x" + value.ToString("X") + + " via=c000-store-skip" + + " (dump sw $v0,0($a1); dest miss; continue" + + " sw $a1,0($a0); no invent 0xFFFF0288/E000/SUD)"); + } + return true; + } + + private static bool IsFfffE000ListInsertSkipVa(uint va) + { + if ((va & ~0xFFFu) != FfffE000Page) + return false; + if (va >= FfffF000Page) + return false; + return true; + } + + // Live 20f3972: dump-match + // sw $v0,0($a1) a1=0xFFFFE288 + // (never-wired E000). Skip dest- + // miss like list-insert so next + // sw $a1,0($a0) / jr $ra can run. + // Do not map/invent E000 / SUD. + // Zero-byte stays on sb-zero / + // sud-beq0. One-shot log. + public static bool TrySkipFfffE000ListInsertStore(MipsBus bus, uint va, + uint value) + { + if (!IsDumpMemListInsertStoreSkipArmed(bus)) + return false; + if (!IsFfffE000ListInsertSkipVa(va)) + return false; + if ((value & 0xFFu) == 0) + return false; + // Boot 07cb2b3: after bada-a0-restore + // kseg/busy returned false with no + // Hive — last line stayed bad-a. + // Dest-miss still skip. Do not + // write / invent E000. + if ((_ffffE000Kseg != 0 || _ffffE000Busy) && !_badASrcLogged) + return false; + if (CanPeekC000StoreDest(bus, va)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000Epc, out dump) + || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + if (!_c000E000SkipLogged) + { + _c000E000SkipLogged = true; + uint next = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000NextPc, out next) + || next == 0) + next = CoredllDllMainC000Next; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk e000-0288 store-skip" + + " epc=0x" + CoredllDllMainC000Epc.ToString("X") + + " bad=0x" + va.ToString("X") + + " word=0x" + dump.ToString("X") + + " next=0x" + next.ToString("X") + + " next-pc=0x" + CoredllDllMainC000NextPc.ToString("X") + + " val=0x" + value.ToString("X") + + " via=e000-store-skip" + + " (dump sw $v0,0($a1); dest miss; continue" + + " sw $a1,0($a0); no invent E000/SUD)"); + } + return true; + } + + private static bool IsFfffF000ListInsertSkipVa(uint va) + { + if (va < FfffF000Page) + return false; + if ((va & ~0xFFFu) == FfffE000Page) + return false; + return true; + } + + // Live c270933: dump-match + // sw $v0,0($a1) a1=0xFFFFF088 + // (never-wired SUD). Skip dest- + // miss like e000-store-skip so + // next sw $a1,0($a0) / jr $ra + // can run. Do not map/invent + // SUD F000 / E000. Zero-byte + // stays on sb-zero / sud-beq0. + // One-shot via=f000-store-skip. + public static bool TrySkipFfffF000ListInsertStore(MipsBus bus, uint va, + uint value) + { + if (!IsDumpMemListInsertStoreSkipArmed(bus)) + return false; + if (!IsFfffF000ListInsertSkipVa(va)) + return false; + if ((value & 0xFFu) == 0) + return false; + if (_ffffF000Busy) + return false; + if (_ffffF000Kseg == FfffF000Page) + _ffffF000Kseg = 0; + if (_ffffF000Kseg != 0) + return false; + if (CanPeekC000StoreDest(bus, va)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000Epc, out dump) + || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + if (!_c000F000SkipLogged) + { + _c000F000SkipLogged = true; + uint next = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000NextPc, out next) + || next == 0) + next = CoredllDllMainC000Next; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk f000-f088 store-skip" + + " epc=0x" + CoredllDllMainC000Epc.ToString("X") + + " bad=0x" + va.ToString("X") + + " word=0x" + dump.ToString("X") + + " next=0x" + next.ToString("X") + + " next-pc=0x" + CoredllDllMainC000NextPc.ToString("X") + + " val=0x" + value.ToString("X") + + " via=f000-store-skip" + + " (dump sw $v0,0($a1); dest miss; continue" + + " sw $a1,0($a0); no invent SUD/E000)"); + } + return true; + } + + private static bool IsPage0ListInsertSkipVa(uint va) + { + return va < 0x1000u; + } + + // Live 738e467: dump-match + // sw $v0,0($a1) a1=0x70 (page 0). + // Skip dest-miss like f000/e000 + // so next sw $a1,0($a0) / jr $ra + // can run. Do not map/invent + // page 0 / 0x80000070. Zero-byte + // stays on sb-zero. One-shot + // via=page0-store-skip. + public static bool TrySkipPage0ListInsertStore(MipsBus bus, uint va, + uint value) + { + if (!IsDumpMemListInsertStoreSkipArmed(bus)) + return false; + if (!IsPage0ListInsertSkipVa(va)) + return false; + if ((value & 0xFFu) == 0) + return false; + if (CanPeekC000StoreDest(bus, va)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000Epc, out dump) + || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + if (!_c000Page0SkipLogged) + { + _c000Page0SkipLogged = true; + uint next = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000NextPc, out next) + || next == 0) + next = CoredllDllMainC000Next; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk page0-0070 store-skip" + + " epc=0x" + CoredllDllMainC000Epc.ToString("X") + + " bad=0x" + va.ToString("X") + + " word=0x" + dump.ToString("X") + + " next=0x" + next.ToString("X") + + " next-pc=0x" + CoredllDllMainC000NextPc.ToString("X") + + " val=0x" + value.ToString("X") + + " via=page0-store-skip" + + " (dump sw $v0,0($a1); dest miss; continue" + + " sw $a1,0($a0); no invent page 0 / 0x80000070)"); + } + return true; + } + + private static bool IsLowUsegListInsertSkipVa(uint va) + { + return va >= 0x1000u && va <= CoredllDllMainLowUsegHi; + } + + // Live fe74462: dump-match + // sw $v0,0($a1) a1=0x1028 (low + // useg above page 0). Boot + // c3e1614: same site a1=0x14E88 + // (page 0x14000, above 0xFFFF). + // Skip dest-miss like page0 so + // next sw $a1,0($a0) / jr $ra + // can run. Do not map/invent + // 0x1000–0x1FFFF. No WalkFirmwarePte. + // Zero-byte stays on sb-zero. + // Unique-dest log (cap 16) so + // 14E88 climb is visible; not a + // C000-style 40-line storm. + public static bool TrySkipLowUsegListInsertStore(MipsBus bus, uint va, + uint value) + { + if (!IsDumpMemListInsertStoreSkipArmed(bus)) + return false; + if (!IsLowUsegListInsertSkipVa(va)) + return false; + if ((value & 0xFFu) == 0) + return false; + if (CanPeekC000StoreDest(bus, va)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000Epc, out dump) + || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + if (_c000LowUsegSkipN < 1 && _c000LowUsegSkipLast != va) + { + _c000LowUsegSkipLast = va; + _c000LowUsegSkipN++; + _c000LowUsegSkipLogged = true; + uint next = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000NextPc, out next) + || next == 0) + next = CoredllDllMainC000Next; + string hive = va > 0xFFFFu + ? "lowuseg-14e88 store-skip" + : "lowuseg-1028 store-skip"; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk " + hive + + " epc=0x" + CoredllDllMainC000Epc.ToString("X") + + " bad=0x" + va.ToString("X") + + " word=0x" + dump.ToString("X") + + " next=0x" + next.ToString("X") + + " next-pc=0x" + CoredllDllMainC000NextPc.ToString("X") + + " val=0x" + value.ToString("X") + + " via=lowuseg-store-skip" + + " (dump sw $v0,0($a1); dest miss; continue" + + " sw $a1,0($a0); no invent 0x1000-0x1FFFF)"); + } + return true; + } + + // Boot a654026: STOP range bumps + // (1000→FFFF→1FFFF→25068). One + // dump-true rule at list-insert + // 0x800151D0: dump sw $v0,0($a1); + // $a1 dest-miss (cannot peek); + // skip store; PC:=0x800151D4. + // Log once per dest class. Do + // not invent pages / leftover + // hop dest / GetProc / fp50. + // No hop 0x8003F8B4. Class + // helpers still log e000-0288 + // when dest is E000. + private static bool IsListInsertDestRefuseVa(uint va) + { + if (va == 0 || (va & 3) != 0) + return true; + if (IsLeftoverDestVa(va)) + return true; + if (va == LeftoverWait99GetProcDest + || va == LeftoverWait99O32RefuseRa + || va == LeftoverWait99O32RefuseDump + || va == CoredllDllMainKdataWrapRefuse) + return true; + if (IsWrapDestFp50Va(va) || va == WrapDestFp50FillLive) + return true; + return false; + } + + private static int ListInsertDestClassId(uint va) + { + if (IsFfffE000ListInsertSkipVa(va)) + return 1; + if (IsFfffF000ListInsertSkipVa(va)) + return 2; + if (IsPage0ListInsertSkipVa(va)) + return 3; + if (va >= 0x1000u && va <= 0xFFFFu) + return 4; + if (va >= 0x10000u && va < 0x80000000u) + return 5; + if (IsC000StoreSkipVa(va)) + return 6; + if (va >= 0x9A000000u && va < 0x9B000000u) + return 7; + if (va >= 0x9F000000u && va < 0xA0000000u) + return 8; + return 9; + } + + private static string ListInsertDestClassName(int id) + { + switch (id) + { + case 1: return "e000"; + case 2: return "f000"; + case 3: return "page0"; + case 4: return "lowuseg"; + case 5: return "kuseg"; + case 6: return "c000"; + case 7: return "9a"; + case 8: return "9f"; + default: return "other"; + } + } + + private static bool TryLogListInsertDestMissOnce(uint va, uint value, + uint dump) + { + int id = ListInsertDestClassId(va); + uint bit = 1u << id; + if ((_listInsertDestClassLogged & bit) != 0) + return false; + _listInsertDestClassLogged |= bit; + if (id == 1) + _c000E000SkipLogged = true; + else if (id == 2) + _c000F000SkipLogged = true; + else if (id == 3) + _c000Page0SkipLogged = true; + else if (id == 4 || id == 5) + { + _c000LowUsegSkipLogged = true; + _c000LowUsegSkipLast = va; + _c000LowUsegSkipN++; + } + else if (id == 6) + { + _c000SkipLogged = true; + _c000SkipLast = va; + _c000SkipN++; + } + uint next = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000NextPc, out next) + || next == 0) + next = CoredllDllMainC000Next; + string cls = ListInsertDestClassName(id); + string hive = id == 1 + ? "e000-0288 store-skip" + : "list-insert dest-miss"; + string via = id == 1 + ? "e000-store-skip" + : "list-insert-dest-miss"; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk " + hive + + " epc=0x" + CoredllDllMainC000Epc.ToString("X") + + " bad=0x" + va.ToString("X") + + " class=" + cls + + " word=0x" + dump.ToString("X") + + " next=0x" + next.ToString("X") + + " next-pc=0x" + CoredllDllMainC000NextPc.ToString("X") + + " val=0x" + value.ToString("X") + + " via=" + via + + " (dump sw $v0,0($a1); dest miss; continue" + + " sw $a1,0($a0); no invent; no range bump)"); + return true; + } + + private static bool TrySkipListInsertClassStore(MipsBus bus, uint va, + uint value) + { + if (IsFfffE000ListInsertSkipVa(va)) + return TrySkipFfffE000ListInsertStore(bus, va, value); + if (IsFfffF000ListInsertSkipVa(va)) + return TrySkipFfffF000ListInsertStore(bus, va, value); + if (IsPage0ListInsertSkipVa(va)) + return TrySkipPage0ListInsertStore(bus, va, value); + if (IsLowUsegListInsertSkipVa(va)) + return TrySkipLowUsegListInsertStore(bus, va, value); + if (IsC000StoreSkipVa(va)) + return TrySkipC0000088Store(bus, va, value); + return false; + } + + // Write32 backup when I-fetch Take + // did not run (EPC already 151D0 + // from a prior TLBS). Same dest-miss + // rule. Do not leftover-skip every + // unbacked store. + public static bool TrySkipListInsertAnyDestMiss(MipsBus bus, uint va, + uint value) + { + if (bus == null) + return false; + uint epc = bus.PeekEpc(); + if (epc != CoredllDllMainC000Epc + && epc != CoredllDllMainC000NextPc) + return false; + if (IsListInsertDestRefuseVa(va)) + return false; + if (CanPeekC000StoreDest(bus, va)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainC000Epc, out dump) + || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + TryLogListInsertDestMissOnce(va, value, dump); + return true; + } + + public static bool TryTakeDumpMemListInsertDestMiss(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (pc != CoredllDllMainC000Epc) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainC000NextPc)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainC000Dump; + if (dump != CoredllDllMainC000Dump) + return false; + if (insn != 0 && insn != dump && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + uint a1 = PeekGpr(regs, 5); + uint v0 = PeekGpr(regs, 2); + if (IsListInsertDestRefuseVa(a1)) + return false; + if (CanPeekC000StoreDest(bus, a1)) + return false; + if (!TrySkipListInsertClassStore(bus, a1, v0)) + TryLogListInsertDestMissOnce(a1, v0, dump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = CoredllDllMainC000NextPc; + return true; + } + + public static uint MapBadAVa(MipsBus bus, uint va) + { + if (_badABusy) + return va; + if (!_leftoverWait99O32NkCoredllSawEntry || !_abs6670JalTakenLogged) + return va; + if (!IsBadAPage0Half(va)) + return va; + if (_badAKseg != 0) + return _badAKseg | (va & 0xFFFu); + if (_badADone) + return va; + TryResolveBadA(bus, va, null); + if (_badAKseg != 0) + return _badAKseg | (va & 0xFFFu); + return va; + } + + // TLB first. Never WalkFirmwarePte (page 0). + // Never map kseg0 0x8000000A (phys<0x10000). + // Map only if dest peeks phys>=0x10000. + private static void TryResolveBadA(MipsBus bus, uint va, uint[] regs) + { + if (bus == null || _badABusy || _badADone) + return; + if (!IsBadAPage0Half(va)) + return; + try + { + _badABusy = true; + uint pfn = 0; + bool valid = false; + bool tlb = bus.TryFindTlbPfn(va, out pfn, out valid) && valid; + if (tlb) + { + uint phys = pfn << 12; + uint kseg = 0x80000000u | (phys & 0x1FFFFFFFu); + uint destw = 0; + if (!IsC000RefuseKseg(kseg) + && TryPeekWord(bus, + (kseg & ~0xFFFu) | (va & 0xFFFu), out destw)) + { + _badAKseg = kseg & ~0xFFFu; + if (!_badAMapLogged) + { + _badAMapLogged = true; + _badADone = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a map va=0x" + + va.ToString("X") + + " -> 0x" + _badAKseg.ToString("X8") + + " pfn=0x" + pfn.ToString("X") + + " dest-word=0x" + destw.ToString("X") + + " via=tlb" + + " (dump lhu $v1,0($a1); peek dest; do not invent page 0)"); + } + return; + } + } + if (regs == null) + return; + _badADone = true; + } + finally + { + _badABusy = false; + } + } + + private static bool IsBadAPage0Half(uint va) + { + return va == CoredllDllMainBadABad + || va == (CoredllDllMainBadABad + 1); + } + + private static bool IsBadADestA0Ok(MipsBus bus, uint src) + { + if (src == 0 || (src & 1) != 0) + return false; + if ((src & ~0xFFFu) == 0) + return false; + if (IsC000RefuseKseg(src & ~0xFFFu) || IsDumpMemRefuseVa(src)) + return false; + uint w = 0; + if (TryPeekLeftoverWait99DumpOnly(src, out w) && w != 0) + return true; + return bus != null && TryPeekWord(bus, src, out w); + } + + private static uint PeekBadADestA0(MipsBus bus) + { + uint src = _abs6670JalA0; + if (IsBadADestA0Ok(bus, src)) + return src; + src = CoredllDllMainBadADestA0; + if (IsBadADestA0Ok(bus, src)) + return src; + return 0; + } + + private static void TryLogBadA1Src(MipsBus bus, uint[] regs, uint pc, + uint liveA1, uint src, string via) + { + if (_badASrcLogged) + return; + _badASrcLogged = true; + uint orLive = 0; + TryPeekWord(bus, CoredllDllMainBadAOrA1Pc, out orLive); + uint orDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAOrA1Pc, out orDump) + || orDump == 0) + orDump = CoredllDllMainBadAOrA1Dump; + uint beq = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadABeqPc, out beq) + || beq == 0) + beq = CoredllDllMainBadABeqDump; + uint a0 = PeekGpr(regs, 4); + uint a1After = PeekGpr(regs, 5); + uint ra = PeekGpr(regs, 31); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a a1-src" + + " epc=0x" + pc.ToString("X") + + " a1=0x" + liveA1.ToString("X") + + " a1-after=0x" + a1After.ToString("X") + + " dest-a0=0x" + src.ToString("X") + + " jal-a0=0x" + _abs6670JalA0.ToString("X") + + " or-pc=0x" + CoredllDllMainBadAOrA1Pc.ToString("X") + + " or-dump=0x" + orDump.ToString("X") + + " or-live=0x" + orLive.ToString("X") + + " or-dis=" + FormatMipsOp(CoredllDllMainBadAOrA1Pc, orDump) + + " beq=0x" + beq.ToString("X") + + " a0=0x" + a0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " via=" + via + + " (dump or $a1,$a0,$0 copies dest jal $a0;" + + " a1-after is GISB WCHAR not stack; no invent page 0)"); + } + + // Live 4bd64a2: $a1=0xA at lhu. + // Dump 0x80043244 or $a1,$a0,$0 + // should copy dest jal $a0 + // (0x800133EC). Heal that or if + // live is abs-store (dump-mem + // refuses: dump is not memop). + // If $a0 is page 0 here, restore + // dest $a0 first. Do not invent + // VA=0xA. Do not leftover-hop. + private static void TryHealBadAOrA1(MipsBus bus, uint[] regs, uint pc, + ref uint insn) + { + if (bus == null || pc != CoredllDllMainBadAOrA1Pc) + return; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainBadAOrA1Dump; + if (dump != CoredllDllMainBadAOrA1Dump) + return; + uint live = insn; + if (live == 0) + TryPeekWord(bus, pc, out live); + if (live != dump && (live == 0 || IsMipsAbsRs0Store(live))) + { + TryHealDumpInsn(bus, pc, live, dump); + insn = dump; + } + uint a0 = PeekGpr(regs, 4); + uint src = PeekBadADestA0(bus); + TrySaveBadAListInsertGprs(regs); + if ((a0 & ~0xFFFu) == 0 && src != 0) + { + uint liveA1 = PeekGpr(regs, 5); + PokeGpr(regs, 4, src); + PokeGpr(regs, 5, src); + TryLogBadA1Src(bus, regs, pc, liveA1, src, + "bada-a0-restore"); + _badARestoreLogged = true; + } + } + + // Live 4bd64a2: lhu base $a1=0xA. + // Restore dest jal $a0 so lhu + // reads the dump-true WCHAR + // (GISB Timeout). Do not map + // page 0. Do not leftover-hop. + public static void TryFixBadA1Source(MipsBus bus, uint[] regs, uint pc, + ref uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_abs6670JalTakenLogged) + return; + if ((pc & 3) != 0 || regs == null) + return; + if (pc == CoredllDllMainBadAOrA1Pc) + TryHealBadAOrA1(bus, regs, pc, ref insn); + if (pc != CoredllDllMainBadAEpc) + return; + uint a1 = PeekGpr(regs, 5); + if ((a1 & ~0xFFFu) != 0) + return; + uint src = PeekBadADestA0(bus); + if (src == 0) + return; + TrySaveBadAListInsertGprs(regs); + PokeGpr(regs, 5, src); + TryLogBadA1Src(bus, regs, pc, a1, src, "bada-a1-restore"); + _badARestoreLogged = true; + } + + private static bool IsExn15C28BadABeforeE000() + { + return _badASrcLogged && !_c000E000SkipLogged; + } + + private static bool IsExn15C28RetCallerRaCapLeave(uint leave) + { + return leave == CoredllDllMainExn15C28OuterJalLink + || leave == CoredllDllMainExn15C28OuterJalLinkAfter + || leave == CoredllDllMainExn15C28OuterJalLinkT1 + || leave == CoredllDllMainExn15C28OuterJalLinkBne + || leave == CoredllDllMainExn15C28OuterJalLinkBneFall + || leave == CoredllDllMainExn15C28OuterJalLinkBneTaken + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi + || IsExn15C28FallEpiLwPc(leave) + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn; + } + + // Boot 07cb2b3 / 5a2878a: after + // bada-a0-restore, ProgressLeave + // yank to 3F78C+ never fetched + // 0x800151D0. Refuse that cap + // until e000-0288 store-skip. + // Keep RetCallerRa inDelay land + // once e000 has logged. + private static bool RefuseExn15C28BadABeforeE000Yank(uint pc, uint leave) + { + if (!IsExn15C28BadABeforeE000()) + return false; + if (!IsExn15C28RetCallerRaCapLeave(leave)) + return false; + if (!_badABeforeE000YankLogged) + { + _badABeforeE000YankLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a before-e000 cap-refuse" + + " pc=0x" + pc.ToString("X") + + " leave=0x" + leave.ToString("X") + + " via=bada-before-e000" + + " (ProgressLeave yank after bada-a0-restore aborted" + + " list-insert 0x800151D0; keep dump-true jal 0x80042920;" + + " no invent E000/F000/SUD; no leftover-hop)"); + } + return true; + } + + // Live 8cae3af: after bada-a0-restore + // at 0x80043244, next is addiu $a3 + // + jal 0x80042920 then e000-0288 + // at 0x800151D0. Tip silent Take / + // ProgressLeave yanked off that + // I-fetch. Dump-true continue only. + // Do not leftover-hop. Do not invent + // E000 / F000 / SUD / 0x9A. + public static bool TryTakeDumpMemBadAAfterRestore(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_abs6670JalTakenLogged) + return false; + if (!_badASrcLogged || _badAJalContinueLogged) + return false; + if (inDelay) + return false; + if (pc != CoredllDllMainBadAOrA1Pc + && pc != CoredllDllMainBadAJalPc) + return false; + uint orDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAOrA1Pc, out orDump) + || orDump == 0) + orDump = CoredllDllMainBadAOrA1Dump; + uint addiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAAddiuPc, out addiuDump) + || addiuDump == 0) + addiuDump = CoredllDllMainBadAAddiuDump; + uint jalDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAJalPc, out jalDump) + || jalDump == 0) + jalDump = CoredllDllMainBadAJalDump; + uint delayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAJalPc + 4, out delayDump) + || delayDump == 0) + delayDump = CoredllDllMainBadAJalDelayDump; + if (orDump != CoredllDllMainBadAOrA1Dump + || addiuDump != CoredllDllMainBadAAddiuDump + || jalDump != CoredllDllMainBadAJalDump + || delayDump != CoredllDllMainBadAJalDelayDump) + return false; + if ((jalDump >> 26) != 3) + return false; + uint dest = (CoredllDllMainBadAJalPc & 0xF0000000u) + | ((jalDump & 0x03FFFFFFu) << 2); + if (dest != CoredllDllMainBadAJalDest) + return false; + if (IsDumpMemRefuseVa(dest) || IsLeftoverDestVa(dest) + || dest == LeftoverWait99GetProcDest + || IsWrapDestSize(dest) || IsWrapDestFp50Va(dest)) + return false; + if (!IsDumpMemAluInsn(orDump) || !IsDumpMemAluInsn(addiuDump) + || !IsDumpMemAluInsn(delayDump)) + return false; + if (pc == CoredllDllMainBadAOrA1Pc + && insn != 0 && insn != orDump && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (pc == CoredllDllMainBadAJalPc + && insn != 0 && insn != jalDump && !IsMipsJumpOrJr(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (pc == CoredllDllMainBadAOrA1Pc && insn != orDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, orDump); + if (pc == CoredllDllMainBadAJalPc && insn != jalDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, jalDump); + TrySaveBadAListInsertGprs(regs); + if (!TryExecDumpMemAlu(regs, orDump) + || !TryExecDumpMemAlu(regs, addiuDump) + || !TryExecDumpMemAlu(regs, delayDump)) + return false; + PokeGpr(regs, 31, CoredllDllMainBadACallerRa); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = dest; + _badAJalContinueLogged = true; + uint a0 = PeekGpr(regs, 4); + uint a1 = PeekGpr(regs, 5); + uint ra = PeekGpr(regs, 31); + uint fp = PeekGpr(regs, 30); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "bada-jal-continue"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a jal-continue" + + " pc=0x" + pc.ToString("X") + + " next=0x" + dest.ToString("X") + + " ra=0x" + ra.ToString("X") + + " a0=0x" + a0.ToString("X") + + " a1=0x" + a1.ToString("X") + + " fp=0x" + fp.ToString("X") + + " via=bada-jal-continue" + + " (dump addiu $a3 + jal 0x80042920; delay or $a0,$fp;" + + " toward e000-0288 0x800151D0; no invent E000/F000/SUD;" + + " no leftover-hop)"); + return true; + } + + // Boot 8f64660: jal-continue landed + // 0x80042920 then froze (e000=0). + // Callee prologue sw / not-% sh + // dest-miss 0x9A / 0x80320A40 — + // no invent. Dump-true walk ALU + + // overlay peek; skip dest-miss + // store; shadow $sp slots; skip + // helper jals / 0x800423F0; then + // leftover list-insert sw at + // 0x800151D0 so Hive logs + // e000-0288 like 8cae3af. + // Refuse ProgressLeave 3F78C+ + // until e000. Keep RetCallerRa + // inDelay once e000 logs. + public static bool TryTakeDumpMemBadACalleeContinue(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_abs6670JalTakenLogged) + return false; + if (!_badAJalContinueLogged || _badACalleeContinueLogged) + return false; + if (_c000E000SkipLogged) + return false; + if (inDelay) + return false; + if (pc != CoredllDllMainBadAJalDest) + return false; + if (IsDumpMemRefuseVa(pc) || IsLeftoverDestVa(pc) + || IsWrapDestSize(pc) || IsWrapDestFp50Va(pc)) + return false; + uint first = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAJalDest, out first) + || first == 0) + return false; + if (!IsDumpMemAluInsn(first)) + return false; + if (insn != 0 && insn != first && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn) && !IsMipsLoad(insn) + && !IsMipsStore(insn) && !IsMipsJumpOrJr(insn)) + return false; + TrySaveBadAListInsertGprs(regs); + if (!TryWalkDumpMemBadACallee(bus, regs, pc)) + return false; + if (!TryResumeBadAListInsert(bus, regs, pc, ref cpuPc)) + return false; + _badACalleeContinueLogged = true; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "bada-callee-continue"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a callee-continue" + + " pc=0x" + pc.ToString("X") + + " next=0x" + cpuPc.ToString("X") + + " ra=0x" + PeekGpr(regs, 31).ToString("X") + + " a0=0x" + PeekGpr(regs, 4).ToString("X") + + " a1=0x" + PeekGpr(regs, 5).ToString("X") + + " s6=0x" + PeekGpr(regs, 22).ToString("X") + + " v0=0x" + PeekGpr(regs, 2).ToString("X") + + " via=bada-callee-continue" + + " (dump-true 0x80042920 through list-insert" + + " 0x800151D0; skip dest-miss 9A/8032; skip" + + " helper jal / 0x800423F0; refuse ProgressLeave" + + " 3F78C+ until e000-0288; no invent E000/F000/SUD;" + + " no leftover-hop)"); + return true; + } + + public static bool TrySkipBadABeforeE000DestMissStore(MipsBus bus, uint va) + { + if (!IsExn15C28BadABeforeE000()) + return false; + if (IsFfffE000ListInsertSkipVa(va) || IsFfffF000ListInsertSkipVa(va)) + return false; + if (!IsExn15C28NoInventPage(va) && !IsExn15C28Na02Frame(va)) + return false; + return true; + } + + private static void TrySaveBadAListInsertGprs(uint[] regs) + { + if (regs == null || _badAListSaved) + return; + uint a1 = PeekGpr(regs, 5); + uint s6 = PeekGpr(regs, 22); + _badAWrapperRa = PeekGpr(regs, 31); + _badAListA0 = PeekGpr(regs, 4); + _badAListV0 = PeekGpr(regs, 2); + _badAListS6 = s6; + if (IsBadAListInsertResumeVa(a1)) + _badAListA1 = a1; + else if (IsBadAListInsertResumeVa(s6)) + _badAListA1 = s6; + _badAListSaved = true; + } + + private static bool IsBadAListInsertResumeVa(uint va) + { + return IsFfffE000ListInsertSkipVa(va) + || IsFfffF000ListInsertSkipVa(va) + || IsPage0ListInsertSkipVa(va) + || IsLowUsegListInsertSkipVa(va); + } + + private static bool IsBadACalleeHelperJalDest(uint dest) + { + return dest == CoredllDllMainBadASecondJalDest + || dest == 0x800426E0u || dest == 0x800595CCu + || dest == 0x8003A170u || dest == 0x8004280Cu + || dest == 0x80042774u || dest == 0x80058764u + || dest == 0x80048128u || dest == 0x80048174u + || dest == 0x80048198u; + } + + private static bool TryPeekLeftoverWait99DumpHalf(uint va, out ushort half) + { + half = 0; + uint word = 0; + uint aligned = va & ~3u; + if ((va & 1) != 0) + return false; + if (!TryPeekLeftoverWait99DumpOnly(aligned, out word)) + return false; + half = (ushort)(((va & 2) != 0) ? (word >> 16) : word); + return true; + } + + private static bool TryWalkDumpMemBadACallee(MipsBus bus, uint[] regs, + uint startPc) + { + if (regs == null || startPc != CoredllDllMainBadAJalDest) + return false; + uint[] shadow = new uint[32]; + bool[] shadowHit = new bool[32]; + uint pc = startPc; + PokeGpr(regs, 31, CoredllDllMainBadACallerRa); + for (int step = 0; step < 8192; step++) + { + if ((pc & 3) != 0 || IsDumpMemRefuseVa(pc) + || IsLeftoverDestVa(pc) || IsWrapDestSize(pc) + || IsWrapDestFp50Va(pc) || IsExn15C28NoInventPage(pc)) + return true; + if (IsExn15C28RetCallerRaCapLeave(pc)) + return true; + uint insn = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out insn)) + return true; + uint op = insn >> 26; + uint fn = insn & 63; + int rs = (int)((insn >> 21) & 31); + int rt = (int)((insn >> 16) & 31); + int simm = (short)(insn & 0xFFFF); + uint rsv = PeekGpr(regs, rs); + uint ea = rsv + (uint)simm; + uint sp = PeekGpr(regs, 29); + if (op == 3) + { + uint dest = (pc & 0xF0000000u) | ((insn & 0x03FFFFFFu) << 2); + uint delay = 0; + TryPeekLeftoverWait99DumpOnly(pc + 4, out delay); + if (delay != 0 && !TryExecBadACalleeMemOrAlu(regs, delay, + shadow, shadowHit, PeekGpr(regs, 29))) + return true; + if (dest == CoredllDllMainBadAListInsert + || dest == CoredllDllMainC000Epc) + return true; + if (IsBadACalleeHelperJalDest(dest) + || dest == CoredllDllMainBadAJalDest) + { + if (dest == CoredllDllMainBadASecondJalDest + || dest == 0x800426E0u) + { + pc = CoredllDllMainBadACalleeEpi; + if (pc == startPc) + return true; + continue; + } + pc += 8; + continue; + } + pc += 8; + continue; + } + if (op == 0 && fn == 8 && rs == 31) + { + uint delay = 0; + TryPeekLeftoverWait99DumpOnly(pc + 4, out delay); + if (delay != 0 && !TryExecBadACalleeMemOrAlu(regs, delay, + shadow, shadowHit, PeekGpr(regs, 29))) + return true; + return true; + } + if (op == 2) + { + uint dest = (pc & 0xF0000000u) | ((insn & 0x03FFFFFFu) << 2); + uint delay = 0; + TryPeekLeftoverWait99DumpOnly(pc + 4, out delay); + if (delay != 0 && !TryExecBadACalleeMemOrAlu(regs, delay, + shadow, shadowHit, PeekGpr(regs, 29))) + return true; + if (dest == 0 || (dest & 3) != 0 || IsDumpMemRefuseVa(dest) + || IsExn15C28NoInventPage(dest) + || IsExn15C28RetCallerRaCapLeave(dest)) + return true; + pc = dest; + continue; + } + if (op == 4 || op == 5 || op == 6 || op == 7) + { + uint delay = 0; + TryPeekLeftoverWait99DumpOnly(pc + 4, out delay); + if (delay != 0 && !TryExecBadACalleeMemOrAlu(regs, delay, + shadow, shadowHit, PeekGpr(regs, 29))) + return true; + uint rtv = PeekGpr(regs, rt); + bool take = false; + if (op == 4) + take = rsv == rtv; + else if (op == 5) + take = rsv != rtv; + else if (op == 6) + take = (int)rsv <= 0; + else + take = (int)rsv > 0; + uint target = unchecked(pc + 4u + (uint)(simm * 4)); + if (take && (target & 3) == 0 + && !IsDumpMemRefuseVa(target) + && !IsExn15C28NoInventPage(target) + && !IsExn15C28RetCallerRaCapLeave(target)) + pc = target; + else + pc += 8; + continue; + } + if (pc == 0x80042994u) + { + pc = CoredllDllMainBadACalleeEpi; + continue; + } + if (!TryExecBadACalleeMemOrAlu(regs, insn, shadow, shadowHit, sp)) + return true; + pc += 4; + if (pc == CoredllDllMainBadASecondJalPc) + { + uint delay = CoredllDllMainBadASecondJalDelayDump; + if (IsDumpMemAluInsn(delay)) + TryExecDumpMemAlu(regs, delay); + return true; + } + } + return true; + } + + private static bool TryExecBadACalleeMemOrAlu(uint[] regs, uint insn, + uint[] shadow, bool[] shadowHit, uint sp) + { + if (insn == 0) + return true; + if (IsDumpMemAluInsn(insn)) + return TryExecDumpMemAlu(regs, insn); + uint op = insn >> 26; + int rs = (int)((insn >> 21) & 31); + int rt = (int)((insn >> 16) & 31); + int simm = (short)(insn & 0xFFFF); + uint ea = PeekGpr(regs, rs) + (uint)simm; + if (IsMipsStore(insn)) + { + if (IsFfffE000ListInsertSkipVa(ea) + || IsFfffF000ListInsertSkipVa(ea)) + return true; + if (IsExn15C28NoInventPage(ea) || IsExn15C28Na02Frame(ea)) + { + TryShadowBadASpStore(shadow, shadowHit, sp, ea, + PeekGpr(regs, rt)); + return true; + } + TryShadowBadASpStore(shadow, shadowHit, sp, ea, + PeekGpr(regs, rt)); + return true; + } + if (IsMipsLoad(insn)) + { + uint word = 0; + if (TryLoadBadASpShadow(shadow, shadowHit, sp, ea, out word)) + { + if (op == 0x25 || op == 0x21) + { + ushort half = (ushort)(((ea & 2) != 0) ? (word >> 16) : word); + if (op == 0x21) + PokeGpr(regs, rt, (uint)(short)half); + else + PokeGpr(regs, rt, half); + } + else + PokeGpr(regs, rt, word); + return true; + } + if (op == 0x25 || op == 0x21) + { + ushort half = 0; + if (TryPeekLeftoverWait99DumpHalf(ea, out half)) + { + if (op == 0x21) + PokeGpr(regs, rt, (uint)(short)half); + else + PokeGpr(regs, rt, half); + } + return true; + } + if (TryPeekLeftoverWait99DumpOnly(ea, out word)) + PokeGpr(regs, rt, word); + return true; + } + return true; + } + + private static void TryShadowBadASpStore(uint[] shadow, bool[] shadowHit, + uint sp, uint ea, uint val) + { + if (shadow == null || shadowHit == null || ea < sp) + return; + uint off = ea - sp; + if (off > 124 || (off & 3) != 0) + return; + int i = (int)(off >> 2); + shadow[i] = val; + shadowHit[i] = true; + } + + private static bool TryLoadBadASpShadow(uint[] shadow, bool[] shadowHit, + uint sp, uint ea, out uint val) + { + val = 0; + if (shadow == null || shadowHit == null || ea < sp) + return false; + uint off = ea - sp; + if (off > 124 || (off & 3) != 0) + return false; + int i = (int)(off >> 2); + if (!shadowHit[i]) + return false; + val = shadow[i]; + return true; + } + + private static bool TryResumeBadAListInsert(MipsBus bus, uint[] regs, + uint fromPc, ref uint cpuPc) + { + uint a1 = _badAListA1; + uint s6 = _badAListS6 != 0 ? _badAListS6 : PeekGpr(regs, 22); + if (!IsBadAListInsertResumeVa(a1) && IsBadAListInsertResumeVa(s6)) + a1 = s6; + if (!IsBadAListInsertResumeVa(a1)) + { + uint liveS6 = PeekGpr(regs, 22); + if (IsBadAListInsertResumeVa(liveS6)) + a1 = liveS6; + } + uint leave = CoredllDllMainC000Epc; + if (IsBadAListInsertResumeVa(a1)) + { + uint v0 = _badAListV0; + if ((v0 & 0xFFu) == 0) + v0 = _badAListS6; + if ((v0 & 0xFFu) == 0) + v0 = a1; + if ((v0 & 0xFFu) == 0) + v0 = PeekGpr(regs, 2); + if (_badAListA0 != 0 && !IsExn15C28NoInventPage(_badAListA0) + && (_badAListA0 & ~0xFFFu) != 0) + PokeGpr(regs, 4, _badAListA0); + PokeGpr(regs, 5, a1); + if ((v0 & 0xFFu) != 0) + PokeGpr(regs, 2, v0); + if ((v0 & 0xFFu) != 0 && bus != null) + { + if (IsFfffE000ListInsertSkipVa(a1)) + TrySkipFfffE000ListInsertStore(bus, a1, v0); + else if (IsFfffF000ListInsertSkipVa(a1)) + TrySkipFfffF000ListInsertStore(bus, a1, v0); + else if (IsPage0ListInsertSkipVa(a1)) + TrySkipPage0ListInsertStore(bus, a1, v0); + else if (IsLowUsegListInsertSkipVa(a1)) + TrySkipLowUsegListInsertStore(bus, a1, v0); + } + leave = CoredllDllMainC000Epc; + } + else + { + uint ra = _badAWrapperRa; + if (ra == 0) + ra = PeekGpr(regs, 31); + if (RefuseExn15C28BadABeforeE000Yank(fromPc, ra)) + ra = 0; + if (ra != 0 && (ra & 3) == 0 && !IsDumpMemRefuseVa(ra) + && !IsExn15C28NoInventPage(ra) && !IsLeftoverDestVa(ra) + && !IsWrapDestSize(ra) && !IsWrapDestFp50Va(ra) + && !IsExn15C28RetCallerRaCapLeave(ra) + && ra != CoredllDllMainBadAJalDest + && ra != CoredllDllMainBadACallerRa + && ra != CoredllDllMainBadASecondJalPc + && ra != CoredllDllMainBadAWrapperEpi) + leave = ra; + else + leave = CoredllDllMainBadAWrapperCallerRa; + } + if (leave == 0 || (leave & 3) != 0 || IsDumpMemRefuseVa(leave) + || IsLeftoverDestVa(leave) || IsWrapDestSize(leave) + || IsWrapDestFp50Va(leave) + || IsExn15C28RetCallerRaCapLeave(leave) + || leave == CoredllDllMainBadAJalDest) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(fromPc); + } + cpuPc = leave; + return true; + } + + // Dump 0x80042960 beq $v1,$0,+506 + // empty WCHAR path. Only if dest + // $a0 cannot peek (failed/zero + // base). Return 0 so $v1=0 and + // PC honors next/beq/ra. Like + // sud-beq0-skip. Do not invent + // page 0 / 0x8000000A / C000. + public static bool TrySkipBadALhuZero(MipsBus bus, uint va) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_abs6670JalTakenLogged) + return false; + if (!IsBadAPage0Half(va)) + return false; + if (_badARestoreLogged) + return false; + if (PeekBadADestA0(bus) != 0) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadAEpc, out dump) + || dump == 0) + dump = CoredllDllMainBadADump; + uint beq = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainBadABeqPc, out beq) + || beq == 0) + beq = CoredllDllMainBadABeqDump; + if (dump != CoredllDllMainBadADump + || beq != CoredllDllMainBadABeqDump) + return false; + if (!_badASkipLogged) + { + _badASkipLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a beq0-skip" + + " epc=0x" + CoredllDllMainBadAEpc.ToString("X") + + " bad=0x" + va.ToString("X") + + " word=0x" + dump.ToString("X") + + " dis=" + FormatMipsOp(CoredllDllMainBadAEpc, dump) + + " next=0x" + CoredllDllMainBadANext.ToString("X") + + " beq=0x" + beq.ToString("X") + + " ra=0x" + CoredllDllMainBadACallerRa.ToString("X") + + " v1=0" + + " via=bada-beq0-skip" + + " (NK beq $v1,$0 empty path; dest $a0 miss;" + + " no page 0 invent)"); + } + return true; + } + + private static bool IsC000RefuseKseg(uint kseg) + { + if (kseg == 0 || (kseg & 3) != 0) + return true; + if ((kseg & 0x1FFFFFFFu) < 0x00010000u) + return true; + return IsDumpMemRefuseVa(kseg); + } + + // TLB first. Then *a0/$v0 class + // (kseg0/kseg1) if that dest peeks. + // Firmware PTE L1 index for + // 0xC0000088 is (0xC000>>16)&0x1FF + // == 0 — refuse (page 0 invent). + // Do not map phys<0x10000. + // Do not invent 0xC0000000. + private static void TryResolveC0000088(MipsBus bus, uint va, uint[] regs) + { + if (bus == null || _c000Busy || _c000Done) + return; + if (!IsC000StoreSkipVa(va)) + return; + try + { + _c000Busy = true; + uint pfn = 0; + bool valid = false; + bool tlb = bus.TryFindTlbPfn(va, out pfn, out valid) && valid; + uint kseg = 0; + uint destw = 0; + bool destOk = false; + string via = "tlb-none"; + if (tlb) + { + uint phys = pfn << 12; + kseg = 0x80000000u | (phys & 0x1FFFFFFFu); + if (!IsC000RefuseKseg(kseg) + && TryPeekWord(bus, + (kseg & ~0xFFFu) | (va & 0xFFFu), out destw)) + { + destOk = true; + via = "tlb"; + } + else + via = "tlb-refuse"; + } + if (!destOk && regs != null) + { + uint vdest = 0; + if (TryPeekC000V0Class(bus, regs, out vdest, out destw, out via)) + { + kseg = vdest & ~0xFFFu; + destOk = true; + } + } + if (destOk) + { + _c000Kseg = kseg & ~0xFFFu; + if (!_c000Logged) + { + _c000Logged = true; + _c000Done = true; + uint v0 = regs != null ? PeekGpr(regs, 2) : 0; + uint a0 = regs != null ? PeekGpr(regs, 4) : 0; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk c000-0088 map va=0x" + + CoredllDllMainC000Page.ToString("X") + + " -> 0x" + _c000Kseg.ToString("X8") + + (tlb ? " pfn=0x" + pfn.ToString("X") : "") + + " dest-word=0x" + destw.ToString("X") + + (regs != null ? " v0=0x" + v0.ToString("X") + + " a0=0x" + a0.ToString("X") : "") + + " via=" + via + + " (dump sw $v0,0($a1); peek dest; do not invent dest)"); + } + return; + } + if (regs == null) + { + if (!_c000Logged) + { + _c000Logged = true; + uint k0 = 0x80000000u | (va & 0x1FFFFFFFu); + uint k0w = 0; + bool k0ok = TryPeekWord(bus, k0, out k0w); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk c000-0088 map va=0x" + + va.ToString("X") + + " pte-miss via=" + via + + (tlb ? " pfn=0x" + pfn.ToString("X") : "") + + (k0ok ? " kseg0=0x" + k0w.ToString("X") : " kseg0-miss") + + " pte=page0-refuse" + + " (dump sw $v0,0($a1); wait v0-class; no page 0)"); + } + return; + } + if (!_c000Done) + { + _c000Done = true; + uint v0 = PeekGpr(regs, 2); + uint a0 = PeekGpr(regs, 4); + uint a0w = 0; + bool a0ok = a0 != 0 && TryPeekWord(bus, a0, out a0w); + uint k0v = 0x80000000u | (v0 & 0x1FFFFFFFu); + uint k0vw = 0; + bool k0vok = TryPeekWord(bus, k0v, out k0vw); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk c000-0088 map va=0x" + + va.ToString("X") + + " pte-miss via=v0-miss" + + " v0=0x" + v0.ToString("X") + + " a0=0x" + a0.ToString("X") + + (a0ok ? " *a0=0x" + a0w.ToString("X") : " *a0-miss") + + (k0vok ? " v0-kseg0=0x" + k0vw.ToString("X") : " v0-kseg0-miss") + + " pte=page0-refuse" + + " (dump sw $v0,0($a1); no invent 0xC0000000)"); + } + } + finally + { + _c000Busy = false; + } + } + + private static bool TryPeekC000V0Class(MipsBus bus, uint[] regs, + out uint dest, out uint destw, out string via) + { + dest = 0; + destw = 0; + via = "v0-miss"; + if (bus == null || regs == null) + return false; + uint v0 = PeekGpr(regs, 2); + uint a0 = PeekGpr(regs, 4); + uint a0w = 0; + TryPeekWord(bus, a0, out a0w); + uint cand = v0 != 0 ? v0 : a0w; + if (cand == 0) + return false; + uint k0 = 0x80000000u | (cand & 0x1FFFFFFFu); + uint k1 = 0xA0000000u | (cand & 0x1FFFFFFFu); + uint t0 = cand; + uint t1 = k0; + uint t2 = k1; + if (t0 != 0 && (t0 & 3) == 0 && !IsC000RefuseKseg(t0 & ~0xFFFu) + && TryPeekWord(bus, t0, out destw)) + { + dest = t0; + via = "v0-peek"; + return true; + } + if (t1 != t0 && (t1 & 3) == 0 && !IsC000RefuseKseg(t1 & ~0xFFFu) + && TryPeekWord(bus, t1, out destw)) + { + dest = t1; + via = "v0-kseg0"; + return true; + } + if (t2 != t0 && t2 != t1 && (t2 & 3) == 0 + && !IsC000RefuseKseg(t2 & ~0xFFFu) + && TryPeekWord(bus, t2, out destw)) + { + dest = t2; + via = "v0-kseg1"; + return true; + } + return false; + } + + private static bool IsMipsStore(uint insn) + { + uint op = insn >> 26; + return op == 0x28 || op == 0x29 || op == 0x2A + || op == 0x2B || op == 0x2E; + } + + private static bool IsMipsAbsRs0Store(uint insn) + { + return IsMipsStore(insn) && ((insn >> 21) & 31) == 0; + } + + private static bool IsDumpMemAlreadyTrue(uint insn) + { + if (IsMipsJumpOrJr(insn)) + return true; + if (IsMipsLoad(insn) || IsMipsStore(insn)) + return ((insn >> 21) & 31) != 0; + return false; + } + + // dump-jr / dump-sw / dump-sb already + // rewrote these EPCs. Dump-mem must + // not log or rewrite them again. + private static bool IsDumpMemPriorHandledPc(uint pc) + { + return pc == CoredllDllMainKdataEpc3 + || pc == CoredllDllMainStk2470Epc + || pc == CoredllDllMainStk1670Epc; + } + + // Fallthrough-execute only at dump-mem + // sites. Live 296037e nest 0x80042470 + // is not one of these. + private static bool IsDumpMemFallthroughPc(uint pc) + { + return pc == CoredllDllMainAbs1828Epc + || pc == CoredllDllMainAbs6670Epc + || pc == CoredllDllMainExn15C28Epc; + } + + // Live 4577e0a: after via=dump-mem-jal, + // do not fallthrough 57470/42628. + // Live 7ad9ab2: after 15C28 heal, + // fallthrough was log-only stall. + // Live e7f0f37: after 15c28-skip / + // stk-skip, heal-already at 15C28 + // undid leave. Hold after leave too. + private static bool IsDumpMemJalHoldPc(uint pc) + { + if ((pc == CoredllDllMainExn15C28Epc + || pc == CoredllDllMainExn15C28NextPc) + && (_exn15C28TakenLogged || _exn15C28Left)) + return true; + if (!_abs6670JalTakenLogged) + return false; + return pc == CoredllDllMainAbs6670Epc + || pc == CoredllDllMainAbs1828Epc; + } + + private static bool IsMipsJumpOrJr(uint insn) + { + uint op = insn >> 26; + if (op == 2 || op == 3) + return true; + if (op != 0) + return false; + uint fn = insn & 0x3F; + return fn == 8 || fn == 9; + } + + private static bool IsDumpMemRefuseVa(uint dest) + { + return dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || dest == LeftoverWait99O32RefuseDump + || dest == CoredllDllMainKdataWrapRefuse + || IsLeftoverDestVa(dest) + || IsWrapDestSize(dest) || IsWrapDestFp50Va(dest) + || IsHdDllImageBase(dest) || dest == WrapDestE32SizeLive + || dest == WrapDestFp50FillLive; + } + + // Write dump-true insn over the live + // abs-store overwrite at EPC. Next + // I-fetch is dump-true without + // rewrite. NK kseg0 only. Do not + // leftover-hop. Do not invent useg. + private static bool TryHealDumpInsn(MipsBus bus, uint pc, uint live, + uint dump) + { + if (bus == null || dump == 0 || dump == live) + return false; + if ((pc & 3) != 0 || pc < 0x80010000u || pc >= 0x80400000u) + return false; + if (IsDumpMemRefuseVa(pc)) + return false; + uint cur = 0; + if (!TryPeekWord(bus, pc, out cur) || cur != live) + return cur == dump; + try { bus.Write32(pc, dump); } + catch { return false; } + uint after = 0; + return TryPeekWord(bus, pc, out after) && after == dump; + } + + private static bool TryNoteDumpMemLogPc(uint pc) + { + if (_dumpMemLoggedPc == null) + return false; + int n = _absStoreMemLogN; + if (n < 0) + n = 0; + if (n > _dumpMemLoggedPc.Length) + n = _dumpMemLoggedPc.Length; + for (int i = 0; i < n; i++) + { + if (_dumpMemLoggedPc[i] == pc) + return false; + } + if (n >= _dumpMemLoggedPc.Length) + return false; + _dumpMemLoggedPc[n] = pc; + _absStoreMemLogN = n + 1; + return true; + } + + private static bool TryNoteDumpMemFallPc(uint pc) + { + if (_dumpMemFallPc == null) + return false; + int n = _dumpMemFallN; + if (n < 0) + n = 0; + if (n > _dumpMemFallPc.Length) + n = _dumpMemFallPc.Length; + for (int i = 0; i < n; i++) + { + if (_dumpMemFallPc[i] == pc) + return false; + } + if (n >= _dumpMemFallPc.Length) + return false; + _dumpMemFallPc[n] = pc; + _dumpMemFallN = n + 1; + return true; + } + + // Once per dump-mem PC: healed jal / + // memop. Do not skip. Execute. Nest + // 0x80042470 is excluded by caller. + private static void TryLogDumpMemFallthrough(uint pc, uint live, + uint[] regs) + { + if (IsDumpMemJalHoldPc(pc)) + return; + if (!IsDumpMemFallthroughPc(pc) || !TryNoteDumpMemFallPc(pc)) + return; + _abs6670DumpSkipLogged = true; + _abs6670FallthroughLogged = true; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + { + if (pc == CoredllDllMainAbs6670Epc) + dump = CoredllDllMainAbs6670Dump; + else if (pc == CoredllDllMainAbs1828Epc) + dump = CoredllDllMainAbs1828Dump; + else if (pc == CoredllDllMainExn15C28Epc) + dump = CoredllDllMainExn15C28Dump; + } + uint ra = PeekGpr(regs, 31); + uint v0 = PeekGpr(regs, 2); + uint fp = PeekGpr(regs, 30); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-store fallthrough" + + " epc=0x" + pc.ToString("X") + + " word=0x" + live.ToString("X") + + (dump != 0 ? " dump=0x" + dump.ToString("X") : "") + + " dis=" + FormatMipsOp(pc, live) + + (dump != 0 ? " dump-dis=" + FormatMipsOp(pc, dump) : "") + + " v0=0x" + v0.ToString("X") + + " fp=0x" + fp.ToString("X") + + " ra=0x" + ra.ToString("X") + + " via=dump-mem-fallthrough reason=heal-already" + + " (execute dump-true; do not invent dest)"); + } + + // Dump delay at 0x80057474 is addiu + // $a0,$v0,13292. Heal if live is the + // abs-store overwrite class. + private static void TryHealDumpMemJalDelay(MipsBus bus, uint pc) + { + if (bus == null || pc != CoredllDllMainAbs6670Epc) + return; + uint delayPc = pc + 4; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(delayPc, out dump) || dump == 0) + dump = CoredllDllMainAbs6670Delay; + if (dump == 0 || IsDumpMemRefuseVa(delayPc)) + return; + uint live = 0; + if (!TryPeekWord(bus, delayPc, out live) || live == 0 || live == dump) + return; + if (!IsMipsAbsRs0Store(live) && live != CoredllDllMainAbs6670Live) + return; + TryHealDumpInsn(bus, delayPc, live, dump); + } + + private static void TryClearDumpMemExn(MipsBus bus, uint pc) + { + if (bus == null || pc != CoredllDllMainAbs6670Epc) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 8)) + return; + bus.ClearExlIfEpc(pc); + } + + private static void TryApplyDumpMemJalDelay(MipsBus bus, uint[] regs, + uint pc) + { + TryHealDumpMemJalDelay(bus, pc); + uint delay = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc + 4, out delay) || delay == 0) + delay = CoredllDllMainAbs6670Delay; + if ((delay >> 26) != 9) + return; + int rs = (int)((delay >> 21) & 31); + int rt = (int)((delay >> 16) & 31); + int imm = (short)(delay & 0xFFFF); + PokeGpr(regs, rt, PeekGpr(regs, rs) + (uint)imm); + } + + // Live f9afdbc: fallthrough at + // 0x80057470 was log-only. Execute + // dump jal: $ra=pc+8, delay addiu, + // PC:=0x8004326C. Live 4577e0a: + // later fallthrough undid $ra to + // 0x80057448. Once applied, keep + // $ra/dest; delay-slot re-fetch + // returns nop (do not CPU-jal). + // Do not leftover-hop. Do not invent dest. + public static bool TryTakeDumpMemJal(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_stk1670SbLogged) + return false; + if (pc != CoredllDllMainAbs6670Epc) + return false; + if (insn != CoredllDllMainAbs6670Dump) + return false; + uint dest = (pc & 0xF0000000u) | ((insn & 0x03FFFFFFu) << 2); + if (dest != CoredllDllMainAbs6670Dest) + return false; + if (dest == 0 || (dest & 3) != 0 || IsDumpMemRefuseVa(dest)) + return false; + uint ra = _abs6670JalRa != 0 ? _abs6670JalRa : (pc + 8); + if (IsDumpMemRefuseVa(ra)) + return false; + if (_abs6670JalTakenLogged) + { + PokeGpr(regs, 31, ra); + if (!inDelay) + cpuPc = dest; + return true; + } + if (inDelay) + return false; + TryClearDumpMemExn(bus, pc); + TryApplyDumpMemJalDelay(bus, regs, pc); + PokeGpr(regs, 31, ra); + cpuPc = dest; + _abs6670JalTakenLogged = true; + _abs6670JalRa = ra; + uint v0 = PeekGpr(regs, 2); + uint a0 = PeekGpr(regs, 4); + if (_abs6670JalA0 == 0) + _abs6670JalA0 = a0; + uint fp = PeekGpr(regs, 30); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-6670 jal" + + " epc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dest=0x" + dest.ToString("X") + + " ra=0x" + ra.ToString("X") + + " v0=0x" + v0.ToString("X") + + " a0=0x" + a0.ToString("X") + + " fp=0x" + fp.ToString("X") + + " via=dump-mem-jal" + + " (execute dump jal; delay addiu; clear exn;" + + " do not invent dest)"); + return true; + } + + // Live 4577e0a: dest 0x8004326C never + // named. One-shot I-fetch after jal. + public static void TryNoteDumpMemJalDest(MipsBus bus, uint[] regs, + uint pc) + { + if (!_abs6670JalTakenLogged || _abs6670DestFetchLogged) + return; + if (pc != CoredllDllMainAbs6670Dest + && pc != CoredllDllMainStk2470Epc) + return; + if (IsDumpMemRefuseVa(pc)) + return; + _abs6670DestFetchLogged = true; + uint word = 0; + TryPeekWord(bus, pc, out word); + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + { + if (pc == CoredllDllMainAbs6670Dest) + dump = CoredllDllMainStk2470Prev; + else + dump = CoredllDllMainStk2470Insn; + } + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + uint a0 = PeekGpr(regs, 4); + uint a1 = PeekGpr(regs, 5); + if (_abs6670JalA0 == 0) + _abs6670JalA0 = a0; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-6670 dest" + + " epc=0x" + pc.ToString("X") + + " word=0x" + word.ToString("X") + + (dump != 0 ? " dump=0x" + dump.ToString("X") : "") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " a0=0x" + a0.ToString("X") + + " a1=0x" + a1.ToString("X") + + " via=dump-mem-jal-dest" + + " (land 0x8004326C; dump-sw; do not invent dest)"); + } + + private static bool TryWriteDumpMem15C28Dest(MipsBus bus, uint dest, + uint value) + { + if (bus == null || dest == 0 || (dest & 3) != 0) + return false; + if ((dest & ~0xFFFu) == 0) + return false; + if (IsDumpMemRefuseVa(dest) || IsC000RefuseKseg(dest & ~0xFFFu)) + return false; + if (IsC000StoreSkipVa(dest)) + return false; + uint peek = 0; + if (!TryPeekWord(bus, dest, out peek)) + return false; + try + { + bus.Write32(dest, value); + return true; + } + catch + { + return false; + } + } + + // Live faf00f3: after 15c2c-skip, + // dump-mem-15c28 hold re-entered + // same EPC (wrote=0 bounce). + // Leave once; do not hold again. + // Swallow later stores on that + // unmapped frame so genex does + // not TLBS back. Do not invent + // 0x9A02 / 0xC6FB stack. + public static bool TrySkip15C28StkStore(MipsBus bus, uint va) + { + if (!_exn15C28Left || _exn15C28StkPage == 0) + return false; + if ((va & ~0xFFFu) != _exn15C28StkPage) + return false; + if ((va & ~0xFFFu) == 0 || IsC000StoreSkipVa(va)) + return false; + if (IsDumpMemRefuseVa(va)) + return false; + if (!_exn15C28StkSkipLogged) + { + _exn15C28StkSkipLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 stk-skip" + + " bad=0x" + va.ToString("X") + + " page=0x" + _exn15C28StkPage.ToString("X") + + " next=0x" + CoredllDllMainExn15C28After.ToString("X") + + " via=dump-mem-15c28-stk-skip" + + " (wrote=0 frame; continue >=0x80015C30;" + + " honor ra; no invent dest)"); + } + return true; + } + + private static void Note15C28Left(uint dest) + { + _exn15C28Left = true; + if (_exn15C28StkPage == 0 && dest != 0) + _exn15C28StkPage = dest & ~0xFFFu; + } + + // Live 7ad9ab2 / 0cb3d43: after + // c000 TLBS, heal=1 at 0x80015C28 + // sw $ra,284($sp) then fallthrough + // heal-already log-only stall. + // Live 98276c7: wrote=0 dest + // 0x9A023F8C then spin. + // Live faf00f3: 15c2c-skip then + // dump-mem-15c28 hold bounce. + // wrote=0: one-shot advance to + // 0x80015C30, honor $ra, leave. + // Live e7f0f37: after skip/stk-skip, + // heal-already fallthrough at + // 0x80015C28 undid leave and spun. + // Re-fetch of 15C28/15C2C after + // leave: keep PC>=0x80015C30, + // do not execute fallthrough. + // Do not invent dest. + public static bool TryTakeDumpMem15C28(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_stk1670SbLogged) + return false; + if (pc != CoredllDllMainExn15C28Epc + && pc != CoredllDllMainExn15C28NextPc) + return false; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return false; + if (_exn15C28Left) + { + if (inDelay) + return false; + // Live e9baf25: 59488 heal=1 + // then 15c28-leave spun + // before dump subu ran. + // Do not leave until exec. + if (_abs59488Logged && !_abs59488ExecLogged) + return false; + // Live f48c2dc: after 59488-exec + // memset-ret *fp-miss then + // leave spun. Do not leave + // until ret skip sticks. + if (_abs59488ExecLogged && !_exn15C28JalRetSkipLogged) + return false; + // Live 20f3972: after memset-ret + // skip, leave yanked PC back + // to 0x80015C30 and spun. + // Skip stuck: never leave. + if (_exn15C28JalRetSkipLogged) + return false; + // Live c270933: after s1-skip, + // leave must stay dead. + if (_exn15C28JalS1SkipLogged) + return false; + // Live fe74462: after ALU exec + // 21048–21058, leave must stay + // dead. + if (_exn15C28AfterS1AluLogged) + return false; + // Live 97fb310: after stk-sw + // skip, leave must stay dead. + if (_exn15C28StkSwSkipLogged) + return false; + if (_exn15C28FpLwSkipLogged) + return false; + if (_exn15C28SpT9SkipLogged) + return false; + if (_exn15C28JalRaEpiSkipLogged) + return false; + if (_exn15C28OuterJalTakenLogged) + return false; + // Live 71fd3f6: leave-hold + // after 59488 re-entry spun + // silently. One-shot only; + // later 15C28 names the next + // miss. Jal-hold still blocks + // heal-already fallthrough. + if (_exn15C28LeaveHoldLogged) + return false; + uint holdRa = PeekGpr(regs, 31); + uint holdSp = PeekGpr(regs, 29); + cpuPc = CoredllDllMainExn15C28After; + _exn15C28LeaveHoldLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 leave" + + " epc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28After.ToString("X") + + " ra=0x" + holdRa.ToString("X") + + " sp=0x" + holdSp.ToString("X") + + " via=dump-mem-15c28-leave" + + " (one-shot after skip/stk-skip;" + + " no heal-already; keep PC>=0x80015C30;" + + " honor ra; no invent dest)"); + return true; + } + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + if (pc == CoredllDllMainExn15C28NextPc) + { + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28Next; + if (insn != nextDump && insn != CoredllDllMainExn15C28Next) + return false; + if (inDelay) + return false; + uint dest2 = sp + CoredllDllMainExn15C28NextOff; + bool wrote2 = TryWriteDumpMem15C28Dest(bus, dest2, 0); + cpuPc = CoredllDllMainExn15C28After; + if (!wrote2) + Note15C28Left(dest2); + if (!_exn15C28NextLogged) + { + _exn15C28NextLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 next" + + " epc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + nextDump.ToString("X") + + " dest=0x" + dest2.ToString("X") + + " next=0x" + CoredllDllMainExn15C28After.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + (wrote2 ? " wrote=1" : " wrote=0") + + " via=" + (wrote2 ? "dump-mem-15c2c" : "dump-mem-15c2c-skip") + + " (dump sw $0,144($sp); dest miss advances;" + + " honor ra; do not invent dest)"); + } + return true; + } + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28Dump; + if (insn != dump && insn != CoredllDllMainExn15C28Dump) + return false; + if (dump != CoredllDllMainExn15C28Dump) + return false; + if (_exn15C28TakenLogged) + return false; + if (inDelay) + return false; + uint dest = sp + CoredllDllMainExn15C28Off; + bool wrote = TryWriteDumpMem15C28Dest(bus, dest, ra); + _exn15C28Wrote = wrote; + _exn15C28TakenLogged = true; + uint nextw = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainExn15C28NextPc, out nextw) + || nextw == 0) + nextw = CoredllDllMainExn15C28Next; + if (!wrote) + { + uint dest2 = sp + CoredllDllMainExn15C28NextOff; + TryWriteDumpMem15C28Dest(bus, dest2, 0); + Note15C28Left(dest); + cpuPc = CoredllDllMainExn15C28After; + if (!_exn15C28NextLogged) + { + _exn15C28NextLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 skip" + + " epc=0x" + pc.ToString("X") + + " dest=0x" + dest.ToString("X") + + " next=0x" + CoredllDllMainExn15C28After.ToString("X") + + " next-word=0x" + nextw.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " wrote=0" + + " via=dump-mem-15c28-skip" + + " (wrote=0; advance >=0x80015C30; honor ra;" + + " do not re-enter hold; no invent dest)"); + } + return true; + } + cpuPc = CoredllDllMainExn15C28NextPc; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 jal-hold" + + " epc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + dump.ToString("X") + + " dest=0x" + dest.ToString("X") + + " next=0x" + cpuPc.ToString("X") + + " next-word=0x" + nextw.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " wrote=1" + + " via=dump-mem-15c28" + + " (execute dump sw $ra,284($sp); hold next;" + + " do not invent dest)"); + return true; + } + + // Live e7f0f37: PC:=0x80015C30 after + // wrote=0 leave. Name dump-true + // first I-fetch (word / dump / + // $ra / $sp). Continue only if + // that insn is already dump-true + // LoadO32 / BindImp. Do not + // leftover-hop dest 0x03F74DEC. + // Do not invent dest / 0x9A02. + public static void TryNoteDumpMem15C28After(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (_exn15C28AfterLogged) + return; + if (pc != CoredllDllMainExn15C28After) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterLogged = true; + uint afterDump = DumpMem15C28AfterWord(pc); + if (afterDump == 0 + && (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0)) + afterDump = CoredllDllMainExn15C28AfterDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterT9 = PeekGpr(regs, 25); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " t9=0x" + afterT9.ToString("X") + + " via=dump-mem-15c28-after" + + " (first I-fetch after leave; honor ra;" + + " no invent dest)"); + } + + private static uint DumpMem15C28AfterWord(uint pc) + { + uint dump = 0; + if (TryPeekLeftoverWait99DumpOnly(pc, out dump) && dump != 0) + return dump; + if (pc == CoredllDllMainExn15C28After) + return CoredllDllMainExn15C28AfterDump; + if (pc == CoredllDllMainExn15C28After2) + return CoredllDllMainExn15C28After2Dump; + if (pc == CoredllDllMainExn15C28After3) + return CoredllDllMainExn15C28After3Dump; + if (pc == CoredllDllMainExn15C28JalPc) + return CoredllDllMainExn15C28JalDump; + if (pc == CoredllDllMainExn15C28JalDelay) + return CoredllDllMainExn15C28JalDelayDump; + if (pc == CoredllDllMainExn15C28JalDest) + return CoredllDllMainExn15C28JalDestDump; + if (pc == CoredllDllMainExn15C28JalThr) + return CoredllDllMainExn15C28JalThrDump; + if (pc == CoredllDllMainExn15C28JalThrLw) + return CoredllDllMainExn15C28JalThrLwDump; + if (pc == CoredllDllMainExn15C28JalRetNext) + return CoredllDllMainExn15C28JalRetNextDump; + if (pc == CoredllDllMainExn15C28JalS1) + return CoredllDllMainExn15C28JalS1Dump; + if (pc == CoredllDllMainExn15C28JalS1Next) + return CoredllDllMainExn15C28JalS1NextDump; + if (pc == CoredllDllMainExn15C28JalS1After) + return CoredllDllMainExn15C28JalS1AfterDump; + if (pc == CoredllDllMainExn15C28JalS1After2) + return CoredllDllMainExn15C28JalS1After2Dump; + if (pc == CoredllDllMainExn15C28JalS1After3) + return CoredllDllMainExn15C28JalS1After3Dump; + if (pc == CoredllDllMainExn15C28JalS1After4) + return CoredllDllMainExn15C28JalS1After4Dump; + if (pc == CoredllDllMainExn15C28JalS1After5) + return CoredllDllMainExn15C28JalS1After5Dump; + if (pc == CoredllDllMainExn15C28JalS1AluNext) + return CoredllDllMainExn15C28JalS1AluNextDump; + if (pc == CoredllDllMainExn15C28StkSwNext) + return CoredllDllMainExn15C28StkSwNextDump; + if (pc == CoredllDllMainExn15C28StkSwDelay) + return CoredllDllMainExn15C28StkSwDelayDump; + if (pc == CoredllDllMainExn15C28FpLw) + return CoredllDllMainExn15C28FpLwDump; + if (pc == CoredllDllMainExn15C28FpLwNext) + return CoredllDllMainExn15C28FpLwNextDump; + if (pc == CoredllDllMainExn15C28FpLwAlu1) + return CoredllDllMainExn15C28FpLwAlu1Dump; + if (pc == CoredllDllMainExn15C28FpLwAlu2) + return CoredllDllMainExn15C28FpLwAlu2Dump; + if (pc == CoredllDllMainExn15C28FpLwA1) + return CoredllDllMainExn15C28FpLwA1Dump; + if (pc == CoredllDllMainExn15C28FpLwSw1) + return CoredllDllMainExn15C28FpLwSw1Dump; + if (pc == CoredllDllMainExn15C28FpLwSw2) + return CoredllDllMainExn15C28FpLwSw2Dump; + if (pc == CoredllDllMainExn15C28FpLwSw3) + return CoredllDllMainExn15C28FpLwSw3Dump; + if (pc == CoredllDllMainExn15C28FpLwBeq) + return CoredllDllMainExn15C28FpLwBeqDump; + if (pc == CoredllDllMainExn15C28FpLwBeqDelay) + return CoredllDllMainExn15C28FpLwBeqDelayDump; + if (pc == CoredllDllMainExn15C28FpLwBeqFall) + return CoredllDllMainExn15C28FpLwBeqFallDump; + if (pc == CoredllDllMainExn15C28FpLwBeqTaken) + return CoredllDllMainExn15C28FpLwBeqTakenDump; + if (pc == CoredllDllMainExn15C28SpT9Next) + return CoredllDllMainExn15C28SpT9NextDump; + if (pc == CoredllDllMainExn15C28EpiJr) + return CoredllDllMainExn15C28EpiJrDump; + if (pc == CoredllDllMainExn15C28EpiDelay) + return CoredllDllMainExn15C28EpiDelayDump; + if (pc == CoredllDllMainExn15C28JalRa) + return CoredllDllMainExn15C28JalRaDump; + if (pc == CoredllDllMainExn15C28JalRaOr) + return CoredllDllMainExn15C28JalRaOrDump; + if (pc == CoredllDllMainExn15C28JalRaEpiEnd) + return CoredllDllMainExn15C28JalRaEpiEndDump; + if (pc == CoredllDllMainExn15C28OuterRa) + return CoredllDllMainExn15C28OuterRaDump; + if (pc == CoredllDllMainExn15C28OuterJalDest) + return CoredllDllMainExn15C28OuterJalDestDump; + if (pc == CoredllDllMainExn15C28OuterJalDest2) + return CoredllDllMainExn15C28OuterJalDest2Dump; + if (pc == CoredllDllMainExn15C28OuterJalDest3) + return CoredllDllMainExn15C28OuterJalDest3Dump; + if (pc == CoredllDllMainExn15C28OuterJalDestNext) + return CoredllDllMainExn15C28OuterJalDestNextDump; + if (pc == CoredllDllMainExn15C28OuterJalDestNop) + return CoredllDllMainExn15C28OuterJalDestNopDump; + if (pc == CoredllDllMainExn15C28OuterJalDestInc) + return CoredllDllMainExn15C28OuterJalDestIncDump; + if (pc == CoredllDllMainExn15C28OuterJalDestSw) + return CoredllDllMainExn15C28OuterJalDestSwDump; + if (pc == CoredllDllMainExn15C28OuterJalDestJr) + return CoredllDllMainExn15C28OuterJalDestJrDump; + if (pc == CoredllDllMainExn15C28OuterJalDestJrDelay) + return CoredllDllMainExn15C28OuterJalDestJrDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLink) + return CoredllDllMainExn15C28OuterJalLinkDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkAlu) + return CoredllDllMainExn15C28OuterJalLinkAluDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkAlu2) + return CoredllDllMainExn15C28OuterJalLinkAlu2Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkAfter) + return CoredllDllMainExn15C28OuterJalLinkAfterDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkT1) + return CoredllDllMainExn15C28OuterJalLinkT1Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkBne) + return CoredllDllMainExn15C28OuterJalLinkBneDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkBneFall) + return CoredllDllMainExn15C28OuterJalLinkBneFallDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkBneTaken) + return CoredllDllMainExn15C28OuterJalLinkBneTakenDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkSltu) + return CoredllDllMainExn15C28OuterJalLinkSltuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkBeq) + return CoredllDllMainExn15C28OuterJalLinkBeqDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkBeqDelay) + return CoredllDllMainExn15C28OuterJalLinkBeqDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkBeqFall) + return CoredllDllMainExn15C28OuterJalLinkBeqFallDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkAddiuNext) + return CoredllDllMainExn15C28OuterJalLinkAddiuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwT4Next) + return CoredllDllMainExn15C28OuterJalLinkLwT4NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS7Next) + return CoredllDllMainExn15C28OuterJalLinkLwS7NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkAdduNext) + return CoredllDllMainExn15C28OuterJalLinkAdduNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwFpNext) + return CoredllDllMainExn15C28OuterJalLinkLwFpNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS6Next) + return CoredllDllMainExn15C28OuterJalLinkLwS6NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS5Next) + return CoredllDllMainExn15C28OuterJalLinkLwS5NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS4Next) + return CoredllDllMainExn15C28OuterJalLinkLwS4NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS3Next) + return CoredllDllMainExn15C28OuterJalLinkLwS3NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS2Next) + return CoredllDllMainExn15C28OuterJalLinkLwS2NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS1Next) + return CoredllDllMainExn15C28OuterJalLinkLwS1NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwS0Next) + return CoredllDllMainExn15C28OuterJalLinkLwS0NextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkLwRaNext) + return CoredllDllMainExn15C28OuterJalLinkLwRaNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiJrDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiJrDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiJrNext) + return CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext) + return CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiSwNext) + return CoredllDllMainExn15C28OuterJalLinkEpiSwNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext) + return CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiLhuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw) + return CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext) + return CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqFall) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqFallDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNextDump; + uint prologueSwDump = DumpMem15C28PrologueSwDump(pc); + if (prologueSwDump != 0) + return prologueSwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelayDump; + uint trampolineDump = DumpMem15C28TrampolineDump(pc); + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && trampolineDump == 0) + trampolineDump = CoredllDllMainExn15C28OuterJalLinkEpiTrampolineDump; + if (trampolineDump != 0 || IsExn15C28TrampolinePc(pc)) + return trampolineDump; + uint retDump = DumpMem15C28RetDump(pc); + if (retDump != 0 || IsExn15C28RetPc(pc)) + return retDump; + uint fallDump = DumpMem15C28RetFallDump(pc); + if (fallDump != 0 || IsExn15C28RetFallPc(pc)) + return fallDump; + return 0; + } + + // Live 8f04283: after leave, dump + // 15C30..15C40 is lui/ori/sw/jal + // 0x80020FA0 / or $a0,$sp. ALU + // words are not dump-mem (not + // abs-store / jump), so heal + // known dump words. sw 292($sp) + // stays stk-skip. Dest is dump- + // true NK, not LoadO32, not + // leftover. Do not invent dest + // / 0x9A02 / KData. + public static void TryFixDumpMem15C28After(MipsBus bus, uint[] regs, + uint pc, ref uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (pc != CoredllDllMainExn15C28After + && pc != CoredllDllMainExn15C28After2 + && pc != CoredllDllMainExn15C28After3 + && pc != CoredllDllMainExn15C28JalPc + && pc != CoredllDllMainExn15C28JalDelay + && pc != CoredllDllMainExn15C28JalDest + && pc != CoredllDllMainExn15C28JalThr + && pc != CoredllDllMainExn15C28JalRetNext + && pc != CoredllDllMainExn15C28JalS1Next + && pc != CoredllDllMainExn15C28JalS1After + && pc != CoredllDllMainExn15C28JalS1After2 + && pc != CoredllDllMainExn15C28JalS1After3 + && pc != CoredllDllMainExn15C28JalS1After4 + && pc != CoredllDllMainExn15C28JalS1After5 + && pc != CoredllDllMainExn15C28StkSwNext + && pc != CoredllDllMainExn15C28OuterRa + && pc != CoredllDllMainExn15C28OuterJalDest + && pc != CoredllDllMainExn15C28OuterJalDest2 + && pc != CoredllDllMainExn15C28OuterJalDest3 + && pc != CoredllDllMainExn15C28OuterJalDestNext + && pc != CoredllDllMainExn15C28OuterJalDestNop + && pc != CoredllDllMainExn15C28OuterJalDestInc + && pc != CoredllDllMainExn15C28OuterJalDestSw + && pc != CoredllDllMainExn15C28OuterJalDestJr + && pc != CoredllDllMainExn15C28OuterJalDestJrDelay + && pc != CoredllDllMainExn15C28OuterJalLink + && pc != CoredllDllMainExn15C28OuterJalLinkAlu + && pc != CoredllDllMainExn15C28OuterJalLinkAlu2 + && pc != CoredllDllMainExn15C28OuterJalLinkAfter + && pc != CoredllDllMainExn15C28OuterJalLinkT1 + && pc != CoredllDllMainExn15C28OuterJalLinkBne + && pc != CoredllDllMainExn15C28OuterJalLinkBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkBneTaken + && pc != CoredllDllMainExn15C28OuterJalLinkSltu + && pc != CoredllDllMainExn15C28OuterJalLinkBeq + && pc != CoredllDllMainExn15C28OuterJalLinkBeqDelay + && pc != CoredllDllMainExn15C28OuterJalLinkBeqFall + && pc != CoredllDllMainExn15C28OuterJalLinkAddiuNext + && pc != CoredllDllMainExn15C28OuterJalLinkLwT4Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS7Next + && pc != CoredllDllMainExn15C28OuterJalLinkAdduNext + && pc != CoredllDllMainExn15C28OuterJalLinkLwFpNext + && pc != CoredllDllMainExn15C28OuterJalLinkLwS6Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS5Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS4Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS3Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS2Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS1Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwS0Next + && pc != CoredllDllMainExn15C28OuterJalLinkLwRaNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiJrDelay + && pc != CoredllDllMainExn15C28OuterJalLinkEpiJrNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiSwNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + && pc != CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqDelay + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqFall + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelay + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + uint afterDump = DumpMem15C28AfterWord(pc); + if (afterDump == 0 || insn == afterDump) + return; + uint afterLive = insn; + insn = afterDump; + TryHealDumpInsn(bus, pc, afterLive, afterDump); + } + + // Live 71fd3f6: after leave/thr, + // epc=0x80059488 live abs store + // sb $a1,-31096($0) (0xA0058688) + // overwrote dump subu $t1,$a1,$t0. + // General dump-mem rejects + // negative imm and ALU dump. + // Rewrite+heal, execute ALU. + // bad=0xFFFF8688 — no invent + // KData page. Rate-limit once. + public static void TryFixDumpMem59488(MipsBus bus, uint[] regs, + uint pc, ref uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalThrLogged) + return; + if (pc != CoredllDllMainAbs59488Epc + && pc != CoredllDllMainAbs59488Next) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + { + if (pc == CoredllDllMainAbs59488Epc) + dump = CoredllDllMainAbs59488Dump; + else + dump = CoredllDllMainAbs59488NextDump; + } + if (pc == CoredllDllMainAbs59488Epc + && dump != CoredllDllMainAbs59488Dump) + return; + if (pc == CoredllDllMainAbs59488Next + && dump != CoredllDllMainAbs59488NextDump) + return; + if (insn == dump) + return; + if (!IsMipsAbsRs0Store(insn) && insn != CoredllDllMainAbs59488Live) + return; + uint live = insn; + insn = dump; + bool heal = TryHealDumpInsn(bus, pc, live, dump); + if (_abs59488Logged || pc != CoredllDllMainAbs59488Epc) + return; + _abs59488Logged = true; + uint ra = PeekGpr(regs, 31); + uint a1 = PeekGpr(regs, 5); + uint t0 = PeekGpr(regs, 8); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-59488" + + " epc=0x" + pc.ToString("X") + + " bad=0x" + CoredllDllMainAbs59488Bad.ToString("X") + + " word=0x" + live.ToString("X") + + " dump=0x" + dump.ToString("X") + + " dis=" + FormatMipsOp(pc, live) + + " dump-dis=" + FormatMipsOp(pc, dump) + + " a1=0x" + a1.ToString("X") + + " t0=0x" + t0.ToString("X") + + " ra=0x" + ra.ToString("X") + + (heal ? " heal=1" : " heal=0") + + " via=dump-mem-59488" + + " (dump subu $t1,$a1,$t0; no invent" + + " 0xFFFF8688; honor ra)"); + } + + // Live e9baf25: heal=1 at 59488 + // (a1=0x50 t0=0x10 expect t1=0x40) + // then 15c28-leave spun — ALU + // never ran (jal-hold lesson). + // Execute dump subu, PC:=0x8005948C, + // clear exn. One-shot log. + // Do not invent 0xFFFF8688. + public static bool TryTakeDumpMem59488(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28JalThrLogged) + return false; + if (pc != CoredllDllMainAbs59488Epc) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainAbs59488Next)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainAbs59488Dump; + if (dump != CoredllDllMainAbs59488Dump) + return false; + if (insn != dump && !IsMipsAbsRs0Store(insn) + && insn != CoredllDllMainAbs59488Live) + return false; + if (_abs59488ExecLogged) + return false; + if (insn != dump) + TryHealDumpInsn(bus, pc, insn, dump); + uint a1 = PeekGpr(regs, 5); + uint t0 = PeekGpr(regs, 8); + uint t1 = a1 - t0; + PokeGpr(regs, 9, t1); + if (bus != null) + bus.ClearExlIfEpc(pc); + cpuPc = CoredllDllMainAbs59488Next; + _abs59488Logged = true; + _abs59488ExecLogged = true; + uint ra = PeekGpr(regs, 31); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-59488 exec" + + " epc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainAbs59488Next.ToString("X") + + " dump=0x" + dump.ToString("X") + + " a1=0x" + a1.ToString("X") + + " t0=0x" + t0.ToString("X") + + " t1=0x" + t1.ToString("X") + + " ra=0x" + ra.ToString("X") + + " via=dump-mem-59488-exec" + + " (dump subu $t1,$a1,$t0; PC>=0x8005948C;" + + " clear exn; honor ra; no invent 0xFFFF8688)"); + return true; + } + + public static void TryNoteDumpMem15C28Jal(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (_exn15C28JalLogged) + return; + if (pc != CoredllDllMainExn15C28JalPc) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(CoredllDllMainExn15C28JalDest)) + return; + uint jalDump = DumpMem15C28AfterWord(pc); + if (jalDump == 0) + jalDump = CoredllDllMainExn15C28JalDump; + if (insn != jalDump && insn != CoredllDllMainExn15C28JalDump) + return; + _exn15C28JalLogged = true; + uint jalRa = PeekGpr(regs, 31); + uint jalSp = PeekGpr(regs, 29); + uint jalV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-jal"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " dest=0x" + CoredllDllMainExn15C28JalDest.ToString("X") + + " via=dump-mem-15c28-jal"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 jal" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + jalDump.ToString("X") + + " dest=0x" + CoredllDllMainExn15C28JalDest.ToString("X") + + " ra=0x" + jalRa.ToString("X") + + " sp=0x" + jalSp.ToString("X") + + " v0=0x" + jalV0.ToString("X") + + " via=dump-mem-15c28-jal" + + " (dump jal 0x80020FA0; delay or $a0,$sp;" + + " not LoadO32; honor ra; no invent dest)"); + } + + public static void TryNoteDumpMem15C28JalDest(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalLogged || _exn15C28JalDestLogged) + return; + if (pc != CoredllDllMainExn15C28JalDest) + return; + if (IsDumpMemRefuseVa(pc)) + return; + _exn15C28JalDestLogged = true; + uint destDump = DumpMem15C28AfterWord(pc); + if (destDump == 0) + destDump = CoredllDllMainExn15C28JalDestDump; + uint destRa = PeekGpr(regs, 31); + uint destSp = PeekGpr(regs, 29); + uint destA0 = PeekGpr(regs, 4); + uint destV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-jal-dest"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " dest=0x" + pc.ToString("X") + + " via=dump-mem-15c28-jal-dest"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 jal-dest" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (destDump != 0 ? " dump=0x" + destDump.ToString("X") : "") + + " ra=0x" + destRa.ToString("X") + + " sp=0x" + destSp.ToString("X") + + " a0=0x" + destA0.ToString("X") + + " v0=0x" + destV0.ToString("X") + + " via=dump-mem-15c28-jal-dest" + + " (land 0x80020FA0 addiu $sp,-200; honor ra;" + + " no invent dest / 0x9A02 / KData)"); + } + + // Dump 0x80020FCC addiu $v0 ThreadPtr + // then lw $v1,0($v0). Peek live + // *ThreadPtr only. Do not invent + // Thread* / 0x9A02 / KData. + public static void TryNoteDumpMem15C28JalThr(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalDestLogged || _exn15C28JalThrLogged) + return; + if (pc != CoredllDllMainExn15C28JalThr + && pc != CoredllDllMainExn15C28JalThrLw) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(ThreadPtr)) + return; + uint thrDump = DumpMem15C28AfterWord(pc); + if (thrDump == 0) + { + if (pc == CoredllDllMainExn15C28JalThr) + thrDump = CoredllDllMainExn15C28JalThrDump; + else + thrDump = CoredllDllMainExn15C28JalThrLwDump; + } + if (insn != thrDump && insn != CoredllDllMainExn15C28JalThrDump + && insn != CoredllDllMainExn15C28JalThrLwDump) + return; + if (pc != CoredllDllMainExn15C28JalThrLw) + return; + _exn15C28JalThrLogged = true; + uint thrV0 = PeekGpr(regs, 2); + uint thrRa = PeekGpr(regs, 31); + uint thrSp = PeekGpr(regs, 29); + uint thrA0 = PeekGpr(regs, 4); + uint thrPeek = 0; + bool thrOk = thrV0 == ThreadPtr + && !IsDumpMemRefuseVa(thrV0) + && TryPeekWord(bus, thrV0, out thrPeek); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-thr"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " v0=0x" + thrV0.ToString("X") + + (thrOk ? " *v0=0x" + thrPeek.ToString("X") : " *v0-miss") + + " via=dump-mem-15c28-thr"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 thr" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + thrDump.ToString("X") + + " v0=0x" + thrV0.ToString("X") + + (thrOk ? " *v0=0x" + thrPeek.ToString("X") : " *v0-miss") + + " ra=0x" + thrRa.ToString("X") + + " sp=0x" + thrSp.ToString("X") + + " a0=0x" + thrA0.ToString("X") + + " via=dump-mem-15c28-thr" + + " (dump lw $v1,0(ThreadPtr); honor ra;" + + " no invent dest / Thread* / 0x9A02)"); + } + + // Dump 0x80021024 jal memset 0x800593F0 + // then 0x8002102C lw $v0,284($fp). + // $fp is the wrote=0 frame. Observe + // the load; do not invent *fp / + // F000 / 0x9A02. + public static void TryNoteDumpMem15C28JalRet(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalThrLogged || _exn15C28JalRetLogged) + return; + if (pc != CoredllDllMainExn15C28JalRet) + return; + if (IsDumpMemRefuseVa(pc)) + return; + uint retDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out retDump) || retDump == 0) + retDump = CoredllDllMainExn15C28JalRetDump; + if (insn != retDump && insn != CoredllDllMainExn15C28JalRetDump) + return; + _exn15C28JalRetLogged = true; + uint retFp = PeekGpr(regs, 30); + uint retSp = PeekGpr(regs, 29); + uint retRa = PeekGpr(regs, 31); + uint retV0 = PeekGpr(regs, 2); + uint retDest = retFp + 284; + uint retPeek = 0; + bool retOk = retDest != 0 && (retDest & 3) == 0 + && (retDest & ~0xFFFu) != 0 + && !IsDumpMemRefuseVa(retDest) + && !IsC000StoreSkipVa(retDest) + && TryPeekWord(bus, retDest, out retPeek); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-memset-ret"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " dest=0x" + retDest.ToString("X") + + (retOk ? " *fp=0x" + retPeek.ToString("X") : " *fp-miss") + + " via=dump-mem-15c28-memset-ret"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 memset-ret" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + retDump.ToString("X") + + " fp=0x" + retFp.ToString("X") + + " dest=0x" + retDest.ToString("X") + + (retOk ? " *fp=0x" + retPeek.ToString("X") : " *fp-miss") + + " ra=0x" + retRa.ToString("X") + + " sp=0x" + retSp.ToString("X") + + " v0=0x" + retV0.ToString("X") + + " via=dump-mem-15c28-memset-ret" + + " (dump lw $v0,284($fp) after memset;" + + " honor ra; no invent dest / F000 / 0x9A02)"); + } + + // Live f48c2dc: after 59488-exec, + // memset-ret lw $v0,284($fp) + // dest=0x9A023F8C *fp-miss then + // 15c28-leave spun. Continue-skip + // when dest cannot peek (advance + // PC past load, honor ra). Load + // $v0 only if peek succeeds. + // Do not invent 0x9A02 / SUD. + // One-shot via=memset-ret-skip. + public static bool TryTakeDumpMem15C28JalRet(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_abs59488ExecLogged) + return false; + if (pc != CoredllDllMainExn15C28JalRet) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28JalRetNext)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28JalRetDump; + if (dump != CoredllDllMainExn15C28JalRetDump) + return false; + if (insn != dump && insn != CoredllDllMainExn15C28JalRetDump) + return false; + if (_exn15C28JalRetSkipLogged) + return false; + uint fp = PeekGpr(regs, 30); + uint ra = PeekGpr(regs, 31); + uint dest = fp + CoredllDllMainExn15C28JalRetOff; + uint peek = 0; + bool destOk = dest != 0 && (dest & 3) == 0 + && (dest & ~0xFFFu) != 0 + && !IsDumpMemRefuseVa(dest) + && dest != FfffF000Page + && (dest & ~0xFFFu) != FfffE000Page + && !IsC000StoreSkipVa(dest) + && TryPeekWord(bus, dest, out peek); + if (destOk) + PokeGpr(regs, 2, peek); + if (bus != null) + bus.ClearExlIfEpc(pc); + cpuPc = CoredllDllMainExn15C28JalRetNext; + _exn15C28JalRetLogged = true; + _exn15C28JalRetSkipLogged = true; + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 memset-ret skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28JalRetNext.ToString("X") + + " dump=0x" + dump.ToString("X") + + " fp=0x" + fp.ToString("X") + + " dest=0x" + dest.ToString("X") + + (destOk ? " *fp=0x" + peek.ToString("X") : " *fp-miss") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + (destOk ? " via=dump-mem-15c28-memset-ret" : " via=dump-mem-15c28-memset-ret-skip") + + " (dump lw $v0,284($fp); dest miss advances;" + + " honor ra; no invent 0x9A02 / SUD)"); + return true; + } + + // Live c270933: after after-memset, + // dump lw $t1,0($s1) at + // 0x80021040 s1=0x9A023FA0 + // *s1-miss then quiet spin. + // Continue-skip when dest cannot + // peek (advance PC past load, + // honor ra). Load $t1 only if + // peek succeeds. Do not invent + // 0x9A02 / SUD. One-shot + // via=dump-mem-15c28-s1-skip. + public static bool TryTakeDumpMem15C28JalS1(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28JalRetSkipLogged) + return false; + if (pc != CoredllDllMainExn15C28JalS1) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28JalS1Next)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28JalS1Dump; + if (dump != CoredllDllMainExn15C28JalS1Dump) + return false; + if (insn != dump && insn != CoredllDllMainExn15C28JalS1Dump) + return false; + if (_exn15C28JalS1SkipLogged) + return false; + uint s1 = PeekGpr(regs, 17); + uint ra = PeekGpr(regs, 31); + uint peek = 0; + bool destOk = s1 != 0 && (s1 & 3) == 0 + && (s1 & ~0xFFFu) != 0 + && !IsDumpMemRefuseVa(s1) + && s1 != FfffF000Page + && (s1 & ~0xFFFu) != FfffE000Page + && !IsC000StoreSkipVa(s1) + && TryPeekWord(bus, s1, out peek); + if (destOk) + PokeGpr(regs, 9, peek); + if (bus != null) + bus.ClearExlIfEpc(pc); + cpuPc = CoredllDllMainExn15C28JalS1Next; + _exn15C28JalS1Logged = true; + _exn15C28JalS1SkipLogged = true; + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + uint t1 = PeekGpr(regs, 9); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 s1 skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28JalS1Next.ToString("X") + + " dump=0x" + dump.ToString("X") + + " s1=0x" + s1.ToString("X") + + (destOk ? " *s1=0x" + peek.ToString("X") : " *s1-miss") + + " t1=0x" + t1.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + (destOk ? " via=dump-mem-15c28-s1" : " via=dump-mem-15c28-s1-skip") + + " (dump lw $t1,0($s1); dest miss advances;" + + " honor ra; no invent 0x9A02 / SUD)"); + return true; + } + + // Live 20f3972: after memset-ret + // skip, dump 0x80021030 lui then + // 0x80021040 lw $t1,0($s1). + // Peek *s1 only. Do not invent + // dest / SUD / 0x9A02. + public static void TryNoteDumpMem15C28JalS1(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalRetSkipLogged || _exn15C28JalS1Logged + || _exn15C28JalS1SkipLogged) + return; + if (pc != CoredllDllMainExn15C28JalRetNext + && pc != CoredllDllMainExn15C28JalS1) + return; + if (IsDumpMemRefuseVa(pc)) + return; + if (pc == CoredllDllMainExn15C28JalRetNext) + return; + uint s1Dump = DumpMem15C28AfterWord(pc); + if (s1Dump == 0) + s1Dump = CoredllDllMainExn15C28JalS1Dump; + if (insn != s1Dump && insn != CoredllDllMainExn15C28JalS1Dump) + return; + _exn15C28JalS1Logged = true; + uint s1 = PeekGpr(regs, 17); + uint s1Ra = PeekGpr(regs, 31); + uint s1Sp = PeekGpr(regs, 29); + uint s1V0 = PeekGpr(regs, 2); + uint s1Peek = 0; + bool s1Ok = s1 != 0 && (s1 & 3) == 0 + && (s1 & ~0xFFFu) != 0 + && !IsDumpMemRefuseVa(s1) + && (s1 & ~0xFFFu) != FfffE000Page + && s1 != FfffF000Page + && !IsC000StoreSkipVa(s1) + && TryPeekWord(bus, s1, out s1Peek); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-s1"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " s1=0x" + s1.ToString("X") + + (s1Ok ? " *s1=0x" + s1Peek.ToString("X") : " *s1-miss") + + " via=dump-mem-15c28-s1"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 s1" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + s1Dump.ToString("X") + + " s1=0x" + s1.ToString("X") + + (s1Ok ? " *s1=0x" + s1Peek.ToString("X") : " *s1-miss") + + " v0=0x" + s1V0.ToString("X") + + " ra=0x" + s1Ra.ToString("X") + + " sp=0x" + s1Sp.ToString("X") + + " via=dump-mem-15c28-s1" + + " (dump lw $t1,0($s1) after memset-ret;" + + " honor ra; no invent dest / SUD / 0x9A02)"); + } + + // Live 20f3972: memset-ret-skip + // set PC=0x80021030 then leave + // silent-stalled. Name first + // I-fetch at that PC (dump lui + // $v1,0x8034). One-shot. + // Do not invent dest / SUD. + public static void TryNoteDumpMem15C28AfterMemset(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalRetSkipLogged || _exn15C28AfterMemsetLogged) + return; + if (pc != CoredllDllMainExn15C28JalRetNext) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterMemsetLogged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = CoredllDllMainExn15C28JalRetNextDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterS1 = PeekGpr(regs, 17); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-memset"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-memset"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-memset" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " s1=0x" + afterS1.ToString("X") + + " via=dump-mem-15c28-after-memset" + + " (first I-fetch after memset-ret-skip;" + + " honor ra; no invent dest / SUD / 0x9A02)"); + } + + // Live c270933: s1-skip set + // PC=0x80021044. Name first + // I-fetch at that PC (dump + // lui $s2,0x8000). One-shot. + // Do not invent dest / SUD / + // 0x9A02. + public static void TryNoteDumpMem15C28AfterS1(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalS1SkipLogged || _exn15C28AfterS1Logged) + return; + if (pc != CoredllDllMainExn15C28JalS1Next) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + TryClearDumpMem15C28AfterS1Exl(bus, pc); + _exn15C28AfterS1Logged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = CoredllDllMainExn15C28JalS1NextDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterS1 = PeekGpr(regs, 17); + uint afterT1 = PeekGpr(regs, 9); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-s1"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-s1"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-s1" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " s1=0x" + afterS1.ToString("X") + + " t1=0x" + afterT1.ToString("X") + + " via=dump-mem-15c28-after-s1" + + " (first I-fetch after s1-skip;" + + " honor ra; no invent dest / SUD / 0x9A02)"); + } + + // Live 738e467: after-s1 named + // lui at 0x80021044 then quiet + // spin (EXL left set / no next + // log). Clear EXL so dump-true + // ALU after lui can run. Name + // first I-fetch at 0x80021048 + // (addiu $t4,$v1,6756). One-shot. + // Do not invent dest / page 0 / + // 0x9A02. + private static void TryClearDumpMem15C28AfterS1Exl(MipsBus bus, uint pc) + { + if (bus == null) + return; + if (pc != CoredllDllMainExn15C28JalS1Next + && pc != CoredllDllMainExn15C28JalS1After) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + bus.ClearExlIfEpc(CoredllDllMainExn15C28JalS1); + bus.ClearExlIfEpc(CoredllDllMainExn15C28JalS1Next); + bus.ClearExlIfEpc(CoredllDllMainExn15C28JalS1After); + } + + public static void TryNoteDumpMem15C28AfterS1Next(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterS1Logged || _exn15C28AfterS1NextLogged) + return; + if (pc != CoredllDllMainExn15C28JalS1After) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + TryClearDumpMem15C28AfterS1Exl(bus, pc); + _exn15C28AfterS1NextLogged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = CoredllDllMainExn15C28JalS1AfterDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterS1 = PeekGpr(regs, 17); + uint afterT1 = PeekGpr(regs, 9); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-s1-next"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-s1-next"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-s1-next" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " s1=0x" + afterS1.ToString("X") + + " t1=0x" + afterT1.ToString("X") + + " via=dump-mem-15c28-after-s1-next" + + " (first I-fetch after after-s1 lui;" + + " clear exl; honor ra; no invent dest / page 0 / 0x9A02)"); + } + + // Dump-true ALU at 0x80021048–0x80021058: + // addiu/ori/andi/lui (and safe + // SPECIAL). Refuse MUL funct 0x16, + // jr/jalr/syscall/break, loads, + // stores. Used to exec healed + // words, not log-only. + private static bool IsDumpMemAluInsn(uint insn) + { + uint op = insn >> 26; + if (op == 0) + { + uint fn = insn & 63; + if (fn == 0x16) + return false; + if (fn == 8 || fn == 9 || fn == 12 || fn == 13) + return false; + if (fn == 24 || fn == 25 || fn == 26 || fn == 27) + return false; + return fn == 0 || fn == 2 || fn == 3 || fn == 4 + || fn == 6 || fn == 7 + || fn == 33 || fn == 35 || fn == 36 || fn == 37 + || fn == 38 || fn == 39 || fn == 42 || fn == 43; + } + return op >= 8 && op <= 15; + } + + private static bool TryExecDumpMemAlu(uint[] regs, uint insn) + { + if (!IsDumpMemAluInsn(insn)) + return false; + uint op = insn >> 26; + int rs = (int)((insn >> 21) & 31); + int rt = (int)((insn >> 16) & 31); + int rd = (int)((insn >> 11) & 31); + int sh = (int)((insn >> 6) & 31); + uint fn = insn & 63; + uint imm = insn & 0xFFFF; + int simm = (short)imm; + uint rsv = PeekGpr(regs, rs); + uint rtv = PeekGpr(regs, rt); + if (op == 0) + { + uint d = 0; + if (fn == 0) + d = rtv << sh; + else if (fn == 2) + d = rtv >> sh; + else if (fn == 3) + d = (uint)((int)rtv >> sh); + else if (fn == 4) + d = rtv << (int)(rsv & 31); + else if (fn == 6) + d = rtv >> (int)(rsv & 31); + else if (fn == 7) + d = (uint)((int)rtv >> (int)(rsv & 31)); + else if (fn == 33) + d = rsv + rtv; + else if (fn == 35) + d = rsv - rtv; + else if (fn == 36) + d = rsv & rtv; + else if (fn == 37) + d = rsv | rtv; + else if (fn == 38) + d = rsv ^ rtv; + else if (fn == 39) + d = ~(rsv | rtv); + else if (fn == 42) + d = (int)rsv < (int)rtv ? 1u : 0u; + else if (fn == 43) + d = rsv < rtv ? 1u : 0u; + else + return false; + PokeGpr(regs, rd, d); + return true; + } + uint dest = 0; + if (op == 8 || op == 9) + dest = rsv + (uint)simm; + else if (op == 10) + dest = (int)rsv < simm ? 1u : 0u; + else if (op == 11) + dest = rsv < (uint)simm ? 1u : 0u; + else if (op == 12) + dest = rsv & imm; + else if (op == 13) + dest = rsv | imm; + else if (op == 14) + dest = rsv ^ imm; + else if (op == 15) + dest = imm << 16; + else + return false; + PokeGpr(regs, rt, dest); + return true; + } + + // Live fe74462: after-s1-next named + // addiu at 0x80021048 then quiet + // spin — heal was log-only. Execute + // dump-true ALU 0x80021048–0x80021058 + // (set regs, PC:=0x8002105C), clear + // EXL. One-shot. No MUL. No invent + // dest / 0x9A02 / page 0. + public static bool TryTakeDumpMem15C28AfterS1Alu(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterS1Logged || _exn15C28AfterS1AluLogged) + return false; + if (pc < CoredllDllMainExn15C28JalS1After + || pc > CoredllDllMainExn15C28JalS1After5) + return false; + if ((pc & 3) != 0) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28JalS1AluNext)) + return false; + uint first = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out first) || first == 0) + first = DumpMem15C28AfterWord(pc); + if (first == 0 || !IsDumpMemAluInsn(first)) + return false; + if (insn != first && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != first && insn != 0) + TryHealDumpInsn(bus, pc, insn, first); + uint ran = 0; + for (uint p = pc; p <= CoredllDllMainExn15C28JalS1After5; p += 4) + { + uint dump = DumpMem15C28AfterWord(p); + if (dump == 0 || !IsDumpMemAluInsn(dump)) + return false; + ran++; + } + for (uint p = pc; p <= CoredllDllMainExn15C28JalS1After5; p += 4) + { + uint dump = DumpMem15C28AfterWord(p); + if (!TryExecDumpMemAlu(regs, dump)) + return false; + } + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + bus.ClearExlIfEpc(CoredllDllMainExn15C28JalS1After); + } + cpuPc = CoredllDllMainExn15C28JalS1AluNext; + _exn15C28AfterS1NextLogged = true; + _exn15C28AfterS1AluLogged = true; + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + uint t4 = PeekGpr(regs, 12); + uint s2 = PeekGpr(regs, 18); + uint s4 = PeekGpr(regs, 20); + uint t2 = PeekGpr(regs, 10); + uint s0 = PeekGpr(regs, 16); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-s1-alu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28JalS1AluNext.ToString("X") + + " dump=0x" + first.ToString("X") + + " n=" + ran.ToString() + + " t4=0x" + t4.ToString("X") + + " s2=0x" + s2.ToString("X") + + " s4=0x" + s4.ToString("X") + + " t2=0x" + t2.ToString("X") + + " s0=0x" + s0.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " via=dump-mem-15c28-after-s1-alu" + + " (dump addiu/ori/andi/lui 0x80021048-0x80021058;" + + " exec regs; PC>=0x8002105C; clear exl; no MUL;" + + " honor ra; no invent dest / 0x9A02)"); + return true; + } + + // Live fe74462: after ALU exec, + // name first I-fetch past + // 0x80021058 (dump sw $t3,52($sp) + // at 0x8002105C). One-shot. + // Do not invent dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterS1Alu(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterS1AluLogged || _exn15C28AfterS1AluNextLogged) + return; + if (pc != CoredllDllMainExn15C28JalS1AluNext) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterS1AluNextLogged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = CoredllDllMainExn15C28JalS1AluNextDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterT3 = PeekGpr(regs, 11); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-s1-alu-next"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-s1-alu-next"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-s1-alu-next" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " t3=0x" + afterT3.ToString("X") + + " via=dump-mem-15c28-after-s1-alu-next" + + " (first I-fetch after 21048-21058 exec;" + + " honor ra; no invent dest / 0x9A02)"); + } + + private static bool IsExn15C28Na02Frame(uint va) + { + return (va & 0xFF000000u) == 0x9A000000u; + } + + // Live fac4e01: after named + // lw $s4 at 0x8003F7D8, ~7× + // after-stk-sw at 0x80021060 + // on 0x9FFFF* frames. Detect + // only; do not invent a 0x9F + // page. + private static bool IsExn15C28NfffFrame(uint va) + { + return (va & 0xFFF00000u) == 0x9FF00000u; + } + + // Live dcf9658: after a3-lui, $sp + // walked 0x9A02… into 0x99FF… + // (0x99FFF5A8 / 0x99FFF128). + // Detect only; do not invent a + // 0x99FF page. + private static bool IsExn15C28N9ffFrame(uint va) + { + return (va & 0xFFF00000u) == 0x99F00000u; + } + + private static bool IsExn15C28StkRecurseFrame(uint va) + { + return IsExn15C28Na02Frame(va) || IsExn15C28NfffFrame(va) + || IsExn15C28N9ffFrame(va); + } + + private static bool IsExn15C28OuterJalLwS4Progress() + { + return _exn15C28AfterOuterJalEpiRetCallerRaBneLogged + || _exn15C28AfterOuterJalEpiRetCallerRaT1Logged + || _exn15C28AfterOuterJalEpiRetCallerRaS3Logged + || _exn15C28AfterOuterJalEpiRetCallerRaLhuLogged + || _exn15C28AfterOuterJalEpiRetCallerRaLogged + || _exn15C28AfterOuterJalEpiRetCallerRaNextLogged + || _exn15C28AfterOuterJalEpiRetCallerNextFnLogged + || _exn15C28AfterOuterJalEpiRetCallerNextFnNextLogged + || _exn15C28AfterOuterJalEpiRetCallerLogged + || _exn15C28AfterOuterJalEpiRetCallerNextLogged + || _exn15C28AfterOuterJalEpiRetFallLogged + || _exn15C28AfterOuterJalEpiRetFallNextLogged + || _exn15C28AfterOuterJalEpiRetBneLogged + || _exn15C28AfterOuterJalEpiRetBneNextLogged + || _exn15C28AfterOuterJalEpiRetLogged + || _exn15C28AfterOuterJalEpiRetNextLogged + || _exn15C28AfterOuterJalEpiTrampolineLogged + || _exn15C28AfterOuterJalEpiTrampolineNextLogged + || _exn15C28AfterOuterJalEpiPrologueJalLogged + || _exn15C28AfterOuterJalEpiPrologueJalNextLogged + || _exn15C28AfterOuterJalEpiPrologueSwLogged + || _exn15C28AfterOuterJalEpiPrologueSwNextLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged + || _exn15C28AfterOuterJalEpiBeqBneFallSwLogged + || _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged + || _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged + || _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged + || _exn15C28AfterOuterJalEpiBeqBneFallLogged + || _exn15C28AfterOuterJalEpiBeqBneNextLogged + || _exn15C28AfterOuterJalEpiBeqBneLogged + || _exn15C28AfterOuterJalEpiBeqSltLogged + || _exn15C28AfterOuterJalEpiBeqSltNextLogged + || _exn15C28AfterOuterJalEpiBeqAddiuLogged + || _exn15C28AfterOuterJalEpiBeqAddiuNextLogged + || _exn15C28AfterOuterJalEpiBeqLogged + || _exn15C28AfterOuterJalEpiBeqNextLogged + || _exn15C28AfterOuterJalEpiSltuLogged + || _exn15C28AfterOuterJalEpiSltuNextLogged + || _exn15C28AfterOuterJalEpiA3LhuLogged + || _exn15C28AfterOuterJalEpiA3LhuNextLogged + || _exn15C28AfterOuterJalEpiA1AddiuNextLogged + || _exn15C28AfterOuterJalEpiA1AddiuLogged + || _exn15C28AfterOuterJalEpiA2SwLogged + || _exn15C28AfterOuterJalEpiA2SwNextLogged + || _exn15C28AfterOuterJalEpiA2AddiuNextLogged + || _exn15C28AfterOuterJalEpiA2AddiuLogged + || _exn15C28AfterOuterJalEpiLhuLogged + || _exn15C28AfterOuterJalEpiA3LuiNextLogged + || _exn15C28AfterOuterJalEpiA3LuiLogged + || _exn15C28AfterOuterJalEpiSwNextLogged + || _exn15C28AfterOuterJalEpiSwLogged + || _exn15C28AfterOuterJalEpiV1AddiuNextLogged + || _exn15C28AfterOuterJalEpiV1AddiuLogged + || _exn15C28AfterOuterJalEpiV0AddiuNextLogged + || _exn15C28AfterOuterJalEpiV0AddiuLogged + || _exn15C28AfterOuterJalEpiLuiNextLogged + || _exn15C28AfterOuterJalEpiLuiLogged + || _exn15C28AfterOuterJalEpiJrNextLogged + || _exn15C28AfterOuterJalEpiJrLogged + || _exn15C28AfterOuterJalEpiAddiuNextLogged + || _exn15C28AfterOuterJalEpiAddiuLogged + || _exn15C28AfterOuterJalLwRaNextLogged + || _exn15C28AfterOuterJalLwRaLogged + || _exn15C28AfterOuterJalLwS0NextLogged + || _exn15C28AfterOuterJalLwS0Logged + || _exn15C28AfterOuterJalLwS1NextLogged + || _exn15C28AfterOuterJalLwS1Logged + || _exn15C28AfterOuterJalLwS2NextLogged + || _exn15C28AfterOuterJalLwS2Logged + || _exn15C28AfterOuterJalLwS3NextLogged + || _exn15C28AfterOuterJalLwS3Logged + || _exn15C28AfterOuterJalLwS4NextLogged + || _exn15C28AfterOuterJalLwS4Logged + || _exn15C28AfterOuterJalLwS5NextLogged; + } + + // Live 97fb310: after-s1-alu-next + // named sw $t3,52($sp) at + // 0x8002105C sp=0x9A023DA8 dest + // 0x9A023DDC *sp-miss then host + // spin. StkPage was 0 so + // 15c28-stk-skip did not fire. + // Swallow dest-miss store, PC:= + // 0x80021060, clear EXL. Do not + // invent 0x9A02. Re-arm whenever + // dump-match + 0x9A02 (rate-limit + // log). via=dump-mem-15c28-stk-sw-skip. + public static bool TryTakeDumpMem15C28StkSw(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterS1AluLogged) + return false; + if (pc != CoredllDllMainExn15C28JalS1AluNext) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28StkSwNext)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28JalS1AluNextDump; + if (dump != CoredllDllMainExn15C28JalS1AluNextDump) + return false; + if (insn != dump && insn != CoredllDllMainExn15C28JalS1AluNextDump + && !IsMipsStore(insn)) + return false; + uint sp = PeekGpr(regs, 29); + uint ra = PeekGpr(regs, 31); + uint dest = sp + CoredllDllMainExn15C28StkSwOff; + if (!IsExn15C28Na02Frame(sp) && !IsExn15C28Na02Frame(dest)) + return false; + if (IsDumpMemRefuseVa(dest) || IsDumpMemRefuseVa(sp)) + return false; + uint peek = 0; + bool destOk = dest != 0 && (dest & 3) == 0 + && !IsDumpMemRefuseVa(dest) + && (dest & ~0xFFFu) != 0 + && !IsExn15C28Na02Frame(dest) + && TryPeekWord(bus, dest, out peek); + if (destOk) + return false; + if (IsExn15C28Na02RecurseCap()) + { + uint leave = 0; + if (!TryLeaveDumpMem15C28PastJalRa(bus, regs, pc, ref cpuPc, out leave)) + return false; + _exn15C28StkSwSkipLogged = true; + _exn15C28AfterS1AluNextLogged = true; + uint capT3 = PeekGpr(regs, 11); + uint capV0 = PeekGpr(regs, 2); + if (_exn15C28StkSwLogN < 8 && _exn15C28StkSwLast != dest) + { + _exn15C28StkSwLogN++; + _exn15C28StkSwLast = dest; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 stk-sw skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + leave.ToString("X") + + " dump=0x" + dump.ToString("X") + + " sp=0x" + sp.ToString("X") + + " dest=0x" + dest.ToString("X") + + " t3=0x" + capT3.ToString("X") + + " v0=0x" + capV0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " cap=1" + + " via=dump-mem-15c28-stk-sw-skip" + + " (0x9A02 recurse cap; dump-true leave;" + + " honor ra; no invent 0x9A02)"); + } + return true; + } + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + Note15C28Left(dest); + cpuPc = CoredllDllMainExn15C28StkSwNext; + _exn15C28StkSwSkipLogged = true; + _exn15C28AfterS1AluNextLogged = true; + uint t3 = PeekGpr(regs, 11); + uint v0 = PeekGpr(regs, 2); + if (_exn15C28StkSwLogN < 8 && _exn15C28StkSwLast != dest) + { + _exn15C28StkSwLogN++; + _exn15C28StkSwLast = dest; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 stk-sw skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28StkSwNext.ToString("X") + + " dump=0x" + dump.ToString("X") + + " sp=0x" + sp.ToString("X") + + " dest=0x" + dest.ToString("X") + + " t3=0x" + t3.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " via=dump-mem-15c28-stk-sw-skip" + + " (dump sw $t3,52($sp); dest miss advances;" + + " re-arm 0x9A02 frames; honor ra; no invent 0x9A02)"); + } + return true; + } + + // Live 97fb310: after stk-sw skip, + // dump 0x80021060 is bne $t2,$0, + // +28 → 0x800210D4; delay + // sw $t4,68($sp) is another + // 0x9A02 dest-miss. Name the + // I-fetch, execute dump-true bne, + // skip delay store, PC:=taken or + // fallthrough. Re-arm with stk-sw + // (rate-limit log). Do not invent + // 0x9A02. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterStkSwBne(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28StkSwSkipLogged) + return false; + if (pc != CoredllDllMainExn15C28StkSwNext) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28StkSwBneFall) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28StkSwBneTaken)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28StkSwNextDump; + if (dump != CoredllDllMainExn15C28StkSwNextDump) + return false; + if (insn != dump && insn != CoredllDllMainExn15C28StkSwNextDump) + return false; + uint delay = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainExn15C28StkSwDelay, + out delay) || delay == 0) + delay = CoredllDllMainExn15C28StkSwDelayDump; + if (delay != 0 && IsDumpMemAluInsn(delay)) + TryExecDumpMemAlu(regs, delay); + uint t2 = PeekGpr(regs, 10); + bool taken = t2 != 0; + uint dest = taken + ? CoredllDllMainExn15C28StkSwBneTaken + : CoredllDllMainExn15C28StkSwBneFall; + if (IsDumpMemRefuseVa(dest)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = dest; + _exn15C28AfterStkSwLogged = true; + _exn15C28AfterStkSwBneLogged = true; + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + string dumpDis = dump != 0 + ? FormatMipsOp(pc, dump) + : "dump-miss"; + uint bneKey = dest ^ sp; + if (_exn15C28AfterStkSwBneLogN < 8 && _exn15C28AfterStkSwBneLast != bneKey) + { + _exn15C28AfterStkSwBneLogN++; + _exn15C28AfterStkSwBneLast = bneKey; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-stk-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " dump=0x" + dump.ToString("X") + + " via=dump-mem-15c28-after-stk-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-stk-sw" + + " pc=0x" + pc.ToString("X") + + " next=0x" + dest.ToString("X") + + " dump=0x" + dump.ToString("X") + + " dump-dis=" + dumpDis + + " t2=0x" + t2.ToString("X") + + (taken ? " taken=1" : " taken=0") + + " delay=0x" + delay.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " via=dump-mem-15c28-after-stk-sw" + + " (dump bne $t2,$0; skip 0x9A02 delay sw;" + + " re-arm 0x9A02 frames; honor ra; no invent 0x9A02)"); + } + return true; + } + + public static void TryNoteDumpMem15C28AfterStkSw(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28StkSwSkipLogged || _exn15C28AfterStkSwLogged) + return; + if (pc != CoredllDllMainExn15C28StkSwNext) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterStkSwLogged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = CoredllDllMainExn15C28StkSwNextDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterT2 = PeekGpr(regs, 10); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-stk-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-stk-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-stk-sw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " t2=0x" + afterT2.ToString("X") + + " via=dump-mem-15c28-after-stk-sw" + + " (first I-fetch after stk-sw-skip;" + + " honor ra; no invent dest / 0x9A02)"); + } + + public static void TryNoteDumpMem15C28AfterStkSwNext(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterStkSwBneLogged || _exn15C28AfterStkSwNextLogged) + return; + if (pc != CoredllDllMainExn15C28StkSwBneFall + && pc != CoredllDllMainExn15C28StkSwBneTaken) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterStkSwNextLogged = true; + uint afterDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out afterDump); + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-stk-sw-next"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-stk-sw-next"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-stk-sw-next" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " via=dump-mem-15c28-after-stk-sw-next" + + " (first I-fetch after stk-sw bne;" + + " honor ra; no invent dest / 0x9A02)"); + } + + // Live b235cc9: after stk-sw + bne + // taken=0, first I-fetch at + // 0x80021068 is dump lw $t7,160($fp) + // dest ≈0x9A023F10 *fp-miss then + // second frame 0x8002105C spent the + // stk-sw latch. Swallow dest-miss + // load (leave $t7); continue-skip + // further dump-true 0x9A02 memops; + // exec dump-true ALU / beq / jal / + // jr. PC:=first non-skip. Clear EXL. + // Re-arm 0x9A02 frames (rate-limit + // log). Do not invent 0x9A02. + public static bool TryTakeDumpMem15C28FpLw(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterS1AluLogged) + return false; + if (pc != CoredllDllMainExn15C28FpLw) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28FpLwNext)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28FpLwDump; + if (dump != CoredllDllMainExn15C28FpLwDump) + return false; + if (insn != dump && insn != CoredllDllMainExn15C28FpLwDump + && !IsMipsLoad(insn)) + return false; + uint fp = PeekGpr(regs, 30); + uint dest = fp + CoredllDllMainExn15C28FpLwOff; + if (!IsExn15C28Na02Frame(fp) && !IsExn15C28Na02Frame(dest)) + return false; + if (IsDumpMemRefuseVa(dest) || IsDumpMemRefuseVa(fp)) + return false; + uint peek = 0; + bool destOk = dest != 0 && (dest & 3) == 0 + && !IsDumpMemRefuseVa(dest) + && (dest & ~0xFFFu) != 0 + && !IsExn15C28Na02Frame(dest) + && TryPeekWord(bus, dest, out peek); + if (destOk) + return false; + if (IsExn15C28Na02RecurseCap()) + { + uint leave = 0; + if (!TryLeaveDumpMem15C28PastJalRa(bus, regs, pc, ref cpuPc, out leave)) + return false; + _exn15C28FpLwSkipLogged = true; + _exn15C28AfterStkSwNextLogged = true; + uint raCap = PeekGpr(regs, 31); + uint spCap = PeekGpr(regs, 29); + uint v0Cap = PeekGpr(regs, 2); + uint t7Cap = PeekGpr(regs, 15); + if (_exn15C28FpLwLogN < 8 && _exn15C28FpLwLast != dest) + { + _exn15C28FpLwLogN++; + _exn15C28FpLwLast = dest; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 fp-lw skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + leave.ToString("X") + + " dump=0x" + dump.ToString("X") + + " nskip=0 nalu=0 br=0 cap=1" + + " fp=0x" + fp.ToString("X") + + " dest=0x" + dest.ToString("X") + + " t7=0x" + t7Cap.ToString("X") + + " v0=0x" + v0Cap.ToString("X") + + " ra=0x" + raCap.ToString("X") + + " sp=0x" + spCap.ToString("X") + + " via=dump-mem-15c28-fp-lw-skip" + + " (0x9A02 recurse cap; dump-true leave;" + + " honor ra; no invent 0x9A02)"); + } + return true; + } + uint walkPc = pc; + int nSkip = 0; + int nAlu = 0; + bool tookBr = false; + for (int i = 0; i < 16; i++) + { + if (IsDumpMemRefuseVa(walkPc)) + break; + uint w = DumpMem15C28AfterWord(walkPc); + if (w == 0) + break; + uint op = w >> 26; + int rs = (int)((w >> 21) & 31); + int rt = (int)((w >> 16) & 31); + int rd = (int)((w >> 11) & 31); + uint fn = w & 63; + short imm = (short)(w & 0xFFFF); + uint bas = PeekGpr(regs, rs); + uint ea = unchecked(bas + (uint)(int)imm); + if ((IsMipsLoad(w) || IsMipsStore(w)) + && (IsExn15C28Na02Frame(bas) || IsExn15C28Na02Frame(ea))) + { + if (IsDumpMemRefuseVa(ea) || IsDumpMemRefuseVa(bas)) + break; + nSkip++; + walkPc += 4; + continue; + } + if (IsDumpMemAluInsn(w)) + { + if (!TryExecDumpMemAlu(regs, w)) + break; + nAlu++; + walkPc += 4; + continue; + } + if (op == 4 || op == 5) + { + uint rsv = PeekGpr(regs, rs); + uint rtv = PeekGpr(regs, rt); + bool taken = op == 4 ? rsv == rtv : rsv != rtv; + uint next = taken + ? unchecked(walkPc + 4 + ((uint)(int)imm << 2)) + : walkPc + 8; + if (IsDumpMemRefuseVa(next)) + return false; + uint delay = DumpMem15C28AfterWord(walkPc + 4); + if (delay != 0 && IsDumpMemAluInsn(delay)) + TryExecDumpMemAlu(regs, delay); + walkPc = next; + tookBr = true; + break; + } + if (op == 2 || op == 3) + { + uint next = (walkPc & 0xF0000000u) | ((w & 0x03FFFFFFu) << 2); + if (IsDumpMemRefuseVa(next)) + return false; + if (op == 3) + PokeGpr(regs, 31, walkPc + 8); + walkPc = next; + tookBr = true; + break; + } + if (op == 0 && (fn == 8 || fn == 9)) + { + uint next = PeekGpr(regs, rs); + if (IsDumpMemRefuseVa(next)) + return false; + if (fn == 9 && rd != 0) + PokeGpr(regs, rd, walkPc + 8); + else if (fn == 9) + PokeGpr(regs, 31, walkPc + 8); + walkPc = next; + tookBr = true; + break; + } + break; + } + if (nSkip == 0) + return false; + if (walkPc == pc || IsDumpMemRefuseVa(walkPc)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + Note15C28Left(dest); + cpuPc = walkPc; + _exn15C28FpLwSkipLogged = true; + _exn15C28AfterStkSwNextLogged = true; + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + uint t7 = PeekGpr(regs, 15); + if (_exn15C28FpLwLogN < 8 && _exn15C28FpLwLast != dest) + { + _exn15C28FpLwLogN++; + _exn15C28FpLwLast = dest; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 fp-lw skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + walkPc.ToString("X") + + " dump=0x" + dump.ToString("X") + + " nskip=" + nSkip.ToString() + + " nalu=" + nAlu.ToString() + + (tookBr ? " br=1" : " br=0") + + " fp=0x" + fp.ToString("X") + + " dest=0x" + dest.ToString("X") + + " t7=0x" + t7.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " via=dump-mem-15c28-fp-lw-skip" + + " (dump lw $t7,160($fp); dest miss advances;" + + " continue-skip 0x9A02 memops; exec ALU/beq;" + + " honor ra; no invent 0x9A02)"); + } + return true; + } + + public static void TryNoteDumpMem15C28AfterFpLw(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28FpLwSkipLogged || _exn15C28AfterFpLwLogged) + return; + if (pc == CoredllDllMainExn15C28FpLw) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterFpLwLogged = true; + uint afterDump = DumpMem15C28AfterWord(pc); + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterFp = PeekGpr(regs, 30); + uint afterT7 = PeekGpr(regs, 15); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-fp-lw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-fp-lw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-fp-lw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " fp=0x" + afterFp.ToString("X") + + " t7=0x" + afterT7.ToString("X") + + " via=dump-mem-15c28-after-fp-lw" + + " (first I-fetch after fp-lw-skip;" + + " honor ra; no invent dest / 0x9A02)"); + } + + private static bool IsExn15C28HelperBody(uint va) + { + return va >= CoredllDllMainExn15C28JalDest + && va <= CoredllDllMainExn15C28EpiDelay; + } + + private static bool IsExn15C28Na02RecurseCap() + { + return _exn15C28SpT9SkipLogged + || _exn15C28AfterFpLwLogged + || _exn15C28FpLwLogN >= 2; + } + + // Live d77b740: after-fp-lw named + // 0x800214D8 lw $t9,52($sp) then + // 8× 0x9A02 frames (sp -= 0x240, + // ra stuck 0x8002102C). Dump next + // is lw $v0,0($t9) — not jalr $t9. + // Do not invent $t9. Dump-true + // helper jr $ra is 0x800219A8 after + // stack restores we cannot invent. + // Live ra 0x8002102C is memset-ret + // inside the helper (recurse). + // Leave via dump-true jal-link + // 0x80015C44. Exec dump-true + // addiu $sp,$sp,200. Cap further + // stk-sw/fp-lw laps. + private static bool TryLeaveDumpMem15C28Helper(MipsBus bus, + uint[] regs, uint fromPc, ref uint cpuPc, out uint leave) + { + leave = 0; + uint ra = PeekGpr(regs, 31); + if (ra != 0 && (ra & 3) == 0 && !IsDumpMemRefuseVa(ra) + && !IsExn15C28HelperBody(ra)) + leave = ra; + else + leave = CoredllDllMainExn15C28JalRa; + if (leave == 0 || (leave & 3) != 0 || IsDumpMemRefuseVa(leave) + || IsDumpMemRefuseVa(fromPc)) + { + leave = 0; + return false; + } + uint delay = 0; + if (!TryPeekLeftoverWait99DumpOnly(CoredllDllMainExn15C28EpiDelay, + out delay) || delay == 0) + delay = CoredllDllMainExn15C28EpiDelayDump; + if (delay == CoredllDllMainExn15C28EpiDelayDump + && IsDumpMemAluInsn(delay)) + TryExecDumpMemAlu(regs, delay); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(fromPc); + } + cpuPc = leave; + _exn15C28SpT9SkipLogged = true; + _exn15C28AfterFpLwLogged = true; + return true; + } + + public static bool TryTakeDumpMem15C28SpT9(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterS1AluLogged) + return false; + if (pc != CoredllDllMainExn15C28SpT9) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28JalRa)) + return false; + uint dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out dump) || dump == 0) + dump = CoredllDllMainExn15C28SpT9Dump; + if (dump != CoredllDllMainExn15C28SpT9Dump) + return false; + if (insn != dump && insn != CoredllDllMainExn15C28SpT9Dump + && !IsMipsLoad(insn)) + return false; + uint sp = PeekGpr(regs, 29); + uint dest = sp + CoredllDllMainExn15C28SpT9Off; + if (!IsExn15C28Na02Frame(sp) && !IsExn15C28Na02Frame(dest)) + return false; + if (IsDumpMemRefuseVa(dest) || IsDumpMemRefuseVa(sp)) + return false; + uint peek = 0; + bool destOk = dest != 0 && (dest & 3) == 0 + && !IsDumpMemRefuseVa(dest) + && (dest & ~0xFFFu) != 0 + && !IsExn15C28Na02Frame(dest) + && TryPeekWord(bus, dest, out peek); + if (destOk) + return false; + uint nextDump = DumpMem15C28AfterWord(CoredllDllMainExn15C28SpT9Next); + if (nextDump == 0) + nextDump = CoredllDllMainExn15C28SpT9NextDump; + if (nextDump != CoredllDllMainExn15C28SpT9NextDump) + return false; + uint leave = 0; + if (!TryLeaveDumpMem15C28Helper(bus, regs, pc, ref cpuPc, out leave)) + return false; + Note15C28Left(dest); + _exn15C28AfterStkSwNextLogged = true; + uint ra = PeekGpr(regs, 31); + uint v0 = PeekGpr(regs, 2); + uint t9 = PeekGpr(regs, 25); + uint fp = PeekGpr(regs, 30); + if (_exn15C28SpT9LogN < 8 && _exn15C28SpT9Last != dest) + { + _exn15C28SpT9LogN++; + _exn15C28SpT9Last = dest; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 sp-t9 skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + leave.ToString("X") + + " dump=0x" + dump.ToString("X") + + " next-dump=0x" + nextDump.ToString("X") + + " sp=0x" + sp.ToString("X") + + " dest=0x" + dest.ToString("X") + + " t9=0x" + t9.ToString("X") + + " fp=0x" + fp.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " via=dump-mem-15c28-sp-t9-skip" + + " (dump lw $t9,52($sp); dest miss; no invent t9;" + + " dump next lw $v0,0($t9); leave dump-jal-ra;" + + " exec addiu $sp,200; honor ra; no invent 0x9A02)"); + } + return true; + } + + public static void TryNoteDumpMem15C28AfterSpT9(MipsBus bus, uint[] regs, + uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28SpT9SkipLogged || _exn15C28AfterSpT9Logged) + return; + if (pc == CoredllDllMainExn15C28SpT9 + || IsExn15C28HelperBody(pc)) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterSpT9Logged = true; + uint afterDump = DumpMem15C28AfterWord(pc); + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterT9 = PeekGpr(regs, 25); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-sp-t9"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-sp-t9"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-sp-t9" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " t9=0x" + afterT9.ToString("X") + + " via=dump-mem-15c28-after-sp-t9" + + " (first I-fetch after sp-t9-skip leave;" + + " honor ra; no invent dest / 0x9A02)"); + } + + private static bool IsDumpMemCop0(uint insn) + { + uint op = insn >> 26; + return op == 16 || op == 17; + } + + private static bool IsExn15C28JalRaEpiRange(uint pc) + { + return pc >= CoredllDllMainExn15C28JalRa + && pc <= CoredllDllMainExn15C28JalRaEpiEnd + && (pc & 3) == 0; + } + + private static bool TryLeaveDumpMem15C28Outer(MipsBus bus, uint[] regs, + uint fromPc, ref uint cpuPc, out uint leave) + { + leave = CoredllDllMainExn15C28OuterRa; + if (leave == 0 || (leave & 3) != 0 || IsDumpMemRefuseVa(leave) + || IsDumpMemRefuseVa(fromPc) || IsExn15C28Na02Frame(leave) + || IsExn15C28HelperBody(leave) || IsWrapDestSize(leave) + || IsWrapDestFp50Va(leave)) + { + leave = 0; + return false; + } + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(fromPc); + } + cpuPc = leave; + _exn15C28JalRaEpiSkipLogged = true; + _exn15C28AfterSpT9Logged = true; + return true; + } + + // Live 5d27a34: stk-sw cap left + // to 0x80048174 after dest ALU + // and spun on the unskipped + // 0x9A lw at 0x80048180. After + // dest ALU, leave 0x80048180 so + // lw-skip can fire. After lw-skip, + // leave cookie 0x80048190. After + // jr, leave dump-true link + // 0x8003F78C. After s3 / bne, + // leave 0x8003F7A0 / taken + // 0x8003F7AC / join 0x8003F7B0. + // After sltu / beq / addiu / + // lw-t4 / lw-s7 / addu, leave + // 0x8003F7B4 / fall 0x8003F7BC / + // 0x8003F7C0 / 0x8003F7C4 / + // 0x8003F7C8 / 0x8003F7CC / + // 0x8003F7D0 / 0x8003F7D4 / + // 0x8003F7D8 / 0x8003F7DC / + // 0x8003F7E0 / 0x8003F7E4 / + // 0x8003F7E8 / 0x8003F7EC / + // 0x8003F7F0 / 0x8003F7F4 / + // 0x8003F7FC / 0x8003F800 / + // 0x8003F808 / 0x8003F80C / + // 0x8003F810 / 0x8003F814. Do + // not leave MUL dest 0x8003F748. + // Live dcf9658: named lhu then + // stuck name-only. After a3-lui + // or this lhu skip, leave + // 0x8003F814. Dest-miss skip + // lhu $v1,0($v0) on ~0x8032024C. + // Do not invent 0x8032 page. + // Do not jr hop 0x8003F78C. + // Live 7b548eb: named sw then + // stuck name-only. After + // v1-addiu or this sw skip, + // leave 0x8003F80C. Dest-miss + // skip sw $v0,0($v1) on + // 0xFFFFDB18. Do not invent + // KData. Do not jr hop + // 0x8003F78C. + // Live ce53ead: named lui then + // stuck name-only. After epi-jr + // or lui, leave 0x8003F800. Do + // not jr hop 0x8003F78C. Live + // 9fc60b8: named jr then stuck + // name-only. After addiu-next + // or epi-jr, leave 0x8003F7FC. + // Do not jr hop 0x8003F78C. + // Live e466bce: + // named addiu then stuck + // name-only. After lw-ra-next + // or addiu, leave 0x8003F7F4. + // Do not jr hop. + // Live ceee1bd: named lw-ra then + // stuck name-only. After + // lw-s0-next or lw-ra, leave + // 0x8003F7F0. Live d5e2773: + // named lw-s0 then 7× after-stk- + // sw cap=1 left 0x8003F7E8. + // After lw-s1-next or lw-s0, + // leave 0x8003F7EC. + // Live e18b007: named lw-s1 then + // spun. After lw-s2-next or + // lw-s1, leave 0x8003F7E8. Live + // 8533465: named lw-s2 then + // spun. After lw-s3-next or + // lw-s2, leave 0x8003F7E4. Live + // Live c9b2f7a: named lw-s3 then + // spun. After lw-s4-next or + // lw-s3, leave 0x8003F7E0. Live + // fac4e01: named lw-s4 then + // 7× after-stk-sw on 0x9FFFF. + // After lw-s5-next or lw-s4, + // leave 0x8003F7DC. Do not + // re-enter 0x8002105C / + // 0x80021060. Live 417729e: + // named lw-s5 then + // spun. After lw-s6-next or + // lw-s5, leave 0x8003F7D8. Live + // ab51f6e: named lw-s6 then + // spun. After lw-fp-next or + // lw-s6, leave 0x8003F7D4. Live + // e99a90c: named lw-fp then + // spun. After addu-next or + // lw-fp, leave 0x8003F7D0. Live + // c5d44f3: named addu then + // spun. After lw-s7-next or + // addu, leave 0x8003F7CC. Live + // 36e0bb7: named lw-s7 then + // spun. After lw-t4-next or + // lw-s7, leave 0x8003F7C8. Live + // 87bbfea: named lw-t4 then 7× + // cap re-leave 0x8003F7C0. After + // addiu-next or lw-t4, leave + // 0x8003F7C4. Live da2ecb1: + // stk-sw cap left cookie + // 0x80048190 after s3 and spun. + // Do not re-enter 0x80048174 / + // 0x80048190 after caller + // progress. + private static uint DumpMem15C28OuterJalProgressLeave() + { + uint leave = DumpMem15C28OuterJalProgressLeaveCore(); + if (leave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa) + return 0; + return leave; + } + + private static uint DumpMem15C28OuterJalProgressLeaveCore() + { + // Boot 90d6470: fat caller jr $ra honored + // 0x8003F8B4. Cap after-stk / twin + // 0x8003F9E8 must re-enter that ra, + // not fall through into the next fn. + if (_exn15C28AfterOuterJalEpiRetCallerRaBneLogged) + { + // After live bne $s4,$t1, + // cap after-stk at the + // live dest (fall 3F7A8 / + // taken 3F7AC). Never + // invent taken. Never + // hop MULT 3F748 / cookie + // / 3F888 / 3F7A0. + uint bneLeave = _exn15C28AfterOuterJalEpiRetCallerRaLeave; + if ((bneLeave == CoredllDllMainExn15C28OuterJalLinkBneFall + || bneLeave == CoredllDllMainExn15C28OuterJalLinkBneTaken) + && IsExn15C28FallEpiOuterLeave(bneLeave) + && bneLeave != CoredllDllMainExn15C28OuterJalLinkBeqTaken + && bneLeave != CoredllDllMainKdataEpcEa88 + && bneLeave != 0x80048190u) + return bneLeave; + return CoredllDllMainExn15C28OuterJalLinkBne; + } + if (_exn15C28AfterOuterJalEpiRetCallerRaT1Logged) + { + // After dump-true addiu + // $t1,$0,4 at 0x8003F79C, + // cap after-stk at + // 0x8003F7A0 (named bne). + // Never re-enter 3F79C / + // 3F798 / 3F78C / cookie / + // MULT 3F748. Do not take + // the bne. + if (IsExn15C28FallEpiOuterLeave( + _exn15C28AfterOuterJalEpiRetCallerRaLeave) + && _exn15C28AfterOuterJalEpiRetCallerRaLeave + != CoredllDllMainExn15C28OuterJalLink + && _exn15C28AfterOuterJalEpiRetCallerRaLeave + != CoredllDllMainExn15C28OuterJalLinkAfter + && _exn15C28AfterOuterJalEpiRetCallerRaLeave + != CoredllDllMainExn15C28OuterJalLinkT1) + return _exn15C28AfterOuterJalEpiRetCallerRaLeave; + return CoredllDllMainExn15C28OuterJalLinkBne; + } + if (_exn15C28AfterOuterJalEpiRetCallerRaS3Logged) + { + // After dump-true epi-ret + // lw at 0x8003F798, cap + // after-stk at 0x8003F79C + // (named addiu $t1,$0,4). + // Never re-enter 3F798 / + // 3F78C / 3F8B4 / cookie / + // MULT 3F748. + if (IsExn15C28FallEpiOuterLeave( + _exn15C28AfterOuterJalEpiRetCallerRaLeave) + && _exn15C28AfterOuterJalEpiRetCallerRaLeave + != CoredllDllMainExn15C28OuterJalLink + && _exn15C28AfterOuterJalEpiRetCallerRaLeave + != CoredllDllMainExn15C28OuterJalLinkAfter) + return _exn15C28AfterOuterJalEpiRetCallerRaLeave; + return CoredllDllMainExn15C28OuterJalLinkT1; + } + if (_exn15C28AfterOuterJalEpiRetCallerRaLhuLogged) + { + // After dump-true epi-ret + // lhu at 0x8003F78C, cap + // after-stk at 0x8003F798 + // (named lw $v0,0($s3)). + // Never re-enter 3F78C / + // 3F8B4 / 3F940 / cookie. + if (IsExn15C28FallEpiOuterLeave( + _exn15C28AfterOuterJalEpiRetCallerRaLeave) + && _exn15C28AfterOuterJalEpiRetCallerRaLeave + != CoredllDllMainExn15C28OuterJalLink) + return _exn15C28AfterOuterJalEpiRetCallerRaLeave; + return CoredllDllMainExn15C28OuterJalLinkAfter; + } + if (_exn15C28AfterOuterJalEpiRetCallerRaLogged + || _exn15C28AfterOuterJalEpiRetCallerRaNextLogged) + { + // Boot 2412828: after fat + // 3F8B4→3F93C→jr, cap + // after-stk at outer ra + // (~0x8003F78C). Never + // re-enter 3F8B4 / 3F940. + if (IsExn15C28FallEpiOuterLeave( + _exn15C28AfterOuterJalEpiRetCallerRaLeave)) + return _exn15C28AfterOuterJalEpiRetCallerRaLeave; + if (IsExn15C28FallEpiOuterLeave( + _exn15C28AfterOuterJalEpiFn854OuterRa)) + return _exn15C28AfterOuterJalEpiFn854OuterRa; + return CoredllDllMainExn15C28OuterJalLink; + } + if (IsExn15C28CallerHonoredRaLeave( + _exn15C28AfterOuterJalEpiRetCallerLeave)) + return _exn15C28AfterOuterJalEpiRetCallerLeave; + if (_exn15C28AfterOuterJalEpiRetCallerNextFnLogged + || _exn15C28AfterOuterJalEpiRetCallerNextFnNextLogged) + { + if (_exn15C28AfterOuterJalEpiRetCallerNextFnLeave != 0 + && (_exn15C28AfterOuterJalEpiRetCallerNextFnLeave & 3) == 0) + return _exn15C28AfterOuterJalEpiRetCallerNextFnLeave; + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnNext; + } + if (_exn15C28AfterOuterJalEpiRetCallerLogged + || _exn15C28AfterOuterJalEpiRetCallerNextLogged) + { + if (_exn15C28AfterOuterJalEpiRetCallerLeave != 0 + && (_exn15C28AfterOuterJalEpiRetCallerLeave & 3) == 0) + return _exn15C28AfterOuterJalEpiRetCallerLeave; + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn; + } + if (_exn15C28AfterOuterJalEpiRetFallLogged + || _exn15C28AfterOuterJalEpiRetFallNextLogged) + { + if (_exn15C28AfterOuterJalEpiRetFallLeave != 0 + && (_exn15C28AfterOuterJalEpiRetFallLeave & 3) == 0) + return _exn15C28AfterOuterJalEpiRetFallLeave; + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallNextFn; + } + if (_exn15C28AfterOuterJalEpiRetBneLogged + || _exn15C28AfterOuterJalEpiRetBneNextLogged) + { + if (_exn15C28AfterOuterJalEpiRetBneLeave != 0 + && (_exn15C28AfterOuterJalEpiRetBneLeave & 3) == 0) + return _exn15C28AfterOuterJalEpiRetBneLeave; + return CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext; + } + if (_exn15C28AfterOuterJalEpiRetLogged + || _exn15C28AfterOuterJalEpiRetNextLogged) + { + if (_exn15C28AfterOuterJalEpiRetLeave != 0 + && (_exn15C28AfterOuterJalEpiRetLeave & 3) == 0) + return _exn15C28AfterOuterJalEpiRetLeave; + return CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall; + } + if (_exn15C28AfterOuterJalEpiTrampolineLogged + || _exn15C28AfterOuterJalEpiTrampolineNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa; + if (_exn15C28AfterOuterJalEpiPrologueJalLogged + || _exn15C28AfterOuterJalEpiPrologueJalNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest; + if (_exn15C28AfterOuterJalEpiPrologueSwLogged + || _exn15C28AfterOuterJalEpiPrologueSwNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal; + if (_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext; + if (_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext; + if (_exn15C28AfterOuterJalEpiBeqBneFallJrLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext; + if (_exn15C28AfterOuterJalEpiBeqBneFallSwLogged + || _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext; + if (_exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged + || _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext; + if (_exn15C28AfterOuterJalEpiBeqBneFallLogged + || _exn15C28AfterOuterJalEpiBeqBneNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall; + if (_exn15C28AfterOuterJalEpiBeqSltLogged + || _exn15C28AfterOuterJalEpiBeqSltNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext; + if (_exn15C28AfterOuterJalEpiBeqAddiuLogged + || _exn15C28AfterOuterJalEpiBeqAddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext; + if (_exn15C28AfterOuterJalEpiBeqLogged + || _exn15C28AfterOuterJalEpiBeqNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken; + if (_exn15C28AfterOuterJalEpiSltuLogged + || _exn15C28AfterOuterJalEpiSltuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiSltuNext; + if (_exn15C28AfterOuterJalEpiA3LhuLogged + || _exn15C28AfterOuterJalEpiA3LhuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext; + if (_exn15C28AfterOuterJalEpiBeqBneLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext; + if (_exn15C28AfterOuterJalEpiA2SwLogged + || _exn15C28AfterOuterJalEpiA2SwNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext; + if (_exn15C28AfterOuterJalEpiA1AddiuLogged + || _exn15C28AfterOuterJalEpiA1AddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiA2Sw; + if (_exn15C28AfterOuterJalEpiA2AddiuLogged + || _exn15C28AfterOuterJalEpiA2AddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext; + if (_exn15C28AfterOuterJalEpiLhuLogged + || _exn15C28AfterOuterJalEpiLhuNextLogged + || _exn15C28AfterOuterJalEpiA3LuiLogged + || _exn15C28AfterOuterJalEpiA3LuiNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiLhuNext; + if (_exn15C28AfterOuterJalEpiSwLogged + || _exn15C28AfterOuterJalEpiSwNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiSwNext; + if (_exn15C28AfterOuterJalEpiV1AddiuLogged + || _exn15C28AfterOuterJalEpiV1AddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext; + if (_exn15C28AfterOuterJalEpiV0AddiuLogged + || _exn15C28AfterOuterJalEpiV0AddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext; + if (_exn15C28AfterOuterJalEpiLuiLogged + || _exn15C28AfterOuterJalEpiJrNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiLuiNext; + if (_exn15C28AfterOuterJalEpiJrLogged + || _exn15C28AfterOuterJalEpiAddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiJrNext; + if (_exn15C28AfterOuterJalEpiAddiuLogged + || _exn15C28AfterOuterJalLwRaNextLogged) + return CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext; + if (_exn15C28AfterOuterJalLwRaLogged + || _exn15C28AfterOuterJalLwS0NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwRaNext; + if (_exn15C28AfterOuterJalLwS0Logged + || _exn15C28AfterOuterJalLwS1NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS0Next; + if (_exn15C28AfterOuterJalLwS1Logged + || _exn15C28AfterOuterJalLwS2NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS1Next; + if (_exn15C28AfterOuterJalLwS2Logged + || _exn15C28AfterOuterJalLwS3NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS2Next; + if (_exn15C28AfterOuterJalLwS3Logged + || _exn15C28AfterOuterJalLwS4NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS3Next; + if (_exn15C28AfterOuterJalLwS4Logged + || _exn15C28AfterOuterJalLwS5NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS4Next; + if (_exn15C28AfterOuterJalLwS5Logged + || _exn15C28AfterOuterJalLwS6NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS5Next; + if (_exn15C28AfterOuterJalLwS6Logged + || _exn15C28AfterOuterJalLwFpNextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS6Next; + if (_exn15C28AfterOuterJalLwFpLogged + || _exn15C28AfterOuterJalAdduNextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwFpNext; + if (_exn15C28AfterOuterJalAdduLogged + || _exn15C28AfterOuterJalLwS7NextLogged) + return CoredllDllMainExn15C28OuterJalLinkAdduNext; + if (_exn15C28AfterOuterJalLwS7Logged + || _exn15C28AfterOuterJalLwT4NextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwS7Next; + if (_exn15C28AfterOuterJalLwT4Logged + || _exn15C28AfterOuterJalAddiuNextLogged) + return CoredllDllMainExn15C28OuterJalLinkLwT4Next; + if (_exn15C28AfterOuterJalAddiuLogged) + return CoredllDllMainExn15C28OuterJalLinkAddiuNext; + if (_exn15C28AfterOuterJalBeqLogged) + return CoredllDllMainExn15C28OuterJalLinkBeqFall; + if (_exn15C28AfterOuterJalSltuLogged) + return CoredllDllMainExn15C28OuterJalLinkBeq; + if (_exn15C28AfterOuterJalLandLogged) + return CoredllDllMainExn15C28OuterJalLinkSltu; + if (_exn15C28AfterOuterJalBneLogged) + return CoredllDllMainExn15C28OuterJalLinkBneTaken; + if (_exn15C28AfterOuterJalS3Logged) + return CoredllDllMainExn15C28OuterJalLinkBne; + if (_exn15C28AfterOuterJalJrLogged) + return CoredllDllMainExn15C28OuterJalLink; + if (_exn15C28AfterOuterJalLwLogged) + return CoredllDllMainExn15C28OuterJalDestJr; + if (_exn15C28AfterOuterJalAluLogged) + return CoredllDllMainExn15C28OuterJalDestNext; + if (_exn15C28OuterJalTakenLogged) + return CoredllDllMainExn15C28OuterJalDest; + return 0; + } + + private static bool TryLeaveDumpMem15C28PastJalRa(MipsBus bus, uint[] regs, + uint fromPc, ref uint cpuPc, out uint leave) + { + if (_exn15C28OuterJalTakenLogged) + { + leave = DumpMem15C28OuterJalProgressLeave(); + if (RefuseExn15C28BadABeforeE000Yank(fromPc, leave)) + { + leave = 0; + return false; + } + if (leave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || (leave == CoredllDllMainExn15C28OuterJalLink + && IsExn15C28StkRecurseFrame(PeekGpr(regs, 29)))) + { + leave = 0; + return false; + } + if (leave == 0 || (leave & 3) != 0 || IsDumpMemRefuseVa(leave) + || IsExn15C28Na02Frame(leave) || IsExn15C28HelperBody(leave) + || IsWrapDestSize(leave) || IsWrapDestFp50Va(leave) + || IsLeftoverDestVa(leave)) + { + leave = 0; + return false; + } + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(fromPc); + } + cpuPc = leave; + return true; + } + return TryLeaveDumpMem15C28Outer(bus, regs, fromPc, ref cpuPc, out leave); + } + + // Live 52d67d1: after-sp-t9 named + // 0x80015C44 lw $s0,208($sp) then + // dump-mem heal 0x80015C78 + // lw $v1,156($sp). Then AddressError + // I-fetch PC=0x9A02BDF8 (= leftover + // v0 0x9A023DF8 | 0x8000) from + // dump or $v0,$v0,$a0 at 0x80015CC4 + // after skipped lw $v0,288($sp). + // 15C44..15CFC is context-restore + + // ERET — do not invent stack / EPC. + // Continue-skip dest-miss 0x9A02 + // memops; do not exec COP0/ERET or + // ALU that mixes leftover 0x9A02. + // Leave dump-true outer jal-ra + // 0x8003F784 (after jal 0x800151C0). + public static bool TryTakeDumpMem15C28JalRaEpi(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28SpT9SkipLogged && !_exn15C28AfterSpT9Logged) + return false; + if (_exn15C28JalRaEpiLogN >= 1 || _exn15C28AfterJalRaEpiLogged + || _exn15C28OuterJalTakenLogged) + return false; + if (!IsExn15C28JalRaEpiRange(pc)) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterRa)) + return false; + uint dump = DumpMem15C28AfterWord(pc); + if (dump == 0) + return false; + if (insn != 0 && insn != dump && !IsMipsLoad(insn) + && !IsMipsStore(insn) && !IsDumpMemAluInsn(insn) + && !IsDumpMemCop0(insn)) + return false; + uint sp = PeekGpr(regs, 29); + if (!IsExn15C28Na02Frame(sp) + && !IsExn15C28Na02Frame(PeekGpr(regs, 30))) + return false; + int nSkip = 0; + int nAlu = 0; + uint walkPc = pc; + for (int i = 0; i < 48; i++) + { + if (!IsExn15C28JalRaEpiRange(walkPc) + || IsDumpMemRefuseVa(walkPc)) + break; + uint w = DumpMem15C28AfterWord(walkPc); + if (w == 0) + break; + if (IsDumpMemCop0(w) || w == CoredllDllMainExn15C28JalRaEpiEndDump) + break; + uint op = w >> 26; + int rs = (int)((w >> 21) & 31); + int rt = (int)((w >> 16) & 31); + int rd = (int)((w >> 11) & 31); + uint fn = w & 63; + short imm = (short)(w & 0xFFFF); + uint bas = PeekGpr(regs, rs); + uint ea = unchecked(bas + (uint)(int)imm); + if ((IsMipsLoad(w) || IsMipsStore(w)) + && (IsExn15C28Na02Frame(bas) || IsExn15C28Na02Frame(ea))) + { + if (IsDumpMemRefuseVa(ea) || IsDumpMemRefuseVa(bas)) + break; + nSkip++; + walkPc += 4; + continue; + } + if (IsDumpMemAluInsn(w)) + { + uint rsv = PeekGpr(regs, rs); + uint rtv = PeekGpr(regs, rt); + if (IsExn15C28Na02Frame(rsv) || IsExn15C28Na02Frame(rtv)) + break; + if (!TryExecDumpMemAlu(regs, w)) + break; + nAlu++; + walkPc += 4; + continue; + } + if (op == 0 && (fn == 17 || fn == 19)) + { + walkPc += 4; + continue; + } + if (op == 2 || op == 3) + { + uint next = (walkPc & 0xF0000000u) | ((w & 0x03FFFFFFu) << 2); + if (IsDumpMemRefuseVa(next) || IsExn15C28Na02Frame(next) + || IsWrapDestSize(next) || IsWrapDestFp50Va(next)) + break; + if (op == 3) + PokeGpr(regs, 31, walkPc + 8); + walkPc = next; + uint leaveJal = 0; + if (!TryLeaveDumpMem15C28Outer(bus, regs, pc, ref cpuPc, + out leaveJal)) + return false; + cpuPc = next; + LogDumpMem15C28JalRaEpi(pc, next, dump, nSkip, nAlu, regs, + "jal"); + return true; + } + if (op == 0 && (fn == 8 || fn == 9)) + { + uint next = PeekGpr(regs, rs); + if (IsDumpMemRefuseVa(next) || IsExn15C28Na02Frame(next) + || IsExn15C28HelperBody(next) || IsWrapDestSize(next) + || IsWrapDestFp50Va(next)) + break; + if (fn == 9 && rd != 0) + PokeGpr(regs, rd, walkPc + 8); + walkPc = next; + uint leaveJr = 0; + if (!TryLeaveDumpMem15C28Outer(bus, regs, pc, ref cpuPc, + out leaveJr)) + return false; + cpuPc = next; + LogDumpMem15C28JalRaEpi(pc, next, dump, nSkip, nAlu, regs, + "jr"); + return true; + } + break; + } + if (nSkip == 0 && pc != CoredllDllMainExn15C28JalRa) + return false; + uint leave = 0; + if (!TryLeaveDumpMem15C28Outer(bus, regs, pc, ref cpuPc, out leave)) + return false; + Note15C28Left(sp); + LogDumpMem15C28JalRaEpi(pc, leave, dump, nSkip, nAlu, regs, "outer"); + return true; + } + + private static void LogDumpMem15C28JalRaEpi(uint pc, uint next, uint dump, + int nSkip, int nAlu, uint[] regs, string how) + { + uint dest = PeekGpr(regs, 29) + 208; + if (_exn15C28JalRaEpiLogN >= 8 && _exn15C28JalRaEpiLast == dest) + return; + if (_exn15C28JalRaEpiLogN < 8) + _exn15C28JalRaEpiLogN++; + _exn15C28JalRaEpiLast = dest; + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + uint fp = PeekGpr(regs, 30); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 jal-ra skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + next.ToString("X") + + " dump=0x" + dump.ToString("X") + + " nskip=" + nSkip.ToString() + + " nalu=" + nAlu.ToString() + + " how=" + how + + " fp=0x" + fp.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " via=dump-mem-15c28-jal-ra-skip" + + " (dump 15C44 epilogue dest-miss skip;" + + " no invent 0x9A02 I-fetch; no ERET;" + + " leave dump-true outer jal-ra 0x8003F784)"); + } + + public static bool TryTakeDumpMem15C28Na02IFetch(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28SpT9SkipLogged && !_exn15C28AfterSpT9Logged + && !_exn15C28JalRaEpiSkipLogged) + return false; + if (!IsExn15C28Na02Frame(pc)) + return false; + if ((pc & 3) != 0) + return false; + uint leave = 0; + if (!TryLeaveDumpMem15C28PastJalRa(bus, regs, pc, ref cpuPc, out leave)) + return false; + if (_exn15C28Na02IFetchLogN < 8 && _exn15C28Na02IFetchLast != pc) + { + _exn15C28Na02IFetchLogN++; + _exn15C28Na02IFetchLast = pc; + uint ra = PeekGpr(regs, 31); + uint sp = PeekGpr(regs, 29); + uint v0 = PeekGpr(regs, 2); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 na0-ifetch" + + " pc=0x" + pc.ToString("X") + + " next=0x" + leave.ToString("X") + + " v0=0x" + v0.ToString("X") + + " ra=0x" + ra.ToString("X") + + " sp=0x" + sp.ToString("X") + + " via=dump-mem-15c28-na0-ifetch" + + " (refuse I-fetch 0x9Axxxxxx; no invent page;" + + " leave dump-true 0x80048174 or outer jal-ra; honor ra)"); + } + return true; + } + + public static void TryNoteDumpMem15C28AfterJalRaEpi(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28JalRaEpiSkipLogged || _exn15C28AfterJalRaEpiLogged) + return; + if (IsExn15C28JalRaEpiRange(pc) || IsExn15C28HelperBody(pc) + || IsExn15C28Na02Frame(pc)) + return; + if (IsDumpMemRefuseVa(pc) || IsDumpMemRefuseVa(pc + 4)) + return; + _exn15C28AfterJalRaEpiLogged = true; + uint afterDump = DumpMem15C28AfterWord(pc); + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-jal-ra"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-jal-ra"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-jal-ra" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " via=dump-mem-15c28-after-jal-ra" + + " (first I-fetch after jal-ra-skip leave;" + + " honor ra; no invent dest / 0x9A02)"); + } + + private static uint DumpMem15C28OuterJalDest(uint pc, uint dump) + { + if (dump == 0) + dump = CoredllDllMainExn15C28OuterRaDump; + return (pc & 0xF0000000u) | ((dump & 0x03FFFFFFu) << 2); + } + + // Delay 0x8003F788 dump-peek only. + // Exec ALU if dump-true and not + // leftover 0x9A02 operands. Do + // not invent delay. + private static void TryApplyDumpMem15C28OuterJalDelay(uint[] regs) + { + uint delay = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalDelay, out delay) + || delay == 0) + return; + if (!IsDumpMemAluInsn(delay)) + return; + int delayRs = (int)((delay >> 21) & 31); + int delayRt = (int)((delay >> 16) & 31); + uint delayRsv = PeekGpr(regs, delayRs); + uint delayRtv = PeekGpr(regs, delayRt); + if (IsExn15C28Na02Frame(delayRsv) || IsExn15C28Na02Frame(delayRtv)) + return; + TryExecDumpMemAlu(regs, delay); + } + + // Live 4878d5b: leave dump-true + // outer jal-ra 0x8003F784. Dump + // is jal 0x80048174 (0x0C01205D). + // Heal abs-store overlay; execute + // dump jal; $ra:=0x8003F78C. + // Delay dump-peek only. Dest is + // encoded, not invented. Not + // LoadO32. No leftover-hop. + // No invent dest / 0x9A02. + public static bool TryTakeDumpMem15C28OuterJal(MipsBus bus, uint[] regs, + uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28JalRaEpiSkipLogged && !_exn15C28AfterJalRaEpiLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterRa) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalDest) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLink)) + return false; + uint jalDump = DumpMem15C28AfterWord(pc); + if (jalDump == 0) + jalDump = CoredllDllMainExn15C28OuterRaDump; + if (jalDump != CoredllDllMainExn15C28OuterRaDump) + return false; + uint jalDest = DumpMem15C28OuterJalDest(pc, jalDump); + if (jalDest != CoredllDllMainExn15C28OuterJalDest) + return false; + if (jalDest == 0 || (jalDest & 3) != 0 + || IsDumpMemRefuseVa(jalDest) + || IsExn15C28Na02Frame(jalDest) + || IsExn15C28HelperBody(jalDest) + || IsLeftoverWait99O32WrapLoopDest(jalDest) + || IsWrapDestSize(jalDest) || IsWrapDestFp50Va(jalDest) + || IsLeftoverDestVa(jalDest)) + return false; + if (insn != 0 && insn != jalDump && !IsMipsLoad(insn) + && !IsMipsStore(insn) && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (_exn15C28OuterJalTakenLogged) + { + PokeGpr(regs, 31, CoredllDllMainExn15C28OuterJalLink); + if (!inDelay) + { + uint again = DumpMem15C28OuterJalProgressLeave(); + cpuPc = again != 0 ? again : jalDest; + } + return true; + } + if (inDelay) + return false; + if (insn != jalDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, jalDump); + TryApplyDumpMem15C28OuterJalDelay(regs); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + PokeGpr(regs, 31, CoredllDllMainExn15C28OuterJalLink); + cpuPc = jalDest; + _exn15C28OuterJalTakenLogged = true; + _exn15C28AfterJalRaEpiLogged = true; + uint jalRa = PeekGpr(regs, 31); + uint jalSp = PeekGpr(regs, 29); + uint jalV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + jalDump.ToString("X") + + " dest=0x" + jalDest.ToString("X") + + " via=dump-mem-15c28-outer-jal"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal" + + " pc=0x" + pc.ToString("X") + + " word=0x" + jalDump.ToString("X") + + (insn != 0 && insn != jalDump ? " live=0x" + insn.ToString("X") : "") + + " dest=0x" + jalDest.ToString("X") + + " ra=0x" + jalRa.ToString("X") + + " sp=0x" + jalSp.ToString("X") + + " v0=0x" + jalV0.ToString("X") + + " via=dump-mem-15c28-outer-jal" + + " (dump jal 0x80048174; delay dump-peek;" + + " not LoadO32; honor ra; no invent dest / 0x9A02)"); + return true; + } + + public static void TryNoteDumpMem15C28AfterOuterJal(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28OuterJalTakenLogged && !_exn15C28JalRaEpiSkipLogged) + return; + if (_exn15C28AfterOuterJalLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalDest) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLogged = true; + uint destDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out destDump)) + destDump = 0; + uint destRa = PeekGpr(regs, 31); + uint destSp = PeekGpr(regs, 29); + uint destV0 = PeekGpr(regs, 2); + uint destA0 = PeekGpr(regs, 4); + string destDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = destDump != 0 + ? FormatMipsOp(pc, destDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (destDump != 0 ? " dump=0x" + destDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (destDump != 0 ? " dump=0x" + destDump.ToString("X") : "") + + " dis=" + destDis + + (destDump != 0 ? " dump-dis=" + dumpDis : "") + + " ra=0x" + destRa.ToString("X") + + " sp=0x" + destSp.ToString("X") + + " v0=0x" + destV0.ToString("X") + + " a0=0x" + destA0.ToString("X") + + " via=dump-mem-15c28-after-outer-jal" + + " (first I-fetch after dump jal 0x80048174;" + + " honor ra; no invent dest / 0x9A02)"); + } + + // Live 1736cd5: dest I-fetch at + // 0x80048174 dump lui/addiu/ + // addiu $k1 then lw $v0,0($a0). + // Heal overlay; execute dump ALU + // 0x80048174–0x8004817C; PC:= + // 0x80048180. $k1 cookie is dump + // 0x80048190, not invented. Do + // not exec lw / jr / COP0. Not + // LoadO32. No leftover-hop. No + // invent $a0 / $s7 / 0x9A02. + public static bool TryTakeDumpMem15C28AfterOuterJal(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28OuterJalTakenLogged) + return false; + if (_exn15C28AfterOuterJalAluLogged) + { + if (inDelay) + return false; + if (pc < CoredllDllMainExn15C28OuterJalDest + || pc > CoredllDllMainExn15C28OuterJalDest3) + return false; + if ((pc & 3) != 0) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (pc < CoredllDllMainExn15C28OuterJalDest + || pc > CoredllDllMainExn15C28OuterJalDest3) + return false; + if ((pc & 3) != 0) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalDestNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint first = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out first) || first == 0) + first = DumpMem15C28AfterWord(pc); + if (first == 0 || !IsDumpMemAluInsn(first)) + return false; + if (insn != first && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != first && insn != 0) + TryHealDumpInsn(bus, pc, insn, first); + uint ran = 0; + for (uint p = CoredllDllMainExn15C28OuterJalDest; + p <= CoredllDllMainExn15C28OuterJalDest3; p += 4) + { + uint dump = DumpMem15C28AfterWord(p); + if (dump == 0 || !IsDumpMemAluInsn(dump)) + return false; + ran++; + } + for (uint p = CoredllDllMainExn15C28OuterJalDest; + p <= CoredllDllMainExn15C28OuterJalDest3; p += 4) + { + uint dump = DumpMem15C28AfterWord(p); + if (!TryExecDumpMemAlu(regs, dump)) + return false; + } + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + bus.ClearExlIfEpc(CoredllDllMainExn15C28OuterJalDest); + } + cpuPc = CoredllDllMainExn15C28OuterJalDestNext; + _exn15C28AfterOuterJalLogged = true; + _exn15C28AfterOuterJalAluLogged = true; + uint destRa = PeekGpr(regs, 31); + uint destSp = PeekGpr(regs, 29); + uint destV0 = PeekGpr(regs, 2); + uint destA0 = PeekGpr(regs, 4); + uint destT0 = PeekGpr(regs, 8); + uint destK1 = PeekGpr(regs, 27); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-dest"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + first.ToString("X") + + " dest=0x" + CoredllDllMainExn15C28OuterJalDestNext.ToString("X") + + " via=dump-mem-15c28-outer-jal-dest"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-dest" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28OuterJalDestNext.ToString("X") + + " dump=0x" + first.ToString("X") + + (insn != 0 && insn != first ? " live=0x" + insn.ToString("X") : "") + + " n=" + ran.ToString() + + " t0=0x" + destT0.ToString("X") + + " k1=0x" + destK1.ToString("X") + + " a0=0x" + destA0.ToString("X") + + " v0=0x" + destV0.ToString("X") + + " ra=0x" + destRa.ToString("X") + + " sp=0x" + destSp.ToString("X") + + " via=dump-mem-15c28-outer-jal-dest" + + " (dump lui/addiu/addiu $k1 0x80048174-0x8004817C;" + + " exec regs; PC>=0x80048180; clear exl; no MUL;" + + " honor ra; no invent $a0 / $s7 / 0x9A02)"); + return true; + } + + // Live 1736cd5: after dest ALU, + // name first I-fetch at + // 0x80048180 (dump lw $v0,0($a0)). + // One-shot. Do not invent $a0 / + // $s7 / dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalDest(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalAluLogged + || _exn15C28AfterOuterJalNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalDestNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalDestNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextV0 = PeekGpr(regs, 2); + uint nextA0 = PeekGpr(regs, 4); + uint nextT0 = PeekGpr(regs, 8); + uint nextK1 = PeekGpr(regs, 27); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-dest"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-dest"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-dest" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t0=0x" + nextT0.ToString("X") + + " k1=0x" + nextK1.ToString("X") + + " a0=0x" + nextA0.ToString("X") + + " v0=0x" + nextV0.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-dest" + + " (first I-fetch after 48174-4817C exec;" + + " honor ra; no invent $a0 / $s7 / 0x9A02)"); + } + + // Live 5d27a34: dest I-fetch at + // 0x80048180 dump lw $v0,0($a0) + // a0=0x9A023E48. Swallow 0x9A + // load (do not invent). Exec + // following dump ALU. Skip 0x9A + // sw. If dump is jr $k1 and + // $k1==0x80048190 cookie, take + // that. Else land cookie + // 0x80048190 (dump jr $ra). Do + // not Write32. Do not invent + // $a0 / $s7 / *a0 / 0x9A02. + // Not LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalDest(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalAluLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalDestNext) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalDestJr) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + if (_exn15C28AfterOuterJalLwLogged) + { + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalDestNextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalDestNextDump) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + uint skipA0 = PeekGpr(regs, 4); + if (!IsExn15C28Na02Frame(skipA0)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint walkPc = CoredllDllMainExn15C28OuterJalDestNop; + int nAlu = 0; + int nSkip = 1; + for (int i = 0; i < 8; i++) + { + if (walkPc < CoredllDllMainExn15C28OuterJalDestNop + || walkPc > CoredllDllMainExn15C28OuterJalDestJr) + break; + if (IsDumpMemRefuseVa(walkPc)) + break; + uint w = DumpMem15C28AfterWord(walkPc); + if (walkPc == CoredllDllMainExn15C28OuterJalDestNop && w == 0) + w = CoredllDllMainExn15C28OuterJalDestNopDump; + if (w == 0 && walkPc != CoredllDllMainExn15C28OuterJalDestNop) + break; + int rs = (int)((w >> 21) & 31); + uint bas = PeekGpr(regs, rs); + short imm = (short)(w & 0xFFFF); + uint ea = unchecked(bas + (uint)(int)imm); + if ((IsMipsLoad(w) || IsMipsStore(w)) + && (IsExn15C28Na02Frame(bas) || IsExn15C28Na02Frame(ea))) + { + nSkip++; + walkPc += 4; + continue; + } + if (IsDumpMemAluInsn(w)) + { + uint aluRs = PeekGpr(regs, rs); + uint aluRt = PeekGpr(regs, (int)((w >> 16) & 31)); + if (!IsExn15C28Na02Frame(aluRs) + && !IsExn15C28Na02Frame(aluRt) + && TryExecDumpMemAlu(regs, w)) + nAlu++; + walkPc += 4; + continue; + } + if ((w >> 26) == 0 && (w & 63) == 8) + { + uint jrTgt = PeekGpr(regs, rs); + if (rs == 27 + && jrTgt == CoredllDllMainExn15C28OuterJalDestJr + && !IsDumpMemRefuseVa(jrTgt) + && !IsExn15C28Na02Frame(jrTgt) + && !IsExn15C28HelperBody(jrTgt) + && !IsLeftoverDestVa(jrTgt) + && !IsWrapDestSize(jrTgt) + && !IsWrapDestFp50Va(jrTgt)) + { + walkPc = jrTgt; + } + break; + } + break; + } + if (walkPc == pc || IsDumpMemRefuseVa(walkPc) + || IsExn15C28Na02Frame(walkPc)) + walkPc = CoredllDllMainExn15C28OuterJalDestJr; + if (walkPc == 0 || (walkPc & 3) != 0 + || IsDumpMemRefuseVa(walkPc) + || IsExn15C28Na02Frame(walkPc) + || IsLeftoverDestVa(walkPc) + || IsWrapDestSize(walkPc) + || IsWrapDestFp50Va(walkPc)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = walkPc; + _exn15C28AfterOuterJalNextLogged = true; + _exn15C28AfterOuterJalLwLogged = true; + uint skipV0 = PeekGpr(regs, 2); + uint skipRa = PeekGpr(regs, 31); + uint skipSp = PeekGpr(regs, 29); + uint skipK1 = PeekGpr(regs, 27); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-lw-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + skipA0.ToString("X") + + " *a0-miss" + + " via=dump-mem-15c28-outer-jal-lw-skip"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-skip" + + " pc=0x" + pc.ToString("X") + + " next=0x" + walkPc.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + " nskip=" + nSkip.ToString() + + " nalu=" + nAlu.ToString() + + " a0=0x" + skipA0.ToString("X") + + " *a0-miss" + + " v0=0x" + skipV0.ToString("X") + + " k1=0x" + skipK1.ToString("X") + + " ra=0x" + skipRa.ToString("X") + + " sp=0x" + skipSp.ToString("X") + + " via=dump-mem-15c28-outer-jal-lw-skip" + + " (dump lw $v0,0($a0); swallow 0x9A;" + + " exec following ALU; skip 0x9A sw;" + + " land cookie 0x80048190; honor ra;" + + " no invent $a0 / $s7 / 0x9A02)"); + return true; + } + + // Live 5d27a34: after 0x9A lw-skip, + // name first I-fetch at cookie + // 0x80048190 (dump jr $ra). One- + // shot. Do not invent dest / + // 0x9A02. Do not exec C lhu TLBL. + public static void TryNoteDumpMem15C28AfterOuterJalInc(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwLogged + || _exn15C28AfterOuterJalIncLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalDestJr) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalIncLogged = true; + uint leaveDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out leaveDump) || leaveDump == 0) + leaveDump = CoredllDllMainExn15C28OuterJalDestJrDump; + uint leaveRa = PeekGpr(regs, 31); + uint leaveSp = PeekGpr(regs, 29); + uint leaveV0 = PeekGpr(regs, 2); + uint leaveA0 = PeekGpr(regs, 4); + uint leaveK1 = PeekGpr(regs, 27); + string leaveDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = leaveDump != 0 + ? FormatMipsOp(pc, leaveDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (leaveDump != 0 ? " dump=0x" + leaveDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (leaveDump != 0 ? " dump=0x" + leaveDump.ToString("X") : "") + + " dis=" + leaveDis + + (leaveDump != 0 ? " dump-dis=" + dumpDis : "") + + " a0=0x" + leaveA0.ToString("X") + + " k1=0x" + leaveK1.ToString("X") + + " v0=0x" + leaveV0.ToString("X") + + " ra=0x" + leaveRa.ToString("X") + + " sp=0x" + leaveSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw" + + " (first I-fetch after 0x9A lw-skip;" + + " cookie 0x80048190; honor ra;" + + " no invent dest / 0x9A02)"); + } + + private static bool TryPeekExn15C28OuterJalIncDest(MipsBus bus, uint dest, + out uint peek) + { + peek = 0; + if (dest == 0 || (dest & 3) != 0) + return false; + if (dest < 0x00010000u || dest >= CoredllDllMainC000Page) + return false; + if (IsExn15C28Na02Frame(dest) || IsDumpMemRefuseVa(dest) + || dest == FfffF000Page + || (dest & ~0xFFFu) == FfffE000Page + || IsC000StoreSkipVa(dest)) + return false; + if (dest >= CoredllDllMainExn15C28OuterJalDest + && dest <= CoredllDllMainExn15C28OuterJalDestJrDelay) + return false; + return TryPeekWord(bus, dest, out peek); + } + + private static bool IsExn15C28OuterJalJrLeave(uint leave) + { + if (leave == 0 || (leave & 3) != 0) + return false; + if (IsDumpMemRefuseVa(leave) || IsExn15C28Na02Frame(leave) + || IsExn15C28HelperBody(leave) || IsExn15C28JalRaEpiRange(leave) + || IsLeftoverDestVa(leave) || IsWrapDestSize(leave) + || IsWrapDestFp50Va(leave) + || IsLeftoverWait99O32WrapLoopDest(leave)) + return false; + if (leave >= CoredllDllMainExn15C28OuterJalDest + && leave <= CoredllDllMainExn15C28OuterJalDestJrDelay) + return false; + return true; + } + + // Live 4a2c700: cookie I-fetch at + // 0x80048190 dump jr $ra. Honor + // dump-true $ra / link 0x8003F78C. + // Delay or $k1,$0,$0. Do not + // invent dest / $ra / 0x9A02. + // Not LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalJr(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalDestJr) + return false; + if (inDelay) + return false; + if (_exn15C28AfterOuterJalJrLogged) + { + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalDestJr + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLink) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint jrDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out jrDump) || jrDump == 0) + jrDump = CoredllDllMainExn15C28OuterJalDestJrDump; + if (jrDump != CoredllDllMainExn15C28OuterJalDestJrDump) + return false; + if (insn != jrDump && insn != 0 && !IsMipsJumpOrJr(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != jrDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, jrDump); + uint delay = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalDestJrDelay, out delay) + || delay == 0) + delay = CoredllDllMainExn15C28OuterJalDestJrDelayDump; + if (delay == CoredllDllMainExn15C28OuterJalDestJrDelayDump + && IsDumpMemAluInsn(delay)) + TryExecDumpMemAlu(regs, delay); + uint jrRa = PeekGpr(regs, 31); + uint jrLeave = jrRa; + if (!IsExn15C28OuterJalJrLeave(jrLeave)) + jrLeave = CoredllDllMainExn15C28OuterJalLink; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = jrLeave; + _exn15C28AfterOuterJalIncLogged = true; + _exn15C28AfterOuterJalJrLogged = true; + uint jrSp = PeekGpr(regs, 29); + uint jrV0 = PeekGpr(regs, 2); + uint jrK1 = PeekGpr(regs, 27); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-jr"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + jrDump.ToString("X") + + " dest=0x" + jrLeave.ToString("X") + + " via=dump-mem-15c28-outer-jal-jr"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-jr" + + " pc=0x" + pc.ToString("X") + + " next=0x" + jrLeave.ToString("X") + + " dump=0x" + jrDump.ToString("X") + + (insn != 0 && insn != jrDump ? " live=0x" + insn.ToString("X") : "") + + " ra=0x" + jrRa.ToString("X") + + " k1=0x" + jrK1.ToString("X") + + " v0=0x" + jrV0.ToString("X") + + " sp=0x" + jrSp.ToString("X") + + " via=dump-mem-15c28-outer-jal-jr" + + " (dump jr $ra at 0x80048190; delay or $k1;" + + " honor ra / link 0x8003F78C;" + + " no invent dest / $ra / 0x9A02)"); + return true; + } + + // Live 4a2c700: after cookie jr, + // name first I-fetch at dump-true + // leave (link 0x8003F78C lhu + // $v0,0($s7)). One-shot. Do not + // invent $s7 / dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalJr(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalJrLogged + || _exn15C28AfterOuterJalJrNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLink + && !IsExn15C28OuterJalJrLeave(pc)) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalJrNextLogged = true; + uint leaveDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out leaveDump) || leaveDump == 0) + leaveDump = pc == CoredllDllMainExn15C28OuterJalLink + ? CoredllDllMainExn15C28OuterJalLinkDump + : 0; + uint leaveRa = PeekGpr(regs, 31); + uint leaveSp = PeekGpr(regs, 29); + uint leaveV0 = PeekGpr(regs, 2); + uint leaveS7 = PeekGpr(regs, 23); + string leaveDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = leaveDump != 0 + ? FormatMipsOp(pc, leaveDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-jr"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (leaveDump != 0 ? " dump=0x" + leaveDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-jr"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-jr" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (leaveDump != 0 ? " dump=0x" + leaveDump.ToString("X") : "") + + " dis=" + leaveDis + + (leaveDump != 0 ? " dump-dis=" + dumpDis : "") + + " s7=0x" + leaveS7.ToString("X") + + " v0=0x" + leaveV0.ToString("X") + + " ra=0x" + leaveRa.ToString("X") + + " sp=0x" + leaveSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-jr" + + " (first I-fetch after cookie jr;" + + " honor ra; no invent $s7 / dest / 0x9A02)"); + } + + private static bool TryPeekExn15C28OuterJalLhuDest(MipsBus bus, uint dest, + out uint peek) + { + peek = 0; + if (dest == 0 || (dest & 1) != 0) + return false; + if (dest < 0x00010000u || dest >= CoredllDllMainC000Page) + return false; + if (IsExn15C28Na02Frame(dest) || IsDumpMemRefuseVa(dest) + || IsExn15C28NfffFrame(dest) || IsExn15C28N9ffFrame(dest) + || dest == FfffF000Page + || (dest & ~0xFFFu) == FfffE000Page + || IsC000StoreSkipVa(dest)) + return false; + uint word = 0; + if (!TryPeekWord(bus, dest & ~3u, out word)) + return false; + peek = (dest & 2) != 0 ? (word >> 16) : (word & 0xFFFFu); + return true; + } + + // Live 1d9baf5: caller I-fetch at + // 0x8003F78C dump lhu $v0,0($s7). + // Peek *$s7 only. Load $v0 if dest + // peeks; dest-miss skips subu/addu + // that use $v0. PC:=0x8003F798. + // Do not invent $s7 / dest / 0x9A02. + // Not LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalLhu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwLogged + || _exn15C28AfterOuterJalLhuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLink) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkAfter) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lhuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lhuDump) || lhuDump == 0) + lhuDump = CoredllDllMainExn15C28OuterJalLinkDump; + if (lhuDump != CoredllDllMainExn15C28OuterJalLinkDump) + return false; + if (insn != lhuDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lhuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lhuDump); + uint lhuS7 = PeekGpr(regs, 23); + uint lhuPeek = 0; + bool destOk = TryPeekExn15C28OuterJalLhuDest(bus, lhuS7, out lhuPeek); + if (destOk) + { + PokeGpr(regs, 2, lhuPeek); + uint alu1 = DumpMem15C28AfterWord( + CoredllDllMainExn15C28OuterJalLinkAlu); + uint alu2 = DumpMem15C28AfterWord( + CoredllDllMainExn15C28OuterJalLinkAlu2); + if (alu1 != 0 && IsDumpMemAluInsn(alu1)) + TryExecDumpMemAlu(regs, alu1); + if (alu2 != 0 && IsDumpMemAluInsn(alu2)) + TryExecDumpMemAlu(regs, alu2); + } + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = CoredllDllMainExn15C28OuterJalLinkAfter; + _exn15C28AfterOuterJalIncLogged = true; + _exn15C28AfterOuterJalLhuLogged = true; + uint lhuRa = PeekGpr(regs, 31); + uint lhuSp = PeekGpr(regs, 29); + uint lhuV0 = PeekGpr(regs, 2); + uint lhuFp = PeekGpr(regs, 30); + uint lhuS6 = PeekGpr(regs, 22); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lhu" + : "dump-mem-15c28-outer-jal-lhu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lhuDump.ToString("X") + + " dest=0x" + lhuS7.ToString("X") + + (destOk ? " *s7=0x" + lhuPeek.ToString("X") : " *s7-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lhu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28OuterJalLinkAfter.ToString("X") + + " dump=0x" + lhuDump.ToString("X") + + (insn != 0 && insn != lhuDump ? " live=0x" + insn.ToString("X") : "") + + " s7=0x" + lhuS7.ToString("X") + + (destOk ? " *s7=0x" + lhuPeek.ToString("X") : " *s7-miss") + + " v0=0x" + lhuV0.ToString("X") + + " fp=0x" + lhuFp.ToString("X") + + " s6=0x" + lhuS6.ToString("X") + + " ra=0x" + lhuRa.ToString("X") + + " sp=0x" + lhuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lhu $v0,0($s7); peek *$s7 only;" + + " dest miss skips $v0 ALU; honor ra;" + + " no invent $s7 / dest / 0x9A02)"); + return true; + } + + // Live 1d9baf5: after caller lhu, + // name first I-fetch at 0x8003F798 + // (dump lw $v0,0($s3)). One-shot. + // Do not invent $s3 / dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalLhu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLhuLogged + || _exn15C28AfterOuterJalLhuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkAfter) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLhuNextLogged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = CoredllDllMainExn15C28OuterJalLinkAfterDump; + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterS3 = PeekGpr(regs, 19); + uint afterS7 = PeekGpr(regs, 23); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lhu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lhu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lhu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " s3=0x" + afterS3.ToString("X") + + " s7=0x" + afterS7.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lhu" + + " (first I-fetch after caller lhu;" + + " honor ra; no invent $s3 / dest / 0x9A02)"); + } + + // Live fc282e4: after caller lhu, + // dump lw $v0,0($s3) at + // 0x8003F798. Peek *$s3 only. + // Load $v0 if dest peeks. Exec + // dump addiu $t1,$0,4. Observe + // bne at 0x8003F7A0. Do not + // invent $s3 / $s4 / taken / + // 0x9A02. Not LoadO32. No + // leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalS3(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLhuLogged + || _exn15C28AfterOuterJalS3Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkAfter) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBne) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint s3Dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out s3Dump) || s3Dump == 0) + s3Dump = CoredllDllMainExn15C28OuterJalLinkAfterDump; + if (s3Dump != CoredllDllMainExn15C28OuterJalLinkAfterDump) + return false; + if (insn != s3Dump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != s3Dump && insn != 0) + TryHealDumpInsn(bus, pc, insn, s3Dump); + uint s3Base = PeekGpr(regs, 19); + uint s3Peek = 0; + bool destOk = TryPeekExn15C28OuterJalIncDest(bus, s3Base, out s3Peek); + if (destOk) + PokeGpr(regs, 2, s3Peek); + uint t1Dump = DumpMem15C28AfterWord( + CoredllDllMainExn15C28OuterJalLinkT1); + if (t1Dump == 0) + t1Dump = CoredllDllMainExn15C28OuterJalLinkT1Dump; + if (t1Dump == CoredllDllMainExn15C28OuterJalLinkT1Dump + && IsDumpMemAluInsn(t1Dump)) + TryExecDumpMemAlu(regs, t1Dump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = CoredllDllMainExn15C28OuterJalLinkBne; + _exn15C28AfterOuterJalLhuNextLogged = true; + _exn15C28AfterOuterJalS3Logged = true; + uint s3Ra = PeekGpr(regs, 31); + uint s3Sp = PeekGpr(regs, 29); + uint s3V0 = PeekGpr(regs, 2); + uint s3S4 = PeekGpr(regs, 20); + uint s3T1 = PeekGpr(regs, 9); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-s3" + : "dump-mem-15c28-outer-jal-s3-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + s3Dump.ToString("X") + + " dest=0x" + s3Base.ToString("X") + + (destOk ? " *s3=0x" + s3Peek.ToString("X") : " *s3-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-s3" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28OuterJalLinkBne.ToString("X") + + " dump=0x" + s3Dump.ToString("X") + + (insn != 0 && insn != s3Dump ? " live=0x" + insn.ToString("X") : "") + + " s3=0x" + s3Base.ToString("X") + + (destOk ? " *s3=0x" + s3Peek.ToString("X") : " *s3-miss") + + " v0=0x" + s3V0.ToString("X") + + " s4=0x" + s3S4.ToString("X") + + " t1=0x" + s3T1.ToString("X") + + " ra=0x" + s3Ra.ToString("X") + + " sp=0x" + s3Sp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $v0,0($s3); peek *$s3 only;" + + " exec addiu $t1,4; observe bne; honor ra;" + + " no invent $s3 / $s4 / taken / 0x9A02)"); + return true; + } + + // Live fc282e4: after s3 lw + t1 + // ALU, name first I-fetch at + // 0x8003F7A0 (dump bne $s4,$t1). + // One-shot. Do not invent $s4 / + // taken / dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalS3(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalS3Logged + || _exn15C28AfterOuterJalS3NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkBne) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalS3NextLogged = true; + uint bneDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out bneDump) || bneDump == 0) + bneDump = CoredllDllMainExn15C28OuterJalLinkBneDump; + uint bneRa = PeekGpr(regs, 31); + uint bneSp = PeekGpr(regs, 29); + uint bneV0 = PeekGpr(regs, 2); + uint bneS3 = PeekGpr(regs, 19); + uint bneS4 = PeekGpr(regs, 20); + uint bneT1 = PeekGpr(regs, 9); + string bneDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = bneDump != 0 + ? FormatMipsOp(pc, bneDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-s3"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (bneDump != 0 ? " dump=0x" + bneDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-s3"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-s3" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (bneDump != 0 ? " dump=0x" + bneDump.ToString("X") : "") + + " dis=" + bneDis + + (bneDump != 0 ? " dump-dis=" + dumpDis : "") + + " s3=0x" + bneS3.ToString("X") + + " s4=0x" + bneS4.ToString("X") + + " t1=0x" + bneT1.ToString("X") + + " v0=0x" + bneV0.ToString("X") + + " ra=0x" + bneRa.ToString("X") + + " sp=0x" + bneSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-s3" + + " (first I-fetch after s3 lw + t1 ALU;" + + " honor ra; no invent $s4 / taken / 0x9A02)"); + } + + // Live e5f4369: after s3 lw + t1 + // ALU, dump bne $s4,$t1 at + // 0x8003F7A0. Live $s4 vs $t1 + // (t1:=4). Delay nop. Taken + // 0x8003F7AC / fall 0x8003F7A8. + // Do not invent $s4 / taken / + // 0x9A02. Not LoadO32. No + // leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalBne(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalS3Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkBne) + return false; + if (_exn15C28AfterOuterJalBneLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkBne + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBneFall) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBneTaken) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint bneDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out bneDump) || bneDump == 0) + bneDump = CoredllDllMainExn15C28OuterJalLinkBneDump; + if (bneDump != CoredllDllMainExn15C28OuterJalLinkBneDump) + return false; + if (insn != bneDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != bneDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, bneDump); + uint bneS4 = PeekGpr(regs, 20); + uint bneT1 = PeekGpr(regs, 9); + bool taken = bneS4 != bneT1; + uint bneDest = taken + ? CoredllDllMainExn15C28OuterJalLinkBneTaken + : CoredllDllMainExn15C28OuterJalLinkBneFall; + if (bneDest == 0 || (bneDest & 3) != 0 + || IsDumpMemRefuseVa(bneDest) + || IsExn15C28Na02Frame(bneDest) + || IsExn15C28HelperBody(bneDest) + || IsExn15C28JalRaEpiRange(bneDest) + || IsLeftoverDestVa(bneDest) + || IsWrapDestSize(bneDest) || IsWrapDestFp50Va(bneDest)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = bneDest; + _exn15C28AfterOuterJalS3NextLogged = true; + _exn15C28AfterOuterJalBneLogged = true; + uint bneRa = PeekGpr(regs, 31); + uint bneSp = PeekGpr(regs, 29); + uint bneV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-bne"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + bneDump.ToString("X") + + " dest=0x" + bneDest.ToString("X") + + " via=dump-mem-15c28-outer-jal-bne"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-bne" + + " pc=0x" + pc.ToString("X") + + " next=0x" + bneDest.ToString("X") + + " dump=0x" + bneDump.ToString("X") + + (insn != 0 && insn != bneDump ? " live=0x" + insn.ToString("X") : "") + + " s4=0x" + bneS4.ToString("X") + + " t1=0x" + bneT1.ToString("X") + + (taken ? " taken=1" : " taken=0") + + " v0=0x" + bneV0.ToString("X") + + " ra=0x" + bneRa.ToString("X") + + " sp=0x" + bneSp.ToString("X") + + " via=dump-mem-15c28-outer-jal-bne" + + " (dump bne $s4,$t1; live compare;" + + " honor ra; no invent $s4 / taken / 0x9A02)"); + return true; + } + + // Live e5f4369: after live bne, + // name first I-fetch at taken + // 0x8003F7AC or fall 0x8003F7A8. + // One-shot. Do not invent dest / + // 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalBne(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalBneLogged + || _exn15C28AfterOuterJalBneNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkBneTaken) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalBneNextLogged = true; + uint afterDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out afterDump) || afterDump == 0) + afterDump = DumpMem15C28AfterWord(pc); + uint afterRa = PeekGpr(regs, 31); + uint afterSp = PeekGpr(regs, 29); + uint afterV0 = PeekGpr(regs, 2); + uint afterS4 = PeekGpr(regs, 20); + string afterDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = afterDump != 0 + ? FormatMipsOp(pc, afterDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-bne"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-bne"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-bne" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (afterDump != 0 ? " dump=0x" + afterDump.ToString("X") : "") + + " dis=" + afterDis + + (afterDump != 0 ? " dump-dis=" + dumpDis : "") + + " s4=0x" + afterS4.ToString("X") + + " v0=0x" + afterV0.ToString("X") + + " ra=0x" + afterRa.ToString("X") + + " sp=0x" + afterSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-bne" + + " (first I-fetch after live bne $s4,$t1;" + + " honor ra; no invent dest / 0x9A02)"); + } + + private static bool TryExecDumpMemAluIfNotNa02(uint[] regs, uint insn) + { + if (!IsDumpMemAluInsn(insn)) + return false; + int rs = (int)((insn >> 21) & 31); + int rt = (int)((insn >> 16) & 31); + uint rsv = PeekGpr(regs, rs); + uint rtv = PeekGpr(regs, rt); + if (IsExn15C28Na02Frame(rsv) || IsExn15C28Na02Frame(rtv)) + return false; + return TryExecDumpMemAlu(regs, insn); + } + + // Live dd85d76: sltu $t3,$fp,$v0 + // skipped because $fp is 0x9A and + // left stale t3=0x80342658. slt / + // sltu / slti / sltiu write 0/1 + // from known rs/rt even if a + // source is 0x9A. Compare is not + // a 0x9A memory op. Do not invent + // $fp / $v0 / dest. + private static bool TryExecDumpMemSltuKnown(uint[] regs, uint insn) + { + if (!IsDumpMemAluInsn(insn)) + return false; + uint op = insn >> 26; + uint fn = insn & 63; + if (op == 0 && (fn == 42 || fn == 43)) + return TryExecDumpMemAlu(regs, insn); + if (op == 10 || op == 11) + return TryExecDumpMemAlu(regs, insn); + return false; + } + + // Live 2e68147: bne landing is + // fall 0x8003F7A8 or $s1,$s0,$0 + // or taken 0x8003F7AC addiu + // $t2,$s4,1. Exec dump ALU if + // operands are not 0x9A. Join + // 0x8003F7B0 sltu. Do not invent + // $s4 / dest / 0x9A02. Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalLand(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalBneLogged + || _exn15C28AfterOuterJalLandLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkBneTaken) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkSltu) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint landDump = DumpMem15C28AfterWord(pc); + if (landDump == 0) + return false; + if (insn != landDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != landDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, landDump); + uint nAlu = 0; + if (pc == CoredllDllMainExn15C28OuterJalLinkBneFall + && TryExecDumpMemAluIfNotNa02(regs, landDump)) + nAlu++; + uint t2Dump = CoredllDllMainExn15C28OuterJalLinkBneTakenDump; + if (TryExecDumpMemAluIfNotNa02(regs, t2Dump)) + nAlu++; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = CoredllDllMainExn15C28OuterJalLinkSltu; + _exn15C28AfterOuterJalBneNextLogged = true; + _exn15C28AfterOuterJalLandLogged = true; + uint landRa = PeekGpr(regs, 31); + uint landSp = PeekGpr(regs, 29); + uint landV0 = PeekGpr(regs, 2); + uint landS1 = PeekGpr(regs, 17); + uint landS4 = PeekGpr(regs, 20); + uint landT2 = PeekGpr(regs, 10); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-land"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + landDump.ToString("X") + + " dest=0x" + CoredllDllMainExn15C28OuterJalLinkSltu.ToString("X") + + " via=dump-mem-15c28-outer-jal-land"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-land" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28OuterJalLinkSltu.ToString("X") + + " dump=0x" + landDump.ToString("X") + + (insn != 0 && insn != landDump ? " live=0x" + insn.ToString("X") : "") + + " nalu=" + nAlu.ToString() + + " s1=0x" + landS1.ToString("X") + + " s4=0x" + landS4.ToString("X") + + " t2=0x" + landT2.ToString("X") + + " v0=0x" + landV0.ToString("X") + + " ra=0x" + landRa.ToString("X") + + " sp=0x" + landSp.ToString("X") + + " via=dump-mem-15c28-outer-jal-land" + + " (dump or/addiu join sltu; skip 0x9A ALU;" + + " honor ra; no invent $s4 / dest / 0x9A02)"); + return true; + } + + // Live 2e68147: after bne landing + // ALU, name first I-fetch at + // 0x8003F7B0 (dump sltu $t3,$fp,$v0). + // One-shot. Do not invent $fp / + // $v0 / dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalLand(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLandLogged + || _exn15C28AfterOuterJalLandNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkSltu) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLandNextLogged = true; + uint sltuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out sltuDump) || sltuDump == 0) + sltuDump = CoredllDllMainExn15C28OuterJalLinkSltuDump; + uint sltuRa = PeekGpr(regs, 31); + uint sltuSp = PeekGpr(regs, 29); + uint sltuV0 = PeekGpr(regs, 2); + uint sltuFp = PeekGpr(regs, 30); + uint sltuT2 = PeekGpr(regs, 10); + string sltuDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = sltuDump != 0 + ? FormatMipsOp(pc, sltuDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-land"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (sltuDump != 0 ? " dump=0x" + sltuDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-land"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-land" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (sltuDump != 0 ? " dump=0x" + sltuDump.ToString("X") : "") + + " dis=" + sltuDis + + (sltuDump != 0 ? " dump-dis=" + dumpDis : "") + + " fp=0x" + sltuFp.ToString("X") + + " t2=0x" + sltuT2.ToString("X") + + " v0=0x" + sltuV0.ToString("X") + + " ra=0x" + sltuRa.ToString("X") + + " sp=0x" + sltuSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-land" + + " (first I-fetch after bne landing ALU;" + + " honor ra; no invent $fp / dest / 0x9A02)"); + } + + // Live 9f5ef29 / dd85d76: sltu + // $t3,$fp,$v0 at 0x8003F7B0. + // Write dump sltu even if $fp is + // 0x9A (result 0/1). Live fp in + // 0x9A and v0=0x28 → t3:=0. + // Next is beq $t3,$0 -> 0x8003F748 + // MULT — refuse. Do not invent + // $fp / $v0 / taken. No MUL. + // Not LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalSltu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLandLogged + || _exn15C28AfterOuterJalSltuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkSltu) + return false; + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBeq) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint sltuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out sltuDump) || sltuDump == 0) + sltuDump = CoredllDllMainExn15C28OuterJalLinkSltuDump; + if (sltuDump != CoredllDllMainExn15C28OuterJalLinkSltuDump) + return false; + if (insn != sltuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != sltuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, sltuDump); + bool sltuOk = TryExecDumpMemAluIfNotNa02(regs, sltuDump); + if (!sltuOk) + sltuOk = TryExecDumpMemSltuKnown(regs, sltuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = CoredllDllMainExn15C28OuterJalLinkBeq; + _exn15C28AfterOuterJalLandNextLogged = true; + _exn15C28AfterOuterJalSltuLogged = true; + uint sltuRa = PeekGpr(regs, 31); + uint sltuSp = PeekGpr(regs, 29); + uint sltuV0 = PeekGpr(regs, 2); + uint sltuFp = PeekGpr(regs, 30); + uint sltuT3 = PeekGpr(regs, 11); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = sltuOk + ? "dump-mem-15c28-outer-jal-sltu" + : "dump-mem-15c28-outer-jal-sltu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + sltuDump.ToString("X") + + " dest=0x" + CoredllDllMainExn15C28OuterJalLinkBeq.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-sltu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + CoredllDllMainExn15C28OuterJalLinkBeq.ToString("X") + + " dump=0x" + sltuDump.ToString("X") + + (insn != 0 && insn != sltuDump ? " live=0x" + insn.ToString("X") : "") + + (sltuOk ? " sltu=1" : " sltu=0") + + " fp=0x" + sltuFp.ToString("X") + + " v0=0x" + sltuV0.ToString("X") + + " t3=0x" + sltuT3.ToString("X") + + " ra=0x" + sltuRa.ToString("X") + + " sp=0x" + sltuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sltu $t3,$fp,$v0; write cmp even if $fp is 0x9A;" + + " beq dest is MULT — refuse; honor ra;" + + " no invent $fp / $v0 / taken / 0x9A02)"); + return true; + } + + // Live 9f5ef29: after sltu, name + // first I-fetch at 0x8003F7B4 + // (dump beq $t3,$0 -> MULT). + // One-shot. Do not exec MUL. Do + // not invent taken / dest / 0x9A02. + public static void TryNoteDumpMem15C28AfterOuterJalSltu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalSltuLogged + || _exn15C28AfterOuterJalSltuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkBeq) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalSltuNextLogged = true; + uint beqDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out beqDump) || beqDump == 0) + beqDump = CoredllDllMainExn15C28OuterJalLinkBeqDump; + uint beqRa = PeekGpr(regs, 31); + uint beqSp = PeekGpr(regs, 29); + uint beqV0 = PeekGpr(regs, 2); + uint beqT3 = PeekGpr(regs, 11); + uint beqFp = PeekGpr(regs, 30); + string beqDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = beqDump != 0 + ? FormatMipsOp(pc, beqDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-sltu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (beqDump != 0 ? " dump=0x" + beqDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-sltu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-sltu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (beqDump != 0 ? " dump=0x" + beqDump.ToString("X") : "") + + " dis=" + beqDis + + (beqDump != 0 ? " dump-dis=" + dumpDis : "") + + " t3=0x" + beqT3.ToString("X") + + " fp=0x" + beqFp.ToString("X") + + " v0=0x" + beqV0.ToString("X") + + " ra=0x" + beqRa.ToString("X") + + " sp=0x" + beqSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-sltu" + + " (first I-fetch after sltu; beq dest MULT;" + + " honor ra; no invent taken / dest / 0x9A02)"); + } + + // Live b7efbff: after sltu, dump + // beq $t3,$0 at 0x8003F7B4. + // Delay andi $s4,$t2,7 runs both + // paths. Taken 0x8003F748 is + // MULT — refuse hop. Fall dump- + // true 0x8003F7BC addiu $v0,$0, + // -9384. Do not invent $t3 / + // taken / dest / KData. Never + // MUL. Not LoadO32. No leftover- + // hop. + public static bool TryTakeDumpMem15C28AfterOuterJalBeq(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalSltuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkBeq) + return false; + if (_exn15C28AfterOuterJalBeqLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeq + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBeqFall) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBeqDelay) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint beqDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out beqDump) || beqDump == 0) + beqDump = CoredllDllMainExn15C28OuterJalLinkBeqDump; + if (beqDump != CoredllDllMainExn15C28OuterJalLinkBeqDump) + return false; + uint delayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkBeqDelay, out delayDump) + || delayDump == 0) + delayDump = CoredllDllMainExn15C28OuterJalLinkBeqDelayDump; + if (delayDump != CoredllDllMainExn15C28OuterJalLinkBeqDelayDump) + return false; + uint takenDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkBeqTaken, out takenDump) + || takenDump == 0) + takenDump = CoredllDllMainExn15C28OuterJalLinkBeqTakenDump; + if (takenDump != CoredllDllMainExn15C28OuterJalLinkBeqTakenDump + || (takenDump >> 26) != 0 || (takenDump & 63) != 0x18) + return false; + uint fallDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkBeqFall, out fallDump) + || fallDump == 0) + fallDump = CoredllDllMainExn15C28OuterJalLinkBeqFallDump; + if (fallDump != CoredllDllMainExn15C28OuterJalLinkBeqFallDump) + return false; + if (insn != beqDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != beqDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, beqDump); + uint beqFall = CoredllDllMainExn15C28OuterJalLinkBeqFall; + if (beqFall == 0 || (beqFall & 3) != 0 + || beqFall == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(beqFall) + || IsExn15C28Na02Frame(beqFall) + || IsExn15C28HelperBody(beqFall) + || IsExn15C28JalRaEpiRange(beqFall) + || IsLeftoverDestVa(beqFall) + || IsWrapDestSize(beqFall) || IsWrapDestFp50Va(beqFall)) + return false; + bool delayOk = TryExecDumpMemAluIfNotNa02(regs, delayDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = beqFall; + _exn15C28AfterOuterJalSltuNextLogged = true; + _exn15C28AfterOuterJalBeqLogged = true; + uint beqRa = PeekGpr(regs, 31); + uint beqSp = PeekGpr(regs, 29); + uint beqV0 = PeekGpr(regs, 2); + uint beqT3 = PeekGpr(regs, 11); + uint beqFp = PeekGpr(regs, 30); + uint beqT2 = PeekGpr(regs, 10); + uint beqS4 = PeekGpr(regs, 20); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = delayOk + ? "dump-mem-15c28-outer-jal-beq" + : "dump-mem-15c28-outer-jal-beq-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + beqDump.ToString("X") + + " dest=0x" + beqFall.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-beq" + + " pc=0x" + pc.ToString("X") + + " next=0x" + beqFall.ToString("X") + + " dump=0x" + beqDump.ToString("X") + + (insn != 0 && insn != beqDump ? " live=0x" + insn.ToString("X") : "") + + " delay=0x" + delayDump.ToString("X") + + (delayOk ? " andi=1" : " andi=0") + + " taken=0x" + CoredllDllMainExn15C28OuterJalLinkBeqTaken.ToString("X") + + " mul=0x" + takenDump.ToString("X") + + " t3=0x" + beqT3.ToString("X") + + " t2=0x" + beqT2.ToString("X") + + " s4=0x" + beqS4.ToString("X") + + " fp=0x" + beqFp.ToString("X") + + " v0=0x" + beqV0.ToString("X") + + " ra=0x" + beqRa.ToString("X") + + " sp=0x" + beqSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump beq $t3,$0; delay andi; MUL dest refuse;" + + " fall addiu; honor ra; no invent $t3 / dest / KData / 0x9A02)"); + return true; + } + + // Live b7efbff: after beq fall, + // name first I-fetch at 0x8003F7BC + // (dump addiu $v0,$0,-9384). + // One-shot. Do not invent dest / + // $v0 / KData / SharedUserData. + // Do not hop MUL. Not LoadO32. + public static void TryNoteDumpMem15C28AfterOuterJalBeq(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalBeqLogged + || _exn15C28AfterOuterJalBeqNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkBeqFall) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalBeqNextLogged = true; + uint fallDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out fallDump) || fallDump == 0) + fallDump = CoredllDllMainExn15C28OuterJalLinkBeqFallDump; + uint fallRa = PeekGpr(regs, 31); + uint fallSp = PeekGpr(regs, 29); + uint fallV0 = PeekGpr(regs, 2); + uint fallT3 = PeekGpr(regs, 11); + uint fallS4 = PeekGpr(regs, 20); + string fallDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = fallDump != 0 + ? FormatMipsOp(pc, fallDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-beq"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (fallDump != 0 ? " dump=0x" + fallDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-beq"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-beq" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (fallDump != 0 ? " dump=0x" + fallDump.ToString("X") : "") + + " dis=" + fallDis + + (fallDump != 0 ? " dump-dis=" + dumpDis : "") + + " t3=0x" + fallT3.ToString("X") + + " s4=0x" + fallS4.ToString("X") + + " v0=0x" + fallV0.ToString("X") + + " ra=0x" + fallRa.ToString("X") + + " sp=0x" + fallSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-beq" + + " (first I-fetch after beq fall; addiu $v0,-9384;" + + " honor ra; no invent dest / $v0 / KData / 0x9A02)"); + } + + // Live 7964d8a: after beq fall, + // dump addiu $v0,$0,-9384 at + // 0x8003F7BC. Exec dump addiu + // (rs=$0 → v0:=0xFFFFDB58). + // Next 0x8003F7C0 lw $t4,0($v0) + // — observe only. Refuse MULT + // dest / SPECIAL 0x16. Do not + // invent *$v0 / SUD / 0x9A02 / + // 0x320255. Not LoadO32. No + // leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalBeqLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkBeqFall) + return false; + if (_exn15C28AfterOuterJalAddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkAddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint addiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out addiuDump) || addiuDump == 0) + addiuDump = CoredllDllMainExn15C28OuterJalLinkBeqFallDump; + if (addiuDump != CoredllDllMainExn15C28OuterJalLinkBeqFallDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkAddiuNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkAddiuNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkAddiuNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != addiuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != addiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, addiuDump); + uint addiuNext = CoredllDllMainExn15C28OuterJalLinkAddiuNext; + if (addiuNext == 0 || (addiuNext & 3) != 0 + || addiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(addiuNext) + || IsExn15C28Na02Frame(addiuNext) + || IsExn15C28HelperBody(addiuNext) + || IsExn15C28JalRaEpiRange(addiuNext) + || IsLeftoverDestVa(addiuNext) + || IsWrapDestSize(addiuNext) || IsWrapDestFp50Va(addiuNext)) + return false; + int addiuRs = (int)((addiuDump >> 21) & 31); + bool addiuOk = addiuRs == 0 + ? TryExecDumpMemAlu(regs, addiuDump) + : TryExecDumpMemAluIfNotNa02(regs, addiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = addiuNext; + _exn15C28AfterOuterJalBeqNextLogged = true; + _exn15C28AfterOuterJalAddiuLogged = true; + uint addiuRa = PeekGpr(regs, 31); + uint addiuSp = PeekGpr(regs, 29); + uint addiuV0 = PeekGpr(regs, 2); + uint addiuT3 = PeekGpr(regs, 11); + uint addiuS4 = PeekGpr(regs, 20); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = addiuOk + ? "dump-mem-15c28-outer-jal-addiu" + : "dump-mem-15c28-outer-jal-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + addiuDump.ToString("X") + + " dest=0x" + addiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + addiuNext.ToString("X") + + " dump=0x" + addiuDump.ToString("X") + + (insn != 0 && insn != addiuDump ? " live=0x" + insn.ToString("X") : "") + + (addiuOk ? " addiu=1" : " addiu=0") + + " v0=0x" + addiuV0.ToString("X") + + " t3=0x" + addiuT3.ToString("X") + + " s4=0x" + addiuS4.ToString("X") + + " ra=0x" + addiuRa.ToString("X") + + " sp=0x" + addiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $v0,$0,-9384; next lw $t4,0($v0);" + + " MUL dest refuse; honor ra;" + + " no invent *$v0 / SUD / dest / 0x9A02 / 0x320255)"); + return true; + } + + // Live 7964d8a: after addiu, name + // first I-fetch at 0x8003F7C0 + // (dump lw $t4,0($v0)). One-shot. + // Do not exec that lw. Do not + // invent *$v0 / dest / SUD / + // 0x9A02 / 0x320255. Do not hop + // MUL. Not LoadO32. + public static void TryNoteDumpMem15C28AfterOuterJalAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalAddiuLogged + || _exn15C28AfterOuterJalAddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkAddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalAddiuNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkAddiuNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextV0 = PeekGpr(regs, 2); + uint nextT3 = PeekGpr(regs, 11); + uint nextS4 = PeekGpr(regs, 20); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " v0=0x" + nextV0.ToString("X") + + " t3=0x" + nextT3.ToString("X") + + " s4=0x" + nextS4.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-addiu" + + " (first I-fetch after addiu; lw $t4,0($v0);" + + " honor ra; no invent *$v0 / dest / SUD / 0x9A02)"); + } + + // Live 87bbfea: lw $t4,0($v0) at + // 0x8003F7C0 v0=0xFFFFDB58. Peek + // dump / firmware PTE only. Dest + // miss → continue-skip; leave $t4. + // Do not invent *0xFFFFDB58 / SUD + // / KData. PC:=0x8003F7C4. Observe + // lw $s7,20($sp). Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. + private static bool TryPeekExn15C28OuterJalLwT4Dest(MipsBus bus, + uint dest, out uint peek) + { + peek = 0; + if (dest == 0 || (dest & 3) != 0) + return false; + if (IsDumpMemRefuseVa(dest) || IsExn15C28Na02Frame(dest)) + return false; + if (dest >= CoredllDllMainC000Page + || dest == FfffF000Page + || (dest & ~0xFFFu) == FfffE000Page) + return false; + if (TryPeekLeftoverWait99DumpOnly(dest, out peek)) + return true; + if (dest >= 0x80010000u && dest < 0x80400000u + && TryPeekWord(bus, dest, out peek)) + return true; + return false; + } + + public static bool TryTakeDumpMem15C28AfterOuterJalLwT4(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalAddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkAddiuNext) + return false; + if (_exn15C28AfterOuterJalLwT4Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwT4Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkAddiuNextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkAddiuNextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwT4Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwT4NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwT4NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwT4Next = CoredllDllMainExn15C28OuterJalLinkLwT4Next; + if (lwT4Next == 0 || (lwT4Next & 3) != 0 + || lwT4Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(lwT4Next) + || IsExn15C28Na02Frame(lwT4Next) + || IsExn15C28HelperBody(lwT4Next) + || IsExn15C28JalRaEpiRange(lwT4Next) + || IsLeftoverDestVa(lwT4Next) + || IsWrapDestSize(lwT4Next) || IsWrapDestFp50Va(lwT4Next)) + return false; + uint lwT4V0 = PeekGpr(regs, 2); + uint lwT4Dest = lwT4V0; + uint lwT4Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwT4Dest, + out lwT4Peek); + if (destOk) + PokeGpr(regs, 12, lwT4Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwT4Next; + _exn15C28AfterOuterJalAddiuNextLogged = true; + _exn15C28AfterOuterJalLwT4Logged = true; + uint lwT4Ra = PeekGpr(regs, 31); + uint lwT4Sp = PeekGpr(regs, 29); + uint lwT4T4 = PeekGpr(regs, 12); + uint lwT4T3 = PeekGpr(regs, 11); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-t4" + : "dump-mem-15c28-outer-jal-lw-t4-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwT4Dest.ToString("X") + + (destOk ? "" : " *v0-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-t4" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwT4Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " v0=0x" + lwT4V0.ToString("X") + + (destOk ? "" : " *v0-miss") + + " t4=0x" + lwT4T4.ToString("X") + + " t3=0x" + lwT4T3.ToString("X") + + " ra=0x" + lwT4Ra.ToString("X") + + " sp=0x" + lwT4Sp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $t4,0($v0); dest-miss skip;" + + " leave $t4; no invent *0xFFFFDB58 / SUD / KData / 0x9A02 / 0x320255)"); + return true; + } + + // Live 87bbfea: after lw-t4 skip, + // name first I-fetch at 0x8003F7C4 + // (dump lw $s7,20($sp)). One-shot. + // Do not exec that lw. Do not + // invent *$sp / dest / 0x9A02 / + // 0x320255. Do not hop MUL. + public static void TryNoteDumpMem15C28AfterOuterJalLwT4(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwT4Logged + || _exn15C28AfterOuterJalLwT4NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwT4Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwT4NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwT4NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextV0 = PeekGpr(regs, 2); + uint nextT4 = PeekGpr(regs, 12); + uint nextS7 = PeekGpr(regs, 23); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-t4"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-t4"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-t4" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " v0=0x" + nextV0.ToString("X") + + " t4=0x" + nextT4.ToString("X") + + " s7=0x" + nextS7.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-t4" + + " (first I-fetch after lw-t4 skip; lw $s7,20($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02)"); + } + + // Live 36e0bb7: lw $s7,20($sp) at + // 0x8003F7C4 sp=0x9A023E70 dest + // 0x9A023E84. Dest-miss skip; + // leave $s7. Do not invent + // 0x9A02. PC:=0x8003F7C8. Observe + // addu $t5,$t4,$fp. Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS7(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwT4Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwT4Next) + return false; + if (_exn15C28AfterOuterJalLwS7Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwT4Next + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS7Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwT4NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwT4NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS7Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS7NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS7NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS7Next = CoredllDllMainExn15C28OuterJalLinkLwS7Next; + if (lwS7Next == 0 || (lwS7Next & 3) != 0 + || lwS7Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(lwS7Next) + || IsExn15C28Na02Frame(lwS7Next) + || IsExn15C28HelperBody(lwS7Next) + || IsExn15C28JalRaEpiRange(lwS7Next) + || IsLeftoverDestVa(lwS7Next) + || IsWrapDestSize(lwS7Next) || IsWrapDestFp50Va(lwS7Next)) + return false; + uint lwS7Sp = PeekGpr(regs, 29); + uint lwS7Dest = unchecked(lwS7Sp + 20); + uint lwS7Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS7Dest, + out lwS7Peek); + if (destOk) + PokeGpr(regs, 23, lwS7Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS7Next; + _exn15C28AfterOuterJalLwT4NextLogged = true; + _exn15C28AfterOuterJalLwS7Logged = true; + uint lwS7Ra = PeekGpr(regs, 31); + uint lwS7S7 = PeekGpr(regs, 23); + uint lwS7T4 = PeekGpr(regs, 12); + uint lwS7V0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s7" + : "dump-mem-15c28-outer-jal-lw-s7-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS7Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s7" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS7Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS7Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s7=0x" + lwS7S7.ToString("X") + + " t4=0x" + lwS7T4.ToString("X") + + " v0=0x" + lwS7V0.ToString("X") + + " ra=0x" + lwS7Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s7,20($sp); dest-miss skip;" + + " leave $s7; no invent 0x9A02 / *0xFFFFDB58 / SUD / 0x320255)"); + return true; + } + + // Live 36e0bb7: after lw-s7 skip, + // name first I-fetch at 0x8003F7C8 + // (dump addu $t5,$t4,$fp). One- + // shot. Do not invent $t4 / $fp / + // dest / 0x9A02. Do not hop MUL. + public static void TryNoteDumpMem15C28AfterOuterJalLwS7(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS7Logged + || _exn15C28AfterOuterJalLwS7NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS7Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS7NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS7NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT4 = PeekGpr(regs, 12); + uint nextFp = PeekGpr(regs, 30); + uint nextS7 = PeekGpr(regs, 23); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s7"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s7"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s7" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t4=0x" + nextT4.ToString("X") + + " fp=0x" + nextFp.ToString("X") + + " s7=0x" + nextS7.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s7" + + " (first I-fetch after lw-s7 skip; addu $t5,$t4,$fp;" + + " honor ra; no invent $fp / dest / 0x9A02)"); + } + + // Live c5d44f3: addu $t5,$t4,$fp + // at 0x8003F7C8 named only. Exec + // dump addu even if $fp is 0x9A + // (ALU write only; no 0x9A page). + // PC:=0x8003F7CC. Observe lw + // $fp,16($sp). Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalAddu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS7Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS7Next) + return false; + if (_exn15C28AfterOuterJalAdduLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS7Next + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkAdduNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint adduDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out adduDump) || adduDump == 0) + adduDump = CoredllDllMainExn15C28OuterJalLinkLwS7NextDump; + if (adduDump != CoredllDllMainExn15C28OuterJalLinkLwS7NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkAdduNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkAdduNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkAdduNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != adduDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != adduDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, adduDump); + uint adduNext = CoredllDllMainExn15C28OuterJalLinkAdduNext; + if (adduNext == 0 || (adduNext & 3) != 0 + || adduNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(adduNext) + || IsExn15C28Na02Frame(adduNext) + || IsExn15C28HelperBody(adduNext) + || IsExn15C28JalRaEpiRange(adduNext) + || IsLeftoverDestVa(adduNext) + || IsWrapDestSize(adduNext) || IsWrapDestFp50Va(adduNext)) + return false; + bool adduOk = TryExecDumpMemAlu(regs, adduDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = adduNext; + _exn15C28AfterOuterJalLwS7NextLogged = true; + _exn15C28AfterOuterJalAdduLogged = true; + uint adduRa = PeekGpr(regs, 31); + uint adduSp = PeekGpr(regs, 29); + uint adduT4 = PeekGpr(regs, 12); + uint adduFp = PeekGpr(regs, 30); + uint adduT5 = PeekGpr(regs, 13); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = adduOk + ? "dump-mem-15c28-outer-jal-addu" + : "dump-mem-15c28-outer-jal-addu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + adduDump.ToString("X") + + " dest=0x" + adduNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-addu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + adduNext.ToString("X") + + " dump=0x" + adduDump.ToString("X") + + (insn != 0 && insn != adduDump ? " live=0x" + insn.ToString("X") : "") + + (adduOk ? " addu=1" : " addu=0") + + " t4=0x" + adduT4.ToString("X") + + " fp=0x" + adduFp.ToString("X") + + " t5=0x" + adduT5.ToString("X") + + " ra=0x" + adduRa.ToString("X") + + " sp=0x" + adduSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addu $t5,$t4,$fp; ALU even if $fp is 0x9A;" + + " no invent 0x9A02 page / *0xFFFFDB58 / SUD / 0x320255)"); + return true; + } + + // Live c5d44f3: after addu, name + // first I-fetch at 0x8003F7CC + // (dump lw $fp,16($sp)). One-shot. + // Do not exec that lw. Do not + // invent *$sp / dest / 0x9A02. + // Do not hop MUL. + public static void TryNoteDumpMem15C28AfterOuterJalAddu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalAdduLogged + || _exn15C28AfterOuterJalAdduNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkAdduNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalAdduNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkAdduNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextFp = PeekGpr(regs, 30); + uint nextT4 = PeekGpr(regs, 12); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-addu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-addu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-addu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " t4=0x" + nextT4.ToString("X") + + " fp=0x" + nextFp.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-addu" + + " (first I-fetch after addu; lw $fp,16($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02)"); + } + + // Live e99a90c: lw $fp,16($sp) + // at 0x8003F7CC named only. Dest + // ~0x9A023E80. Dest-miss skip; + // leave $fp. Do not invent + // 0x9A02. PC:=0x8003F7D0. Observe + // lw $s6,24($sp). Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static bool TryTakeDumpMem15C28AfterOuterJalLwFp(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalAdduLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkAdduNext) + return false; + if (_exn15C28AfterOuterJalLwFpLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkAdduNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwFpNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkAdduNextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkAdduNextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwFpNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwFpNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwFpNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwFpNext = CoredllDllMainExn15C28OuterJalLinkLwFpNext; + if (lwFpNext == 0 || (lwFpNext & 3) != 0 + || lwFpNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(lwFpNext) + || IsExn15C28Na02Frame(lwFpNext) + || IsExn15C28HelperBody(lwFpNext) + || IsExn15C28JalRaEpiRange(lwFpNext) + || IsLeftoverDestVa(lwFpNext) + || IsWrapDestSize(lwFpNext) || IsWrapDestFp50Va(lwFpNext)) + return false; + uint lwFpSp = PeekGpr(regs, 29); + uint lwFpDest = unchecked(lwFpSp + 16); + uint lwFpPeek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwFpDest, + out lwFpPeek); + if (destOk) + PokeGpr(regs, 30, lwFpPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwFpNext; + _exn15C28AfterOuterJalAdduNextLogged = true; + _exn15C28AfterOuterJalLwFpLogged = true; + uint lwFpRa = PeekGpr(regs, 31); + uint lwFpFp = PeekGpr(regs, 30); + uint lwFpT5 = PeekGpr(regs, 13); + uint lwFpT4 = PeekGpr(regs, 12); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-fp" + : "dump-mem-15c28-outer-jal-lw-fp-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwFpDest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-fp" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwFpNext.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwFpSp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " fp=0x" + lwFpFp.ToString("X") + + " t5=0x" + lwFpT5.ToString("X") + + " t4=0x" + lwFpT4.ToString("X") + + " ra=0x" + lwFpRa.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $fp,16($sp); dest-miss skip;" + + " leave $fp; no invent 0x9A02 / *0xFFFFDB58 / SUD / 0x320255)"); + return true; + } + + // Live e99a90c: after lw-fp skip, + // name first I-fetch at 0x8003F7D0 + // (dump lw $s6,24($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02. + // Do not hop MUL. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwFp(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwFpLogged + || _exn15C28AfterOuterJalLwFpNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwFpNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwFpNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwFpNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextFp = PeekGpr(regs, 30); + uint nextS6 = PeekGpr(regs, 22); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-fp"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-fp"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-fp" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " fp=0x" + nextFp.ToString("X") + + " s6=0x" + nextS6.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-fp" + + " (first I-fetch after lw-fp skip; lw $s6,24($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02)"); + } + + // Live ab51f6e: lw $s6,24($sp) + // at 0x8003F7D0 named only. Dest + // ~0x9A023E88. Dest-miss skip; + // leave $s6. Do not invent + // 0x9A02. PC:=0x8003F7D4. Observe + // lw $s5,28($sp). Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS6(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwFpLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwFpNext) + return false; + if (_exn15C28AfterOuterJalLwS6Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwFpNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS6Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwFpNextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwFpNextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS6Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS6NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS6NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS6Next = CoredllDllMainExn15C28OuterJalLinkLwS6Next; + if (lwS6Next == 0 || (lwS6Next & 3) != 0 + || lwS6Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(lwS6Next) + || IsExn15C28Na02Frame(lwS6Next) + || IsExn15C28HelperBody(lwS6Next) + || IsExn15C28JalRaEpiRange(lwS6Next) + || IsLeftoverDestVa(lwS6Next) + || IsWrapDestSize(lwS6Next) || IsWrapDestFp50Va(lwS6Next)) + return false; + uint lwS6Sp = PeekGpr(regs, 29); + uint lwS6Dest = unchecked(lwS6Sp + 24); + uint lwS6Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS6Dest, + out lwS6Peek); + if (destOk) + PokeGpr(regs, 22, lwS6Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS6Next; + _exn15C28AfterOuterJalLwFpNextLogged = true; + _exn15C28AfterOuterJalLwS6Logged = true; + uint lwS6Ra = PeekGpr(regs, 31); + uint lwS6S6 = PeekGpr(regs, 22); + uint lwS6T5 = PeekGpr(regs, 13); + uint lwS6Fp = PeekGpr(regs, 30); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s6" + : "dump-mem-15c28-outer-jal-lw-s6-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS6Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s6" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS6Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS6Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s6=0x" + lwS6S6.ToString("X") + + " t5=0x" + lwS6T5.ToString("X") + + " fp=0x" + lwS6Fp.ToString("X") + + " ra=0x" + lwS6Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s6,24($sp); dest-miss skip;" + + " leave $s6; no invent 0x9A02 / *0xFFFFDB58 / SUD / 0x320255)"); + return true; + } + + // Live ab51f6e: after lw-s6 skip, + // name first I-fetch at 0x8003F7D4 + // (dump lw $s5,28($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02. + // Do not hop MUL. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS6(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS6Logged + || _exn15C28AfterOuterJalLwS6NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS6Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS6NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS6NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS6 = PeekGpr(regs, 22); + uint nextS5 = PeekGpr(regs, 21); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s6"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s6"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s6" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s6=0x" + nextS6.ToString("X") + + " s5=0x" + nextS5.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s6" + + " (first I-fetch after lw-s6 skip; lw $s5,28($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02)"); + } + + // Live 417729e: lw $s5,28($sp) + // at 0x8003F7D4 named only. Dest + // ~0x9A023E8C. Dest-miss skip; + // leave $s5. Do not invent + // 0x9A02. PC:=0x8003F7D8. Observe + // lw $s4,32($sp). Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS5(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS6Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS6Next) + return false; + if (_exn15C28AfterOuterJalLwS5Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS6Next + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS5Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS6NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS6NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS5Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS5NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS5NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS5Next = CoredllDllMainExn15C28OuterJalLinkLwS5Next; + if (lwS5Next == 0 || (lwS5Next & 3) != 0 + || lwS5Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(lwS5Next) + || IsExn15C28Na02Frame(lwS5Next) + || IsExn15C28HelperBody(lwS5Next) + || IsExn15C28JalRaEpiRange(lwS5Next) + || IsLeftoverDestVa(lwS5Next) + || IsWrapDestSize(lwS5Next) || IsWrapDestFp50Va(lwS5Next)) + return false; + uint lwS5Sp = PeekGpr(regs, 29); + uint lwS5Dest = unchecked(lwS5Sp + 28); + uint lwS5Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS5Dest, + out lwS5Peek); + if (destOk) + PokeGpr(regs, 21, lwS5Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS5Next; + _exn15C28AfterOuterJalLwS6NextLogged = true; + _exn15C28AfterOuterJalLwS5Logged = true; + uint lwS5Ra = PeekGpr(regs, 31); + uint lwS5S5 = PeekGpr(regs, 21); + uint lwS5T5 = PeekGpr(regs, 13); + uint lwS5S6 = PeekGpr(regs, 22); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s5" + : "dump-mem-15c28-outer-jal-lw-s5-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS5Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s5" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS5Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS5Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s5=0x" + lwS5S5.ToString("X") + + " t5=0x" + lwS5T5.ToString("X") + + " s6=0x" + lwS5S6.ToString("X") + + " ra=0x" + lwS5Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s5,28($sp); dest-miss skip;" + + " leave $s5; no invent 0x9A02 / *0xFFFFDB58 / SUD / 0x320255)"); + return true; + } + + // Live 417729e: after lw-s5 skip, + // name first I-fetch at 0x8003F7D8 + // (dump lw $s4,32($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02. + // Do not hop MUL. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS5(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS5Logged + || _exn15C28AfterOuterJalLwS5NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS5Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS5NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS5NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS5 = PeekGpr(regs, 21); + uint nextS4 = PeekGpr(regs, 20); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s5"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s5"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s5" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s5=0x" + nextS5.ToString("X") + + " s4=0x" + nextS4.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s5" + + " (first I-fetch after lw-s5 skip; lw $s4,32($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02)"); + } + + // Live fac4e01: lw $s4,32($sp) + // at 0x8003F7D8 named only. Dest + // ~0x9A023E90. Dest-miss skip; + // leave $s4. Do not invent + // 0x9A02. PC:=0x8003F7DC. Observe + // lw $s3,36($sp). Refuse MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + // Do not re-enter 0x8002105C / + // 0x80021060 on 0x9FFFF. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS4(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS5Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS5Next) + return false; + if (_exn15C28AfterOuterJalLwS4Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS5Next + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS4Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS5NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS5NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS4Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS4NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS4NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS4Next = CoredllDllMainExn15C28OuterJalLinkLwS4Next; + if (lwS4Next == 0 || (lwS4Next & 3) != 0 + || lwS4Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lwS4Next == CoredllDllMainExn15C28JalS1AluNext + || lwS4Next == CoredllDllMainExn15C28StkSwNext + || IsDumpMemRefuseVa(lwS4Next) + || IsExn15C28Na02Frame(lwS4Next) + || IsExn15C28NfffFrame(lwS4Next) + || IsExn15C28HelperBody(lwS4Next) + || IsExn15C28JalRaEpiRange(lwS4Next) + || IsLeftoverDestVa(lwS4Next) + || IsWrapDestSize(lwS4Next) || IsWrapDestFp50Va(lwS4Next)) + return false; + uint lwS4Sp = PeekGpr(regs, 29); + uint lwS4Dest = unchecked(lwS4Sp + 32); + uint lwS4Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS4Dest, + out lwS4Peek); + if (destOk) + PokeGpr(regs, 20, lwS4Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS4Next; + _exn15C28AfterOuterJalLwS5NextLogged = true; + _exn15C28AfterOuterJalLwS4Logged = true; + uint lwS4Ra = PeekGpr(regs, 31); + uint lwS4S4 = PeekGpr(regs, 20); + uint lwS4T5 = PeekGpr(regs, 13); + uint lwS4S5 = PeekGpr(regs, 21); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s4" + : "dump-mem-15c28-outer-jal-lw-s4-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS4Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s4" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS4Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS4Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s4=0x" + lwS4S4.ToString("X") + + " t5=0x" + lwS4T5.ToString("X") + + " s5=0x" + lwS4S5.ToString("X") + + " ra=0x" + lwS4Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s4,32($sp); dest-miss skip;" + + " leave $s4; no invent 0x9A02 / 0x9F / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live fac4e01: after lw-s4 skip, + // name first I-fetch at 0x8003F7DC + // (dump lw $s3,36($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02. + // Do not hop MUL. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS4(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS4Logged + || _exn15C28AfterOuterJalLwS4NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS4Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS4NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS4NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS4 = PeekGpr(regs, 20); + uint nextS3 = PeekGpr(regs, 19); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s4"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s4"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s4" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s4=0x" + nextS4.ToString("X") + + " s3=0x" + nextS3.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s4" + + " (first I-fetch after lw-s4 skip; lw $s3,36($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02 / 0x9F)"); + } + + // Live c9b2f7a: lw $s3,36($sp) + // at 0x8003F7DC named only. Dest + // ~0x9A023E94. Dest-miss skip; + // leave $s3. Do not invent + // 0x9A02 / 0x9F. PC:=0x8003F7E0. + // Observe lw $s2,40($sp). Refuse + // MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. Do not re-enter + // 0x8002105C / 0x80021060. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS3(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS4Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS4Next) + return false; + if (_exn15C28AfterOuterJalLwS3Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS4Next + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS3Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS4NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS4NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS3Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS3NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS3NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS3Next = CoredllDllMainExn15C28OuterJalLinkLwS3Next; + if (lwS3Next == 0 || (lwS3Next & 3) != 0 + || lwS3Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lwS3Next == CoredllDllMainExn15C28JalS1AluNext + || lwS3Next == CoredllDllMainExn15C28StkSwNext + || IsDumpMemRefuseVa(lwS3Next) + || IsExn15C28Na02Frame(lwS3Next) + || IsExn15C28NfffFrame(lwS3Next) + || IsExn15C28HelperBody(lwS3Next) + || IsExn15C28JalRaEpiRange(lwS3Next) + || IsLeftoverDestVa(lwS3Next) + || IsWrapDestSize(lwS3Next) || IsWrapDestFp50Va(lwS3Next)) + return false; + uint lwS3Sp = PeekGpr(regs, 29); + uint lwS3Dest = unchecked(lwS3Sp + 36); + uint lwS3Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS3Dest, + out lwS3Peek); + if (destOk) + PokeGpr(regs, 19, lwS3Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS3Next; + _exn15C28AfterOuterJalLwS4NextLogged = true; + _exn15C28AfterOuterJalLwS3Logged = true; + uint lwS3Ra = PeekGpr(regs, 31); + uint lwS3S3 = PeekGpr(regs, 19); + uint lwS3T5 = PeekGpr(regs, 13); + uint lwS3S4 = PeekGpr(regs, 20); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s3" + : "dump-mem-15c28-outer-jal-lw-s3-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS3Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s3" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS3Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS3Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s3=0x" + lwS3S3.ToString("X") + + " t5=0x" + lwS3T5.ToString("X") + + " s4=0x" + lwS3S4.ToString("X") + + " ra=0x" + lwS3Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s3,36($sp); dest-miss skip;" + + " leave $s3; no invent 0x9A02 / 0x9F / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live c9b2f7a: after lw-s3 skip, + // name first I-fetch at 0x8003F7E0 + // (dump lw $s2,40($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02 + // / 0x9F. Do not hop MUL. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS3(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS3Logged + || _exn15C28AfterOuterJalLwS3NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS3Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS3NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS3NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS3 = PeekGpr(regs, 19); + uint nextS2 = PeekGpr(regs, 18); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s3"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s3"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s3" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s3=0x" + nextS3.ToString("X") + + " s2=0x" + nextS2.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s3" + + " (first I-fetch after lw-s3 skip; lw $s2,40($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02 / 0x9F)"); + } + + // Live 8533465: lw $s2,40($sp) + // at 0x8003F7E0 named only. Dest + // ~0x9A023E98. Dest-miss skip; + // leave $s2. Do not invent + // 0x9A02 / 0x9F. PC:=0x8003F7E4. + // Observe lw $s1,44($sp). Refuse + // MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. Do not re-enter + // 0x8002105C / 0x80021060. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS2(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS3Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS3Next) + return false; + if (_exn15C28AfterOuterJalLwS2Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS3Next + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS2Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS3NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS3NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS2Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS2NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS2NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS2Next = CoredllDllMainExn15C28OuterJalLinkLwS2Next; + if (lwS2Next == 0 || (lwS2Next & 3) != 0 + || lwS2Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lwS2Next == CoredllDllMainExn15C28JalS1AluNext + || lwS2Next == CoredllDllMainExn15C28StkSwNext + || IsDumpMemRefuseVa(lwS2Next) + || IsExn15C28Na02Frame(lwS2Next) + || IsExn15C28NfffFrame(lwS2Next) + || IsExn15C28HelperBody(lwS2Next) + || IsExn15C28JalRaEpiRange(lwS2Next) + || IsLeftoverDestVa(lwS2Next) + || IsWrapDestSize(lwS2Next) || IsWrapDestFp50Va(lwS2Next)) + return false; + uint lwS2Sp = PeekGpr(regs, 29); + uint lwS2Dest = unchecked(lwS2Sp + 40); + uint lwS2Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS2Dest, + out lwS2Peek); + if (destOk) + PokeGpr(regs, 18, lwS2Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS2Next; + _exn15C28AfterOuterJalLwS3NextLogged = true; + _exn15C28AfterOuterJalLwS2Logged = true; + uint lwS2Ra = PeekGpr(regs, 31); + uint lwS2S2 = PeekGpr(regs, 18); + uint lwS2T5 = PeekGpr(regs, 13); + uint lwS2S3 = PeekGpr(regs, 19); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s2" + : "dump-mem-15c28-outer-jal-lw-s2-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS2Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s2" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS2Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS2Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s2=0x" + lwS2S2.ToString("X") + + " t5=0x" + lwS2T5.ToString("X") + + " s3=0x" + lwS2S3.ToString("X") + + " ra=0x" + lwS2Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s2,40($sp); dest-miss skip;" + + " leave $s2; no invent 0x9A02 / 0x9F / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live 8533465: after lw-s2 skip, + // name first I-fetch at 0x8003F7E4 + // (dump lw $s1,44($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02 + // / 0x9F. Do not hop MUL. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS2(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS2Logged + || _exn15C28AfterOuterJalLwS2NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS2Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS2NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS2NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS2 = PeekGpr(regs, 18); + uint nextS1 = PeekGpr(regs, 17); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s2"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s2"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s2" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s2=0x" + nextS2.ToString("X") + + " s1=0x" + nextS1.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s2" + + " (first I-fetch after lw-s2 skip; lw $s1,44($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02 / 0x9F)"); + } + + // Live e18b007: lw $s1,44($sp) + // at 0x8003F7E4 named only. Dest + // ~0x9A023E9C. Dest-miss skip; + // leave $s1. Do not invent + // 0x9A02 / 0x9F. PC:=0x8003F7E8. + // Observe lw $s0,48($sp). Refuse + // MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. Do not re-enter + // 0x8002105C / 0x80021060. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS1(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS2Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS2Next) + return false; + if (_exn15C28AfterOuterJalLwS1Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS2Next + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS1Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS2NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS2NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS1Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS1NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS1NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS1Next = CoredllDllMainExn15C28OuterJalLinkLwS1Next; + if (lwS1Next == 0 || (lwS1Next & 3) != 0 + || lwS1Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lwS1Next == CoredllDllMainExn15C28JalS1AluNext + || lwS1Next == CoredllDllMainExn15C28StkSwNext + || IsDumpMemRefuseVa(lwS1Next) + || IsExn15C28Na02Frame(lwS1Next) + || IsExn15C28NfffFrame(lwS1Next) + || IsExn15C28HelperBody(lwS1Next) + || IsExn15C28JalRaEpiRange(lwS1Next) + || IsLeftoverDestVa(lwS1Next) + || IsWrapDestSize(lwS1Next) || IsWrapDestFp50Va(lwS1Next)) + return false; + uint lwS1Sp = PeekGpr(regs, 29); + uint lwS1Dest = unchecked(lwS1Sp + 44); + uint lwS1Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS1Dest, + out lwS1Peek); + if (destOk) + PokeGpr(regs, 17, lwS1Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS1Next; + _exn15C28AfterOuterJalLwS2NextLogged = true; + _exn15C28AfterOuterJalLwS1Logged = true; + uint lwS1Ra = PeekGpr(regs, 31); + uint lwS1S1 = PeekGpr(regs, 17); + uint lwS1T5 = PeekGpr(regs, 13); + uint lwS1S2 = PeekGpr(regs, 18); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s1" + : "dump-mem-15c28-outer-jal-lw-s1-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS1Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s1" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS1Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS1Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s1=0x" + lwS1S1.ToString("X") + + " t5=0x" + lwS1T5.ToString("X") + + " s2=0x" + lwS1S2.ToString("X") + + " ra=0x" + lwS1Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s1,44($sp); dest-miss skip;" + + " leave $s1; no invent 0x9A02 / 0x9F / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live e18b007: after lw-s1 skip, + // name first I-fetch at 0x8003F7E8 + // (dump lw $s0,48($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02 + // / 0x9F. Do not hop MUL. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS1(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS1Logged + || _exn15C28AfterOuterJalLwS1NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS1Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS1NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS1NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS1 = PeekGpr(regs, 17); + uint nextS0 = PeekGpr(regs, 16); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s1"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s1"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s1" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s1=0x" + nextS1.ToString("X") + + " s0=0x" + nextS0.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s1" + + " (first I-fetch after lw-s1 skip; lw $s0,48($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02 / 0x9F)"); + } + + // Live d5e2773: lw $s0,48($sp) + // at 0x8003F7E8 named only. Dest + // ~0x9A023EA0. Dest-miss skip; + // leave $s0. Do not invent + // 0x9A02 / 0x9F. PC:=0x8003F7EC. + // Observe lw $ra,52($sp). Refuse + // MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. Do not re-enter + // 0x8002105C / 0x80021060. + public static bool TryTakeDumpMem15C28AfterOuterJalLwS0(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS1Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS1Next) + return false; + if (_exn15C28AfterOuterJalLwS0Logged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS1Next + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwS0Next) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS1NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS1NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwS0Next, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS0NextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwS0NextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwS0Next = CoredllDllMainExn15C28OuterJalLinkLwS0Next; + if (lwS0Next == 0 || (lwS0Next & 3) != 0 + || lwS0Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lwS0Next == CoredllDllMainExn15C28JalS1AluNext + || lwS0Next == CoredllDllMainExn15C28StkSwNext + || IsDumpMemRefuseVa(lwS0Next) + || IsExn15C28Na02Frame(lwS0Next) + || IsExn15C28NfffFrame(lwS0Next) + || IsExn15C28HelperBody(lwS0Next) + || IsExn15C28JalRaEpiRange(lwS0Next) + || IsLeftoverDestVa(lwS0Next) + || IsWrapDestSize(lwS0Next) || IsWrapDestFp50Va(lwS0Next)) + return false; + uint lwS0Sp = PeekGpr(regs, 29); + uint lwS0Dest = unchecked(lwS0Sp + 48); + uint lwS0Peek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwS0Dest, + out lwS0Peek); + if (destOk) + PokeGpr(regs, 16, lwS0Peek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwS0Next; + _exn15C28AfterOuterJalLwS1NextLogged = true; + _exn15C28AfterOuterJalLwS0Logged = true; + uint lwS0Ra = PeekGpr(regs, 31); + uint lwS0S0 = PeekGpr(regs, 16); + uint lwS0T5 = PeekGpr(regs, 13); + uint lwS0S1 = PeekGpr(regs, 17); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-s0" + : "dump-mem-15c28-outer-jal-lw-s0-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwS0Dest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-s0" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwS0Next.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwS0Sp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " s0=0x" + lwS0S0.ToString("X") + + " t5=0x" + lwS0T5.ToString("X") + + " s1=0x" + lwS0S1.ToString("X") + + " ra=0x" + lwS0Ra.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $s0,48($sp); dest-miss skip;" + + " leave $s0; no invent 0x9A02 / 0x9F / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live d5e2773: after lw-s0 skip, + // name first I-fetch at 0x8003F7EC + // (dump lw $ra,52($sp)). One- + // shot. Do not exec that lw. Do + // not invent *$sp / dest / 0x9A02 + // / 0x9F. Do not hop MUL. Do not + // treat SPECIAL 0x16 as MUL or + // ri-nop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwS0(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwS0Logged + || _exn15C28AfterOuterJalLwS0NextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS0Next) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwS0NextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwS0NextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS0 = PeekGpr(regs, 16); + uint nextS1 = PeekGpr(regs, 17); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-s0"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-s0"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-s0" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s0=0x" + nextS0.ToString("X") + + " s1=0x" + nextS1.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-s0" + + " (first I-fetch after lw-s0 skip; lw $ra,52($sp);" + + " honor ra; no invent *$sp / dest / 0x9A02 / 0x9F)"); + } + + // Live ceee1bd: lw $ra,52($sp) + // at 0x8003F7EC named only. Dest + // ~0x9A023EA4. Dest-miss skip; + // leave $ra (live link + // 0x8003F78C). Do not invent + // stack return / 0x9A02 / 0x9F. + // PC:=0x8003F7F0. Observe addiu + // $sp,$sp,56. Refuse MULT / + // SPECIAL 0x16 / jr hop. Not + // LoadO32. No leftover-hop. Live + // $t5 wrap 0x1A3658D4 is dump- + // true only. Do not re-enter + // 0x8002105C / 0x80021060. + public static bool TryTakeDumpMem15C28AfterOuterJalLwRa(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwS0Logged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwS0Next) + return false; + if (_exn15C28AfterOuterJalLwRaLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwS0Next + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkLwRaNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint lwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lwDump) || lwDump == 0) + lwDump = CoredllDllMainExn15C28OuterJalLinkLwS0NextDump; + if (lwDump != CoredllDllMainExn15C28OuterJalLinkLwS0NextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkLwRaNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwRaNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkLwRaNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16 + || (nextDump & 63) == 0x08)) + return false; + if (insn != lwDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lwDump); + uint lwRaNext = CoredllDllMainExn15C28OuterJalLinkLwRaNext; + if (lwRaNext == 0 || (lwRaNext & 3) != 0 + || lwRaNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lwRaNext == CoredllDllMainExn15C28JalS1AluNext + || lwRaNext == CoredllDllMainExn15C28StkSwNext + || IsDumpMemRefuseVa(lwRaNext) + || IsExn15C28Na02Frame(lwRaNext) + || IsExn15C28NfffFrame(lwRaNext) + || IsExn15C28HelperBody(lwRaNext) + || IsExn15C28JalRaEpiRange(lwRaNext) + || IsLeftoverDestVa(lwRaNext) + || IsWrapDestSize(lwRaNext) || IsWrapDestFp50Va(lwRaNext)) + return false; + uint lwRaSp = PeekGpr(regs, 29); + uint lwRaDest = unchecked(lwRaSp + 52); + uint lwRaPeek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, lwRaDest, + out lwRaPeek); + if (destOk) + PokeGpr(regs, 31, lwRaPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lwRaNext; + _exn15C28AfterOuterJalLwS0NextLogged = true; + _exn15C28AfterOuterJalLwRaLogged = true; + uint lwRaRa = PeekGpr(regs, 31); + uint lwRaS0 = PeekGpr(regs, 16); + uint lwRaT5 = PeekGpr(regs, 13); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-lw-ra" + : "dump-mem-15c28-outer-jal-lw-ra-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lwDump.ToString("X") + + " dest=0x" + lwRaDest.ToString("X") + + (destOk ? "" : " *sp-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-lw-ra" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lwRaNext.ToString("X") + + " dump=0x" + lwDump.ToString("X") + + (insn != 0 && insn != lwDump ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lw=1" : " lw=0") + + " sp=0x" + lwRaSp.ToString("X") + + (destOk ? "" : " *sp-miss") + + " ra=0x" + lwRaRa.ToString("X") + + " t5=0x" + lwRaT5.ToString("X") + + " s0=0x" + lwRaS0.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $ra,52($sp); dest-miss skip;" + + " leave $ra; no invent 0x9A02 / 0x9F / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live ceee1bd: after lw-ra skip, + // name first I-fetch at 0x8003F7F0 + // (dump addiu $sp,$sp,56). One- + // shot. Do not exec jr $ra. Do + // not invent *$sp / dest / $ra / + // 0x9A02 / 0x9F. Do not hop MUL. + // Do not treat SPECIAL 0x16 as + // MUL or ri-nop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalLwRa(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalLwRaLogged + || _exn15C28AfterOuterJalLwRaNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwRaNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalLwRaNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkLwRaNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextS0 = PeekGpr(regs, 16); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-lw-ra"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-lw-ra"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-lw-ra" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " s0=0x" + nextS0.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-lw-ra" + + " (first I-fetch after lw-ra skip; addiu $sp,$sp,56;" + + " honor ra; no invent *$sp / dest / $ra / 0x9A02 / 0x9F)"); + } + + // Live e466bce: addiu $sp,$sp,56 + // at 0x8003F7F0 named only. Exec + // dump addiu even if $sp stays + // 0x9A (ALU write only; no 0x9A + // page). PC:=0x8003F7F4. Observe + // jr $ra. Refuse jr hop / MULT / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + // Do not re-enter 0x8002105C / + // 0x80021060. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalLwRaLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkLwRaNext) + return false; + if (_exn15C28AfterOuterJalEpiAddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkLwRaNext + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiAddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiAddiuDump) || epiAddiuDump == 0) + epiAddiuDump = CoredllDllMainExn15C28OuterJalLinkLwRaNextDump; + if (epiAddiuDump != CoredllDllMainExn15C28OuterJalLinkLwRaNextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16)) + return false; + if (insn != epiAddiuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiAddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiAddiuDump); + uint epiAddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext; + if (epiAddiuNext == 0 || (epiAddiuNext & 3) != 0 + || epiAddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiAddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiAddiuNext == CoredllDllMainExn15C28StkSwNext + || epiAddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiAddiuNext) + || IsExn15C28Na02Frame(epiAddiuNext) + || IsExn15C28NfffFrame(epiAddiuNext) + || IsExn15C28HelperBody(epiAddiuNext) + || IsExn15C28JalRaEpiRange(epiAddiuNext) + || IsLeftoverDestVa(epiAddiuNext) + || IsWrapDestSize(epiAddiuNext) || IsWrapDestFp50Va(epiAddiuNext)) + return false; + bool epiAddiuOk = TryExecDumpMemAlu(regs, epiAddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiAddiuNext; + _exn15C28AfterOuterJalLwRaNextLogged = true; + _exn15C28AfterOuterJalEpiAddiuLogged = true; + uint epiAddiuRa = PeekGpr(regs, 31); + uint epiAddiuSp = PeekGpr(regs, 29); + uint epiAddiuT5 = PeekGpr(regs, 13); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiAddiuOk + ? "dump-mem-15c28-outer-jal-epi-addiu" + : "dump-mem-15c28-outer-jal-epi-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiAddiuDump.ToString("X") + + " dest=0x" + epiAddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiAddiuNext.ToString("X") + + " dump=0x" + epiAddiuDump.ToString("X") + + (insn != 0 && insn != epiAddiuDump ? " live=0x" + insn.ToString("X") : "") + + (epiAddiuOk ? " addiu=1" : " addiu=0") + + " sp=0x" + epiAddiuSp.ToString("X") + + " t5=0x" + epiAddiuT5.ToString("X") + + " ra=0x" + epiAddiuRa.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $sp,$sp,56; ALU even if $sp is 0x9A;" + + " no invent 0x9A02 page / no jr hop / *0xFFFFDB58 / SUD)"); + return true; + } + + // Live e466bce: after addiu, name + // first I-fetch at 0x8003F7F4 + // (dump jr $ra). One-shot. Do + // not exec jr / delay. Do not + // invent $ra / dest / 0x9A02 / + // 0x9F. Do not hop MUL. Do not + // treat SPECIAL 0x16 as MUL or + // ri-nop. Live $t5 wrap + // 0x1A3658D4 is dump-true only. + public static void TryNoteDumpMem15C28AfterOuterJalEpiAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiAddiuLogged + || _exn15C28AfterOuterJalEpiAddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiAddiuNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-addiu" + + " (first I-fetch after epi addiu; jr $ra;" + + " honor ra; no jr hop; no invent $ra / dest / 0x9A02 / 0x9F)"); + } + + // Dump-true jr $ra at 0x8003F7F4 + // after lw $ra,52($sp) and + // addiu $sp,56. JUMP sane caller + // — not 0x8003F8B4 / 0x8003F7FC. + // Delay sw $t5,0($v0) dest-miss + // skip; leave $t5. Do not invent + // *0xFFFFDB58 / SUD / 0x9A / 0x9F. + // Refuse MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiJr(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiAddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext) + return false; + if (_exn15C28AfterOuterJalEpiJrLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || (capLeave == CoredllDllMainExn15C28OuterJalLink + && IsExn15C28StkRecurseFrame(PeekGpr(regs, 29)))) + return false; + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrDelay + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiJrNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiJrDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiJrDump) || epiJrDump == 0) + epiJrDump = CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump; + if (epiJrDump != CoredllDllMainExn15C28OuterJalLinkEpiAddiuNextDump) + return false; + uint delayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiJrDelay, out delayDump) + || delayDump == 0) + delayDump = CoredllDllMainExn15C28OuterJalLinkEpiJrDelayDump; + if (delayDump != CoredllDllMainExn15C28OuterJalLinkEpiJrDelayDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiJrNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16 + || (nextDump & 63) == 0x08)) + return false; + if (insn != epiJrDump && insn != 0 && !IsMipsJumpOrJr(insn) + && !IsMipsStore(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiJrDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiJrDump); + uint epiJrRa = PeekGpr(regs, 31); + uint epiJrSp = PeekGpr(regs, 29); + if (!IsExn15C28DumpTrueEpiJrCaller(epiJrRa, epiJrSp)) + return false; + uint epiJrV0 = PeekGpr(regs, 2); + uint epiJrDest = unchecked(epiJrV0 + 0); + uint epiJrPeek = 0; + bool destOk = TryPeekExn15C28OuterJalLwT4Dest(bus, epiJrDest, + out epiJrPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiJrRa; + _exn15C28AfterOuterJalEpiAddiuNextLogged = true; + _exn15C28AfterOuterJalEpiJrLogged = true; + uint epiJrT5 = PeekGpr(regs, 13); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-jr" + : "dump-mem-15c28-outer-jal-epi-jr-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiJrDump.ToString("X") + + " dest=0x" + epiJrRa.ToString("X") + + (destOk ? "" : " *v0-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-jr" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiJrRa.ToString("X") + + " dump=0x" + epiJrDump.ToString("X") + + (insn != 0 && insn != epiJrDump ? " live=0x" + insn.ToString("X") : "") + + " delay=0x" + delayDump.ToString("X") + + (destOk ? " sw=1" : " sw=0") + + " dest=0x" + epiJrDest.ToString("X") + + (destOk ? "" : " *v0-miss") + + " v0=0x" + epiJrV0.ToString("X") + + " t5=0x" + epiJrT5.ToString("X") + + " ra=0x" + epiJrRa.ToString("X") + + " sp=0x" + epiJrSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump jr $ra JUMP caller; no hop 0x8003F8B4;" + + " delay sw dest-miss skip; leave $t5;" + + " no invent *0xFFFFDB58 / SUD / 0x9A02 / 0x9F)"); + return true; + } + + private static bool IsExn15C28DumpTrueEpiJrCaller(uint ra, uint sp) + { + if (ra == 0 || (ra & 3) != 0) + return false; + if (ra == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || ra == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || ra == CoredllDllMainExn15C28OuterJalLinkEpiJrDelay + || ra == CoredllDllMainExn15C28OuterJalLinkEpiJrNext) + return false; + if (IsDumpMemRefuseVa(ra) || IsExn15C28Na02Frame(ra) + || IsExn15C28NfffFrame(ra) || IsExn15C28N9ffFrame(ra) + || IsExn15C28HelperBody(ra) || IsLeftoverDestVa(ra) + || IsWrapDestSize(ra) || IsWrapDestFp50Va(ra)) + return false; + if (IsExn15C28StkRecurseFrame(sp) + && ra == CoredllDllMainExn15C28OuterJalLink) + return false; + return ra >= 0x80011000u && ra < 0x8005AB44u; + } + + // Live 9fc60b8: after epi-jr skip, + // name first I-fetch at 0x8003F7FC + // (dump lui $v0,0x8032). One- + // shot. Do not hop $ra. Do not + // invent *$v0 / dest / $ra / + // 0x9A02 / 0x9F / *0xFFFFDB58. + // Do not hop MUL. Do not treat + // SPECIAL 0x16 as MUL or ri-nop. + public static void TryNoteDumpMem15C28AfterOuterJalEpiJr(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiJrLogged + || _exn15C28AfterOuterJalEpiJrNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiJrNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiJrNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextV0 = PeekGpr(regs, 2); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-jr"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-jr"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-jr" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " v0=0x" + nextV0.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-jr" + + " (first I-fetch after epi-jr skip; lui $v0,0x8032;" + + " honor ra; no jr hop; no invent $ra / *0xFFFFDB58 / 0x9A02)"); + } + + // Live ce53ead: lui $v0,0x8032 + // at 0x8003F7FC named only. Exec + // dump lui (ALU $v0:=0x80320000). + // PC:=0x8003F800. Observe addiu + // $v0,$v0,588 (ALU-safe; name + // only). Refuse jr hop 0x8003F78C + // / MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Do + // not invent *0xFFFFDB58 / SUD / + // 0x9A02 / 0x8032 page. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiLui(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiJrLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiJrNext) + return false; + if (_exn15C28AfterOuterJalEpiLuiLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + && _exn15C28AfterOuterJalEpiV0AddiuLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiLuiNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiLuiDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiLuiDump) || epiLuiDump == 0) + epiLuiDump = CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump; + if (epiLuiDump != CoredllDllMainExn15C28OuterJalLinkEpiJrNextDump) + return false; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiLuiNext, out nextDump) + || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump; + if (nextDump != CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump) + return false; + if ((nextDump >> 26) == 0 + && ((nextDump & 63) == 0x18 || (nextDump & 63) == 0x16 + || (nextDump & 63) == 0x08)) + return false; + if (insn != epiLuiDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiLuiDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiLuiDump); + uint epiLuiNext = CoredllDllMainExn15C28OuterJalLinkEpiLuiNext; + if (epiLuiNext == 0 || (epiLuiNext & 3) != 0 + || epiLuiNext == CoredllDllMainExn15C28OuterJalLink + || epiLuiNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiLuiNext == CoredllDllMainExn15C28JalS1AluNext + || epiLuiNext == CoredllDllMainExn15C28StkSwNext + || epiLuiNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiLuiNext) + || IsExn15C28Na02Frame(epiLuiNext) + || IsExn15C28NfffFrame(epiLuiNext) + || IsExn15C28HelperBody(epiLuiNext) + || IsExn15C28JalRaEpiRange(epiLuiNext) + || IsLeftoverDestVa(epiLuiNext) + || IsWrapDestSize(epiLuiNext) || IsWrapDestFp50Va(epiLuiNext)) + return false; + bool epiLuiOk = TryExecDumpMemAlu(regs, epiLuiDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiLuiNext; + _exn15C28AfterOuterJalEpiJrNextLogged = true; + _exn15C28AfterOuterJalEpiLuiLogged = true; + uint epiLuiRa = PeekGpr(regs, 31); + uint epiLuiSp = PeekGpr(regs, 29); + uint epiLuiT5 = PeekGpr(regs, 13); + uint epiLuiV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiLuiOk + ? "dump-mem-15c28-outer-jal-epi-lui" + : "dump-mem-15c28-outer-jal-epi-lui-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiLuiDump.ToString("X") + + " dest=0x" + epiLuiNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-lui" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiLuiNext.ToString("X") + + " dump=0x" + epiLuiDump.ToString("X") + + (insn != 0 && insn != epiLuiDump ? " live=0x" + insn.ToString("X") : "") + + (epiLuiOk ? " lui=1" : " lui=0") + + " v0=0x" + epiLuiV0.ToString("X") + + " t5=0x" + epiLuiT5.ToString("X") + + " ra=0x" + epiLuiRa.ToString("X") + + " sp=0x" + epiLuiSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lui $v0,0x8032; ALU $v0:=0x80320000;" + + " no invent 0x8032 page / *0xFFFFDB58 / SUD / 0x9A02;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live ce53ead: after lui exec, + // name first I-fetch at 0x8003F800 + // (dump addiu $v0,$v0,588). One- + // shot. ALU-safe — name only this + // miss. Do not invent dest / $ra / + // 0x9A02 / 0x9F / *0xFFFFDB58. + // Do not hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiLui(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiLuiLogged + || _exn15C28AfterOuterJalEpiLuiNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiLuiNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiLuiNextLogged = true; + uint nextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out nextDump) || nextDump == 0) + nextDump = CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump; + uint nextRa = PeekGpr(regs, 31); + uint nextSp = PeekGpr(regs, 29); + uint nextT5 = PeekGpr(regs, 13); + uint nextV0 = PeekGpr(regs, 2); + string nextDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string dumpDis = nextDump != 0 + ? FormatMipsOp(pc, nextDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-lui"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-lui"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-lui" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (nextDump != 0 ? " dump=0x" + nextDump.ToString("X") : "") + + " dis=" + nextDis + + (nextDump != 0 ? " dump-dis=" + dumpDis : "") + + " t5=0x" + nextT5.ToString("X") + + " v0=0x" + nextV0.ToString("X") + + " ra=0x" + nextRa.ToString("X") + + " sp=0x" + nextSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-lui" + + " (first I-fetch after lui exec; addiu $v0,$v0,588;" + + " honor ra; no jr hop; no invent $ra / *0xFFFFDB58 / 0x9A02)"); + } + + // Live 166818f: addiu $v0,$v0,588 + // at 0x8003F800 named only. Exec + // dump addiu (ALU $v0:=0x8032024C). + // PC:=0x8003F804. Observe addiu + // $v1,$zero,-9448 (ALU-safe; name + // only). Refuse jr hop 0x8003F78C + // / MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Do + // not invent *0xFFFFDB58 / SUD / + // 0x9A02 / 0x8032 page / 0xFFFFDB18. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiV0Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiLuiLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiLuiNext) + return false; + if (_exn15C28AfterOuterJalEpiV0AddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + && _exn15C28AfterOuterJalEpiV1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + && _exn15C28AfterOuterJalEpiSwLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiV0AddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiV0AddiuDump) + || epiV0AddiuDump == 0) + epiV0AddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump; + if (epiV0AddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiLuiNextDump) + return false; + uint epiV0AddiuNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext, + out epiV0AddiuNextDump) + || epiV0AddiuNextDump == 0) + epiV0AddiuNextDump = CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump; + if (epiV0AddiuNextDump != CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump) + return false; + if ((epiV0AddiuNextDump >> 26) == 0 + && ((epiV0AddiuNextDump & 63) == 0x18 + || (epiV0AddiuNextDump & 63) == 0x16 + || (epiV0AddiuNextDump & 63) == 0x08)) + return false; + if (insn != epiV0AddiuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiV0AddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiV0AddiuDump); + uint epiV0AddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext; + if (epiV0AddiuNext == 0 || (epiV0AddiuNext & 3) != 0 + || epiV0AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiV0AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiV0AddiuNext == CoredllDllMainExn15C28OuterJalLink + || epiV0AddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiV0AddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiV0AddiuNext == CoredllDllMainExn15C28StkSwNext + || epiV0AddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiV0AddiuNext) + || IsExn15C28Na02Frame(epiV0AddiuNext) + || IsExn15C28NfffFrame(epiV0AddiuNext) + || IsExn15C28HelperBody(epiV0AddiuNext) + || IsExn15C28JalRaEpiRange(epiV0AddiuNext) + || IsLeftoverDestVa(epiV0AddiuNext) + || IsWrapDestSize(epiV0AddiuNext) + || IsWrapDestFp50Va(epiV0AddiuNext)) + return false; + bool epiV0AddiuOk = TryExecDumpMemAlu(regs, epiV0AddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiV0AddiuNext; + _exn15C28AfterOuterJalEpiLuiNextLogged = true; + _exn15C28AfterOuterJalEpiV0AddiuLogged = true; + uint epiV0AddiuRa = PeekGpr(regs, 31); + uint epiV0AddiuSp = PeekGpr(regs, 29); + uint epiV0AddiuT5 = PeekGpr(regs, 13); + uint epiV0AddiuV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiV0AddiuOk + ? "dump-mem-15c28-outer-jal-epi-v0-addiu" + : "dump-mem-15c28-outer-jal-epi-v0-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiV0AddiuDump.ToString("X") + + " dest=0x" + epiV0AddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-v0-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiV0AddiuNext.ToString("X") + + " dump=0x" + epiV0AddiuDump.ToString("X") + + (insn != 0 && insn != epiV0AddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiV0AddiuOk ? " addiu=1" : " addiu=0") + + " v0=0x" + epiV0AddiuV0.ToString("X") + + " t5=0x" + epiV0AddiuT5.ToString("X") + + " ra=0x" + epiV0AddiuRa.ToString("X") + + " sp=0x" + epiV0AddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $v0,$v0,588; ALU $v0:=0x8032024C;" + + " no invent 0x8032 page / *0xFFFFDB58 / SUD / 0x9A02;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 166818f: after addiu exec, + // name first I-fetch at 0x8003F804 + // (dump addiu $v1,$zero,-9448). + // One-shot. ALU-safe — name only + // this miss. Do not invent dest / + // $ra / 0x9A02 / 0x9F / 0xFFFFDB18 + // / *0xFFFFDB58. Do not hop MUL / + // jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiV0Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiV0AddiuLogged + || _exn15C28AfterOuterJalEpiV0AddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiV0AddiuNextLogged = true; + uint epiV0NoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiV0NoteDump) + || epiV0NoteDump == 0) + epiV0NoteDump = CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump; + uint epiV0NoteRa = PeekGpr(regs, 31); + uint epiV0NoteSp = PeekGpr(regs, 29); + uint epiV0NoteT5 = PeekGpr(regs, 13); + uint epiV0NoteV0 = PeekGpr(regs, 2); + uint epiV0NoteV1 = PeekGpr(regs, 3); + string epiV0NoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiV0NoteDumpDis = epiV0NoteDump != 0 + ? FormatMipsOp(pc, epiV0NoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-v0-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiV0NoteDump != 0 ? " dump=0x" + epiV0NoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-v0-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-v0-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiV0NoteDump != 0 ? " dump=0x" + epiV0NoteDump.ToString("X") : "") + + " dis=" + epiV0NoteDis + + (epiV0NoteDump != 0 ? " dump-dis=" + epiV0NoteDumpDis : "") + + " t5=0x" + epiV0NoteT5.ToString("X") + + " v0=0x" + epiV0NoteV0.ToString("X") + + " v1=0x" + epiV0NoteV1.ToString("X") + + " ra=0x" + epiV0NoteRa.ToString("X") + + " sp=0x" + epiV0NoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-v0-addiu" + + " (first I-fetch after addiu exec; addiu $v1,$zero,-9448;" + + " honor ra; no jr hop; no invent $ra / 0xFFFFDB18 / *0xFFFFDB58 / 0x9A02)"); + } + + // Live 02dffcd: addiu $v1,$zero,-9448 + // at 0x8003F804 named only. Exec + // dump addiu (ALU $v1:=0xFFFFDB18). + // PC:=0x8003F808. Observe sw $v0,0($v1) + // (dest-miss; name only). Refuse jr + // hop 0x8003F78C / MULT / SPECIAL + // 0x16. Not LoadO32. No leftover-hop. + // Do not invent *0xFFFFDB58 / SUD / + // 0x9A02 / 0xFFFFDB18 page / KData. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiV1Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiV0AddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext) + return false; + if (_exn15C28AfterOuterJalEpiV1AddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + && _exn15C28AfterOuterJalEpiSwLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiV1AddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiV1AddiuDump) + || epiV1AddiuDump == 0) + epiV1AddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump; + if (epiV1AddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNextDump) + return false; + uint epiV1AddiuNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext, + out epiV1AddiuNextDump) + || epiV1AddiuNextDump == 0) + epiV1AddiuNextDump = CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump; + if (epiV1AddiuNextDump != CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump) + return false; + if ((epiV1AddiuNextDump >> 26) == 0 + && ((epiV1AddiuNextDump & 63) == 0x18 + || (epiV1AddiuNextDump & 63) == 0x16 + || (epiV1AddiuNextDump & 63) == 0x08)) + return false; + if (insn != epiV1AddiuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiV1AddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiV1AddiuDump); + uint epiV1AddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext; + if (epiV1AddiuNext == 0 || (epiV1AddiuNext & 3) != 0 + || epiV1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || epiV1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiV1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiV1AddiuNext == CoredllDllMainExn15C28OuterJalLink + || epiV1AddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiV1AddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiV1AddiuNext == CoredllDllMainExn15C28StkSwNext + || epiV1AddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiV1AddiuNext) + || IsExn15C28Na02Frame(epiV1AddiuNext) + || IsExn15C28NfffFrame(epiV1AddiuNext) + || IsExn15C28HelperBody(epiV1AddiuNext) + || IsExn15C28JalRaEpiRange(epiV1AddiuNext) + || IsLeftoverDestVa(epiV1AddiuNext) + || IsWrapDestSize(epiV1AddiuNext) + || IsWrapDestFp50Va(epiV1AddiuNext)) + return false; + bool epiV1AddiuOk = TryExecDumpMemAlu(regs, epiV1AddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiV1AddiuNext; + _exn15C28AfterOuterJalEpiV0AddiuNextLogged = true; + _exn15C28AfterOuterJalEpiV1AddiuLogged = true; + uint epiV1AddiuRa = PeekGpr(regs, 31); + uint epiV1AddiuSp = PeekGpr(regs, 29); + uint epiV1AddiuT5 = PeekGpr(regs, 13); + uint epiV1AddiuV0 = PeekGpr(regs, 2); + uint epiV1AddiuV1 = PeekGpr(regs, 3); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiV1AddiuOk + ? "dump-mem-15c28-outer-jal-epi-v1-addiu" + : "dump-mem-15c28-outer-jal-epi-v1-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiV1AddiuDump.ToString("X") + + " dest=0x" + epiV1AddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-v1-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiV1AddiuNext.ToString("X") + + " dump=0x" + epiV1AddiuDump.ToString("X") + + (insn != 0 && insn != epiV1AddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiV1AddiuOk ? " addiu=1" : " addiu=0") + + " v0=0x" + epiV1AddiuV0.ToString("X") + + " v1=0x" + epiV1AddiuV1.ToString("X") + + " t5=0x" + epiV1AddiuT5.ToString("X") + + " ra=0x" + epiV1AddiuRa.ToString("X") + + " sp=0x" + epiV1AddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $v1,$zero,-9448; ALU $v1:=0xFFFFDB18;" + + " no invent 0xFFFFDB18 page / *0xFFFFDB58 / SUD / 0x9A02;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 02dffcd: after v1 addiu exec, + // name first I-fetch at 0x8003F808 + // (dump sw $v0,0($v1)). One-shot. + // Dest-miss — name only this miss. + // Do not invent dest / $ra / 0x9A02 + // / 0x9F / 0xFFFFDB18 / *0xFFFFDB58 + // / KData. Do not hop MUL / jr + // 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiV1Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiV1AddiuLogged + || _exn15C28AfterOuterJalEpiV1AddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiV1AddiuNextLogged = true; + uint epiV1NoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiV1NoteDump) + || epiV1NoteDump == 0) + epiV1NoteDump = CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump; + uint epiV1NoteRa = PeekGpr(regs, 31); + uint epiV1NoteSp = PeekGpr(regs, 29); + uint epiV1NoteT5 = PeekGpr(regs, 13); + uint epiV1NoteV0 = PeekGpr(regs, 2); + uint epiV1NoteV1 = PeekGpr(regs, 3); + string epiV1NoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiV1NoteDumpDis = epiV1NoteDump != 0 + ? FormatMipsOp(pc, epiV1NoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-v1-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiV1NoteDump != 0 ? " dump=0x" + epiV1NoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-v1-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-v1-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiV1NoteDump != 0 ? " dump=0x" + epiV1NoteDump.ToString("X") : "") + + " dis=" + epiV1NoteDis + + (epiV1NoteDump != 0 ? " dump-dis=" + epiV1NoteDumpDis : "") + + " t5=0x" + epiV1NoteT5.ToString("X") + + " v0=0x" + epiV1NoteV0.ToString("X") + + " v1=0x" + epiV1NoteV1.ToString("X") + + " ra=0x" + epiV1NoteRa.ToString("X") + + " sp=0x" + epiV1NoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-v1-addiu" + + " (first I-fetch after v1 addiu exec; sw $v0,0($v1);" + + " honor ra; no jr hop; no invent $ra / 0xFFFFDB18 / *0xFFFFDB58 / 0x9A02)"); + } + + // Live 7b548eb: sw $v0,0($v1) at + // 0x8003F808 named only. Dest + // 0xFFFFDB18 is KData-class — + // dest-miss skip; leave $v0 / + // $v1. Do not Write32. Do not + // invent 0xFFFFDB18 / SUD / + // KData / 0x9A02. PC:=0x8003F80C + // (sequential dump-true +4; + // observe only; peek dump, do + // not invent next word). Refuse + // jr hop 0x8003F78C / MULT / + // SPECIAL 0x16. Not LoadO32. + // No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiSw(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiV1AddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext) + return false; + if (_exn15C28AfterOuterJalEpiSwLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + && _exn15C28AfterOuterJalEpiA3LuiLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + && _exn15C28AfterOuterJalEpiLhuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + && _exn15C28AfterOuterJalEpiA2AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + && _exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + && !_exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && _exn15C28AfterOuterJalEpiA3LhuLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiSwNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiSwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiSwDump) || epiSwDump == 0) + epiSwDump = CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump; + if (epiSwDump != CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNextDump) + return false; + uint epiSwNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiSwNext, out epiSwNextDump); + if (epiSwNextDump != 0 && (epiSwNextDump >> 26) == 0 + && ((epiSwNextDump & 63) == 0x18 + || (epiSwNextDump & 63) == 0x16 + || (epiSwNextDump & 63) == 0x08)) + return false; + if (insn != epiSwDump && insn != 0 && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiSwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiSwDump); + uint epiSwNext = CoredllDllMainExn15C28OuterJalLinkEpiSwNext; + if (epiSwNext == 0 || (epiSwNext & 3) != 0 + || epiSwNext == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || epiSwNext == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || epiSwNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiSwNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiSwNext == CoredllDllMainExn15C28OuterJalLink + || epiSwNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiSwNext == CoredllDllMainExn15C28JalS1AluNext + || epiSwNext == CoredllDllMainExn15C28StkSwNext + || epiSwNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiSwNext) + || IsExn15C28Na02Frame(epiSwNext) + || IsExn15C28NfffFrame(epiSwNext) + || IsExn15C28HelperBody(epiSwNext) + || IsExn15C28JalRaEpiRange(epiSwNext) + || IsLeftoverDestVa(epiSwNext) + || IsWrapDestSize(epiSwNext) + || IsWrapDestFp50Va(epiSwNext)) + return false; + uint epiSwV0 = PeekGpr(regs, 2); + uint epiSwV1 = PeekGpr(regs, 3); + uint epiSwDest = unchecked(epiSwV1 + 0); + uint epiSwPeek = 0; + bool destOk = !IsC000StoreSkipVa(epiSwDest) + && TryPeekExn15C28OuterJalLwT4Dest(bus, epiSwDest, out epiSwPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiSwNext; + _exn15C28AfterOuterJalEpiV1AddiuNextLogged = true; + _exn15C28AfterOuterJalEpiSwLogged = true; + uint epiSwRa = PeekGpr(regs, 31); + uint epiSwSp = PeekGpr(regs, 29); + uint epiSwT5 = PeekGpr(regs, 13); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-sw" + : "dump-mem-15c28-outer-jal-epi-sw-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiSwDump.ToString("X") + + " dest=0x" + epiSwDest.ToString("X") + + (destOk ? "" : " *v1-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-sw" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiSwNext.ToString("X") + + " dump=0x" + epiSwDump.ToString("X") + + (insn != 0 && insn != epiSwDump + ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " sw=1" : " sw=0") + + " dest=0x" + epiSwDest.ToString("X") + + (destOk ? "" : " *v1-miss") + + " v0=0x" + epiSwV0.ToString("X") + + " v1=0x" + epiSwV1.ToString("X") + + " t5=0x" + epiSwT5.ToString("X") + + " ra=0x" + epiSwRa.ToString("X") + + " sp=0x" + epiSwSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sw $v0,0($v1); dest-miss skip;" + + " leave $v0 / $v1; no invent 0xFFFFDB18 / *0xFFFFDB58 / SUD / KData / 0x9A02;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 7b548eb: after sw dest-miss + // skip, name first I-fetch at + // 0x8003F80C. One-shot. Peek dump + // only — do not invent next word + // / dest / $ra / 0x9A02 / 0x9F / + // 0xFFFFDB18 / *0xFFFFDB58 / + // KData. Do not hop MUL / jr + // 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiSw(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiSwLogged + || _exn15C28AfterOuterJalEpiSwNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiSwNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiSwNextLogged = true; + uint epiSwNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out epiSwNoteDump); + uint epiSwNoteRa = PeekGpr(regs, 31); + uint epiSwNoteSp = PeekGpr(regs, 29); + uint epiSwNoteT5 = PeekGpr(regs, 13); + uint epiSwNoteV0 = PeekGpr(regs, 2); + uint epiSwNoteV1 = PeekGpr(regs, 3); + string epiSwNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiSwNoteDumpDis = epiSwNoteDump != 0 + ? FormatMipsOp(pc, epiSwNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiSwNoteDump != 0 ? " dump=0x" + epiSwNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-sw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiSwNoteDump != 0 ? " dump=0x" + epiSwNoteDump.ToString("X") : "") + + " dis=" + epiSwNoteDis + + (epiSwNoteDump != 0 ? " dump-dis=" + epiSwNoteDumpDis : "") + + " t5=0x" + epiSwNoteT5.ToString("X") + + " v0=0x" + epiSwNoteV0.ToString("X") + + " v1=0x" + epiSwNoteV1.ToString("X") + + " ra=0x" + epiSwNoteRa.ToString("X") + + " sp=0x" + epiSwNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-sw" + + " (first I-fetch after sw dest-miss skip;" + + " honor ra; no jr hop; no invent $ra / 0xFFFFDB18 / *0xFFFFDB58 / 0x9A02)"); + } + + // Live 475ffcb: lui $a3,0x8034 at + // 0x8003F80C named only. Exec + // dump lui (ALU $a3:=0x80340000). + // PC:=0x8003F810. Observe lhu + // $v1,0($v0) (load; name only). + // Refuse jr hop 0x8003F78C / + // MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Do + // not invent *0xFFFFDB18 / + // *0xFFFFDB58 / SUD / 0x9A02 / + // 0x8032 page. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiA3Lui(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiSwLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiSwNext) + return false; + if (_exn15C28AfterOuterJalEpiA3LuiLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + && _exn15C28AfterOuterJalEpiA2AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + && _exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + && !_exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && _exn15C28AfterOuterJalEpiA3LhuLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiA3LuiDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA3LuiDump) + || epiA3LuiDump == 0) + epiA3LuiDump = CoredllDllMainExn15C28OuterJalLinkEpiSwNextDump; + if (epiA3LuiDump != CoredllDllMainExn15C28OuterJalLinkEpiSwNextDump) + return false; + uint epiA3LuiNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext, + out epiA3LuiNextDump) + || epiA3LuiNextDump == 0) + epiA3LuiNextDump = CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump; + if (epiA3LuiNextDump != CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump) + return false; + if ((epiA3LuiNextDump >> 26) == 0 + && ((epiA3LuiNextDump & 63) == 0x18 + || (epiA3LuiNextDump & 63) == 0x16 + || (epiA3LuiNextDump & 63) == 0x08)) + return false; + if (insn != epiA3LuiDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiA3LuiDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiA3LuiDump); + uint epiA3LuiNext = CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext; + if (epiA3LuiNext == 0 || (epiA3LuiNext & 3) != 0 + || epiA3LuiNext == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || epiA3LuiNext == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || epiA3LuiNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiA3LuiNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiA3LuiNext == CoredllDllMainExn15C28OuterJalLink + || epiA3LuiNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiA3LuiNext == CoredllDllMainExn15C28JalS1AluNext + || epiA3LuiNext == CoredllDllMainExn15C28StkSwNext + || epiA3LuiNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiA3LuiNext) + || IsExn15C28Na02Frame(epiA3LuiNext) + || IsExn15C28NfffFrame(epiA3LuiNext) + || IsExn15C28HelperBody(epiA3LuiNext) + || IsExn15C28JalRaEpiRange(epiA3LuiNext) + || IsLeftoverDestVa(epiA3LuiNext) + || IsWrapDestSize(epiA3LuiNext) + || IsWrapDestFp50Va(epiA3LuiNext)) + return false; + bool epiA3LuiOk = TryExecDumpMemAlu(regs, epiA3LuiDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiA3LuiNext; + _exn15C28AfterOuterJalEpiSwNextLogged = true; + _exn15C28AfterOuterJalEpiA3LuiLogged = true; + uint epiA3LuiRa = PeekGpr(regs, 31); + uint epiA3LuiSp = PeekGpr(regs, 29); + uint epiA3LuiT5 = PeekGpr(regs, 13); + uint epiA3LuiV0 = PeekGpr(regs, 2); + uint epiA3LuiV1 = PeekGpr(regs, 3); + uint epiA3LuiA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiA3LuiOk + ? "dump-mem-15c28-outer-jal-epi-a3-lui" + : "dump-mem-15c28-outer-jal-epi-a3-lui-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiA3LuiDump.ToString("X") + + " dest=0x" + epiA3LuiNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-a3-lui" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiA3LuiNext.ToString("X") + + " dump=0x" + epiA3LuiDump.ToString("X") + + (insn != 0 && insn != epiA3LuiDump + ? " live=0x" + insn.ToString("X") : "") + + (epiA3LuiOk ? " lui=1" : " lui=0") + + " a3=0x" + epiA3LuiA3.ToString("X") + + " v0=0x" + epiA3LuiV0.ToString("X") + + " v1=0x" + epiA3LuiV1.ToString("X") + + " t5=0x" + epiA3LuiT5.ToString("X") + + " ra=0x" + epiA3LuiRa.ToString("X") + + " sp=0x" + epiA3LuiSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lui $a3,0x8034; ALU $a3:=0x80340000;" + + " no invent 0x8032 page / *0xFFFFDB18 / *0xFFFFDB58 / SUD / 0x9A02;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 475ffcb: after lui exec, + // name first I-fetch at 0x8003F810 + // (dump lhu $v1,0($v0)). One-shot. + // Load — name only this miss. Do + // not invent dest / $ra / 0x9A02 + // / 0x9F / 0x8032 page / + // *0xFFFFDB18 / *0xFFFFDB58. + // Do not hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiA3Lui(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiA3LuiLogged + || _exn15C28AfterOuterJalEpiA3LuiNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiA3LuiNextLogged = true; + uint epiA3NoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA3NoteDump) + || epiA3NoteDump == 0) + epiA3NoteDump = CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump; + uint epiA3NoteRa = PeekGpr(regs, 31); + uint epiA3NoteSp = PeekGpr(regs, 29); + uint epiA3NoteT5 = PeekGpr(regs, 13); + uint epiA3NoteV0 = PeekGpr(regs, 2); + uint epiA3NoteV1 = PeekGpr(regs, 3); + uint epiA3NoteA3 = PeekGpr(regs, 7); + string epiA3NoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiA3NoteDumpDis = epiA3NoteDump != 0 + ? FormatMipsOp(pc, epiA3NoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-a3-lui"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA3NoteDump != 0 ? " dump=0x" + epiA3NoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-a3-lui"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-a3-lui" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA3NoteDump != 0 ? " dump=0x" + epiA3NoteDump.ToString("X") : "") + + " dis=" + epiA3NoteDis + + (epiA3NoteDump != 0 ? " dump-dis=" + epiA3NoteDumpDis : "") + + " t5=0x" + epiA3NoteT5.ToString("X") + + " a3=0x" + epiA3NoteA3.ToString("X") + + " v0=0x" + epiA3NoteV0.ToString("X") + + " v1=0x" + epiA3NoteV1.ToString("X") + + " ra=0x" + epiA3NoteRa.ToString("X") + + " sp=0x" + epiA3NoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-a3-lui" + + " (first I-fetch after lui exec; lhu $v1,0($v0);" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFDB18 / 0x9A02)"); + } + + // Live dcf9658: lhu $v1,0($v0) at + // 0x8003F810 named only. Dest + // ~0x8032024C — peek dump / + // firmware only. Dest-miss skip; + // leave $v1. Do not invent + // 0x8032 page / *0xFFFFDB18 / + // SUD / KData / 0x9A02. + // PC:=0x8003F814 (sequential + // dump-true +4; observe only; + // peek dump, do not invent next + // word). Refuse jr hop 0x8003F78C + // / MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiLhu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiA3LuiLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext) + return false; + if (_exn15C28AfterOuterJalEpiLhuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + && _exn15C28AfterOuterJalEpiA2AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + && _exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + && !_exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && _exn15C28AfterOuterJalEpiA3LhuLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiLhuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiLhuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiLhuDump) || epiLhuDump == 0) + epiLhuDump = CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump; + if (epiLhuDump != CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNextDump) + return false; + uint epiLhuNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiLhuNext, out epiLhuNextDump); + if (epiLhuNextDump != 0 && (epiLhuNextDump >> 26) == 0 + && ((epiLhuNextDump & 63) == 0x18 + || (epiLhuNextDump & 63) == 0x16 + || (epiLhuNextDump & 63) == 0x08)) + return false; + if (insn != epiLhuDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiLhuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiLhuDump); + uint epiLhuNext = CoredllDllMainExn15C28OuterJalLinkEpiLhuNext; + if (epiLhuNext == 0 || (epiLhuNext & 3) != 0 + || epiLhuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiLhuNext == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || epiLhuNext == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || epiLhuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiLhuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiLhuNext == CoredllDllMainExn15C28OuterJalLink + || epiLhuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiLhuNext == CoredllDllMainExn15C28JalS1AluNext + || epiLhuNext == CoredllDllMainExn15C28StkSwNext + || epiLhuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiLhuNext) + || IsExn15C28Na02Frame(epiLhuNext) + || IsExn15C28NfffFrame(epiLhuNext) + || IsExn15C28N9ffFrame(epiLhuNext) + || IsExn15C28HelperBody(epiLhuNext) + || IsExn15C28JalRaEpiRange(epiLhuNext) + || IsLeftoverDestVa(epiLhuNext) + || IsWrapDestSize(epiLhuNext) + || IsWrapDestFp50Va(epiLhuNext)) + return false; + uint epiLhuV0 = PeekGpr(regs, 2); + uint epiLhuDest = unchecked(epiLhuV0 + 0); + uint epiLhuPeek = 0; + bool destOk = TryPeekExn15C28OuterJalLhuDest(bus, epiLhuDest, + out epiLhuPeek); + if (destOk) + PokeGpr(regs, 3, epiLhuPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiLhuNext; + _exn15C28AfterOuterJalEpiA3LuiNextLogged = true; + _exn15C28AfterOuterJalEpiLhuLogged = true; + uint epiLhuRa = PeekGpr(regs, 31); + uint epiLhuSp = PeekGpr(regs, 29); + uint epiLhuT5 = PeekGpr(regs, 13); + uint epiLhuV1 = PeekGpr(regs, 3); + uint epiLhuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-lhu" + : "dump-mem-15c28-outer-jal-epi-lhu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiLhuDump.ToString("X") + + " dest=0x" + epiLhuDest.ToString("X") + + (destOk ? "" : " *v0-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-lhu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiLhuNext.ToString("X") + + " dump=0x" + epiLhuDump.ToString("X") + + (insn != 0 && insn != epiLhuDump + ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lhu=1" : " lhu=0") + + " dest=0x" + epiLhuDest.ToString("X") + + (destOk ? "" : " *v0-miss") + + " v0=0x" + epiLhuV0.ToString("X") + + " v1=0x" + epiLhuV1.ToString("X") + + " a3=0x" + epiLhuA3.ToString("X") + + " t5=0x" + epiLhuT5.ToString("X") + + " ra=0x" + epiLhuRa.ToString("X") + + " sp=0x" + epiLhuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lhu $v1,0($v0); dest-miss skip;" + + " leave $v1; no invent 0x8032 page / *0xFFFFDB18 / *0xFFFFDB58 / SUD / 0x9A02;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live dcf9658: after lhu skip, + // name first I-fetch at 0x8003F814. + // One-shot. Peek dump only — do + // not invent next word / dest / + // $ra / 0x9A02 / 0x9F / 0x8032 + // page / *0xFFFFDB18 / + // *0xFFFFDB58 / KData. Do not + // hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiLhu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiLhuLogged + || _exn15C28AfterOuterJalEpiLhuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiLhuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiLhuNextLogged = true; + uint epiLhuNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out epiLhuNoteDump); + uint epiLhuNoteRa = PeekGpr(regs, 31); + uint epiLhuNoteSp = PeekGpr(regs, 29); + uint epiLhuNoteT5 = PeekGpr(regs, 13); + uint epiLhuNoteV0 = PeekGpr(regs, 2); + uint epiLhuNoteV1 = PeekGpr(regs, 3); + uint epiLhuNoteA3 = PeekGpr(regs, 7); + string epiLhuNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiLhuNoteDumpDis = epiLhuNoteDump != 0 + ? FormatMipsOp(pc, epiLhuNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-lhu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiLhuNoteDump != 0 ? " dump=0x" + epiLhuNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-lhu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-lhu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiLhuNoteDump != 0 ? " dump=0x" + epiLhuNoteDump.ToString("X") : "") + + " dis=" + epiLhuNoteDis + + (epiLhuNoteDump != 0 ? " dump-dis=" + epiLhuNoteDumpDis : "") + + " t5=0x" + epiLhuNoteT5.ToString("X") + + " a3=0x" + epiLhuNoteA3.ToString("X") + + " v0=0x" + epiLhuNoteV0.ToString("X") + + " v1=0x" + epiLhuNoteV1.ToString("X") + + " ra=0x" + epiLhuNoteRa.ToString("X") + + " sp=0x" + epiLhuNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-lhu" + + " (first I-fetch after lhu dest-miss skip;" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFDB18 / 0x9A02)"); + } + + // Live 5142c73: addiu $a2,$a3,-908 + // at 0x8003F814 named only. Exec + // dump addiu (ALU $a2:=0x8033FC74 + // from $a3=0x80340000). PC:= + // 0x8003F818. Observe addiu + // $a1,$v0,160 (ALU-safe; name + // only). Refuse jr hop 0x8003F78C + // / MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Do + // not invent 0x8033 page / SUD + // 0xFFFFFC74 / 0x9A02 / 0x99FF. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiA2Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiLhuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiLhuNext) + return false; + if (_exn15C28AfterOuterJalEpiA2AddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + && !_exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + && _exn15C28AfterOuterJalEpiA1AddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && _exn15C28AfterOuterJalEpiA3LhuLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiA2AddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA2AddiuDump) + || epiA2AddiuDump == 0) + epiA2AddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiLhuNextDump; + if (epiA2AddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiLhuNextDump) + return false; + uint epiA2AddiuNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext, + out epiA2AddiuNextDump) + || epiA2AddiuNextDump == 0) + epiA2AddiuNextDump = CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump; + if (epiA2AddiuNextDump != CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump) + return false; + if ((epiA2AddiuNextDump >> 26) == 0 + && ((epiA2AddiuNextDump & 63) == 0x18 + || (epiA2AddiuNextDump & 63) == 0x16 + || (epiA2AddiuNextDump & 63) == 0x08)) + return false; + uint epiA2AddiuSwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA2Sw, + out epiA2AddiuSwDump) + || epiA2AddiuSwDump == 0) + epiA2AddiuSwDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump; + if (epiA2AddiuSwDump != CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump) + return false; + if ((epiA2AddiuSwDump >> 26) == 0 + && ((epiA2AddiuSwDump & 63) == 0x18 + || (epiA2AddiuSwDump & 63) == 0x16 + || (epiA2AddiuSwDump & 63) == 0x08)) + return false; + if (insn != epiA2AddiuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiA2AddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiA2AddiuDump); + uint epiA2AddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext; + if (epiA2AddiuNext == 0 || (epiA2AddiuNext & 3) != 0 + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLink + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiA2AddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiA2AddiuNext == CoredllDllMainExn15C28StkSwNext + || epiA2AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiA2AddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiA2AddiuNext) + || IsExn15C28Na02Frame(epiA2AddiuNext) + || IsExn15C28NfffFrame(epiA2AddiuNext) + || IsExn15C28N9ffFrame(epiA2AddiuNext) + || IsExn15C28HelperBody(epiA2AddiuNext) + || IsExn15C28JalRaEpiRange(epiA2AddiuNext) + || IsLeftoverDestVa(epiA2AddiuNext) + || IsWrapDestSize(epiA2AddiuNext) + || IsWrapDestFp50Va(epiA2AddiuNext)) + return false; + bool epiA2AddiuOk = TryExecDumpMemAlu(regs, epiA2AddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiA2AddiuNext; + _exn15C28AfterOuterJalEpiLhuNextLogged = true; + _exn15C28AfterOuterJalEpiA2AddiuLogged = true; + uint epiA2AddiuRa = PeekGpr(regs, 31); + uint epiA2AddiuSp = PeekGpr(regs, 29); + uint epiA2AddiuT5 = PeekGpr(regs, 13); + uint epiA2AddiuV0 = PeekGpr(regs, 2); + uint epiA2AddiuV1 = PeekGpr(regs, 3); + uint epiA2AddiuA2 = PeekGpr(regs, 6); + uint epiA2AddiuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiA2AddiuOk + ? "dump-mem-15c28-outer-jal-epi-a2-addiu" + : "dump-mem-15c28-outer-jal-epi-a2-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiA2AddiuDump.ToString("X") + + " dest=0x" + epiA2AddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-a2-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiA2AddiuNext.ToString("X") + + " dump=0x" + epiA2AddiuDump.ToString("X") + + (insn != 0 && insn != epiA2AddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiA2AddiuOk ? " addiu=1" : " addiu=0") + + " a2=0x" + epiA2AddiuA2.ToString("X") + + " a3=0x" + epiA2AddiuA3.ToString("X") + + " v0=0x" + epiA2AddiuV0.ToString("X") + + " v1=0x" + epiA2AddiuV1.ToString("X") + + " t5=0x" + epiA2AddiuT5.ToString("X") + + " ra=0x" + epiA2AddiuRa.ToString("X") + + " sp=0x" + epiA2AddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $a2,$a3,-908; ALU $a2:=0x8033FC74;" + + " no invent 0x8033 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 5142c73: after addiu exec, + // name first I-fetch at 0x8003F818 + // (dump addiu $a1,$v0,160). One-shot. + // ALU-safe — name only this miss. + // Do not invent dest / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / 0x8033 + // page / *0xFFFFFC74 / SUD. Do not + // hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiA2Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiA2AddiuLogged + || _exn15C28AfterOuterJalEpiA2AddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiA2AddiuNextLogged = true; + uint epiA2NoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA2NoteDump) + || epiA2NoteDump == 0) + epiA2NoteDump = CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump; + uint epiA2NoteRa = PeekGpr(regs, 31); + uint epiA2NoteSp = PeekGpr(regs, 29); + uint epiA2NoteT5 = PeekGpr(regs, 13); + uint epiA2NoteV0 = PeekGpr(regs, 2); + uint epiA2NoteV1 = PeekGpr(regs, 3); + uint epiA2NoteA2 = PeekGpr(regs, 6); + uint epiA2NoteA3 = PeekGpr(regs, 7); + string epiA2NoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiA2NoteDumpDis = epiA2NoteDump != 0 + ? FormatMipsOp(pc, epiA2NoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-a2-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA2NoteDump != 0 ? " dump=0x" + epiA2NoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-a2-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-a2-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA2NoteDump != 0 ? " dump=0x" + epiA2NoteDump.ToString("X") : "") + + " dis=" + epiA2NoteDis + + (epiA2NoteDump != 0 ? " dump-dis=" + epiA2NoteDumpDis : "") + + " t5=0x" + epiA2NoteT5.ToString("X") + + " a2=0x" + epiA2NoteA2.ToString("X") + + " a3=0x" + epiA2NoteA3.ToString("X") + + " v0=0x" + epiA2NoteV0.ToString("X") + + " v1=0x" + epiA2NoteV1.ToString("X") + + " ra=0x" + epiA2NoteRa.ToString("X") + + " sp=0x" + epiA2NoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-a2-addiu" + + " (first I-fetch after a2 addiu exec; addiu $a1,$v0,160;" + + " honor ra; no jr hop; no invent $ra / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 5142c73: sw $v1,0($a2) at + // 0x8003F81C. Dest is $a2 after + // addiu (0x8033FC74) — peek dump / + // firmware only. Dest-miss skip; + // leave regs. NEVER write SUD + // 0xFFFFFC74 / FFFF / 0x9A / 0x99. + // Do not invent 0x8033 page / + // *0xFFFFFC74 / SUD / 0x9A02 / + // 0x99FF. PC:=0x8003F820. Hard-stop + // TLBS-SUD re-entry. Refuse jr hop + // 0x8003F78C / MULT / SPECIAL 0x16. + // Not LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiA2Sw(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiA1AddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA2Sw) + return false; + if (_exn15C28AfterOuterJalEpiA2SwLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && _exn15C28AfterOuterJalEpiA3LhuLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiA2SwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA2SwDump) || epiA2SwDump == 0) + epiA2SwDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump; + if (epiA2SwDump != CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump) + return false; + uint epiA2SwNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext, out epiA2SwNextDump); + if (epiA2SwNextDump != 0 && (epiA2SwNextDump >> 26) == 0 + && ((epiA2SwNextDump & 63) == 0x18 + || (epiA2SwNextDump & 63) == 0x16 + || (epiA2SwNextDump & 63) == 0x08)) + return false; + if (insn != epiA2SwDump && insn != 0 && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiA2SwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiA2SwDump); + uint epiA2SwNext = CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext; + if (epiA2SwNext == 0 || (epiA2SwNext & 3) != 0 + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLink + || epiA2SwNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiA2SwNext == CoredllDllMainExn15C28JalS1AluNext + || epiA2SwNext == CoredllDllMainExn15C28StkSwNext + || epiA2SwNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiA2SwNext) + || IsExn15C28Na02Frame(epiA2SwNext) + || IsExn15C28NfffFrame(epiA2SwNext) + || IsExn15C28N9ffFrame(epiA2SwNext) + || IsExn15C28HelperBody(epiA2SwNext) + || IsExn15C28JalRaEpiRange(epiA2SwNext) + || IsLeftoverDestVa(epiA2SwNext) + || IsWrapDestSize(epiA2SwNext) + || IsWrapDestFp50Va(epiA2SwNext)) + return false; + uint epiA2SwA2 = PeekGpr(regs, 6); + uint epiA2SwV1 = PeekGpr(regs, 3); + uint epiA2SwDest = unchecked(epiA2SwA2 + 0); + bool destSud = epiA2SwDest == 0xFFFFFC74u + || epiA2SwDest >= 0xFFFF0000u + || (epiA2SwDest & ~0xFFFu) == FfffF000Page + || IsC000StoreSkipVa(epiA2SwDest) + || IsExn15C28StkRecurseFrame(epiA2SwDest) + || IsLeftoverDestVa(epiA2SwDest) + || IsWrapDestSize(epiA2SwDest) + || IsWrapDestFp50Va(epiA2SwDest) + || IsDumpMemRefuseVa(epiA2SwDest); + uint epiA2SwPeek = 0; + bool destOk = !destSud + && TryPeekExn15C28OuterJalLwT4Dest(bus, epiA2SwDest, out epiA2SwPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiA2SwNext; + _exn15C28AfterOuterJalEpiA2AddiuNextLogged = true; + _exn15C28AfterOuterJalEpiA2SwLogged = true; + uint epiA2SwRa = PeekGpr(regs, 31); + uint epiA2SwSp = PeekGpr(regs, 29); + uint epiA2SwT5 = PeekGpr(regs, 13); + uint epiA2SwV0 = PeekGpr(regs, 2); + uint epiA2SwA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-a2-sw" + : "dump-mem-15c28-outer-jal-epi-a2-sw-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiA2SwDump.ToString("X") + + " dest=0x" + epiA2SwDest.ToString("X") + + (destOk ? "" : " *a2-miss") + + (destSud ? " sud-refuse" : "") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-a2-sw" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiA2SwNext.ToString("X") + + " dump=0x" + epiA2SwDump.ToString("X") + + (insn != 0 && insn != epiA2SwDump + ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " sw=1" : " sw=0") + + " dest=0x" + epiA2SwDest.ToString("X") + + (destOk ? "" : " *a2-miss") + + (destSud ? " sud-refuse" : "") + + " a2=0x" + epiA2SwA2.ToString("X") + + " v1=0x" + epiA2SwV1.ToString("X") + + " v0=0x" + epiA2SwV0.ToString("X") + + " a3=0x" + epiA2SwA3.ToString("X") + + " t5=0x" + epiA2SwT5.ToString("X") + + " ra=0x" + epiA2SwRa.ToString("X") + + " sp=0x" + epiA2SwSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sw $v1,0($a2); dest-miss skip;" + + " NEVER write SUD 0xFFFFFC74; leave regs;" + + " no invent 0x8033 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 5142c73: after sw dest-miss + // skip, name first I-fetch at + // 0x8003F820. One-shot. Peek dump + // only — do not invent next word + // / dest / $ra / 0x9A02 / 0x99FF / + // 0x8033 page / *0xFFFFFC74 / SUD. + // Do not hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiA2Sw(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiA2SwLogged + || _exn15C28AfterOuterJalEpiA2SwNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiA2SwNextLogged = true; + uint epiA2SwNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA2SwNoteDump) + || epiA2SwNoteDump == 0) + epiA2SwNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump; + uint epiA2SwNoteRa = PeekGpr(regs, 31); + uint epiA2SwNoteSp = PeekGpr(regs, 29); + uint epiA2SwNoteT5 = PeekGpr(regs, 13); + uint epiA2SwNoteV0 = PeekGpr(regs, 2); + uint epiA2SwNoteV1 = PeekGpr(regs, 3); + uint epiA2SwNoteA2 = PeekGpr(regs, 6); + string epiA2SwNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiA2SwNoteDumpDis = epiA2SwNoteDump != 0 + ? FormatMipsOp(pc, epiA2SwNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-a2-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA2SwNoteDump != 0 ? " dump=0x" + epiA2SwNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-a2-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-a2-sw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA2SwNoteDump != 0 ? " dump=0x" + epiA2SwNoteDump.ToString("X") : "") + + " dis=" + epiA2SwNoteDis + + (epiA2SwNoteDump != 0 ? " dump-dis=" + epiA2SwNoteDumpDis : "") + + " t5=0x" + epiA2SwNoteT5.ToString("X") + + " a2=0x" + epiA2SwNoteA2.ToString("X") + + " v0=0x" + epiA2SwNoteV0.ToString("X") + + " v1=0x" + epiA2SwNoteV1.ToString("X") + + " ra=0x" + epiA2SwNoteRa.ToString("X") + + " sp=0x" + epiA2SwNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-a2-sw" + + " (first I-fetch after a2-sw dest-miss skip;" + + " honor ra; no jr hop; no invent $ra / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live e73cf23: addiu $a1,$v0,160 + // at 0x8003F818 named only. Exec + // dump addiu (ALU $a1:=0x803202EC + // from $v0=0x8032024C). PC:= + // 0x8003F81C. Do not skip to + // 0x8003F81C / 0x8003F820 until + // $a1 written. Refuse jr hop + // 0x8003F78C / MULT / SPECIAL 0x16. + // Not LoadO32. No leftover-hop. + // Do not invent 0x8032 / 0x8033 + // page / SUD 0xFFFFFC74 / 0x9A02 / + // 0x99FF. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiA1Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiA2AddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext) + return false; + if (_exn15C28AfterOuterJalEpiA1AddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + && _exn15C28AfterOuterJalEpiA2SwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && _exn15C28AfterOuterJalEpiA3LhuLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiA2Sw) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiA1AddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA1AddiuDump) + || epiA1AddiuDump == 0) + epiA1AddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump; + if (epiA1AddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNextDump) + return false; + uint epiA1AddiuSwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA2Sw, + out epiA1AddiuSwDump) + || epiA1AddiuSwDump == 0) + epiA1AddiuSwDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump; + if (epiA1AddiuSwDump != CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump) + return false; + if ((epiA1AddiuSwDump >> 26) == 0 + && ((epiA1AddiuSwDump & 63) == 0x18 + || (epiA1AddiuSwDump & 63) == 0x16 + || (epiA1AddiuSwDump & 63) == 0x08)) + return false; + uint epiA1AddiuLhuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext, + out epiA1AddiuLhuDump) + || epiA1AddiuLhuDump == 0) + epiA1AddiuLhuDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump; + if (epiA1AddiuLhuDump != CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump) + return false; + if ((epiA1AddiuLhuDump >> 26) == 0 + && ((epiA1AddiuLhuDump & 63) == 0x18 + || (epiA1AddiuLhuDump & 63) == 0x16 + || (epiA1AddiuLhuDump & 63) == 0x08)) + return false; + if (insn != epiA1AddiuDump && insn != 0 && !IsMipsAbsRs0Store(insn) + && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiA1AddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiA1AddiuDump); + uint epiA1AddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiA2Sw; + if (epiA1AddiuNext == 0 || (epiA1AddiuNext & 3) != 0 + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLink + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiA1AddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiA1AddiuNext == CoredllDllMainExn15C28StkSwNext + || epiA1AddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiA1AddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiA1AddiuNext) + || IsExn15C28Na02Frame(epiA1AddiuNext) + || IsExn15C28NfffFrame(epiA1AddiuNext) + || IsExn15C28N9ffFrame(epiA1AddiuNext) + || IsExn15C28HelperBody(epiA1AddiuNext) + || IsExn15C28JalRaEpiRange(epiA1AddiuNext) + || IsLeftoverDestVa(epiA1AddiuNext) + || IsWrapDestSize(epiA1AddiuNext) + || IsWrapDestFp50Va(epiA1AddiuNext)) + return false; + bool epiA1AddiuOk = TryExecDumpMemAlu(regs, epiA1AddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiA1AddiuNext; + _exn15C28AfterOuterJalEpiA2AddiuNextLogged = true; + _exn15C28AfterOuterJalEpiA1AddiuLogged = true; + uint epiA1AddiuRa = PeekGpr(regs, 31); + uint epiA1AddiuSp = PeekGpr(regs, 29); + uint epiA1AddiuT5 = PeekGpr(regs, 13); + uint epiA1AddiuV0 = PeekGpr(regs, 2); + uint epiA1AddiuV1 = PeekGpr(regs, 3); + uint epiA1AddiuA1 = PeekGpr(regs, 5); + uint epiA1AddiuA2 = PeekGpr(regs, 6); + uint epiA1AddiuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiA1AddiuOk + ? "dump-mem-15c28-outer-jal-epi-a1-addiu" + : "dump-mem-15c28-outer-jal-epi-a1-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiA1AddiuDump.ToString("X") + + " dest=0x" + epiA1AddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-a1-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiA1AddiuNext.ToString("X") + + " dump=0x" + epiA1AddiuDump.ToString("X") + + (insn != 0 && insn != epiA1AddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiA1AddiuOk ? " addiu=1" : " addiu=0") + + " a1=0x" + epiA1AddiuA1.ToString("X") + + " a2=0x" + epiA1AddiuA2.ToString("X") + + " a3=0x" + epiA1AddiuA3.ToString("X") + + " v0=0x" + epiA1AddiuV0.ToString("X") + + " v1=0x" + epiA1AddiuV1.ToString("X") + + " t5=0x" + epiA1AddiuT5.ToString("X") + + " ra=0x" + epiA1AddiuRa.ToString("X") + + " sp=0x" + epiA1AddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $a1,$v0,160; ALU $a1:=0x803202EC;" + + " no invent 0x8032 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live e73cf23: after a1 addiu exec, + // name first I-fetch at 0x8003F81C + // (dump sw $v1,0($a2)). One-shot. + // Store — dest-miss skip is the + // a2-sw take. Do not invent dest / + // $ra / 0x9A02 / 0x99FF / 0x8033 + // page / *0xFFFFFC74 / SUD. Do not + // hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiA1Addiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiA1AddiuLogged + || _exn15C28AfterOuterJalEpiA1AddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA2Sw) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiA1AddiuNextLogged = true; + uint epiA1NoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA1NoteDump) + || epiA1NoteDump == 0) + epiA1NoteDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwDump; + uint epiA1NoteRa = PeekGpr(regs, 31); + uint epiA1NoteSp = PeekGpr(regs, 29); + uint epiA1NoteT5 = PeekGpr(regs, 13); + uint epiA1NoteV0 = PeekGpr(regs, 2); + uint epiA1NoteV1 = PeekGpr(regs, 3); + uint epiA1NoteA1 = PeekGpr(regs, 5); + uint epiA1NoteA2 = PeekGpr(regs, 6); + string epiA1NoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiA1NoteDumpDis = epiA1NoteDump != 0 + ? FormatMipsOp(pc, epiA1NoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-a1-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA1NoteDump != 0 ? " dump=0x" + epiA1NoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-a1-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-a1-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA1NoteDump != 0 ? " dump=0x" + epiA1NoteDump.ToString("X") : "") + + " dis=" + epiA1NoteDis + + (epiA1NoteDump != 0 ? " dump-dis=" + epiA1NoteDumpDis : "") + + " t5=0x" + epiA1NoteT5.ToString("X") + + " a1=0x" + epiA1NoteA1.ToString("X") + + " a2=0x" + epiA1NoteA2.ToString("X") + + " v0=0x" + epiA1NoteV0.ToString("X") + + " v1=0x" + epiA1NoteV1.ToString("X") + + " ra=0x" + epiA1NoteRa.ToString("X") + + " sp=0x" + epiA1NoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-a1-addiu" + + " (first I-fetch after a1 addiu exec; sw $v1,0($a2);" + + " honor ra; no jr hop; no invent $ra / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live e73cf23: lhu $a3,0($v0) at + // 0x8003F820 named only. Dest + // ~0x8032024C — live mapped + // KSEG0 halfword if already + // backed (CopyO32 / kernel + // unpack). Unbacked: $a3:=0 + // (CE zero-fill). Do not invent + // firmware / 0x8032 page / + // *0xFFFFFC74 / SUD / 0x9A02 / + // 0x99FF. + // PC:=0x8003F824 (sequential + // dump-true +4; observe only; + // peek dump, do not invent next + // word). Refuse jr hop 0x8003F78C + // / MULT / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiA3Lhu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiA1AddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext) + return false; + if (_exn15C28AfterOuterJalEpiA3LhuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + && _exn15C28AfterOuterJalEpiSltuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + && _exn15C28AfterOuterJalEpiBeqLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + && _exn15C28AfterOuterJalEpiBeqAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + && _exn15C28AfterOuterJalEpiBeqSltLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + && _exn15C28AfterOuterJalEpiBeqBneFallLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiA3LhuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA3LhuDump) || epiA3LhuDump == 0) + epiA3LhuDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump; + if (epiA3LhuDump != CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump) + return false; + uint epiA3LhuNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext, out epiA3LhuNextDump); + if (epiA3LhuNextDump != 0 && (epiA3LhuNextDump >> 26) == 0 + && ((epiA3LhuNextDump & 63) == 0x18 + || (epiA3LhuNextDump & 63) == 0x16 + || (epiA3LhuNextDump & 63) == 0x08)) + return false; + if (insn != epiA3LhuDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiA3LhuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiA3LhuDump); + uint epiA3LhuNext = CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext; + if (epiA3LhuNext == 0 || (epiA3LhuNext & 3) != 0 + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLink + || epiA3LhuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiA3LhuNext == CoredllDllMainExn15C28JalS1AluNext + || epiA3LhuNext == CoredllDllMainExn15C28StkSwNext + || epiA3LhuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiA3LhuNext) + || IsExn15C28Na02Frame(epiA3LhuNext) + || IsExn15C28NfffFrame(epiA3LhuNext) + || IsExn15C28N9ffFrame(epiA3LhuNext) + || IsExn15C28HelperBody(epiA3LhuNext) + || IsExn15C28JalRaEpiRange(epiA3LhuNext) + || IsLeftoverDestVa(epiA3LhuNext) + || IsWrapDestSize(epiA3LhuNext) + || IsWrapDestFp50Va(epiA3LhuNext)) + return false; + uint epiA3LhuV0 = PeekGpr(regs, 2); + uint epiA3LhuDest = unchecked(epiA3LhuV0 + 0); + uint epiA3LhuPeek = 0; + bool destOk = TryPeekExn15C28OuterJalLhuDest(bus, epiA3LhuDest, + out epiA3LhuPeek); + // Live mapped/backed KSEG0 halfword only. + // Unbacked / refuse (SUD / 0x9A / 0x99 / + // leftover): $a3:=0 (CE zero-fill). + // Do not invent firmware / magic struct / + // 0x8032 page / SUD. + PokeGpr(regs, 7, destOk ? epiA3LhuPeek : 0); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiA3LhuNext; + _exn15C28AfterOuterJalEpiA2SwNextLogged = true; + _exn15C28AfterOuterJalEpiA1AddiuNextLogged = true; + _exn15C28AfterOuterJalEpiA3LhuLogged = true; + uint epiA3LhuRa = PeekGpr(regs, 31); + uint epiA3LhuSp = PeekGpr(regs, 29); + uint epiA3LhuT5 = PeekGpr(regs, 13); + uint epiA3LhuV1 = PeekGpr(regs, 3); + uint epiA3LhuA1 = PeekGpr(regs, 5); + uint epiA3LhuA2 = PeekGpr(regs, 6); + uint epiA3LhuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-a3-lhu" + : "dump-mem-15c28-outer-jal-epi-a3-lhu-zero"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiA3LhuDump.ToString("X") + + " dest=0x" + epiA3LhuDest.ToString("X") + + (destOk ? "" : " *v0-zero") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-a3-lhu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiA3LhuNext.ToString("X") + + " dump=0x" + epiA3LhuDump.ToString("X") + + (insn != 0 && insn != epiA3LhuDump + ? " live=0x" + insn.ToString("X") : "") + + (destOk ? " lhu=1" : " lhu=0 zero=1") + + " dest=0x" + epiA3LhuDest.ToString("X") + + (destOk ? "" : " *v0-zero") + + " a1=0x" + epiA3LhuA1.ToString("X") + + " a2=0x" + epiA3LhuA2.ToString("X") + + " a3=0x" + epiA3LhuA3.ToString("X") + + " v0=0x" + epiA3LhuV0.ToString("X") + + " v1=0x" + epiA3LhuV1.ToString("X") + + " t5=0x" + epiA3LhuT5.ToString("X") + + " ra=0x" + epiA3LhuRa.ToString("X") + + " sp=0x" + epiA3LhuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lhu $a3,0($v0); live mapped peek or $a3:=0;" + + " no invent 0x8032 page / firmware / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live e73cf23: after lhu skip, + // name first I-fetch at 0x8003F824. + // One-shot. Peek dump only — do + // not invent next word / dest / + // $ra / 0x9A02 / 0x99FF / 0x8032 + // page / *0xFFFFFC74 / SUD. Do not + // hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiA3Lhu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiA3LhuLogged + || _exn15C28AfterOuterJalEpiA3LhuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiA3LhuNextLogged = true; + uint epiA3LhuNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiA3LhuNoteDump) + || epiA3LhuNoteDump == 0) + epiA3LhuNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNextDump; + uint epiA3LhuNoteRa = PeekGpr(regs, 31); + uint epiA3LhuNoteSp = PeekGpr(regs, 29); + uint epiA3LhuNoteT5 = PeekGpr(regs, 13); + uint epiA3LhuNoteV0 = PeekGpr(regs, 2); + uint epiA3LhuNoteV1 = PeekGpr(regs, 3); + uint epiA3LhuNoteA1 = PeekGpr(regs, 5); + uint epiA3LhuNoteA2 = PeekGpr(regs, 6); + uint epiA3LhuNoteA3 = PeekGpr(regs, 7); + string epiA3LhuNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiA3LhuNoteDumpDis = epiA3LhuNoteDump != 0 + ? FormatMipsOp(pc, epiA3LhuNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-a3-lhu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA3LhuNoteDump != 0 ? " dump=0x" + epiA3LhuNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-a3-lhu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-a3-lhu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiA3LhuNoteDump != 0 ? " dump=0x" + epiA3LhuNoteDump.ToString("X") : "") + + " dis=" + epiA3LhuNoteDis + + (epiA3LhuNoteDump != 0 ? " dump-dis=" + epiA3LhuNoteDumpDis : "") + + " t5=0x" + epiA3LhuNoteT5.ToString("X") + + " a1=0x" + epiA3LhuNoteA1.ToString("X") + + " a2=0x" + epiA3LhuNoteA2.ToString("X") + + " a3=0x" + epiA3LhuNoteA3.ToString("X") + + " v0=0x" + epiA3LhuNoteV0.ToString("X") + + " v1=0x" + epiA3LhuNoteV1.ToString("X") + + " ra=0x" + epiA3LhuNoteRa.ToString("X") + + " sp=0x" + epiA3LhuNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-a3-lhu" + + " (first I-fetch after a3 lhu dest-miss skip;" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 479eba6: sltu $a0,$a3,$v1 + // at 0x8003F824 named only. Exec + // dump sltu (ALU compare even if + // nearby regs look odd). Equal + // $a3=$v1=0x1E8 → $a0:=0. + // PC:=0x8003F828. Observe beq + // (name only). Refuse jr hop + // 0x8003F78C / MULT / SPECIAL 0x16. + // Not LoadO32. No leftover-hop. + // Do not invent 0x8032 / 0x8033 + // page / SUD / 0x9A02 / 0x99FF / + // *0xFFFFFC74. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiSltu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiA3LhuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext) + return false; + if (_exn15C28AfterOuterJalEpiSltuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + && _exn15C28AfterOuterJalEpiBeqLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + && _exn15C28AfterOuterJalEpiBeqAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + && _exn15C28AfterOuterJalEpiBeqSltLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + && _exn15C28AfterOuterJalEpiBeqBneFallLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiSltuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiSltuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiSltuDump) + || epiSltuDump == 0) + epiSltuDump = CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNextDump; + if (epiSltuDump != CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNextDump) + return false; + uint epiSltuNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiSltuNext, + out epiSltuNextDump) + || epiSltuNextDump == 0) + epiSltuNextDump = CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump; + if (epiSltuNextDump != CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump) + return false; + if ((epiSltuNextDump >> 26) == 0 + && ((epiSltuNextDump & 63) == 0x18 + || (epiSltuNextDump & 63) == 0x16 + || (epiSltuNextDump & 63) == 0x08)) + return false; + if (insn != epiSltuDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiSltuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiSltuDump); + uint epiSltuNext = CoredllDllMainExn15C28OuterJalLinkEpiSltuNext; + if (epiSltuNext == 0 || (epiSltuNext & 3) != 0 + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiSltuNext == CoredllDllMainExn15C28OuterJalLink + || epiSltuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiSltuNext == CoredllDllMainExn15C28JalS1AluNext + || epiSltuNext == CoredllDllMainExn15C28StkSwNext + || epiSltuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiSltuNext) + || IsExn15C28Na02Frame(epiSltuNext) + || IsExn15C28NfffFrame(epiSltuNext) + || IsExn15C28N9ffFrame(epiSltuNext) + || IsExn15C28HelperBody(epiSltuNext) + || IsExn15C28JalRaEpiRange(epiSltuNext) + || IsLeftoverDestVa(epiSltuNext) + || IsWrapDestSize(epiSltuNext) + || IsWrapDestFp50Va(epiSltuNext)) + return false; + bool epiSltuOk = TryExecDumpMemSltuKnown(regs, epiSltuDump); + if (!epiSltuOk) + epiSltuOk = TryExecDumpMemAlu(regs, epiSltuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiSltuNext; + _exn15C28AfterOuterJalEpiA3LhuNextLogged = true; + _exn15C28AfterOuterJalEpiSltuLogged = true; + uint epiSltuRa = PeekGpr(regs, 31); + uint epiSltuSp = PeekGpr(regs, 29); + uint epiSltuT5 = PeekGpr(regs, 13); + uint epiSltuV0 = PeekGpr(regs, 2); + uint epiSltuV1 = PeekGpr(regs, 3); + uint epiSltuA0 = PeekGpr(regs, 4); + uint epiSltuA1 = PeekGpr(regs, 5); + uint epiSltuA2 = PeekGpr(regs, 6); + uint epiSltuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiSltuOk + ? "dump-mem-15c28-outer-jal-epi-sltu" + : "dump-mem-15c28-outer-jal-epi-sltu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiSltuDump.ToString("X") + + " dest=0x" + epiSltuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-sltu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiSltuNext.ToString("X") + + " dump=0x" + epiSltuDump.ToString("X") + + (insn != 0 && insn != epiSltuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiSltuOk ? " sltu=1" : " sltu=0") + + " a0=0x" + epiSltuA0.ToString("X") + + " a1=0x" + epiSltuA1.ToString("X") + + " a2=0x" + epiSltuA2.ToString("X") + + " a3=0x" + epiSltuA3.ToString("X") + + " v0=0x" + epiSltuV0.ToString("X") + + " v1=0x" + epiSltuV1.ToString("X") + + " t5=0x" + epiSltuT5.ToString("X") + + " ra=0x" + epiSltuRa.ToString("X") + + " sp=0x" + epiSltuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sltu $a0,$a3,$v1; ALU $a0:=0 when $a3==$v1;" + + " no invent 0x8032 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 479eba6: after sltu exec, + // name first I-fetch at 0x8003F828 + // (dump beq $a0,$zero,+2). One-shot. + // Do not invent dest / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / + // *0xFFFFFC74 / SUD. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiSltu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiSltuLogged + || _exn15C28AfterOuterJalEpiSltuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiSltuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiSltuNextLogged = true; + uint epiSltuNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiSltuNoteDump) + || epiSltuNoteDump == 0) + epiSltuNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump; + uint epiSltuNoteRa = PeekGpr(regs, 31); + uint epiSltuNoteSp = PeekGpr(regs, 29); + uint epiSltuNoteT5 = PeekGpr(regs, 13); + uint epiSltuNoteV0 = PeekGpr(regs, 2); + uint epiSltuNoteV1 = PeekGpr(regs, 3); + uint epiSltuNoteA0 = PeekGpr(regs, 4); + uint epiSltuNoteA1 = PeekGpr(regs, 5); + uint epiSltuNoteA3 = PeekGpr(regs, 7); + string epiSltuNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiSltuNoteDumpDis = epiSltuNoteDump != 0 + ? FormatMipsOp(pc, epiSltuNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-sltu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiSltuNoteDump != 0 ? " dump=0x" + epiSltuNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-sltu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-sltu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiSltuNoteDump != 0 ? " dump=0x" + epiSltuNoteDump.ToString("X") : "") + + " dis=" + epiSltuNoteDis + + (epiSltuNoteDump != 0 ? " dump-dis=" + epiSltuNoteDumpDis : "") + + " t5=0x" + epiSltuNoteT5.ToString("X") + + " a0=0x" + epiSltuNoteA0.ToString("X") + + " a1=0x" + epiSltuNoteA1.ToString("X") + + " a3=0x" + epiSltuNoteA3.ToString("X") + + " v0=0x" + epiSltuNoteV0.ToString("X") + + " v1=0x" + epiSltuNoteV1.ToString("X") + + " ra=0x" + epiSltuNoteRa.ToString("X") + + " sp=0x" + epiSltuNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-sltu" + + " (first I-fetch after sltu exec; beq $a0,$zero,+2;" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 9973a3b: after sltu exec, + // dump beq $a0,$zero,+2 at + // 0x8003F828 named only. $a0==0 + // → taken 0x8003F834 (addiu + // $v0,$v0,20). Delay 0x8003F82C + // dump nop (ALU). Fall 0x8003F830 + // only if $a0!=0. Refuse MULT + // 0x8003F748 / jr 0x8003F78C / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF / *0xFFFFFC74. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeq(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiSltuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiSltuNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + && _exn15C28AfterOuterJalEpiBeqAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + && _exn15C28AfterOuterJalEpiBeqSltLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + && _exn15C28AfterOuterJalEpiBeqBneFallLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqDelay) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqFall) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqDump) + || epiBeqDump == 0) + epiBeqDump = CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump; + if (epiBeqDump != CoredllDllMainExn15C28OuterJalLinkEpiSltuNextDump) + return false; + uint epiBeqDelayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqDelay, + out epiBeqDelayDump) + || epiBeqDelayDump == 0) + epiBeqDelayDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqDelayDump; + if (epiBeqDelayDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqDelayDump) + return false; + if ((epiBeqDelayDump >> 26) == 0 + && ((epiBeqDelayDump & 63) == 0x18 + || (epiBeqDelayDump & 63) == 0x16 + || (epiBeqDelayDump & 63) == 0x08)) + return false; + uint epiBeqTakenDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken, + out epiBeqTakenDump) + || epiBeqTakenDump == 0) + epiBeqTakenDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump; + if (epiBeqTakenDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump) + return false; + if ((epiBeqTakenDump >> 26) == 0 + && ((epiBeqTakenDump & 63) == 0x18 + || (epiBeqTakenDump & 63) == 0x16 + || (epiBeqTakenDump & 63) == 0x08)) + return false; + uint epiBeqFallDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqFall, + out epiBeqFallDump) + || epiBeqFallDump == 0) + epiBeqFallDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqFallDump; + if (epiBeqFallDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqFallDump) + return false; + if ((epiBeqFallDump >> 26) == 0 + && ((epiBeqFallDump & 63) == 0x18 + || (epiBeqFallDump & 63) == 0x16 + || (epiBeqFallDump & 63) == 0x08)) + return false; + if (insn != epiBeqDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqDump); + bool epiBeqTaken = PeekGpr(regs, 4) == 0; + uint epiBeqDest = epiBeqTaken + ? CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + : CoredllDllMainExn15C28OuterJalLinkEpiBeqFall; + if (epiBeqDest == 0 || (epiBeqDest & 3) != 0 + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqDest == CoredllDllMainExn15C28OuterJalLink + || epiBeqDest == CoredllDllMainExn15C28JalS1AluNext + || epiBeqDest == CoredllDllMainExn15C28StkSwNext + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqDest == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqDest == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqDest) + || IsExn15C28Na02Frame(epiBeqDest) + || IsExn15C28NfffFrame(epiBeqDest) + || IsExn15C28N9ffFrame(epiBeqDest) + || IsExn15C28HelperBody(epiBeqDest) + || IsExn15C28JalRaEpiRange(epiBeqDest) + || IsLeftoverDestVa(epiBeqDest) + || IsWrapDestSize(epiBeqDest) + || IsWrapDestFp50Va(epiBeqDest)) + return false; + if (!IsDumpMemAluInsn(epiBeqDelayDump)) + return false; + bool epiBeqDelayOk = TryExecDumpMemAlu(regs, epiBeqDelayDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqDest; + _exn15C28AfterOuterJalEpiSltuNextLogged = true; + _exn15C28AfterOuterJalEpiBeqLogged = true; + uint epiBeqRa = PeekGpr(regs, 31); + uint epiBeqSp = PeekGpr(regs, 29); + uint epiBeqT5 = PeekGpr(regs, 13); + uint epiBeqV0 = PeekGpr(regs, 2); + uint epiBeqV1 = PeekGpr(regs, 3); + uint epiBeqA0 = PeekGpr(regs, 4); + uint epiBeqA1 = PeekGpr(regs, 5); + uint epiBeqA2 = PeekGpr(regs, 6); + uint epiBeqA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiBeqDelayOk + ? "dump-mem-15c28-outer-jal-epi-beq" + : "dump-mem-15c28-outer-jal-epi-beq-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqDump.ToString("X") + + " dest=0x" + epiBeqDest.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqDest.ToString("X") + + " dump=0x" + epiBeqDump.ToString("X") + + (insn != 0 && insn != epiBeqDump + ? " live=0x" + insn.ToString("X") : "") + + " delay=0x" + epiBeqDelayDump.ToString("X") + + (epiBeqDelayOk ? " nop=1" : " nop=0") + + (epiBeqTaken ? " taken=1" : " taken=0") + + " fall=0x" + CoredllDllMainExn15C28OuterJalLinkEpiBeqFall.ToString("X") + + " mul=0x" + CoredllDllMainExn15C28OuterJalLinkBeqTaken.ToString("X") + + " a0=0x" + epiBeqA0.ToString("X") + + " a1=0x" + epiBeqA1.ToString("X") + + " a2=0x" + epiBeqA2.ToString("X") + + " a3=0x" + epiBeqA3.ToString("X") + + " v0=0x" + epiBeqV0.ToString("X") + + " v1=0x" + epiBeqV1.ToString("X") + + " t5=0x" + epiBeqT5.ToString("X") + + " ra=0x" + epiBeqRa.ToString("X") + + " sp=0x" + epiBeqSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump beq $a0,$zero,+2; delay nop; taken 0x8003F834;" + + " no invent 0x8032 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 9973a3b: after epi-beq take, + // name first I-fetch at 0x8003F834 + // (dump addiu $v0,$v0,20). One-shot. + // Do not invent dest / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / + // *0xFFFFFC74 / SUD. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeq(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqLogged + || _exn15C28AfterOuterJalEpiBeqNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqNextLogged = true; + uint epiBeqNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqNoteDump) + || epiBeqNoteDump == 0) + epiBeqNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump; + uint epiBeqNoteRa = PeekGpr(regs, 31); + uint epiBeqNoteSp = PeekGpr(regs, 29); + uint epiBeqNoteT5 = PeekGpr(regs, 13); + uint epiBeqNoteV0 = PeekGpr(regs, 2); + uint epiBeqNoteV1 = PeekGpr(regs, 3); + uint epiBeqNoteA0 = PeekGpr(regs, 4); + uint epiBeqNoteA1 = PeekGpr(regs, 5); + uint epiBeqNoteA3 = PeekGpr(regs, 7); + string epiBeqNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqNoteDumpDis = epiBeqNoteDump != 0 + ? FormatMipsOp(pc, epiBeqNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqNoteDump != 0 ? " dump=0x" + epiBeqNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqNoteDump != 0 ? " dump=0x" + epiBeqNoteDump.ToString("X") : "") + + " dis=" + epiBeqNoteDis + + (epiBeqNoteDump != 0 ? " dump-dis=" + epiBeqNoteDumpDis : "") + + " t5=0x" + epiBeqNoteT5.ToString("X") + + " a0=0x" + epiBeqNoteA0.ToString("X") + + " a1=0x" + epiBeqNoteA1.ToString("X") + + " a3=0x" + epiBeqNoteA3.ToString("X") + + " v0=0x" + epiBeqNoteV0.ToString("X") + + " v1=0x" + epiBeqNoteV1.ToString("X") + + " ra=0x" + epiBeqNoteRa.ToString("X") + + " sp=0x" + epiBeqNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq" + + " (first I-fetch after epi-beq take; addiu $v0,$v0,20;" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live db9d12b: after epi-beq land, + // dump addiu $v0,$v0,20 at + // 0x8003F834 named only. Exec + // dump addiu (ALU $v0:=0x80320260). + // PC:=0x8003F838. Observe slt + // (name only). Refuse jr hop + // 0x8003F78C / MULT 0x8003F748 / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF / *0xFFFFFC74. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken) + return false; + if (_exn15C28AfterOuterJalEpiBeqAddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + && _exn15C28AfterOuterJalEpiBeqSltLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + && _exn15C28AfterOuterJalEpiBeqBneFallLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqAddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqAddiuDump) + || epiBeqAddiuDump == 0) + epiBeqAddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump; + if (epiBeqAddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqTakenDump) + return false; + uint epiBeqAddiuNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext, + out epiBeqAddiuNextDump) + || epiBeqAddiuNextDump == 0) + epiBeqAddiuNextDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump; + if (epiBeqAddiuNextDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump) + return false; + if ((epiBeqAddiuNextDump >> 26) == 0 + && ((epiBeqAddiuNextDump & 63) == 0x18 + || (epiBeqAddiuNextDump & 63) == 0x16 + || (epiBeqAddiuNextDump & 63) == 0x08)) + return false; + if (insn != epiBeqAddiuDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqAddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqAddiuDump); + uint epiBeqAddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext; + if (epiBeqAddiuNext == 0 || (epiBeqAddiuNext & 3) != 0 + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqAddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqAddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqAddiuNext == CoredllDllMainExn15C28StkSwNext + || epiBeqAddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqAddiuNext) + || IsExn15C28Na02Frame(epiBeqAddiuNext) + || IsExn15C28NfffFrame(epiBeqAddiuNext) + || IsExn15C28N9ffFrame(epiBeqAddiuNext) + || IsExn15C28HelperBody(epiBeqAddiuNext) + || IsExn15C28JalRaEpiRange(epiBeqAddiuNext) + || IsLeftoverDestVa(epiBeqAddiuNext) + || IsWrapDestSize(epiBeqAddiuNext) + || IsWrapDestFp50Va(epiBeqAddiuNext)) + return false; + bool epiBeqAddiuOk = TryExecDumpMemAlu(regs, epiBeqAddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqAddiuNext; + _exn15C28AfterOuterJalEpiBeqNextLogged = true; + _exn15C28AfterOuterJalEpiBeqAddiuLogged = true; + uint epiBeqAddiuRa = PeekGpr(regs, 31); + uint epiBeqAddiuSp = PeekGpr(regs, 29); + uint epiBeqAddiuT5 = PeekGpr(regs, 13); + uint epiBeqAddiuV0 = PeekGpr(regs, 2); + uint epiBeqAddiuV1 = PeekGpr(regs, 3); + uint epiBeqAddiuA0 = PeekGpr(regs, 4); + uint epiBeqAddiuA1 = PeekGpr(regs, 5); + uint epiBeqAddiuA2 = PeekGpr(regs, 6); + uint epiBeqAddiuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiBeqAddiuOk + ? "dump-mem-15c28-outer-jal-epi-beq-addiu" + : "dump-mem-15c28-outer-jal-epi-beq-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqAddiuDump.ToString("X") + + " dest=0x" + epiBeqAddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqAddiuNext.ToString("X") + + " dump=0x" + epiBeqAddiuDump.ToString("X") + + (insn != 0 && insn != epiBeqAddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiBeqAddiuOk ? " addiu=1" : " addiu=0") + + " a0=0x" + epiBeqAddiuA0.ToString("X") + + " a1=0x" + epiBeqAddiuA1.ToString("X") + + " a2=0x" + epiBeqAddiuA2.ToString("X") + + " a3=0x" + epiBeqAddiuA3.ToString("X") + + " v0=0x" + epiBeqAddiuV0.ToString("X") + + " v1=0x" + epiBeqAddiuV1.ToString("X") + + " t5=0x" + epiBeqAddiuT5.ToString("X") + + " ra=0x" + epiBeqAddiuRa.ToString("X") + + " sp=0x" + epiBeqAddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $v0,$v0,20; ALU $v0:=0x80320260;" + + " no invent 0x8032 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live db9d12b: after addiu exec, + // name first I-fetch at 0x8003F838 + // (dump slt $t0,$v0,$a1). One-shot. + // Do not invent dest / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / + // *0xFFFFFC74 / SUD. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqAddiuLogged + || _exn15C28AfterOuterJalEpiBeqAddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqAddiuNextLogged = true; + uint epiBeqAddiuNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqAddiuNoteDump) + || epiBeqAddiuNoteDump == 0) + epiBeqAddiuNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump; + uint epiBeqAddiuNoteRa = PeekGpr(regs, 31); + uint epiBeqAddiuNoteSp = PeekGpr(regs, 29); + uint epiBeqAddiuNoteT5 = PeekGpr(regs, 13); + uint epiBeqAddiuNoteV0 = PeekGpr(regs, 2); + uint epiBeqAddiuNoteV1 = PeekGpr(regs, 3); + uint epiBeqAddiuNoteA0 = PeekGpr(regs, 4); + uint epiBeqAddiuNoteA1 = PeekGpr(regs, 5); + uint epiBeqAddiuNoteA3 = PeekGpr(regs, 7); + string epiBeqAddiuNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqAddiuNoteDumpDis = epiBeqAddiuNoteDump != 0 + ? FormatMipsOp(pc, epiBeqAddiuNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqAddiuNoteDump != 0 ? " dump=0x" + epiBeqAddiuNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqAddiuNoteDump != 0 ? " dump=0x" + epiBeqAddiuNoteDump.ToString("X") : "") + + " dis=" + epiBeqAddiuNoteDis + + (epiBeqAddiuNoteDump != 0 ? " dump-dis=" + epiBeqAddiuNoteDumpDis : "") + + " t5=0x" + epiBeqAddiuNoteT5.ToString("X") + + " a0=0x" + epiBeqAddiuNoteA0.ToString("X") + + " a1=0x" + epiBeqAddiuNoteA1.ToString("X") + + " a3=0x" + epiBeqAddiuNoteA3.ToString("X") + + " v0=0x" + epiBeqAddiuNoteV0.ToString("X") + + " v1=0x" + epiBeqAddiuNoteV1.ToString("X") + + " ra=0x" + epiBeqAddiuNoteRa.ToString("X") + + " sp=0x" + epiBeqAddiuNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-addiu" + + " (first I-fetch after addiu exec; slt $t0,$v0,$a1;" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 71d9731: after addiu exec, + // dump slt $t0,$v0,$a1 at + // 0x8003F838 named only. Exec + // dump slt (signed ALU; $v0 < $a1 + // → $t0:=1). PC:=0x8003F83C. + // Observe bne (name only). Refuse + // jr hop 0x8003F78C / MULT + // 0x8003F748 / SPECIAL 0x16. Not + // LoadO32. No leftover-hop. Do + // not invent 0x8032 / 0x8033 page + // / SUD / 0x9A02 / 0x99FF / + // *0xFFFFFC74. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqSlt(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqAddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqSltLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + && (!_exn15C28AfterOuterJalEpiBeqBneLogged + || _exn15C28AfterOuterJalEpiBeqBneFallLogged)) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + && _exn15C28AfterOuterJalEpiBeqBneFallLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqSltDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqSltDump) + || epiBeqSltDump == 0) + epiBeqSltDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump; + if (epiBeqSltDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNextDump) + return false; + uint epiBeqSltNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext, + out epiBeqSltNextDump) + || epiBeqSltNextDump == 0) + epiBeqSltNextDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump; + if (epiBeqSltNextDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump) + return false; + if ((epiBeqSltNextDump >> 26) == 0 + && ((epiBeqSltNextDump & 63) == 0x18 + || (epiBeqSltNextDump & 63) == 0x16 + || (epiBeqSltNextDump & 63) == 0x08)) + return false; + if (insn != epiBeqSltDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqSltDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqSltDump); + uint epiBeqSltNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext; + if (epiBeqSltNext == 0 || (epiBeqSltNext & 3) != 0 + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqSltNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqSltNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqSltNext == CoredllDllMainExn15C28StkSwNext + || epiBeqSltNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqSltNext) + || IsExn15C28Na02Frame(epiBeqSltNext) + || IsExn15C28NfffFrame(epiBeqSltNext) + || IsExn15C28N9ffFrame(epiBeqSltNext) + || IsExn15C28HelperBody(epiBeqSltNext) + || IsExn15C28JalRaEpiRange(epiBeqSltNext) + || IsLeftoverDestVa(epiBeqSltNext) + || IsWrapDestSize(epiBeqSltNext) + || IsWrapDestFp50Va(epiBeqSltNext)) + return false; + bool epiBeqSltOk = TryExecDumpMemSltuKnown(regs, epiBeqSltDump); + if (!epiBeqSltOk) + epiBeqSltOk = TryExecDumpMemAlu(regs, epiBeqSltDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqSltNext; + _exn15C28AfterOuterJalEpiBeqAddiuNextLogged = true; + _exn15C28AfterOuterJalEpiBeqSltLogged = true; + uint epiBeqSltRa = PeekGpr(regs, 31); + uint epiBeqSltSp = PeekGpr(regs, 29); + uint epiBeqSltT5 = PeekGpr(regs, 13); + uint epiBeqSltT0 = PeekGpr(regs, 8); + uint epiBeqSltV0 = PeekGpr(regs, 2); + uint epiBeqSltV1 = PeekGpr(regs, 3); + uint epiBeqSltA0 = PeekGpr(regs, 4); + uint epiBeqSltA1 = PeekGpr(regs, 5); + uint epiBeqSltA2 = PeekGpr(regs, 6); + uint epiBeqSltA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiBeqSltOk + ? "dump-mem-15c28-outer-jal-epi-beq-slt" + : "dump-mem-15c28-outer-jal-epi-beq-slt-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqSltDump.ToString("X") + + " dest=0x" + epiBeqSltNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-slt" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqSltNext.ToString("X") + + " dump=0x" + epiBeqSltDump.ToString("X") + + (insn != 0 && insn != epiBeqSltDump + ? " live=0x" + insn.ToString("X") : "") + + (epiBeqSltOk ? " slt=1" : " slt=0") + + " t0=0x" + epiBeqSltT0.ToString("X") + + " a0=0x" + epiBeqSltA0.ToString("X") + + " a1=0x" + epiBeqSltA1.ToString("X") + + " a2=0x" + epiBeqSltA2.ToString("X") + + " a3=0x" + epiBeqSltA3.ToString("X") + + " v0=0x" + epiBeqSltV0.ToString("X") + + " v1=0x" + epiBeqSltV1.ToString("X") + + " t5=0x" + epiBeqSltT5.ToString("X") + + " ra=0x" + epiBeqSltRa.ToString("X") + + " sp=0x" + epiBeqSltSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump slt $t0,$v0,$a1; ALU $t0:=1 when $v0<$a1;" + + " no invent 0x8032 page / *0xFFFFFC74 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 71d9731: after slt exec, + // name first I-fetch at 0x8003F83C + // (dump bne $t0,$zero,-8). One-shot. + // Do not invent dest / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / + // *0xFFFFFC74 / SUD. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqSlt(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqSltLogged + || _exn15C28AfterOuterJalEpiBeqSltNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqSltNextLogged = true; + uint epiBeqSltNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqSltNoteDump) + || epiBeqSltNoteDump == 0) + epiBeqSltNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump; + uint epiBeqSltNoteRa = PeekGpr(regs, 31); + uint epiBeqSltNoteSp = PeekGpr(regs, 29); + uint epiBeqSltNoteT5 = PeekGpr(regs, 13); + uint epiBeqSltNoteT0 = PeekGpr(regs, 8); + uint epiBeqSltNoteV0 = PeekGpr(regs, 2); + uint epiBeqSltNoteV1 = PeekGpr(regs, 3); + uint epiBeqSltNoteA0 = PeekGpr(regs, 4); + uint epiBeqSltNoteA1 = PeekGpr(regs, 5); + uint epiBeqSltNoteA3 = PeekGpr(regs, 7); + string epiBeqSltNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqSltNoteDumpDis = epiBeqSltNoteDump != 0 + ? FormatMipsOp(pc, epiBeqSltNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-slt"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqSltNoteDump != 0 ? " dump=0x" + epiBeqSltNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-slt"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-slt" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqSltNoteDump != 0 ? " dump=0x" + epiBeqSltNoteDump.ToString("X") : "") + + " dis=" + epiBeqSltNoteDis + + (epiBeqSltNoteDump != 0 ? " dump-dis=" + epiBeqSltNoteDumpDis : "") + + " t5=0x" + epiBeqSltNoteT5.ToString("X") + + " t0=0x" + epiBeqSltNoteT0.ToString("X") + + " a0=0x" + epiBeqSltNoteA0.ToString("X") + + " a1=0x" + epiBeqSltNoteA1.ToString("X") + + " a3=0x" + epiBeqSltNoteA3.ToString("X") + + " v0=0x" + epiBeqSltNoteV0.ToString("X") + + " v1=0x" + epiBeqSltNoteV1.ToString("X") + + " ra=0x" + epiBeqSltNoteRa.ToString("X") + + " sp=0x" + epiBeqSltNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-slt" + + " (first I-fetch after slt exec; bne $t0,$zero,-8;" + + " honor ra; no jr hop; no invent $ra / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 721c102: after slt exec, + // dump bne $t0,$zero,-8 at + // 0x8003F83C named only. $t0!=0 + // → taken 0x8003F820 (rewind + // scan body so lhu/sltu/beq/ + // addiu/slt re-fire; $v0+=20 + // until $v0>=$a1). $t0==0 → fall + // 0x8003F844. Delay 0x8003F840 + // dump nop. Refuse jr hop + // 0x8003F78C / MULT 0x8003F748 / + // SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF / *0xFFFFFC74 / + // *0xFFFFDB58. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqBne(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqSltLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqBneFallLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + && _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelay) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqBneDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneDump) + || epiBeqBneDump == 0) + epiBeqBneDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump; + if (epiBeqBneDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNextDump) + return false; + uint epiBeqBneDelayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelay, + out epiBeqBneDelayDump) + || epiBeqBneDelayDump == 0) + epiBeqBneDelayDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelayDump; + if (epiBeqBneDelayDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneDelayDump) + return false; + if ((epiBeqBneDelayDump >> 26) == 0 + && ((epiBeqBneDelayDump & 63) == 0x18 + || (epiBeqBneDelayDump & 63) == 0x16 + || (epiBeqBneDelayDump & 63) == 0x08)) + return false; + uint epiBeqBneFallDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall, + out epiBeqBneFallDump) + || epiBeqBneFallDump == 0) + epiBeqBneFallDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump; + if (epiBeqBneFallDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump) + return false; + if ((epiBeqBneFallDump >> 26) == 0 + && ((epiBeqBneFallDump & 63) == 0x18 + || (epiBeqBneFallDump & 63) == 0x16 + || (epiBeqBneFallDump & 63) == 0x08)) + return false; + uint epiBeqBneTakenDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext, + out epiBeqBneTakenDump) + || epiBeqBneTakenDump == 0) + epiBeqBneTakenDump = CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump; + if (epiBeqBneTakenDump != CoredllDllMainExn15C28OuterJalLinkEpiA2SwNextDump) + return false; + if ((epiBeqBneTakenDump >> 26) == 0 + && ((epiBeqBneTakenDump & 63) == 0x18 + || (epiBeqBneTakenDump & 63) == 0x16 + || (epiBeqBneTakenDump & 63) == 0x08)) + return false; + if (insn != epiBeqBneDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqBneDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqBneDump); + bool epiBeqBneTaken = PeekGpr(regs, 8) != 0; + uint epiBeqBneDest = epiBeqBneTaken + ? CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + : CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall; + if (epiBeqBneDest == 0 || (epiBeqBneDest & 3) != 0 + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLink + || epiBeqBneDest == CoredllDllMainExn15C28JalS1AluNext + || epiBeqBneDest == CoredllDllMainExn15C28StkSwNext + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqBneDest == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqBneDest == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqBneDest) + || IsExn15C28Na02Frame(epiBeqBneDest) + || IsExn15C28NfffFrame(epiBeqBneDest) + || IsExn15C28N9ffFrame(epiBeqBneDest) + || IsExn15C28HelperBody(epiBeqBneDest) + || IsExn15C28JalRaEpiRange(epiBeqBneDest) + || IsLeftoverDestVa(epiBeqBneDest) + || IsWrapDestSize(epiBeqBneDest) + || IsWrapDestFp50Va(epiBeqBneDest)) + return false; + if (!IsDumpMemAluInsn(epiBeqBneDelayDump)) + return false; + bool epiBeqBneDelayOk = TryExecDumpMemAlu(regs, epiBeqBneDelayDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + if (epiBeqBneTaken) + { + _exn15C28AfterOuterJalEpiA3LhuLogged = false; + _exn15C28AfterOuterJalEpiA3LhuNextLogged = false; + _exn15C28AfterOuterJalEpiSltuLogged = false; + _exn15C28AfterOuterJalEpiSltuNextLogged = false; + _exn15C28AfterOuterJalEpiBeqLogged = false; + _exn15C28AfterOuterJalEpiBeqNextLogged = false; + _exn15C28AfterOuterJalEpiBeqAddiuLogged = false; + _exn15C28AfterOuterJalEpiBeqAddiuNextLogged = false; + _exn15C28AfterOuterJalEpiBeqSltLogged = false; + _exn15C28AfterOuterJalEpiBeqSltNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneLogged = true; + } + else + { + _exn15C28AfterOuterJalEpiBeqSltNextLogged = true; + _exn15C28AfterOuterJalEpiBeqBneLogged = true; + _exn15C28AfterOuterJalEpiBeqBneFallLogged = true; + } + cpuPc = epiBeqBneDest; + uint epiBeqBneRa = PeekGpr(regs, 31); + uint epiBeqBneSp = PeekGpr(regs, 29); + uint epiBeqBneT5 = PeekGpr(regs, 13); + uint epiBeqBneT0 = PeekGpr(regs, 8); + uint epiBeqBneV0 = PeekGpr(regs, 2); + uint epiBeqBneV1 = PeekGpr(regs, 3); + uint epiBeqBneA0 = PeekGpr(regs, 4); + uint epiBeqBneA1 = PeekGpr(regs, 5); + uint epiBeqBneA2 = PeekGpr(regs, 6); + uint epiBeqBneA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiBeqBneDelayOk + ? "dump-mem-15c28-outer-jal-epi-beq-bne" + : "dump-mem-15c28-outer-jal-epi-beq-bne-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqBneDump.ToString("X") + + " dest=0x" + epiBeqBneDest.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-bne" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqBneDest.ToString("X") + + " dump=0x" + epiBeqBneDump.ToString("X") + + (insn != 0 && insn != epiBeqBneDump + ? " live=0x" + insn.ToString("X") : "") + + " delay=0x" + epiBeqBneDelayDump.ToString("X") + + (epiBeqBneDelayOk ? " nop=1" : " nop=0") + + (epiBeqBneTaken ? " taken=1" : " taken=0") + + " fall=0x" + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall.ToString("X") + + " loop=0x" + CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext.ToString("X") + + " t0=0x" + epiBeqBneT0.ToString("X") + + " a0=0x" + epiBeqBneA0.ToString("X") + + " a1=0x" + epiBeqBneA1.ToString("X") + + " a2=0x" + epiBeqBneA2.ToString("X") + + " a3=0x" + epiBeqBneA3.ToString("X") + + " v0=0x" + epiBeqBneV0.ToString("X") + + " v1=0x" + epiBeqBneV1.ToString("X") + + " t5=0x" + epiBeqBneT5.ToString("X") + + " ra=0x" + epiBeqBneRa.ToString("X") + + " sp=0x" + epiBeqBneSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump bne $t0,$zero,-8; delay nop; taken 0x8003F820 scan;" + + " fall 0x8003F844; no invent 0x8032 page / *0xFFFFFC74 / *0xFFFFDB58 / SUD / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 721c102: after bne fall, + // name first I-fetch at 0x8003F844 + // (dump addiu $t1,$0,-10920). + // One-shot. Do not invent dest / + // $t1 / *0xFFFFDB58 / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / + // *0xFFFFFC74 / SUD. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqBne(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqBneFallLogged + || _exn15C28AfterOuterJalEpiBeqBneNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqBneNextLogged = true; + uint epiBeqBneNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneNoteDump) + || epiBeqBneNoteDump == 0) + epiBeqBneNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump; + uint epiBeqBneNoteRa = PeekGpr(regs, 31); + uint epiBeqBneNoteSp = PeekGpr(regs, 29); + uint epiBeqBneNoteT5 = PeekGpr(regs, 13); + uint epiBeqBneNoteT0 = PeekGpr(regs, 8); + uint epiBeqBneNoteT1 = PeekGpr(regs, 9); + uint epiBeqBneNoteV0 = PeekGpr(regs, 2); + uint epiBeqBneNoteV1 = PeekGpr(regs, 3); + uint epiBeqBneNoteA0 = PeekGpr(regs, 4); + uint epiBeqBneNoteA1 = PeekGpr(regs, 5); + uint epiBeqBneNoteA3 = PeekGpr(regs, 7); + string epiBeqBneNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqBneNoteDumpDis = epiBeqBneNoteDump != 0 + ? FormatMipsOp(pc, epiBeqBneNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-bne"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneNoteDump != 0 ? " dump=0x" + epiBeqBneNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-bne" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneNoteDump != 0 ? " dump=0x" + epiBeqBneNoteDump.ToString("X") : "") + + " dis=" + epiBeqBneNoteDis + + (epiBeqBneNoteDump != 0 ? " dump-dis=" + epiBeqBneNoteDumpDis : "") + + " t5=0x" + epiBeqBneNoteT5.ToString("X") + + " t0=0x" + epiBeqBneNoteT0.ToString("X") + + " t1=0x" + epiBeqBneNoteT1.ToString("X") + + " a0=0x" + epiBeqBneNoteA0.ToString("X") + + " a1=0x" + epiBeqBneNoteA1.ToString("X") + + " a3=0x" + epiBeqBneNoteA3.ToString("X") + + " v0=0x" + epiBeqBneNoteV0.ToString("X") + + " v1=0x" + epiBeqBneNoteV1.ToString("X") + + " ra=0x" + epiBeqBneNoteRa.ToString("X") + + " sp=0x" + epiBeqBneNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne" + + " (first I-fetch after bne fall; addiu $t1,$0,-10920;" + + " honor ra; no jr hop; no invent $ra / *0xFFFFDB58 / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 75d1028: addiu $t1,$0,-10920 + // at 0x8003F844 named only. Exec + // dump addiu (ALU $t1:=0xFFFFDB58). + // PC:=0x8003F848 (sequential + // dump-true +4; observe only; + // peek dump, do not invent next + // word / *0xFFFFDB58). Refuse jr + // hop 0x8003F78C / MULT 0x8003F748 + // / SPECIAL 0x16. Not LoadO32. No + // leftover-hop. Do not invent + // 0x8032 / 0x8033 page / SUD / + // 0x9A02 / 0x99FF / *0xFFFFFC74 / + // *0xFFFFDB58 / KData. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFall(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqBneFallLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall) + return false; + if (_exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + && _exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqBneFallAddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallAddiuDump) + || epiBeqBneFallAddiuDump == 0) + epiBeqBneFallAddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump; + if (epiBeqBneFallAddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallDump) + return false; + uint epiBeqBneFallNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext, + out epiBeqBneFallNextDump); + if (epiBeqBneFallNextDump != 0 && (epiBeqBneFallNextDump >> 26) == 0 + && ((epiBeqBneFallNextDump & 63) == 0x18 + || (epiBeqBneFallNextDump & 63) == 0x16 + || (epiBeqBneFallNextDump & 63) == 0x08)) + return false; + if (insn != epiBeqBneFallAddiuDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqBneFallAddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqBneFallAddiuDump); + uint epiBeqBneFallNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext; + if (epiBeqBneFallNext == 0 || (epiBeqBneFallNext & 3) != 0 + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqBneFallNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqBneFallNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqBneFallNext == CoredllDllMainExn15C28StkSwNext + || epiBeqBneFallNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqBneFallNext) + || IsExn15C28Na02Frame(epiBeqBneFallNext) + || IsExn15C28NfffFrame(epiBeqBneFallNext) + || IsExn15C28N9ffFrame(epiBeqBneFallNext) + || IsExn15C28HelperBody(epiBeqBneFallNext) + || IsExn15C28JalRaEpiRange(epiBeqBneFallNext) + || IsLeftoverDestVa(epiBeqBneFallNext) + || IsWrapDestSize(epiBeqBneFallNext) + || IsWrapDestFp50Va(epiBeqBneFallNext)) + return false; + bool epiBeqBneFallAddiuOk = TryExecDumpMemAlu(regs, epiBeqBneFallAddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqBneFallNext; + _exn15C28AfterOuterJalEpiBeqBneNextLogged = true; + _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged = true; + uint epiBeqBneFallAddiuRa = PeekGpr(regs, 31); + uint epiBeqBneFallAddiuSp = PeekGpr(regs, 29); + uint epiBeqBneFallAddiuT5 = PeekGpr(regs, 13); + uint epiBeqBneFallAddiuT0 = PeekGpr(regs, 8); + uint epiBeqBneFallAddiuT1 = PeekGpr(regs, 9); + uint epiBeqBneFallAddiuV0 = PeekGpr(regs, 2); + uint epiBeqBneFallAddiuV1 = PeekGpr(regs, 3); + uint epiBeqBneFallAddiuA0 = PeekGpr(regs, 4); + uint epiBeqBneFallAddiuA1 = PeekGpr(regs, 5); + uint epiBeqBneFallAddiuA2 = PeekGpr(regs, 6); + uint epiBeqBneFallAddiuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiBeqBneFallAddiuOk + ? "dump-mem-15c28-outer-jal-epi-beq-bne-fall" + : "dump-mem-15c28-outer-jal-epi-beq-bne-fall-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqBneFallAddiuDump.ToString("X") + + " dest=0x" + epiBeqBneFallNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-bne-fall" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqBneFallNext.ToString("X") + + " dump=0x" + epiBeqBneFallAddiuDump.ToString("X") + + (insn != 0 && insn != epiBeqBneFallAddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiBeqBneFallNextDump != 0 + ? " next-dump=0x" + epiBeqBneFallNextDump.ToString("X") : "") + + (epiBeqBneFallAddiuOk ? " addiu=1" : " addiu=0") + + " t1=0x" + epiBeqBneFallAddiuT1.ToString("X") + + " t0=0x" + epiBeqBneFallAddiuT0.ToString("X") + + " a0=0x" + epiBeqBneFallAddiuA0.ToString("X") + + " a1=0x" + epiBeqBneFallAddiuA1.ToString("X") + + " a2=0x" + epiBeqBneFallAddiuA2.ToString("X") + + " a3=0x" + epiBeqBneFallAddiuA3.ToString("X") + + " v0=0x" + epiBeqBneFallAddiuV0.ToString("X") + + " v1=0x" + epiBeqBneFallAddiuV1.ToString("X") + + " t5=0x" + epiBeqBneFallAddiuT5.ToString("X") + + " ra=0x" + epiBeqBneFallAddiuRa.ToString("X") + + " sp=0x" + epiBeqBneFallAddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $t1,$0,-10920; ALU $t1:=0xFFFFDB58;" + + " no invent *0xFFFFDB58 / *0xFFFFFC74 / SUD / KData / 0x8032 page / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 75d1028: after addiu exec, + // name first I-fetch at 0x8003F848. + // One-shot. Peek dump only — do + // not invent next word / dest / + // $t1 / *0xFFFFDB58 / $ra / 0x9A02 + // / 0x99FF / 0x8032 page / + // *0xFFFFFC74 / SUD / KData. Do + // not hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFall(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged + || _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged = true; + uint epiBeqBneFallNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallNoteDump); + uint epiBeqBneFallNoteRa = PeekGpr(regs, 31); + uint epiBeqBneFallNoteSp = PeekGpr(regs, 29); + uint epiBeqBneFallNoteT5 = PeekGpr(regs, 13); + uint epiBeqBneFallNoteT0 = PeekGpr(regs, 8); + uint epiBeqBneFallNoteT1 = PeekGpr(regs, 9); + uint epiBeqBneFallNoteV0 = PeekGpr(regs, 2); + uint epiBeqBneFallNoteV1 = PeekGpr(regs, 3); + uint epiBeqBneFallNoteA0 = PeekGpr(regs, 4); + uint epiBeqBneFallNoteA1 = PeekGpr(regs, 5); + uint epiBeqBneFallNoteA3 = PeekGpr(regs, 7); + string epiBeqBneFallNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqBneFallNoteDumpDis = epiBeqBneFallNoteDump != 0 + ? FormatMipsOp(pc, epiBeqBneFallNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-bne-fall"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallNoteDump != 0 + ? " dump=0x" + epiBeqBneFallNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-bne-fall" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallNoteDump != 0 + ? " dump=0x" + epiBeqBneFallNoteDump.ToString("X") : "") + + " dis=" + epiBeqBneFallNoteDis + + (epiBeqBneFallNoteDump != 0 + ? " dump-dis=" + epiBeqBneFallNoteDumpDis : "") + + " t5=0x" + epiBeqBneFallNoteT5.ToString("X") + + " t0=0x" + epiBeqBneFallNoteT0.ToString("X") + + " t1=0x" + epiBeqBneFallNoteT1.ToString("X") + + " a0=0x" + epiBeqBneFallNoteA0.ToString("X") + + " a1=0x" + epiBeqBneFallNoteA1.ToString("X") + + " a3=0x" + epiBeqBneFallNoteA3.ToString("X") + + " v0=0x" + epiBeqBneFallNoteV0.ToString("X") + + " v1=0x" + epiBeqBneFallNoteV1.ToString("X") + + " ra=0x" + epiBeqBneFallNoteRa.ToString("X") + + " sp=0x" + epiBeqBneFallNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall" + + " (first I-fetch after bne-fall addiu; peek dump, do not invent next word;" + + " honor ra; no jr hop; no invent $ra / *0xFFFFDB58 / 0x8032 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live d77479b: sw $v1,0($a2) at + // 0x8003F848 named only then TLBS + // + 0x9A02/0x9FFFF stk recurse + // re-landing on 0x8003F848. Same + // dest family as 0x8003F81C + // (0x8033FC74). Dest-miss skip; + // leave $v1/$a2/$t1. NEVER write + // / invent 0x8033 page / SUD / + // *0xFFFFDB58 / 0x9A02 / 0x99FF. + // PC:=0x8003F84C (dump jr $ra + // observe only; do not hop + // 0x8003F78C). Refuse MULT + // 0x8003F748 / SPECIAL 0x16. + // After skip, cap leaves + // >=0x8003F84C (stop storm). + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallSw(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + && _exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqBneFallSwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallSwDump) + || epiBeqBneFallSwDump == 0) + epiBeqBneFallSwDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNextDump; + if (epiBeqBneFallSwDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNextDump) + return false; + uint epiBeqBneFallSwNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext, + out epiBeqBneFallSwNextDump); + // Next is dump jr $ra (0x03E00008) — observe + // only later. Do not refuse this skip + // because next is jr. Still refuse MULT + // / SPECIAL 0x16 as next. + if (epiBeqBneFallSwNextDump != 0 && (epiBeqBneFallSwNextDump >> 26) == 0 + && ((epiBeqBneFallSwNextDump & 63) == 0x18 + || (epiBeqBneFallSwNextDump & 63) == 0x16)) + return false; + if (insn != epiBeqBneFallSwDump && insn != 0 && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiBeqBneFallSwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqBneFallSwDump); + uint epiBeqBneFallSwNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext; + if (epiBeqBneFallSwNext == 0 || (epiBeqBneFallSwNext & 3) != 0 + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqBneFallSwNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqBneFallSwNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqBneFallSwNext == CoredllDllMainExn15C28StkSwNext + || epiBeqBneFallSwNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqBneFallSwNext) + || IsExn15C28Na02Frame(epiBeqBneFallSwNext) + || IsExn15C28NfffFrame(epiBeqBneFallSwNext) + || IsExn15C28N9ffFrame(epiBeqBneFallSwNext) + || IsExn15C28HelperBody(epiBeqBneFallSwNext) + || IsExn15C28JalRaEpiRange(epiBeqBneFallSwNext) + || IsLeftoverDestVa(epiBeqBneFallSwNext) + || IsWrapDestSize(epiBeqBneFallSwNext) + || IsWrapDestFp50Va(epiBeqBneFallSwNext)) + return false; + uint epiBeqBneFallSwA2 = PeekGpr(regs, 6); + uint epiBeqBneFallSwV1 = PeekGpr(regs, 3); + uint epiBeqBneFallSwT1 = PeekGpr(regs, 9); + uint epiBeqBneFallSwDest = unchecked(epiBeqBneFallSwA2 + 0); + bool destSud = epiBeqBneFallSwDest == 0xFFFFFC74u + || epiBeqBneFallSwDest == 0xFFFFDB58u + || epiBeqBneFallSwDest >= 0xFFFF0000u + || (epiBeqBneFallSwDest & ~0xFFFu) == FfffF000Page + || IsC000StoreSkipVa(epiBeqBneFallSwDest) + || IsExn15C28StkRecurseFrame(epiBeqBneFallSwDest) + || IsLeftoverDestVa(epiBeqBneFallSwDest) + || IsWrapDestSize(epiBeqBneFallSwDest) + || IsWrapDestFp50Va(epiBeqBneFallSwDest) + || IsDumpMemRefuseVa(epiBeqBneFallSwDest); + uint epiBeqBneFallSwPeek = 0; + bool destOk = !destSud + && TryPeekExn15C28OuterJalLwT4Dest(bus, epiBeqBneFallSwDest, + out epiBeqBneFallSwPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqBneFallSwNext; + _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged = true; + _exn15C28AfterOuterJalEpiBeqBneFallSwLogged = true; + uint epiBeqBneFallSwRa = PeekGpr(regs, 31); + uint epiBeqBneFallSwSp = PeekGpr(regs, 29); + uint epiBeqBneFallSwT5 = PeekGpr(regs, 13); + uint epiBeqBneFallSwT0 = PeekGpr(regs, 8); + uint epiBeqBneFallSwV0 = PeekGpr(regs, 2); + uint epiBeqBneFallSwA0 = PeekGpr(regs, 4); + uint epiBeqBneFallSwA1 = PeekGpr(regs, 5); + uint epiBeqBneFallSwA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-beq-bne-fall-sw" + : "dump-mem-15c28-outer-jal-epi-beq-bne-fall-sw-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqBneFallSwDump.ToString("X") + + " dest=0x" + epiBeqBneFallSwDest.ToString("X") + + (destOk ? "" : " *a2-miss") + + (destSud ? " sud-refuse" : "") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-bne-fall-sw" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqBneFallSwNext.ToString("X") + + " dump=0x" + epiBeqBneFallSwDump.ToString("X") + + (insn != 0 && insn != epiBeqBneFallSwDump + ? " live=0x" + insn.ToString("X") : "") + + (epiBeqBneFallSwNextDump != 0 + ? " next-dump=0x" + epiBeqBneFallSwNextDump.ToString("X") : "") + + (destOk ? " sw=1" : " sw=0") + + " dest=0x" + epiBeqBneFallSwDest.ToString("X") + + (destOk ? "" : " *a2-miss") + + (destSud ? " sud-refuse" : "") + + " a2=0x" + epiBeqBneFallSwA2.ToString("X") + + " v1=0x" + epiBeqBneFallSwV1.ToString("X") + + " t1=0x" + epiBeqBneFallSwT1.ToString("X") + + " t0=0x" + epiBeqBneFallSwT0.ToString("X") + + " a0=0x" + epiBeqBneFallSwA0.ToString("X") + + " a1=0x" + epiBeqBneFallSwA1.ToString("X") + + " a3=0x" + epiBeqBneFallSwA3.ToString("X") + + " v0=0x" + epiBeqBneFallSwV0.ToString("X") + + " t5=0x" + epiBeqBneFallSwT5.ToString("X") + + " ra=0x" + epiBeqBneFallSwRa.ToString("X") + + " sp=0x" + epiBeqBneFallSwSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sw $v1,0($a2); dest-miss skip; leave $v1/$a2/$t1;" + + " NEVER write 0x8033FC74 / SUD 0xFFFFFC74 / *0xFFFFDB58;" + + " no invent 0x8033 page / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live d77479b: after dest-miss + // skip, name first I-fetch at + // 0x8003F84C. One-shot. Peek dump + // only — do not invent next word + // / dest / $t1 / *0xFFFFDB58 / + // $ra / 0x9A02 / 0x99FF / 0x8033 + // page / *0xFFFFFC74 / SUD / + // KData. Do not hop MUL / jr + // 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallSw(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqBneFallSwLogged + || _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged = true; + uint epiBeqBneFallSwNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallSwNoteDump); + uint epiBeqBneFallSwNoteRa = PeekGpr(regs, 31); + uint epiBeqBneFallSwNoteSp = PeekGpr(regs, 29); + uint epiBeqBneFallSwNoteT5 = PeekGpr(regs, 13); + uint epiBeqBneFallSwNoteT0 = PeekGpr(regs, 8); + uint epiBeqBneFallSwNoteT1 = PeekGpr(regs, 9); + uint epiBeqBneFallSwNoteV0 = PeekGpr(regs, 2); + uint epiBeqBneFallSwNoteV1 = PeekGpr(regs, 3); + uint epiBeqBneFallSwNoteA0 = PeekGpr(regs, 4); + uint epiBeqBneFallSwNoteA1 = PeekGpr(regs, 5); + uint epiBeqBneFallSwNoteA2 = PeekGpr(regs, 6); + uint epiBeqBneFallSwNoteA3 = PeekGpr(regs, 7); + string epiBeqBneFallSwNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqBneFallSwNoteDumpDis = epiBeqBneFallSwNoteDump != 0 + ? FormatMipsOp(pc, epiBeqBneFallSwNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallSwNoteDump != 0 + ? " dump=0x" + epiBeqBneFallSwNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-bne-fall-sw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallSwNoteDump != 0 + ? " dump=0x" + epiBeqBneFallSwNoteDump.ToString("X") : "") + + " dis=" + epiBeqBneFallSwNoteDis + + (epiBeqBneFallSwNoteDump != 0 + ? " dump-dis=" + epiBeqBneFallSwNoteDumpDis : "") + + " t5=0x" + epiBeqBneFallSwNoteT5.ToString("X") + + " t0=0x" + epiBeqBneFallSwNoteT0.ToString("X") + + " t1=0x" + epiBeqBneFallSwNoteT1.ToString("X") + + " a0=0x" + epiBeqBneFallSwNoteA0.ToString("X") + + " a1=0x" + epiBeqBneFallSwNoteA1.ToString("X") + + " a2=0x" + epiBeqBneFallSwNoteA2.ToString("X") + + " a3=0x" + epiBeqBneFallSwNoteA3.ToString("X") + + " v0=0x" + epiBeqBneFallSwNoteV0.ToString("X") + + " v1=0x" + epiBeqBneFallSwNoteV1.ToString("X") + + " ra=0x" + epiBeqBneFallSwNoteRa.ToString("X") + + " sp=0x" + epiBeqBneFallSwNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-sw" + + " (first I-fetch after fall sw dest-miss skip; peek dump, do not invent next word;" + + " honor ra; no jr hop; no invent $ra / *0xFFFFDB58 / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live f438996: jr $ra at + // 0x8003F84C named only. $ra is + // still outer link 0x8003F78C + // (lw-ra skipped). Do not jr hop. + // Delay 0x8003F850 dump + // sw $zero,0($t1) dest + // 0xFFFFDB58 — dest-miss skip; + // NEVER write / invent + // *0xFFFFDB58 / SUD. PC:=0x8003F854 + // (dump addiu observe only). + // Refuse MULT 0x8003F748 / + // SPECIAL 0x16. After skip, cap + // leaves >=0x8003F854 (stop + // 0x9A/0x9FFFF storm). Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallJr(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqBneFallSwLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqBneFallJrDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallJrDump) + || epiBeqBneFallJrDump == 0) + epiBeqBneFallJrDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNextDump; + if (epiBeqBneFallJrDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNextDump) + return false; + uint epiBeqBneFallJrDelayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay, + out epiBeqBneFallJrDelayDump) + || epiBeqBneFallJrDelayDump == 0) + epiBeqBneFallJrDelayDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelayDump; + if (epiBeqBneFallJrDelayDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelayDump) + return false; + uint epiBeqBneFallJrNextDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext, + out epiBeqBneFallJrNextDump) + || epiBeqBneFallJrNextDump == 0) + epiBeqBneFallJrNextDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump; + if (epiBeqBneFallJrNextDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump) + return false; + if ((epiBeqBneFallJrNextDump >> 26) == 0 + && ((epiBeqBneFallJrNextDump & 63) == 0x18 + || (epiBeqBneFallJrNextDump & 63) == 0x16 + || (epiBeqBneFallJrNextDump & 63) == 0x08)) + return false; + if (insn != epiBeqBneFallJrDump && insn != 0 && !IsMipsJumpOrJr(insn) + && !IsMipsStore(insn) && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqBneFallJrDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqBneFallJrDump); + uint epiBeqBneFallJrNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext; + if (epiBeqBneFallJrNext == 0 || (epiBeqBneFallJrNext & 3) != 0 + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqBneFallJrNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqBneFallJrNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqBneFallJrNext == CoredllDllMainExn15C28StkSwNext + || epiBeqBneFallJrNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqBneFallJrNext) + || IsExn15C28Na02Frame(epiBeqBneFallJrNext) + || IsExn15C28NfffFrame(epiBeqBneFallJrNext) + || IsExn15C28N9ffFrame(epiBeqBneFallJrNext) + || IsExn15C28HelperBody(epiBeqBneFallJrNext) + || IsExn15C28JalRaEpiRange(epiBeqBneFallJrNext) + || IsLeftoverDestVa(epiBeqBneFallJrNext) + || IsWrapDestSize(epiBeqBneFallJrNext) + || IsWrapDestFp50Va(epiBeqBneFallJrNext)) + return false; + uint epiBeqBneFallJrT1 = PeekGpr(regs, 9); + uint epiBeqBneFallJrDelayDest = unchecked(epiBeqBneFallJrT1 + 0); + bool destSud = epiBeqBneFallJrDelayDest == 0xFFFFDB58u + || epiBeqBneFallJrDelayDest == 0xFFFFFC74u + || epiBeqBneFallJrDelayDest >= 0xFFFF0000u + || (epiBeqBneFallJrDelayDest & ~0xFFFu) == FfffF000Page + || IsC000StoreSkipVa(epiBeqBneFallJrDelayDest) + || IsExn15C28StkRecurseFrame(epiBeqBneFallJrDelayDest) + || IsLeftoverDestVa(epiBeqBneFallJrDelayDest) + || IsWrapDestSize(epiBeqBneFallJrDelayDest) + || IsWrapDestFp50Va(epiBeqBneFallJrDelayDest) + || IsDumpMemRefuseVa(epiBeqBneFallJrDelayDest); + uint epiBeqBneFallJrPeek = 0; + bool destOk = !destSud + && TryPeekExn15C28OuterJalLwT4Dest(bus, epiBeqBneFallJrDelayDest, + out epiBeqBneFallJrPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqBneFallJrNext; + _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged = true; + _exn15C28AfterOuterJalEpiBeqBneFallJrLogged = true; + TrySaveExn15C28Fn854OuterRa(regs); + uint epiBeqBneFallJrRa = PeekGpr(regs, 31); + uint epiBeqBneFallJrSp = PeekGpr(regs, 29); + uint epiBeqBneFallJrT5 = PeekGpr(regs, 13); + uint epiBeqBneFallJrT0 = PeekGpr(regs, 8); + uint epiBeqBneFallJrV0 = PeekGpr(regs, 2); + uint epiBeqBneFallJrV1 = PeekGpr(regs, 3); + uint epiBeqBneFallJrA0 = PeekGpr(regs, 4); + uint epiBeqBneFallJrA1 = PeekGpr(regs, 5); + uint epiBeqBneFallJrA2 = PeekGpr(regs, 6); + uint epiBeqBneFallJrA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-beq-bne-fall-jr" + : "dump-mem-15c28-outer-jal-epi-beq-bne-fall-jr-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqBneFallJrDump.ToString("X") + + " dest=0x" + epiBeqBneFallJrDelayDest.ToString("X") + + (destOk ? "" : " *t1-miss") + + (destSud ? " sud-refuse" : "") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-bne-fall-jr" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqBneFallJrNext.ToString("X") + + " dump=0x" + epiBeqBneFallJrDump.ToString("X") + + (insn != 0 && insn != epiBeqBneFallJrDump + ? " live=0x" + insn.ToString("X") : "") + + " delay=0x" + epiBeqBneFallJrDelayDump.ToString("X") + + (destOk ? " sw=1" : " sw=0") + + " dest=0x" + epiBeqBneFallJrDelayDest.ToString("X") + + (destOk ? "" : " *t1-miss") + + (destSud ? " sud-refuse" : "") + + " t1=0x" + epiBeqBneFallJrT1.ToString("X") + + " t0=0x" + epiBeqBneFallJrT0.ToString("X") + + " a0=0x" + epiBeqBneFallJrA0.ToString("X") + + " a1=0x" + epiBeqBneFallJrA1.ToString("X") + + " a2=0x" + epiBeqBneFallJrA2.ToString("X") + + " a3=0x" + epiBeqBneFallJrA3.ToString("X") + + " v0=0x" + epiBeqBneFallJrV0.ToString("X") + + " v1=0x" + epiBeqBneFallJrV1.ToString("X") + + " t5=0x" + epiBeqBneFallJrT5.ToString("X") + + " ra=0x" + epiBeqBneFallJrRa.ToString("X") + + " sp=0x" + epiBeqBneFallJrSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump jr $ra; no hop 0x8003F78C;" + + " delay sw $zero,0($t1) dest-miss skip; leave $t1;" + + " NEVER write *0xFFFFDB58 / SUD 0xFFFFFC74;" + + " no invent 0x9A02 / 0x99FF; no MULT 0x8003F748)"); + return true; + } + + // Live f438996: after jr skip + + // delay dest-miss, name first + // I-fetch at 0x8003F854. One-shot. + // Peek dump only — do not invent + // next word / dest / $t1 / + // *0xFFFFDB58 / $ra / 0x9A02 / + // 0x99FF / 0x8033 page / + // *0xFFFFFC74 / SUD / KData. Do + // not hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallJr(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqBneFallJrLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged = true; + uint epiBeqBneFallJrNoteDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallJrNoteDump) + || epiBeqBneFallJrNoteDump == 0) + epiBeqBneFallJrNoteDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump; + uint epiBeqBneFallJrNoteRa = PeekGpr(regs, 31); + uint epiBeqBneFallJrNoteSp = PeekGpr(regs, 29); + uint epiBeqBneFallJrNoteT5 = PeekGpr(regs, 13); + uint epiBeqBneFallJrNoteT0 = PeekGpr(regs, 8); + uint epiBeqBneFallJrNoteT1 = PeekGpr(regs, 9); + uint epiBeqBneFallJrNoteV0 = PeekGpr(regs, 2); + uint epiBeqBneFallJrNoteV1 = PeekGpr(regs, 3); + uint epiBeqBneFallJrNoteA0 = PeekGpr(regs, 4); + uint epiBeqBneFallJrNoteA1 = PeekGpr(regs, 5); + uint epiBeqBneFallJrNoteA2 = PeekGpr(regs, 6); + uint epiBeqBneFallJrNoteA3 = PeekGpr(regs, 7); + string epiBeqBneFallJrNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqBneFallJrNoteDumpDis = epiBeqBneFallJrNoteDump != 0 + ? FormatMipsOp(pc, epiBeqBneFallJrNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallJrNoteDump != 0 + ? " dump=0x" + epiBeqBneFallJrNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-bne-fall-jr" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallJrNoteDump != 0 + ? " dump=0x" + epiBeqBneFallJrNoteDump.ToString("X") : "") + + " dis=" + epiBeqBneFallJrNoteDis + + (epiBeqBneFallJrNoteDump != 0 + ? " dump-dis=" + epiBeqBneFallJrNoteDumpDis : "") + + " t5=0x" + epiBeqBneFallJrNoteT5.ToString("X") + + " t0=0x" + epiBeqBneFallJrNoteT0.ToString("X") + + " t1=0x" + epiBeqBneFallJrNoteT1.ToString("X") + + " a0=0x" + epiBeqBneFallJrNoteA0.ToString("X") + + " a1=0x" + epiBeqBneFallJrNoteA1.ToString("X") + + " a2=0x" + epiBeqBneFallJrNoteA2.ToString("X") + + " a3=0x" + epiBeqBneFallJrNoteA3.ToString("X") + + " v0=0x" + epiBeqBneFallJrNoteV0.ToString("X") + + " v1=0x" + epiBeqBneFallJrNoteV1.ToString("X") + + " ra=0x" + epiBeqBneFallJrNoteRa.ToString("X") + + " sp=0x" + epiBeqBneFallJrNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr" + + " (first I-fetch after fall jr skip + delay dest-miss; peek dump, do not invent next word;" + + " honor ra; no jr hop; no invent $ra / *0xFFFFDB58 / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live c4c77e1: addiu $sp,$sp,-48 + // at 0x8003F854 named only. Exec + // dump addiu (ALU $sp:=$sp-48; + // $sp may stay 0x9A — ALU write + // only; do not invent 0x9A page). + // PC:=0x8003F858 (sequential + // dump-true +4; observe only; + // peek dump, do not invent next + // word). Refuse jr hop 0x8003F78C + // / MULT 0x8003F748 / SPECIAL + // 0x16. Not LoadO32. No leftover- + // hop. Do not invent 0x8032 / + // 0x8033 page / SUD / 0x9A02 / + // 0x99FF / *0xFFFFFC74 / + // *0xFFFFDB58 / KData. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqBneFallJrLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + && _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqBneFallJrAddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallJrAddiuDump) + || epiBeqBneFallJrAddiuDump == 0) + epiBeqBneFallJrAddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump; + if (epiBeqBneFallJrAddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNextDump) + return false; + uint epiBeqBneFallJrAddiuNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext, + out epiBeqBneFallJrAddiuNextDump); + if (epiBeqBneFallJrAddiuNextDump != 0 && (epiBeqBneFallJrAddiuNextDump >> 26) == 0 + && ((epiBeqBneFallJrAddiuNextDump & 63) == 0x18 + || (epiBeqBneFallJrAddiuNextDump & 63) == 0x16 + || (epiBeqBneFallJrAddiuNextDump & 63) == 0x08)) + return false; + if (insn != epiBeqBneFallJrAddiuDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != epiBeqBneFallJrAddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqBneFallJrAddiuDump); + uint epiBeqBneFallJrAddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext; + if (epiBeqBneFallJrAddiuNext == 0 || (epiBeqBneFallJrAddiuNext & 3) != 0 + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqBneFallJrAddiuNext == CoredllDllMainExn15C28StkSwNext + || epiBeqBneFallJrAddiuNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqBneFallJrAddiuNext) + || IsExn15C28Na02Frame(epiBeqBneFallJrAddiuNext) + || IsExn15C28NfffFrame(epiBeqBneFallJrAddiuNext) + || IsExn15C28N9ffFrame(epiBeqBneFallJrAddiuNext) + || IsExn15C28HelperBody(epiBeqBneFallJrAddiuNext) + || IsExn15C28JalRaEpiRange(epiBeqBneFallJrAddiuNext) + || IsLeftoverDestVa(epiBeqBneFallJrAddiuNext) + || IsWrapDestSize(epiBeqBneFallJrAddiuNext) + || IsWrapDestFp50Va(epiBeqBneFallJrAddiuNext)) + return false; + bool epiBeqBneFallJrAddiuOk = TryExecDumpMemAlu(regs, epiBeqBneFallJrAddiuDump); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqBneFallJrAddiuNext; + _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged = true; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged = true; + TrySaveExn15C28Fn854OuterRa(regs); + uint epiBeqBneFallJrAddiuRa = PeekGpr(regs, 31); + uint epiBeqBneFallJrAddiuSp = PeekGpr(regs, 29); + uint epiBeqBneFallJrAddiuT5 = PeekGpr(regs, 13); + uint epiBeqBneFallJrAddiuT0 = PeekGpr(regs, 8); + uint epiBeqBneFallJrAddiuT1 = PeekGpr(regs, 9); + uint epiBeqBneFallJrAddiuV0 = PeekGpr(regs, 2); + uint epiBeqBneFallJrAddiuV1 = PeekGpr(regs, 3); + uint epiBeqBneFallJrAddiuA0 = PeekGpr(regs, 4); + uint epiBeqBneFallJrAddiuA1 = PeekGpr(regs, 5); + uint epiBeqBneFallJrAddiuA2 = PeekGpr(regs, 6); + uint epiBeqBneFallJrAddiuA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = epiBeqBneFallJrAddiuOk + ? "dump-mem-15c28-outer-jal-epi-beq-bne-fall-jr-addiu" + : "dump-mem-15c28-outer-jal-epi-beq-bne-fall-jr-addiu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqBneFallJrAddiuDump.ToString("X") + + " dest=0x" + epiBeqBneFallJrAddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-bne-fall-jr-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqBneFallJrAddiuNext.ToString("X") + + " dump=0x" + epiBeqBneFallJrAddiuDump.ToString("X") + + (insn != 0 && insn != epiBeqBneFallJrAddiuDump + ? " live=0x" + insn.ToString("X") : "") + + (epiBeqBneFallJrAddiuNextDump != 0 + ? " next-dump=0x" + epiBeqBneFallJrAddiuNextDump.ToString("X") : "") + + (epiBeqBneFallJrAddiuOk ? " addiu=1" : " addiu=0") + + " t1=0x" + epiBeqBneFallJrAddiuT1.ToString("X") + + " t0=0x" + epiBeqBneFallJrAddiuT0.ToString("X") + + " a0=0x" + epiBeqBneFallJrAddiuA0.ToString("X") + + " a1=0x" + epiBeqBneFallJrAddiuA1.ToString("X") + + " a2=0x" + epiBeqBneFallJrAddiuA2.ToString("X") + + " a3=0x" + epiBeqBneFallJrAddiuA3.ToString("X") + + " v0=0x" + epiBeqBneFallJrAddiuV0.ToString("X") + + " v1=0x" + epiBeqBneFallJrAddiuV1.ToString("X") + + " t5=0x" + epiBeqBneFallJrAddiuT5.ToString("X") + + " ra=0x" + epiBeqBneFallJrAddiuRa.ToString("X") + + " sp=0x" + epiBeqBneFallJrAddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $sp,$sp,-48; ALU $sp:=$sp-48; no invent 0x9A page / *0xFFFFDB58 / *0xFFFFFC74 / SUD / KData / 0x8033 page / 0x9A02 / 0x99FF;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live c4c77e1: after addiu exec, + // name first I-fetch at 0x8003F858. + // One-shot. Peek dump only — do + // not invent next word / dest / + // $sp / 0x9A page / *0xFFFFDB58 / + // $ra / 0x9A02 / 0x99FF / 0x8033 + // page / *0xFFFFFC74 / SUD / + // KData. Do not hop MUL / jr + // 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiu(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged = true; + uint epiBeqBneFallJrAddiuNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallJrAddiuNoteDump); + uint epiBeqBneFallJrAddiuNoteRa = PeekGpr(regs, 31); + uint epiBeqBneFallJrAddiuNoteSp = PeekGpr(regs, 29); + uint epiBeqBneFallJrAddiuNoteT5 = PeekGpr(regs, 13); + uint epiBeqBneFallJrAddiuNoteT0 = PeekGpr(regs, 8); + uint epiBeqBneFallJrAddiuNoteT1 = PeekGpr(regs, 9); + uint epiBeqBneFallJrAddiuNoteV0 = PeekGpr(regs, 2); + uint epiBeqBneFallJrAddiuNoteV1 = PeekGpr(regs, 3); + uint epiBeqBneFallJrAddiuNoteA0 = PeekGpr(regs, 4); + uint epiBeqBneFallJrAddiuNoteA1 = PeekGpr(regs, 5); + uint epiBeqBneFallJrAddiuNoteA2 = PeekGpr(regs, 6); + uint epiBeqBneFallJrAddiuNoteA3 = PeekGpr(regs, 7); + string epiBeqBneFallJrAddiuNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqBneFallJrAddiuNoteDumpDis = epiBeqBneFallJrAddiuNoteDump != 0 + ? FormatMipsOp(pc, epiBeqBneFallJrAddiuNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallJrAddiuNoteDump != 0 + ? " dump=0x" + epiBeqBneFallJrAddiuNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-bne-fall-jr-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallJrAddiuNoteDump != 0 + ? " dump=0x" + epiBeqBneFallJrAddiuNoteDump.ToString("X") : "") + + " dis=" + epiBeqBneFallJrAddiuNoteDis + + (epiBeqBneFallJrAddiuNoteDump != 0 + ? " dump-dis=" + epiBeqBneFallJrAddiuNoteDumpDis : "") + + " t5=0x" + epiBeqBneFallJrAddiuNoteT5.ToString("X") + + " t0=0x" + epiBeqBneFallJrAddiuNoteT0.ToString("X") + + " t1=0x" + epiBeqBneFallJrAddiuNoteT1.ToString("X") + + " a0=0x" + epiBeqBneFallJrAddiuNoteA0.ToString("X") + + " a1=0x" + epiBeqBneFallJrAddiuNoteA1.ToString("X") + + " a2=0x" + epiBeqBneFallJrAddiuNoteA2.ToString("X") + + " a3=0x" + epiBeqBneFallJrAddiuNoteA3.ToString("X") + + " v0=0x" + epiBeqBneFallJrAddiuNoteV0.ToString("X") + + " v1=0x" + epiBeqBneFallJrAddiuNoteV1.ToString("X") + + " ra=0x" + epiBeqBneFallJrAddiuNoteRa.ToString("X") + + " sp=0x" + epiBeqBneFallJrAddiuNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr-addiu" + + " (first I-fetch after fall jr-addiu; peek dump, do not invent next word;" + + " honor ra; no jr hop; no invent $ra / 0x9A page / *0xFFFFDB58 / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + // Live 89f8975: sw $ra,40($sp) at + // 0x8003F858 named only. Dest + // $sp+40=0x9A023EA0 — same 0x9A02 + // dest-miss family. Continue-skip; + // leave $ra/$sp. NEVER write / + // invent 0x9A page / *0xFFFFDB58 + // / SUD / E000 / F000. PC:= + // 0x8003F85C (dump sw $fp observe + // only; peek dump, do not invent + // next word). Refuse jr hop + // 0x8003F78C / MULT 0x8003F748 / + // SPECIAL 0x16. After skip, cap + // leaves >=0x8003F85C (stop + // 0x9A/0x9FFFF storm). Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiuSw(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext) + return false; + if (_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + && _exn15C28AfterOuterJalEpiPrologueSwLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV1AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiV0AddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint epiBeqBneFallJrAddiuSwDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallJrAddiuSwDump) + || epiBeqBneFallJrAddiuSwDump == 0) + epiBeqBneFallJrAddiuSwDump = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNextDump; + if (epiBeqBneFallJrAddiuSwDump != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNextDump) + return false; + uint epiBeqBneFallJrAddiuSwNextDump = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext, + out epiBeqBneFallJrAddiuSwNextDump); + if (epiBeqBneFallJrAddiuSwNextDump != 0 && (epiBeqBneFallJrAddiuSwNextDump >> 26) == 0 + && ((epiBeqBneFallJrAddiuSwNextDump & 63) == 0x18 + || (epiBeqBneFallJrAddiuSwNextDump & 63) == 0x16 + || (epiBeqBneFallJrAddiuSwNextDump & 63) == 0x08)) + return false; + if (insn != epiBeqBneFallJrAddiuSwDump && insn != 0 && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != epiBeqBneFallJrAddiuSwDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, epiBeqBneFallJrAddiuSwDump); + uint epiBeqBneFallJrAddiuSwNext = CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext; + if (epiBeqBneFallJrAddiuSwNext == 0 || (epiBeqBneFallJrAddiuSwNext & 3) != 0 + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqSltNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqAddiuNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqTaken + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiSltuNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LhuNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2SwNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2Sw + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA2AddiuNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiLhuNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiA3LuiNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiLuiNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkEpiJrNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLink + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28JalS1AluNext + || epiBeqBneFallJrAddiuSwNext == CoredllDllMainExn15C28StkSwNext + || epiBeqBneFallJrAddiuSwNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(epiBeqBneFallJrAddiuSwNext) + || IsExn15C28Na02Frame(epiBeqBneFallJrAddiuSwNext) + || IsExn15C28NfffFrame(epiBeqBneFallJrAddiuSwNext) + || IsExn15C28N9ffFrame(epiBeqBneFallJrAddiuSwNext) + || IsExn15C28HelperBody(epiBeqBneFallJrAddiuSwNext) + || IsExn15C28JalRaEpiRange(epiBeqBneFallJrAddiuSwNext) + || IsLeftoverDestVa(epiBeqBneFallJrAddiuSwNext) + || IsWrapDestSize(epiBeqBneFallJrAddiuSwNext) + || IsWrapDestFp50Va(epiBeqBneFallJrAddiuSwNext)) + return false; + uint epiBeqBneFallJrAddiuSwSp = PeekGpr(regs, 29); + uint epiBeqBneFallJrAddiuSwRa = PeekGpr(regs, 31); + uint epiBeqBneFallJrAddiuSwDest = unchecked(epiBeqBneFallJrAddiuSwSp + 40); + bool destSud = epiBeqBneFallJrAddiuSwDest == 0xFFFFFC74u + || epiBeqBneFallJrAddiuSwDest == 0xFFFFDB58u + || epiBeqBneFallJrAddiuSwDest >= 0xFFFF0000u + || (epiBeqBneFallJrAddiuSwDest & ~0xFFFu) == FfffF000Page + || IsC000StoreSkipVa(epiBeqBneFallJrAddiuSwDest) + || IsExn15C28StkRecurseFrame(epiBeqBneFallJrAddiuSwDest) + || IsLeftoverDestVa(epiBeqBneFallJrAddiuSwDest) + || IsWrapDestSize(epiBeqBneFallJrAddiuSwDest) + || IsWrapDestFp50Va(epiBeqBneFallJrAddiuSwDest) + || IsDumpMemRefuseVa(epiBeqBneFallJrAddiuSwDest); + uint epiBeqBneFallJrAddiuSwPeek = 0; + bool destOk = !destSud + && TryPeekExn15C28OuterJalLwT4Dest(bus, epiBeqBneFallJrAddiuSwDest, + out epiBeqBneFallJrAddiuSwPeek); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = epiBeqBneFallJrAddiuSwNext; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged = true; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged = true; + uint epiBeqBneFallJrAddiuSwT5 = PeekGpr(regs, 13); + uint epiBeqBneFallJrAddiuSwT0 = PeekGpr(regs, 8); + uint epiBeqBneFallJrAddiuSwT1 = PeekGpr(regs, 9); + uint epiBeqBneFallJrAddiuSwV0 = PeekGpr(regs, 2); + uint epiBeqBneFallJrAddiuSwV1 = PeekGpr(regs, 3); + uint epiBeqBneFallJrAddiuSwA0 = PeekGpr(regs, 4); + uint epiBeqBneFallJrAddiuSwA1 = PeekGpr(regs, 5); + uint epiBeqBneFallJrAddiuSwA2 = PeekGpr(regs, 6); + uint epiBeqBneFallJrAddiuSwA3 = PeekGpr(regs, 7); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-beq-bne-fall-jr-addiu-sw" + : "dump-mem-15c28-outer-jal-epi-beq-bne-fall-jr-addiu-sw-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + epiBeqBneFallJrAddiuSwDump.ToString("X") + + " dest=0x" + epiBeqBneFallJrAddiuSwDest.ToString("X") + + (destOk ? "" : " *sp-miss") + + (destSud ? " sud-refuse" : "") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-beq-bne-fall-jr-addiu-sw" + + " pc=0x" + pc.ToString("X") + + " next=0x" + epiBeqBneFallJrAddiuSwNext.ToString("X") + + " dump=0x" + epiBeqBneFallJrAddiuSwDump.ToString("X") + + (insn != 0 && insn != epiBeqBneFallJrAddiuSwDump + ? " live=0x" + insn.ToString("X") : "") + + (epiBeqBneFallJrAddiuSwNextDump != 0 + ? " next-dump=0x" + epiBeqBneFallJrAddiuSwNextDump.ToString("X") : "") + + (destOk ? " sw=1" : " sw=0") + + " dest=0x" + epiBeqBneFallJrAddiuSwDest.ToString("X") + + (destOk ? "" : " *sp-miss") + + (destSud ? " sud-refuse" : "") + + " t1=0x" + epiBeqBneFallJrAddiuSwT1.ToString("X") + + " t0=0x" + epiBeqBneFallJrAddiuSwT0.ToString("X") + + " a0=0x" + epiBeqBneFallJrAddiuSwA0.ToString("X") + + " a1=0x" + epiBeqBneFallJrAddiuSwA1.ToString("X") + + " a2=0x" + epiBeqBneFallJrAddiuSwA2.ToString("X") + + " a3=0x" + epiBeqBneFallJrAddiuSwA3.ToString("X") + + " v0=0x" + epiBeqBneFallJrAddiuSwV0.ToString("X") + + " v1=0x" + epiBeqBneFallJrAddiuSwV1.ToString("X") + + " t5=0x" + epiBeqBneFallJrAddiuSwT5.ToString("X") + + " ra=0x" + epiBeqBneFallJrAddiuSwRa.ToString("X") + + " sp=0x" + epiBeqBneFallJrAddiuSwSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sw $ra,40($sp); dest-miss skip; leave $ra/$sp;" + + " NEVER write 0x9A page / *0xFFFFDB58 / SUD 0xFFFFFC74 / E000 / F000;" + + " no invent 0x9A02 / 0x99FF / 0x8033 page;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 89f8975: after dest-miss + // skip, name first I-fetch at + // 0x8003F85C. One-shot. Peek dump + // only — do not invent next word + // / dest / 0x9A page / *0xFFFFDB58 + // / $ra / 0x9A02 / 0x99FF / 0x8033 + // page / *0xFFFFFC74 / SUD / + // E000 / F000 / KData. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiuSw(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged + || _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged = true; + uint epiBeqBneFallJrAddiuSwNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out epiBeqBneFallJrAddiuSwNoteDump); + uint epiBeqBneFallJrAddiuSwNoteRa = PeekGpr(regs, 31); + uint epiBeqBneFallJrAddiuSwNoteSp = PeekGpr(regs, 29); + uint epiBeqBneFallJrAddiuSwNoteT5 = PeekGpr(regs, 13); + uint epiBeqBneFallJrAddiuSwNoteT0 = PeekGpr(regs, 8); + uint epiBeqBneFallJrAddiuSwNoteT1 = PeekGpr(regs, 9); + uint epiBeqBneFallJrAddiuSwNoteV0 = PeekGpr(regs, 2); + uint epiBeqBneFallJrAddiuSwNoteV1 = PeekGpr(regs, 3); + uint epiBeqBneFallJrAddiuSwNoteA0 = PeekGpr(regs, 4); + uint epiBeqBneFallJrAddiuSwNoteA1 = PeekGpr(regs, 5); + uint epiBeqBneFallJrAddiuSwNoteA2 = PeekGpr(regs, 6); + uint epiBeqBneFallJrAddiuSwNoteA3 = PeekGpr(regs, 7); + string epiBeqBneFallJrAddiuSwNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string epiBeqBneFallJrAddiuSwNoteDumpDis = epiBeqBneFallJrAddiuSwNoteDump != 0 + ? FormatMipsOp(pc, epiBeqBneFallJrAddiuSwNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr-addiu-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallJrAddiuSwNoteDump != 0 + ? " dump=0x" + epiBeqBneFallJrAddiuSwNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr-addiu-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-beq-bne-fall-jr-addiu-sw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (epiBeqBneFallJrAddiuSwNoteDump != 0 + ? " dump=0x" + epiBeqBneFallJrAddiuSwNoteDump.ToString("X") : "") + + " dis=" + epiBeqBneFallJrAddiuSwNoteDis + + (epiBeqBneFallJrAddiuSwNoteDump != 0 + ? " dump-dis=" + epiBeqBneFallJrAddiuSwNoteDumpDis : "") + + " t5=0x" + epiBeqBneFallJrAddiuSwNoteT5.ToString("X") + + " t0=0x" + epiBeqBneFallJrAddiuSwNoteT0.ToString("X") + + " t1=0x" + epiBeqBneFallJrAddiuSwNoteT1.ToString("X") + + " a0=0x" + epiBeqBneFallJrAddiuSwNoteA0.ToString("X") + + " a1=0x" + epiBeqBneFallJrAddiuSwNoteA1.ToString("X") + + " a2=0x" + epiBeqBneFallJrAddiuSwNoteA2.ToString("X") + + " a3=0x" + epiBeqBneFallJrAddiuSwNoteA3.ToString("X") + + " v0=0x" + epiBeqBneFallJrAddiuSwNoteV0.ToString("X") + + " v1=0x" + epiBeqBneFallJrAddiuSwNoteV1.ToString("X") + + " ra=0x" + epiBeqBneFallJrAddiuSwNoteRa.ToString("X") + + " sp=0x" + epiBeqBneFallJrAddiuSwNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-beq-bne-fall-jr-addiu-sw" + + " (first I-fetch after fall jr-addiu sw dest-miss skip; peek dump, do not invent next word;" + + " honor ra; no jr hop; no invent $ra / 0x9A page / *0xFFFFDB58 / 0x8033 page / *0xFFFFFC74 / 0x9A02 / 0x99FF)"); + } + + private static uint DumpMem15C28PrologueSwDump(uint pc) + { + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueSwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw2) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw2Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw3) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw3Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw4) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw4Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw5) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw5Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw6) + return CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw6Dump; + return 0; + } + + private static bool IsExn15C28PrologueSwPc(uint pc) + { + return pc >= CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw6 + && (pc & 3) == 0; + } + + // Live 1099cb8: sw $fp/$s7/$s6/ + // $s5/$s4/$s3 at 0x8003F85C– + // 0x8003F870 named only. Dest + // $sp+16..36 = 0x9A023E88..9C — + // same 0x9A02 dest-miss family. + // Continue-skip all six; leave + // regs. NEVER write / invent 0x9A + // page / *0xFFFFDB58 / SUD / E000 + // / F000. PC:=0x8003F874 (dump + // jal observe only). Refuse jr + // hop 0x8003F78C / MULT + // 0x8003F748 / SPECIAL 0x16. + // After skip, cap leaves + // >=0x8003F874 (stop 0x9A/0x9FFFF + // storm). Not LoadO32. No leftover- + // hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiPrologueSw(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged) + return false; + if (_exn15C28AfterOuterJalEpiPrologueSwLogged) + { + if (inDelay) + return false; + if (!IsExn15C28PrologueSwPc(pc) + && pc != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || IsExn15C28PrologueSwPc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + && _exn15C28AfterOuterJalEpiPrologueJalLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && _exn15C28AfterOuterJalEpiTrampolineLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrDelay + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (!IsExn15C28PrologueSwPc(pc)) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint prologueSwFirst = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out prologueSwFirst) + || prologueSwFirst == 0) + prologueSwFirst = DumpMem15C28PrologueSwDump(pc); + if (prologueSwFirst == 0 || prologueSwFirst != DumpMem15C28PrologueSwDump(pc)) + return false; + if (insn != prologueSwFirst && insn != 0 && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != prologueSwFirst && insn != 0) + TryHealDumpInsn(bus, pc, insn, prologueSwFirst); + int prologueSwN = 0; + uint prologueSwSp = PeekGpr(regs, 29); + for (uint p = pc; p <= CoredllDllMainExn15C28OuterJalLinkEpiPrologueSw6; p += 4) + { + uint prologueSwDump = DumpMem15C28PrologueSwDump(p); + uint prologueSwPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly(p, out prologueSwPeek) + || prologueSwPeek == 0) + prologueSwPeek = prologueSwDump; + if (prologueSwDump == 0 || prologueSwPeek != prologueSwDump) + return false; + if ((prologueSwDump >> 26) != 43) + return false; + uint prologueSwImm = (uint)(short)(prologueSwDump & 0xFFFF); + uint prologueSwDest = unchecked(prologueSwSp + prologueSwImm); + if (prologueSwDest == 0xFFFFFC74u + || prologueSwDest == 0xFFFFDB58u + || prologueSwDest >= 0xFFFF0000u + || (prologueSwDest & ~0xFFFu) == FfffF000Page + || IsC000StoreSkipVa(prologueSwDest) + || IsLeftoverDestVa(prologueSwDest) + || IsWrapDestSize(prologueSwDest) + || IsWrapDestFp50Va(prologueSwDest) + || IsDumpMemRefuseVa(prologueSwDest)) + return false; + if (!IsExn15C28StkRecurseFrame(prologueSwDest) + && !IsExn15C28StkRecurseFrame(prologueSwSp)) + return false; + prologueSwN++; + } + uint prologueSwNext = CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal; + if (prologueSwNext == 0 || (prologueSwNext & 3) != 0 + || IsExn15C28PrologueSwPc(prologueSwNext) + || prologueSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + || prologueSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + || prologueSwNext == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || prologueSwNext == CoredllDllMainExn15C28OuterJalLink + || prologueSwNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || prologueSwNext == CoredllDllMainExn15C28JalS1AluNext + || prologueSwNext == CoredllDllMainExn15C28StkSwNext + || prologueSwNext == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(prologueSwNext) + || IsExn15C28Na02Frame(prologueSwNext) + || IsExn15C28NfffFrame(prologueSwNext) + || IsExn15C28N9ffFrame(prologueSwNext) + || IsExn15C28HelperBody(prologueSwNext) + || IsExn15C28JalRaEpiRange(prologueSwNext) + || IsLeftoverDestVa(prologueSwNext) + || IsWrapDestSize(prologueSwNext) + || IsWrapDestFp50Va(prologueSwNext)) + return false; + uint prologueJalPeek = 0; + TryPeekLeftoverWait99DumpOnly(prologueSwNext, out prologueJalPeek); + if (prologueJalPeek != 0 && (prologueJalPeek >> 26) == 0 + && ((prologueJalPeek & 63) == 0x18 + || (prologueJalPeek & 63) == 0x16)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = prologueSwNext; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged = true; + _exn15C28AfterOuterJalEpiPrologueSwLogged = true; + uint prologueSwRa = PeekGpr(regs, 31); + uint prologueSwT5 = PeekGpr(regs, 13); + uint prologueSwA0 = PeekGpr(regs, 4); + uint prologueSwFp = PeekGpr(regs, 30); + uint prologueSwS7 = PeekGpr(regs, 23); + uint prologueSwS3 = PeekGpr(regs, 19); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-prologue-sw-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + prologueSwFirst.ToString("X") + + " dest=0x" + prologueSwNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-prologue-sw" + + " pc=0x" + pc.ToString("X") + + " next=0x" + prologueSwNext.ToString("X") + + " dump=0x" + prologueSwFirst.ToString("X") + + (insn != 0 && insn != prologueSwFirst + ? " live=0x" + insn.ToString("X") : "") + + " n=" + prologueSwN.ToString() + + " sw=0 *sp-miss" + + " fp=0x" + prologueSwFp.ToString("X") + + " s7=0x" + prologueSwS7.ToString("X") + + " s3=0x" + prologueSwS3.ToString("X") + + " a0=0x" + prologueSwA0.ToString("X") + + " t5=0x" + prologueSwT5.ToString("X") + + " ra=0x" + prologueSwRa.ToString("X") + + " sp=0x" + prologueSwSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump sw $fp/$s7/$s6/$s5/$s4/$s3 0x8003F85C-0x8003F870;" + + " dest-miss skip; leave regs; NEVER write 0x9A page / *0xFFFFDB58 / SUD / E000 / F000;" + + " no invent 0x9A02 / 0x99FF; no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 1099cb8: after prologue sw + // skip, name first I-fetch at + // 0x8003F874. One-shot. Peek dump + // only — do not invent next word + // / dest / 0x9A page / $ra / + // 0x80014F30 page. Do not hop MUL + // / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiPrologueSw(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiPrologueSwLogged + || _exn15C28AfterOuterJalEpiPrologueSwNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiPrologueSwNextLogged = true; + uint prologueSwNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out prologueSwNoteDump); + uint prologueSwNoteRa = PeekGpr(regs, 31); + uint prologueSwNoteSp = PeekGpr(regs, 29); + uint prologueSwNoteA0 = PeekGpr(regs, 4); + uint prologueSwNoteFp = PeekGpr(regs, 30); + string prologueSwNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string prologueSwNoteDumpDis = prologueSwNoteDump != 0 + ? FormatMipsOp(pc, prologueSwNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-prologue-sw"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (prologueSwNoteDump != 0 + ? " dump=0x" + prologueSwNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-prologue-sw"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-prologue-sw" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (prologueSwNoteDump != 0 + ? " dump=0x" + prologueSwNoteDump.ToString("X") : "") + + " dis=" + prologueSwNoteDis + + (prologueSwNoteDump != 0 + ? " dump-dis=" + prologueSwNoteDumpDis : "") + + " a0=0x" + prologueSwNoteA0.ToString("X") + + " fp=0x" + prologueSwNoteFp.ToString("X") + + " ra=0x" + prologueSwNoteRa.ToString("X") + + " sp=0x" + prologueSwNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-prologue-sw" + + " (first I-fetch after prologue sw dest-miss skip; peek dump, do not invent next word;" + + " honor ra; no jr hop; no invent $ra / 0x9A page / *0xFFFFDB58 / 0x9A02 / 0x99FF)"); + } + + // Live 1099cb8: jal 0x80014F30 at + // 0x8003F874. Exec dump jal: + // $ra:=0x8003F87C (link; not + // stale 0x8003F78C). Delay or + // $fp,$a0,$0 at 0x8003F878 — + // $fp:=$a0. PC:=0x80014F30 + // (I-fetch dump-true at callee; + // do not invent target pages). + // Refuse leftover / MULT + // 0x8003F748 / jr hop 0x8003F78C + // / SPECIAL 0x16. After jal, cap + // leaves >=0x80014F30. Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiPrologueJal(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiPrologueSwLogged) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal) + return false; + if (_exn15C28AfterOuterJalEpiPrologueJalLogged) + { + if (inDelay) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelay + || IsExn15C28PrologueSwPc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || (capLeave == PeekGpr(regs, 31) + && (!_exn15C28AfterOuterJalEpiTrampolineLogged + || _exn15C28AfterOuterJalEpiRetLogged)) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && (!_exn15C28AfterOuterJalEpiTrampolineLogged + || _exn15C28AfterOuterJalEpiRetLogged)) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint prologueJalDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out prologueJalDump) + || prologueJalDump == 0) + prologueJalDump = CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDump; + if (prologueJalDump != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDump) + return false; + if ((prologueJalDump >> 26) != 3) + return false; + uint prologueJalDest = (pc & 0xF0000000u) | ((prologueJalDump & 0x03FFFFFFu) << 2); + if (prologueJalDest != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest) + return false; + uint prologueJalDelayDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelay, + out prologueJalDelayDump) || prologueJalDelayDump == 0) + prologueJalDelayDump = CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelayDump; + if (prologueJalDelayDump != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelayDump) + return false; + if (!IsDumpMemAluInsn(prologueJalDelayDump)) + return false; + if (insn != prologueJalDump && insn != 0 && (insn >> 26) != 3 + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != prologueJalDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, prologueJalDump); + if (prologueJalDest == 0 || (prologueJalDest & 3) != 0 + || prologueJalDest == pc + || prologueJalDest == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelay + || prologueJalDest == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + || IsExn15C28PrologueSwPc(prologueJalDest) + || prologueJalDest == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuSwNext + || prologueJalDest == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrAddiuNext + || prologueJalDest == CoredllDllMainExn15C28OuterJalLink + || prologueJalDest == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || prologueJalDest == CoredllDllMainExn15C28JalS1AluNext + || prologueJalDest == CoredllDllMainExn15C28StkSwNext + || prologueJalDest == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(prologueJalDest) + || IsExn15C28Na02Frame(prologueJalDest) + || IsExn15C28NfffFrame(prologueJalDest) + || IsExn15C28N9ffFrame(prologueJalDest) + || IsExn15C28HelperBody(prologueJalDest) + || IsExn15C28JalRaEpiRange(prologueJalDest) + || IsLeftoverDestVa(prologueJalDest) + || IsWrapDestSize(prologueJalDest) + || IsWrapDestFp50Va(prologueJalDest)) + return false; + uint prologueJalRa = CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa; + if (prologueJalRa == 0 || (prologueJalRa & 3) != 0 + || IsDumpMemRefuseVa(prologueJalRa) + || prologueJalRa == CoredllDllMainExn15C28OuterJalLink + || prologueJalRa == CoredllDllMainExn15C28OuterJalLinkBeqTaken) + return false; + bool prologueJalDelayOk = TryExecDumpMemAlu(regs, prologueJalDelayDump); + if (!prologueJalDelayOk) + return false; + PokeGpr(regs, 31, prologueJalRa); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = prologueJalDest; + _exn15C28AfterOuterJalEpiPrologueSwNextLogged = true; + _exn15C28AfterOuterJalEpiPrologueJalLogged = true; + uint prologueJalSp = PeekGpr(regs, 29); + uint prologueJalA0 = PeekGpr(regs, 4); + uint prologueJalFp = PeekGpr(regs, 30); + uint prologueJalT5 = PeekGpr(regs, 13); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-prologue-jal"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + prologueJalDump.ToString("X") + + " dest=0x" + prologueJalDest.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-prologue-jal" + + " pc=0x" + pc.ToString("X") + + " next=0x" + prologueJalDest.ToString("X") + + " dump=0x" + prologueJalDump.ToString("X") + + (insn != 0 && insn != prologueJalDump + ? " live=0x" + insn.ToString("X") : "") + + " delay=0x" + prologueJalDelayDump.ToString("X") + + (prologueJalDelayOk ? " or=1" : " or=0") + + " a0=0x" + prologueJalA0.ToString("X") + + " fp=0x" + prologueJalFp.ToString("X") + + " t5=0x" + prologueJalT5.ToString("X") + + " ra=0x" + prologueJalRa.ToString("X") + + " sp=0x" + prologueJalSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump jal 0x80014F30; $ra:=0x8003F87C; delay or $fp,$a0;" + + " I-fetch dump-true at callee; no invent dest / 0x9A page / *0xFFFFDB58 / SUD / E000 / F000;" + + " no jr hop 0x8003F78C; no MULT 0x8003F748)"); + return true; + } + + // Live 1099cb8: after jal exec, + // name first I-fetch at + // 0x80014F30. One-shot. Peek dump + // only — do not invent callee + // page / dest / 0x9A / $ra. Do + // not hop MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiPrologueJal(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiPrologueJalLogged + || _exn15C28AfterOuterJalEpiPrologueJalNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiPrologueJalNextLogged = true; + uint prologueJalNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out prologueJalNoteDump); + uint prologueJalNoteRa = PeekGpr(regs, 31); + uint prologueJalNoteSp = PeekGpr(regs, 29); + uint prologueJalNoteA0 = PeekGpr(regs, 4); + uint prologueJalNoteFp = PeekGpr(regs, 30); + string prologueJalNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string prologueJalNoteDumpDis = prologueJalNoteDump != 0 + ? FormatMipsOp(pc, prologueJalNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-prologue-jal"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (prologueJalNoteDump != 0 + ? " dump=0x" + prologueJalNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-prologue-jal"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-prologue-jal" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (prologueJalNoteDump != 0 + ? " dump=0x" + prologueJalNoteDump.ToString("X") : "") + + " dis=" + prologueJalNoteDis + + (prologueJalNoteDump != 0 + ? " dump-dis=" + prologueJalNoteDumpDis : "") + + " a0=0x" + prologueJalNoteA0.ToString("X") + + " fp=0x" + prologueJalNoteFp.ToString("X") + + " ra=0x" + prologueJalNoteRa.ToString("X") + + " sp=0x" + prologueJalNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-prologue-jal" + + " (first I-fetch after prologue jal; peek dump, do not invent callee page;" + + " honor ra=0x8003F87C; no jr hop 0x8003F78C; no invent 0x9A page / *0xFFFFDB58 / 0x9A02 / 0x99FF)"); + } + + private static uint DumpMem15C28TrampolineDump(uint pc) + { + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest) + return CoredllDllMainExn15C28OuterJalLinkEpiTrampolineDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiu) + return CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJr) + return CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrDelay + || pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineNop + || pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDelay) + return 0; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0) + return CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRa) + return CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDump; + return 0; + } + + private static bool IsExn15C28TrampolinePc(uint pc) + { + return pc >= CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDelay + && (pc & 3) == 0; + } + + private static bool IsMipsJrRs(uint insn, int rs) + { + return (insn >> 26) == 0 + && (insn & 63) == 8 + && ((insn >> 21) & 31) == (uint)rs + && ((insn >> 16) & 31) == 0 + && ((insn >> 11) & 31) == 0; + } + + // Live 5f426bf: lui $t0,0x8001 at + // 0x80014F30 named only. Exec + // dump-true trampoline: + // lui/addiu $t0:=0x80014F40; + // jr $t0 + nop → 0x80014F40 + // (dump-true body hop; NOT stale + // $ra=0x8003F78C); mtc0 $0,$12; + // nop; jr $ra ($ra=0x8003F87C) + + // nop. PC:=0x8003F87C. Do not + // invent KSEG / 0x9A / SUD / E000. + // Refuse MULT 0x8003F748 / + // SPECIAL 0x16. After trampoline, + // cap leaves >=0x8003F87C. Not + // LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiTrampoline(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiPrologueJalLogged) + return false; + if (_exn15C28AfterOuterJalEpiTrampolineLogged) + { + if (inDelay) + return false; + if (!IsExn15C28TrampolinePc(pc) + && pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || IsExn15C28TrampolinePc(capLeave) + || (IsExn15C28RetPc(capLeave) + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && _exn15C28AfterOuterJalEpiRetLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDelay + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint trampolineLui = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out trampolineLui) + || trampolineLui == 0) + trampolineLui = CoredllDllMainExn15C28OuterJalLinkEpiTrampolineDump; + if (trampolineLui != CoredllDllMainExn15C28OuterJalLinkEpiTrampolineDump) + return false; + if (insn != trampolineLui && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != trampolineLui && insn != 0) + TryHealDumpInsn(bus, pc, insn, trampolineLui); + uint trampolineAddiu = DumpMem15C28TrampolineDump( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiu); + uint trampolineJr = DumpMem15C28TrampolineDump( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJr); + uint trampolineMtc0 = DumpMem15C28TrampolineDump( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0); + uint trampolineJrRa = DumpMem15C28TrampolineDump( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRa); + uint trampolineAddiuPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiu, + out trampolineAddiuPeek) || trampolineAddiuPeek == 0) + trampolineAddiuPeek = trampolineAddiu; + uint trampolineJrPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJr, + out trampolineJrPeek) || trampolineJrPeek == 0) + trampolineJrPeek = trampolineJr; + uint trampolineMtc0Peek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0, + out trampolineMtc0Peek) || trampolineMtc0Peek == 0) + trampolineMtc0Peek = trampolineMtc0; + uint trampolineJrRaPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRa, + out trampolineJrRaPeek) || trampolineJrRaPeek == 0) + trampolineJrRaPeek = trampolineJrRa; + if (trampolineAddiuPeek != CoredllDllMainExn15C28OuterJalLinkEpiTrampolineAddiuDump + || trampolineJrPeek != CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrDump + || trampolineMtc0Peek != CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0Dump + || trampolineJrRaPeek != CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDump) + return false; + if (!IsDumpMemAluInsn(trampolineLui) + || !IsDumpMemAluInsn(trampolineAddiuPeek) + || !IsMipsJrRs(trampolineJrPeek, 8) + || !IsDumpMemCop0(trampolineMtc0Peek) + || !IsMipsJrRs(trampolineJrRaPeek, 31)) + return false; + uint trampolineJrDelayPeek = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrDelay, + out trampolineJrDelayPeek); + uint trampolineNopPeek = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineNop, + out trampolineNopPeek); + uint trampolineJrRaDelayPeek = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiTrampolineJrRaDelay, + out trampolineJrRaDelayPeek); + if ((trampolineJrDelayPeek != 0 && trampolineJrDelayPeek != 0x00000000u) + || (trampolineNopPeek != 0 && trampolineNopPeek != 0x00000000u) + || (trampolineJrRaDelayPeek != 0 && trampolineJrRaDelayPeek != 0x00000000u)) + return false; + if (!TryExecDumpMemAlu(regs, trampolineLui)) + return false; + if (!TryExecDumpMemAlu(regs, trampolineAddiuPeek)) + return false; + uint trampolineT0 = PeekGpr(regs, 8); + if (trampolineT0 != CoredllDllMainExn15C28OuterJalLinkEpiTrampolineMtc0) + return false; + if (trampolineT0 == 0 || (trampolineT0 & 3) != 0 + || trampolineT0 == CoredllDllMainExn15C28OuterJalLink + || trampolineT0 == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || trampolineT0 == CoredllDllMainExn15C28JalS1AluNext + || trampolineT0 == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(trampolineT0) + || IsExn15C28Na02Frame(trampolineT0) + || IsExn15C28NfffFrame(trampolineT0) + || IsExn15C28N9ffFrame(trampolineT0) + || IsExn15C28HelperBody(trampolineT0) + || IsExn15C28JalRaEpiRange(trampolineT0) + || IsLeftoverDestVa(trampolineT0) + || IsWrapDestSize(trampolineT0) + || IsWrapDestFp50Va(trampolineT0)) + return false; + uint trampolineRa = PeekGpr(regs, 31); + if (trampolineRa != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + || trampolineRa == CoredllDllMainExn15C28OuterJalLink + || trampolineRa == 0 || (trampolineRa & 3) != 0 + || IsDumpMemRefuseVa(trampolineRa) + || IsExn15C28Na02Frame(trampolineRa) + || IsExn15C28HelperBody(trampolineRa) + || IsExn15C28JalRaEpiRange(trampolineRa) + || IsLeftoverDestVa(trampolineRa) + || IsWrapDestSize(trampolineRa) + || IsWrapDestFp50Va(trampolineRa)) + return false; + if (bus == null || !bus.TryExecDumpMemMtc0ZeroStatus(trampolineMtc0Peek)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = trampolineRa; + _exn15C28AfterOuterJalEpiPrologueJalNextLogged = true; + _exn15C28AfterOuterJalEpiTrampolineLogged = true; + uint trampolineSp = PeekGpr(regs, 29); + uint trampolineA0 = PeekGpr(regs, 4); + uint trampolineFp = PeekGpr(regs, 30); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-trampoline"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + trampolineLui.ToString("X") + + " dest=0x" + trampolineRa.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-trampoline" + + " pc=0x" + pc.ToString("X") + + " next=0x" + trampolineRa.ToString("X") + + " dump=0x" + trampolineLui.ToString("X") + + (insn != 0 && insn != trampolineLui + ? " live=0x" + insn.ToString("X") : "") + + " t0=0x" + trampolineT0.ToString("X") + + " mtc0=1" + + " a0=0x" + trampolineA0.ToString("X") + + " fp=0x" + trampolineFp.ToString("X") + + " ra=0x" + trampolineRa.ToString("X") + + " sp=0x" + trampolineSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lui/addiu/jr $t0 → 0x80014F40; mtc0 $0,$12; jr $ra → 0x8003F87C;" + + " dump-true trampoline hop, not stale-ra 0x8003F78C; no invent KSEG / 0x9A / SUD / E000;" + + " no MULT 0x8003F748)"); + return true; + } + + // Live 5f426bf: after trampoline, + // name first I-fetch at + // 0x8003F87C. One-shot. Peek dump + // only — do not invent next word / + // dest / 0x9A / $ra. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiTrampoline(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiTrampolineLogged + || _exn15C28AfterOuterJalEpiTrampolineNextLogged) + return; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiTrampolineNextLogged = true; + uint trampolineNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out trampolineNoteDump); + uint trampolineNoteRa = PeekGpr(regs, 31); + uint trampolineNoteSp = PeekGpr(regs, 29); + uint trampolineNoteT0 = PeekGpr(regs, 8); + uint trampolineNoteA0 = PeekGpr(regs, 4); + uint trampolineNoteFp = PeekGpr(regs, 30); + string trampolineNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string trampolineNoteDumpDis = trampolineNoteDump != 0 + ? FormatMipsOp(pc, trampolineNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-trampoline"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (trampolineNoteDump != 0 + ? " dump=0x" + trampolineNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-trampoline"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-trampoline" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (trampolineNoteDump != 0 + ? " dump=0x" + trampolineNoteDump.ToString("X") : "") + + " dis=" + trampolineNoteDis + + (trampolineNoteDump != 0 + ? " dump-dis=" + trampolineNoteDumpDis : "") + + " t0=0x" + trampolineNoteT0.ToString("X") + + " a0=0x" + trampolineNoteA0.ToString("X") + + " fp=0x" + trampolineNoteFp.ToString("X") + + " ra=0x" + trampolineNoteRa.ToString("X") + + " sp=0x" + trampolineNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-trampoline" + + " (first I-fetch after trampoline jr $ra; peek dump, do not invent next word;" + + " honor ra=0x8003F87C; no jr hop 0x8003F78C; no invent 0x9A page / *0xFFFFDB58 / 0x9A02 / 0x99FF)"); + } + + private static uint DumpMem15C28RetDump(uint pc) + { + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa) + return CoredllDllMainExn15C28OuterJalLinkEpiRetLuiDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetAddiu) + return CoredllDllMainExn15C28OuterJalLinkEpiRetAddiuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetLw) + return CoredllDllMainExn15C28OuterJalLinkEpiRetLwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetSltu) + return CoredllDllMainExn15C28OuterJalLinkEpiRetSltuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBne) + return CoredllDllMainExn15C28OuterJalLinkEpiRetBneDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneDelay) + return 0; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall) + return CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken) + return CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDump; + return 0; + } + + private static bool IsExn15C28RetBnePc(uint pc) + { + return pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + || pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken; + } + + private static bool IsExn15C28RetPc(uint pc) + { + return pc >= CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiRetBneDelay + && (pc & 3) == 0; + } + + // Dump-only peek of *$s7. Unbacked + // / 0x8032 / 0x8033 / SUD / 0x9A / + // E000 / F000 → miss (zero). Never + // invent those pages via bus. + private static bool TryPeekExn15C28OuterJalRetLwDest(uint dest, + out uint peek) + { + peek = 0; + if (dest == 0 || (dest & 3) != 0) + return false; + if (IsDumpMemRefuseVa(dest) || IsExn15C28Na02Frame(dest) + || IsExn15C28NfffFrame(dest) || IsExn15C28N9ffFrame(dest) + || dest >= CoredllDllMainC000Page + || dest == FfffF000Page + || (dest & ~0xFFFu) == FfffE000Page + || (dest & ~0xFFFu) == 0x80320000u + || (dest & ~0xFFFu) == 0x80330000u + || dest == 0xFFFFFC74u || dest == 0xFFFFDB58u) + return false; + return TryPeekLeftoverWait99DumpOnly(dest, out peek); + } + + // Live 6e264a7: lui $v0,0x8034 at + // 0x8003F87C named only + after- + // stk-sw spam leave 0x8003F87C on + // 0x9FFFF. Exec dump-true: + // lui $v0:=0x80340000; addiu + // $s7:=0x8033FC78; lw peek-or-zero + // (NO invent 0x8033); sltu + // $v0:=($v1<$fp); bne + nop + // take/fall from ALU. PC:=fall + // 0x8003F894 or taken 0x8003F8BC. + // Break 0x9FFFF/0x9A recurse. + // Keep EA88 / E000 dest-miss skip. + // No MUL / jr hop 0x8003F78C. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRet(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiTrampolineLogged) + return false; + if (_exn15C28AfterOuterJalEpiRetLogged) + { + if (inDelay) + return false; + if (!IsExn15C28RetPc(pc) + && pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || IsExn15C28RetPc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + || IsExn15C28TrampolinePc(capLeave) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && _exn15C28AfterOuterJalEpiRetBneLogged) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + && _exn15C28AfterOuterJalEpiRetBneLogged) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint retLui = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out retLui) || retLui == 0) + retLui = CoredllDllMainExn15C28OuterJalLinkEpiRetLuiDump; + if (retLui != CoredllDllMainExn15C28OuterJalLinkEpiRetLuiDump) + return false; + if (insn != retLui && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn) && !IsMipsLoad(insn)) + return false; + if (insn != retLui && insn != 0) + TryHealDumpInsn(bus, pc, insn, retLui); + uint retAddiuPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetAddiu, + out retAddiuPeek) || retAddiuPeek == 0) + retAddiuPeek = CoredllDllMainExn15C28OuterJalLinkEpiRetAddiuDump; + uint retLwPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetLw, + out retLwPeek) || retLwPeek == 0) + retLwPeek = CoredllDllMainExn15C28OuterJalLinkEpiRetLwDump; + uint retSltuPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetSltu, + out retSltuPeek) || retSltuPeek == 0) + retSltuPeek = CoredllDllMainExn15C28OuterJalLinkEpiRetSltuDump; + uint retBnePeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBne, + out retBnePeek) || retBnePeek == 0) + retBnePeek = CoredllDllMainExn15C28OuterJalLinkEpiRetBneDump; + if (retAddiuPeek != CoredllDllMainExn15C28OuterJalLinkEpiRetAddiuDump + || retLwPeek != CoredllDllMainExn15C28OuterJalLinkEpiRetLwDump + || retSltuPeek != CoredllDllMainExn15C28OuterJalLinkEpiRetSltuDump + || retBnePeek != CoredllDllMainExn15C28OuterJalLinkEpiRetBneDump) + return false; + if (!IsDumpMemAluInsn(retLui) + || !IsDumpMemAluInsn(retAddiuPeek) + || !IsMipsLoad(retLwPeek) + || !IsDumpMemAluInsn(retSltuPeek) + || (retBnePeek >> 26) != 5) + return false; + if ((retSltuPeek & 63) == 0x18 || (retSltuPeek & 63) == 0x16 + || (retBnePeek & 63) == 0x18 || (retBnePeek & 63) == 0x16) + return false; + uint retDelayPeek = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneDelay, + out retDelayPeek); + if (retDelayPeek != 0 && retDelayPeek != 0x00000000u) + return false; + uint retFallPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall, + out retFallPeek) || retFallPeek == 0) + retFallPeek = CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump; + uint retTakenPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken, + out retTakenPeek) || retTakenPeek == 0) + retTakenPeek = CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDump; + if (retFallPeek != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump + || retTakenPeek != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDump) + return false; + if ((retFallPeek >> 26) == 0 + && ((retFallPeek & 63) == 0x18 || (retFallPeek & 63) == 0x16 + || (retFallPeek & 63) == 0x08)) + return false; + if ((retTakenPeek >> 26) == 0 + && ((retTakenPeek & 63) == 0x18 || (retTakenPeek & 63) == 0x16 + || (retTakenPeek & 63) == 0x08)) + return false; + if (!TryExecDumpMemAlu(regs, retLui)) + return false; + if (!TryExecDumpMemAlu(regs, retAddiuPeek)) + return false; + uint retS7 = PeekGpr(regs, 23); + if (retS7 != CoredllDllMainExn15C28OuterJalLinkEpiRetS7) + return false; + uint retLwDest = retS7; + uint retLwWord = 0; + bool retLwOk = TryPeekExn15C28OuterJalRetLwDest(retLwDest, + out retLwWord); + PokeGpr(regs, 3, retLwOk ? retLwWord : 0); + bool retSltuOk = TryExecDumpMemSltuKnown(regs, retSltuPeek); + if (!retSltuOk) + retSltuOk = TryExecDumpMemAlu(regs, retSltuPeek); + if (!retSltuOk) + return false; + int retBneImm = (short)(retBnePeek & 0xFFFF); + uint retBneTaken = unchecked( + CoredllDllMainExn15C28OuterJalLinkEpiRetBne + 4u + + (uint)(retBneImm * 4)); + if (retBneTaken != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken) + return false; + bool retBneTake = PeekGpr(regs, 2) != 0; + uint retBneDest = retBneTake + ? CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken + : CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall; + if (retBneDest == 0 || (retBneDest & 3) != 0 + || retBneDest == CoredllDllMainExn15C28OuterJalLink + || retBneDest == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || retBneDest == CoredllDllMainExn15C28JalS1AluNext + || retBneDest == CoredllDllMainExn15C28StkSwNext + || retBneDest == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + || IsExn15C28RetPc(retBneDest) + || retBneDest == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(retBneDest) + || IsExn15C28Na02Frame(retBneDest) + || IsExn15C28NfffFrame(retBneDest) + || IsExn15C28N9ffFrame(retBneDest) + || IsExn15C28HelperBody(retBneDest) + || IsExn15C28JalRaEpiRange(retBneDest) + || IsLeftoverDestVa(retBneDest) + || IsWrapDestSize(retBneDest) + || IsWrapDestFp50Va(retBneDest)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = retBneDest; + _exn15C28AfterOuterJalEpiTrampolineNextLogged = true; + _exn15C28AfterOuterJalEpiRetLogged = true; + _exn15C28AfterOuterJalEpiRetLeave = retBneDest; + uint retSp = PeekGpr(regs, 29); + uint retRa = PeekGpr(regs, 31); + uint retV0 = PeekGpr(regs, 2); + uint retV1 = PeekGpr(regs, 3); + uint retFp = PeekGpr(regs, 30); + uint retA0 = PeekGpr(regs, 4); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = retLwOk + ? "dump-mem-15c28-outer-jal-epi-ret" + : "dump-mem-15c28-outer-jal-epi-ret-lw-zero"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + retLui.ToString("X") + + " dest=0x" + retBneDest.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret" + + " pc=0x" + pc.ToString("X") + + " next=0x" + retBneDest.ToString("X") + + " dump=0x" + retLui.ToString("X") + + (insn != 0 && insn != retLui + ? " live=0x" + insn.ToString("X") : "") + + " s7=0x" + retS7.ToString("X") + + (retLwOk ? " lw=1" : " lw=0 zero=1") + + " dest=0x" + retLwDest.ToString("X") + + (retSltuOk ? " sltu=1" : " sltu=0") + + (retBneTake ? " bne=1" : " bne=0") + + " v0=0x" + retV0.ToString("X") + + " v1=0x" + retV1.ToString("X") + + " fp=0x" + retFp.ToString("X") + + " a0=0x" + retA0.ToString("X") + + " ra=0x" + retRa.ToString("X") + + " sp=0x" + retSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lui/addiu $s7:=0x8033FC78; lw peek-or-zero; sltu; bne take/fall;" + + " no invent 0x8033 / 0x9A / 0x9F / SUD / E000; no MULT 0x8003F748;" + + " no jr hop 0x8003F78C)"); + return true; + } + + // Live 6e264a7: after ret batch, + // name first I-fetch at bne dest + // (fall 0x8003F894 or taken + // 0x8003F8BC). One-shot. Peek dump + // only — do not invent next word / + // 0x8033 / 0x9A / SUD. Do not hop + // MUL / jr 0x8003F78C. + public static void TryNoteDumpMem15C28AfterOuterJalEpiRet(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiRetLogged + || _exn15C28AfterOuterJalEpiRetNextLogged) + return; + if (pc != _exn15C28AfterOuterJalEpiRetLeave + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiRetNextLogged = true; + uint retNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out retNoteDump); + if (retNoteDump == 0) + retNoteDump = DumpMem15C28RetDump(pc); + uint retNoteRa = PeekGpr(regs, 31); + uint retNoteSp = PeekGpr(regs, 29); + uint retNoteV0 = PeekGpr(regs, 2); + uint retNoteV1 = PeekGpr(regs, 3); + uint retNoteS7 = PeekGpr(regs, 23); + uint retNoteFp = PeekGpr(regs, 30); + string retNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string retNoteDumpDis = retNoteDump != 0 + ? FormatMipsOp(pc, retNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-ret"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (retNoteDump != 0 + ? " dump=0x" + retNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-ret"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-ret" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (retNoteDump != 0 + ? " dump=0x" + retNoteDump.ToString("X") : "") + + " dis=" + retNoteDis + + (retNoteDump != 0 + ? " dump-dis=" + retNoteDumpDis : "") + + " v0=0x" + retNoteV0.ToString("X") + + " v1=0x" + retNoteV1.ToString("X") + + " s7=0x" + retNoteS7.ToString("X") + + " fp=0x" + retNoteFp.ToString("X") + + " ra=0x" + retNoteRa.ToString("X") + + " sp=0x" + retNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-ret" + + " (first I-fetch after 3F87C lui/addiu/lw/sltu/bne; peek dump, do not invent next word;" + + " no jr hop 0x8003F78C; no invent 0x8033 / 0x9A / 0x9F / SUD)"); + } + + // Live 17ec945: first I-fetch after + // ret bne. Fall 0x8003F894 dump + // lui $v0,0x8034 — exec ALU + // $v0:=0x80340000; PC:=0x8003F898 + // observe. Taken 0x8003F8BC dump + // jal 0x80014F1C — delay peek 0/nop + // only (do not invent delay); + // $ra:=0x8003F8C4; PC:=0x80014F1C + // observe (do not invent callee + // word). Refuse leftover / MULT + // 0x8003F748 / jr hop 0x8003F78C / + // hop 0x8003F888 / SPECIAL 0x16. + // After take, cap leaves >= fall + // next or jal dest. Not LoadO32. + // No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetBne(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetLogged) + return false; + if (_exn15C28AfterOuterJalEpiRetBneLogged) + { + if (inDelay) + return false; + if (!IsExn15C28RetBnePc(pc)) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || IsExn15C28RetBnePc(capLeave) + || IsExn15C28RetPc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + || IsExn15C28TrampolinePc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJal + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == CoredllDllMainKdataEpcEa88 + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + bool retBneFall = pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall; + bool retBneTaken = pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTaken; + if (!retBneFall && !retBneTaken) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenRa) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint retBneDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out retBneDump) || retBneDump == 0) + retBneDump = DumpMem15C28RetDump(pc); + uint retBneExpect = retBneFall + ? CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump + : CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDump; + if (retBneDump != retBneExpect) + return false; + if ((retBneDump & 63) == 0x18 || (retBneDump & 63) == 0x16) + return false; + if (insn != retBneDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn) && (insn >> 26) != 3) + return false; + if (insn != retBneDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, retBneDump); + uint retBneNext = 0; + string retBneVia = "dump-mem-15c28-outer-jal-epi-ret-bne"; + if (retBneFall) + { + if (!IsDumpMemAluInsn(retBneDump)) + return false; + if (!TryExecDumpMemAlu(regs, retBneDump)) + return false; + retBneNext = CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext; + } + else + { + if ((retBneDump >> 26) != 3) + return false; + uint retBneJalDest = (pc & 0xF0000000u) + | ((retBneDump & 0x03FFFFFFu) << 2); + if (retBneJalDest != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest) + return false; + uint retBneDelayPeek = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenDelay, + out retBneDelayPeek); + if (retBneDelayPeek != 0 && retBneDelayPeek != 0x00000000u) + { + if (!IsDumpMemAluInsn(retBneDelayPeek) + || (retBneDelayPeek & 63) == 0x18 + || (retBneDelayPeek & 63) == 0x16) + return false; + if (!TryExecDumpMemAlu(regs, retBneDelayPeek)) + return false; + } + uint retBneRa = CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenRa; + if (retBneRa == 0 || (retBneRa & 3) != 0 + || retBneRa == CoredllDllMainExn15C28OuterJalLink + || retBneRa == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || IsDumpMemRefuseVa(retBneRa) + || IsExn15C28Na02Frame(retBneRa) + || IsExn15C28HelperBody(retBneRa) + || IsExn15C28JalRaEpiRange(retBneRa)) + return false; + PokeGpr(regs, 31, retBneRa); + retBneNext = retBneJalDest; + retBneVia = "dump-mem-15c28-outer-jal-epi-ret-bne-jal"; + } + if (retBneNext == 0 || (retBneNext & 3) != 0 + || retBneNext == pc + || retBneNext == CoredllDllMainExn15C28OuterJalLink + || retBneNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || retBneNext == CoredllDllMainExn15C28JalS1AluNext + || retBneNext == CoredllDllMainExn15C28StkSwNext + || retBneNext == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + || retBneNext == CoredllDllMainKdataEpcEa88 + || IsExn15C28RetPc(retBneNext) + || IsExn15C28RetBnePc(retBneNext) + || IsExn15C28TrampolinePc(retBneNext) + || (retBneNext == PeekGpr(regs, 31) + && retBneNext != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest) + || IsDumpMemRefuseVa(retBneNext) + || IsExn15C28Na02Frame(retBneNext) + || IsExn15C28NfffFrame(retBneNext) + || IsExn15C28N9ffFrame(retBneNext) + || IsExn15C28HelperBody(retBneNext) + || IsExn15C28JalRaEpiRange(retBneNext) + || IsLeftoverDestVa(retBneNext) + || IsWrapDestSize(retBneNext) + || IsWrapDestFp50Va(retBneNext)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = retBneNext; + _exn15C28AfterOuterJalEpiRetNextLogged = true; + _exn15C28AfterOuterJalEpiRetBneLogged = true; + _exn15C28AfterOuterJalEpiRetBneLeave = retBneNext; + uint retBneSp = PeekGpr(regs, 29); + uint retBneRaLog = PeekGpr(regs, 31); + uint retBneV0 = PeekGpr(regs, 2); + uint retBneFp = PeekGpr(regs, 30); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = retBneVia; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + retBneDump.ToString("X") + + " dest=0x" + retBneNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-bne" + + " pc=0x" + pc.ToString("X") + + " next=0x" + retBneNext.ToString("X") + + " dump=0x" + retBneDump.ToString("X") + + (insn != 0 && insn != retBneDump + ? " live=0x" + insn.ToString("X") : "") + + (retBneFall ? " lui=1" : " jal=1") + + " v0=0x" + retBneV0.ToString("X") + + " fp=0x" + retBneFp.ToString("X") + + " ra=0x" + retBneRaLog.ToString("X") + + " sp=0x" + retBneSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump fall lui $v0,0x8034 → 0x8003F898 or taken jal 0x80014F1C;" + + " delay peek 0/nop only; no invent callee / 0x8033 / 0x9A / 0x9F / SUD / E000;" + + " no hop 0x8003F888; no MULT 0x8003F748; no jr hop 0x8003F78C)"); + return true; + } + + // Live 17ec945: after ret-bne + // take, name first I-fetch at + // 0x8003F898 or 0x80014F1C. + // One-shot. Peek dump only — do + // not invent next word / dest / + // 0x8033 / 0x9A / SUD. Do not hop + // MUL / jr 0x8003F78C / 0x8003F888. + public static void TryNoteDumpMem15C28AfterOuterJalEpiRetBne(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiRetBneLogged + || _exn15C28AfterOuterJalEpiRetBneNextLogged) + return; + if (pc != _exn15C28AfterOuterJalEpiRetBneLeave + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiRetBneNextLogged = true; + uint retBneNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out retBneNoteDump); + uint retBneNoteRa = PeekGpr(regs, 31); + uint retBneNoteSp = PeekGpr(regs, 29); + uint retBneNoteV0 = PeekGpr(regs, 2); + uint retBneNoteFp = PeekGpr(regs, 30); + string retBneNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string retBneNoteDumpDis = retBneNoteDump != 0 + ? FormatMipsOp(pc, retBneNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-ret-bne"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (retBneNoteDump != 0 + ? " dump=0x" + retBneNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-bne"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-ret-bne" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (retBneNoteDump != 0 + ? " dump=0x" + retBneNoteDump.ToString("X") : "") + + " dis=" + retBneNoteDis + + (retBneNoteDump != 0 + ? " dump-dis=" + retBneNoteDumpDis : "") + + " v0=0x" + retBneNoteV0.ToString("X") + + " fp=0x" + retBneNoteFp.ToString("X") + + " ra=0x" + retBneNoteRa.ToString("X") + + " sp=0x" + retBneNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-bne" + + " (first I-fetch after ret bne fall lui / taken jal; peek dump, do not invent next word;" + + " no hop 0x8003F888; no jr hop 0x8003F78C; no invent 0x8033 / 0x9A / 0x9F / SUD)"); + } + + private static uint DumpMem15C28RetFallDump(uint pc) + { + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall) + return CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddiuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallLw) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallLwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubu) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallSw) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallSwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddu) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallAdduDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJal) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRaDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest) + return CoredllDllMainExn15C28OuterJalLinkEpiIntOnDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiIntOnOri) + return CoredllDllMainExn15C28OuterJalLinkEpiIntOnOriDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiIntOnJr) + return CoredllDllMainExn15C28OuterJalLinkEpiIntOnJrDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0) + return CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLw) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS7) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS7Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS6) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS6Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS5) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS5Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS4) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS4Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS3) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwS3Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwRa) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwRaDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJr) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelayDump; + return 0; + } + + private static bool IsExn15C28RetFallPc(uint pc) + { + return (pc >= CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiRetFallGotoDelay + && (pc & 3) == 0) + || (pc >= CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0 + && (pc & 3) == 0) + || (pc >= CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelay + && (pc & 3) == 0); + } + + private static bool IsExn15C28NoInventPage(uint dest) + { + uint page16 = dest & 0xFFFF0000u; + return dest == 0 + || IsDumpMemRefuseVa(dest) + || IsExn15C28Na02Frame(dest) + || IsExn15C28NfffFrame(dest) + || IsExn15C28N9ffFrame(dest) + || dest >= CoredllDllMainC000Page + || dest == FfffF000Page + || (dest & ~0xFFFu) == FfffE000Page + || page16 == 0x80320000u || page16 == 0x80330000u + || dest == 0xFFFFFC74u || dest == 0xFFFFDB58u + || dest == 0xFFFFDB18u + || dest == CoredllDllMainExn15C28OuterJalLinkEpiIntOnKdata; + } + + // Live 17ec945: named stall at + // 0x8003F894 + after-stk-sw spam + // next=0x8003F894 ~2h. Fat dump- + // true FALL of fn 0x8003F854: + // lui/addiu $v0:=0x8033FC70; lw + // $s5 peek-or-zero; subu; sw skip + // *$s7; addu; jal 0x80014F1C + + // delay sw skip *$v0; INT-ON stub + // (lw *0xFFFFD890 zero / ori 1 / + // jr / mtc0 Status); b 0x8003F93C; + // $v0:=$s5; skip 9A lw; skip jr + // $ra (no hop 0x8003F8B4/0x8003F78C). + // PC:=0x8003F964. Break 0x9FFFF + // recurse. No invent 0x8033 / KData + // / SUD / 0x9A / 0x9F. No MUL. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetFall(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetLogged) + return false; + if (_exn15C28AfterOuterJalEpiRetFallLogged) + { + if (inDelay) + return false; + if (!IsExn15C28RetFallPc(pc) + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || IsExn15C28RetFallPc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + || IsExn15C28TrampolinePc(capLeave) + || (capLeave == CoredllDllMainExn15C28OuterJalLink + && !_exn15C28AfterOuterJalEpiRetCallerRaLogged) + || capLeave == CoredllDllMainExn15C28JalS1AluNext + || capLeave == CoredllDllMainExn15C28StkSwNext + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == CoredllDllMainKdataEpcEa88 + || (_exn15C28AfterOuterJalEpiRetCallerLogged + && (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || IsExn15C28CallerPc(capLeave) + || IsExn15C28ListPopPc(capLeave))) + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + && _exn15C28AfterOuterJalEpiRetCallerNextFnLogged) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetFallNextFn) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint fallLui = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall, + out fallLui) || fallLui == 0) + fallLui = CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump; + uint fallAddiu = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext, + out fallAddiu) || fallAddiu == 0) + fallAddiu = CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddiuDump; + uint fallLw = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallLw, out fallLw) + || fallLw == 0) + fallLw = CoredllDllMainExn15C28OuterJalLinkEpiRetFallLwDump; + uint fallSubu = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubu, out fallSubu) + || fallSubu == 0) + fallSubu = CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubuDump; + uint fallSw = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallSw, out fallSw) + || fallSw == 0) + fallSw = CoredllDllMainExn15C28OuterJalLinkEpiRetFallSwDump; + uint fallAddu = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddu, out fallAddu) + || fallAddu == 0) + fallAddu = CoredllDllMainExn15C28OuterJalLinkEpiRetFallAdduDump; + uint fallJal = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallJal, out fallJal) + || fallJal == 0) + fallJal = CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDump; + uint fallJalDelay = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelay, + out fallJalDelay) || fallJalDelay == 0) + fallJalDelay = CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelayDump; + uint fallGoto = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa, out fallGoto) + || fallGoto == 0) + fallGoto = CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRaDump; + uint stubLw = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest, + out stubLw) || stubLw == 0) + stubLw = CoredllDllMainExn15C28OuterJalLinkEpiIntOnDump; + uint stubOri = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiIntOnOri, out stubOri) + || stubOri == 0) + stubOri = CoredllDllMainExn15C28OuterJalLinkEpiIntOnOriDump; + uint stubJr = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiIntOnJr, out stubJr) + || stubJr == 0) + stubJr = CoredllDllMainExn15C28OuterJalLinkEpiIntOnJrDump; + uint stubMtc0 = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0, out stubMtc0) + || stubMtc0 == 0) + stubMtc0 = CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0Dump; + uint epiOr = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi, out epiOr) + || epiOr == 0) + epiOr = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiDump; + uint epiJr = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJr, out epiJr) + || epiJr == 0) + epiJr = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDump; + uint epiJrDelay = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelay, + out epiJrDelay) || epiJrDelay == 0) + epiJrDelay = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelayDump; + if (fallLui != CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallDump + || fallAddiu != CoredllDllMainExn15C28OuterJalLinkEpiRetFallAddiuDump + || fallLw != CoredllDllMainExn15C28OuterJalLinkEpiRetFallLwDump + || fallSubu != CoredllDllMainExn15C28OuterJalLinkEpiRetFallSubuDump + || fallSw != CoredllDllMainExn15C28OuterJalLinkEpiRetFallSwDump + || fallAddu != CoredllDllMainExn15C28OuterJalLinkEpiRetFallAdduDump + || fallJal != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDump + || fallJalDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalDelayDump + || fallGoto != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRaDump + || stubLw != CoredllDllMainExn15C28OuterJalLinkEpiIntOnDump + || stubOri != CoredllDllMainExn15C28OuterJalLinkEpiIntOnOriDump + || stubJr != CoredllDllMainExn15C28OuterJalLinkEpiIntOnJrDump + || stubMtc0 != CoredllDllMainExn15C28OuterJalLinkEpiIntOnMtc0Dump + || epiOr != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiDump + || epiJr != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDump + || epiJrDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelayDump) + return false; + if (!IsDumpMemAluInsn(fallLui) || !IsDumpMemAluInsn(fallAddiu) + || !IsMipsLoad(fallLw) || !IsDumpMemAluInsn(fallSubu) + || !IsMipsStore(fallSw) || !IsDumpMemAluInsn(fallAddu) + || (fallJal >> 26) != 3 || !IsMipsStore(fallJalDelay) + || (fallGoto >> 26) != 4 || !IsMipsLoad(stubLw) + || !IsDumpMemAluInsn(stubOri) || !IsMipsJrRs(stubJr, 31) + || !IsDumpMemCop0(stubMtc0) || !IsDumpMemAluInsn(epiOr) + || !IsMipsJrRs(epiJr, 31) || !IsDumpMemAluInsn(epiJrDelay)) + return false; + if ((fallSubu & 63) == 0x18 || (fallSubu & 63) == 0x16 + || (fallAddu & 63) == 0x18 || (fallAddu & 63) == 0x16 + || (epiJrDelay & 63) == 0x18 || (epiJrDelay & 63) == 0x16) + return false; + uint fallJalDest = (CoredllDllMainExn15C28OuterJalLinkEpiRetFallJal + & 0xF0000000u) | ((fallJal & 0x03FFFFFFu) << 2); + if (fallJalDest != CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest) + return false; + int fallGotoImm = (short)(fallGoto & 0xFFFF); + uint fallGotoDest = unchecked( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + 4u + + (uint)(fallGotoImm * 4)); + if (fallGotoDest != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi) + return false; + if (insn != 0 && insn != fallLui && insn != fallAddiu + && !IsDumpMemAluInsn(insn) && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != 0 && insn != fallLui && pc == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall) + TryHealDumpInsn(bus, pc, insn, fallLui); + if (!TryExecDumpMemAlu(regs, fallLui)) + return false; + if (!TryExecDumpMemAlu(regs, fallAddiu)) + return false; + uint fallV0 = PeekGpr(regs, 2); + if (fallV0 != CoredllDllMainExn15C28OuterJalLinkEpiRetFallV0) + return false; + uint fallS7 = PeekGpr(regs, 23); + uint fallLwWord = 0; + bool fallLwOk = !IsExn15C28NoInventPage(fallV0) + && TryPeekExn15C28OuterJalRetLwDest(fallV0, out fallLwWord); + PokeGpr(regs, 21, fallLwOk ? fallLwWord : 0); + if (!TryExecDumpMemAlu(regs, fallSubu)) + return false; + uint fallSwDest = fallS7; + bool fallSwSkip = IsExn15C28NoInventPage(fallSwDest) + || !TryPeekExn15C28OuterJalRetLwDest(fallSwDest, out _); + if (!fallSwSkip) + return false; + if (!TryExecDumpMemAlu(regs, fallAddu)) + return false; + uint fallDelayDest = fallV0; + bool fallDelaySkip = IsExn15C28NoInventPage(fallDelayDest) + || !TryPeekExn15C28OuterJalRetLwDest(fallDelayDest, out _); + if (!fallDelaySkip) + return false; + TrySaveExn15C28Fn854OuterRa(regs); + PokeGpr(regs, 31, CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa); + uint stubDest = CoredllDllMainExn15C28OuterJalLinkEpiIntOnKdata; + uint stubWord = 0; + bool stubLwOk = !IsExn15C28NoInventPage(stubDest) + && TryPeekExn15C28OuterJalRetLwDest(stubDest, out stubWord); + PokeGpr(regs, 8, stubLwOk ? stubWord : 0); + if (!TryExecDumpMemAlu(regs, stubOri)) + return false; + if (bus == null || !bus.TryExecDumpMemMtc0Status(stubMtc0, PeekGpr(regs, 8))) + return false; + if (!TryExecDumpMemAlu(regs, epiOr)) + return false; + if (!TryExecDumpMemAlu(regs, epiJrDelay)) + return false; + uint fallLeave = CoredllDllMainExn15C28OuterJalLinkEpiRetFallNextFn; + if (fallLeave == 0 || (fallLeave & 3) != 0 + || fallLeave == CoredllDllMainExn15C28OuterJalLink + || fallLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || fallLeave == CoredllDllMainExn15C28JalS1AluNext + || fallLeave == CoredllDllMainExn15C28StkSwNext + || fallLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || fallLeave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalRa + || fallLeave == PeekGpr(regs, 31) + || IsDumpMemRefuseVa(fallLeave) + || IsExn15C28Na02Frame(fallLeave) + || IsExn15C28NfffFrame(fallLeave) + || IsExn15C28N9ffFrame(fallLeave) + || IsExn15C28HelperBody(fallLeave) + || IsLeftoverDestVa(fallLeave) + || IsWrapDestSize(fallLeave) + || IsWrapDestFp50Va(fallLeave)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = fallLeave; + _exn15C28AfterOuterJalEpiRetNextLogged = true; + _exn15C28AfterOuterJalEpiRetBneLogged = true; + _exn15C28AfterOuterJalEpiRetBneNextLogged = true; + _exn15C28AfterOuterJalEpiRetBneLeave = fallLeave; + _exn15C28AfterOuterJalEpiRetFallLogged = true; + _exn15C28AfterOuterJalEpiRetFallLeave = fallLeave; + uint fallSp = PeekGpr(regs, 29); + uint fallRa = PeekGpr(regs, 31); + uint fallV0Log = PeekGpr(regs, 2); + uint fallV1 = PeekGpr(regs, 3); + uint fallS5 = PeekGpr(regs, 21); + uint fallFp = PeekGpr(regs, 30); + uint fallT0 = PeekGpr(regs, 8); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-ret-fall"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + fallLui.ToString("X") + + " dest=0x" + fallLeave.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-fall" + + " pc=0x" + pc.ToString("X") + + " next=0x" + fallLeave.ToString("X") + + " dump=0x" + fallLui.ToString("X") + + (insn != 0 && insn != fallLui + ? " live=0x" + insn.ToString("X") : "") + + " v0=0x" + fallV0Log.ToString("X") + + " v1=0x" + fallV1.ToString("X") + + " s5=0x" + fallS5.ToString("X") + + " s7=0x" + fallS7.ToString("X") + + (fallLwOk ? " lw=1" : " lw=0 zero=1") + + (fallSwSkip ? " sw-skip=1" : " sw-skip=0") + + (stubLwOk ? " inton-lw=1" : " inton-lw=0 zero=1") + + " t0=0x" + fallT0.ToString("X") + + " mtc0=1" + + " fp=0x" + fallFp.ToString("X") + + " ra=0x" + fallRa.ToString("X") + + " sp=0x" + fallSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (fat FALL 3F894–3F8B0 + INT-ON 14F1C + b 3F93C + epi skip;" + + " no invent 0x8033 / *0xFFFFD890 / SUD / 0x9A / 0x9F; no jr hop 0x8003F78C;" + + " no MULT 0x8003F748; break after-stk-sw 3F894 loop)"); + return true; + } + + public static void TryNoteDumpMem15C28AfterOuterJalEpiRetFall(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiRetFallLogged + || _exn15C28AfterOuterJalEpiRetFallNextLogged) + return; + if (pc != _exn15C28AfterOuterJalEpiRetFallLeave + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetFallNextFn) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc)) + return; + _exn15C28AfterOuterJalEpiRetFallNextLogged = true; + uint fallNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out fallNoteDump); + uint fallNoteRa = PeekGpr(regs, 31); + uint fallNoteSp = PeekGpr(regs, 29); + uint fallNoteV0 = PeekGpr(regs, 2); + uint fallNoteS5 = PeekGpr(regs, 21); + string fallNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string fallNoteDumpDis = fallNoteDump != 0 + ? FormatMipsOp(pc, fallNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-ret-fall"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (fallNoteDump != 0 + ? " dump=0x" + fallNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-fall"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-ret-fall" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (fallNoteDump != 0 + ? " dump=0x" + fallNoteDump.ToString("X") : "") + + " dis=" + fallNoteDis + + (fallNoteDump != 0 + ? " dump-dis=" + fallNoteDumpDis : "") + + " v0=0x" + fallNoteV0.ToString("X") + + " s5=0x" + fallNoteS5.ToString("X") + + " ra=0x" + fallNoteRa.ToString("X") + + " sp=0x" + fallNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-fall" + + " (first I-fetch after fat FALL / INT-ON / epi skip; peek dump, do not invent next word;" + + " no jr hop 0x8003F78C; no invent 0x8033 / 0x9A / 0x9F / SUD)"); + } + + private static bool IsExn15C28CallerPc(uint pc) + { + return pc >= CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelay + && (pc & 3) == 0; + } + + private static bool IsExn15C28ListPopPc(uint pc) + { + return pc >= CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelay + && (pc & 3) == 0; + } + + private static uint DumpMem15C28CallerDump(uint pc) + { + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRa) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRaDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFp) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFpDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNop) + return 0; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMult) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMultDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLui) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLuiDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiu) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiuDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMflo) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMfloDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddu) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAdduDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJal) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRa) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRaDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBneDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenter) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFp) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFpDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGoto) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Delay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16DelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Delay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12DelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLw) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJr) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelayDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3Dump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLw) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLwDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeq) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeqDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJr) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDump; + if (pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelay) + return CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelayDump; + return 0; + } + + private static uint PeekExn15C28CallerDump(uint pc, uint fallback) + { + uint callerPeek = 0; + if (TryPeekLeftoverWait99DumpOnly(pc, out callerPeek) && callerPeek != 0) + return callerPeek; + uint callerTable = DumpMem15C28CallerDump(pc); + if (callerTable != 0) + return callerTable; + return fallback; + } + + private static bool TryPeekExn15C28CallerWordOrZero(uint dest, out uint peek) + { + peek = 0; + if (dest == 0 || (dest & 3) != 0 || IsExn15C28NoInventPage(dest)) + return false; + return TryPeekLeftoverWait99DumpOnly(dest, out peek); + } + + private static uint PeekExn15C28CallerHalfOrZero(uint dest) + { + if (dest == 0 || (dest & 1) != 0 || IsExn15C28NoInventPage(dest)) + return 0; + uint callerHalf = 0; + if (!TryPeekLeftoverWait99DumpOnly(dest & ~3u, out callerHalf)) + return 0; + return (dest & 2) != 0 ? (callerHalf >> 16) : (callerHalf & 0xFFFFu); + } + + private static bool IsExn15C28CallerInsaneA0(uint a0) + { + return IsExn15C28NoInventPage(a0) || IsExn15C28StkRecurseFrame(a0) + || IsDumpMemRefuseVa(a0) || (a0 & 3) != 0 || a0 >= 0x10000u; + } + + // Boot 90d6470: live $ra 0x8003F8B4 + // (FALL jal-link / dump b 0x8003F93C) + // is sane. Do not treat it as insane + // (that forced fall-through leave at + // twin 0x8003F9E8 and TLBS 0x800151D0). + private static bool IsExn15C28CallerInsaneLeave(uint leave) + { + return leave == 0 || (leave & 3) != 0 + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || leave == CoredllDllMainExn15C28OuterJalLink + || leave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || leave == CoredllDllMainExn15C28JalS1AluNext + || leave == CoredllDllMainExn15C28StkSwNext + || leave == CoredllDllMainExn15C28OuterJalLinkEpiPrologueJalDest + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneTakenJalDest + || leave == CoredllDllMainExn15C28OuterJalDestJr + || leave == CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRa + || IsExn15C28CallerPc(leave) || IsExn15C28ListPopPc(leave) + || (IsExn15C28RetFallPc(leave) + && leave != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa) + || IsExn15C28TrampolinePc(leave) + || IsDumpMemRefuseVa(leave) || IsExn15C28Na02Frame(leave) + || IsExn15C28NfffFrame(leave) || IsExn15C28N9ffFrame(leave) + || IsExn15C28HelperBody(leave) || IsExn15C28JalRaEpiRange(leave) + || IsLeftoverDestVa(leave) || IsWrapDestSize(leave) + || IsWrapDestFp50Va(leave); + } + + private static bool IsExn15C28CallerHonoredRaLeave(uint leave) + { + return leave != 0 && (leave & 3) == 0 + && leave != CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + && leave != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + && leave >= 0x80011000u && leave < 0x8005AB44u + && !IsExn15C28CallerInsaneLeave(leave); + } + + // Boot 2412828: 3F854 entered from + // 3F84C fall with live outer link + // ~0x8003F78C. FALL epi jr must + // honor that, not loop 3F8B4. + // 3F78C here is dump-true return, + // not a mid-function jr hop. + private static bool IsExn15C28FallEpiOuterLeave(uint leave) + { + if (leave == 0 || (leave & 3) != 0) + return false; + if (leave < 0x80011000u || leave >= 0x8005AB44u) + return false; + if (leave >= CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + && leave <= CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelay) + return false; + if (leave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || leave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || leave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || leave == 0x80048190u + || leave == 0x8003F888u) + return false; + if (IsExn15C28CallerPc(leave) || IsExn15C28ListPopPc(leave) + || IsExn15C28TrampolinePc(leave) || IsExn15C28HelperBody(leave) + || IsExn15C28JalRaEpiRange(leave) || IsDumpMemRefuseVa(leave) + || IsExn15C28Na02Frame(leave) || IsExn15C28NfffFrame(leave) + || IsExn15C28N9ffFrame(leave) || IsLeftoverDestVa(leave) + || IsWrapDestSize(leave) || IsWrapDestFp50Va(leave)) + return false; + return true; + } + + private static void TrySaveExn15C28Fn854OuterRa(uint[] regs) + { + if (_exn15C28AfterOuterJalEpiFn854OuterRa != 0) + return; + uint ra = PeekGpr(regs, 31); + if (IsExn15C28FallEpiOuterLeave(ra)) + _exn15C28AfterOuterJalEpiFn854OuterRa = ra; + } + + private static bool IsExn15C28FallEpiLwPc(uint pc) + { + return pc >= CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLw + && pc <= CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwRa + && (pc & 3) == 0; + } + + // Dump-true epi 3F940..3F958 is + // lw $fp/$s7..$ra,imm($sp) — or + // nop. Order/imm may differ from + // the invented 8FBE0010 map. + // Skip only; do not write GPRs. + private static bool IsExn15C28FallEpiSkipLw(uint word) + { + if (word == 0) + return true; + if (!IsMipsLoad(word)) + return false; + if ((word & 63) == 0x18 || (word & 63) == 0x16) + return false; + return true; + } + + private static void LogExn15C28RetCallerRaRefuse(uint pc, uint insn, + string why) + { + if (_exn15C28AfterOuterJalEpiRetCallerRaRefuseLogged) + return; + _exn15C28AfterOuterJalEpiRetCallerRaRefuseLogged = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-ra-refuse" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + " why=" + why + + " via=dump-mem-15c28-outer-jal-epi-ret-caller-ra-refuse" + + " (silent false on honored 3F8B4; peek dump;" + + " no invent 0x9A / 0x8032 / SUD; no hop 0x80048190)"); + } + + private static bool RefuseExn15C28RetCallerRa(uint pc, uint insn, + string why) + { + LogExn15C28RetCallerRaRefuse(pc, insn, why); + return false; + } + + private static bool TryExecDumpMem15C28CallerListPop(uint[] regs, + out bool empty, out bool lwZero) + { + empty = true; + lwZero = true; + uint callerPopLui = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopDump); + uint callerPopAdd = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2Dump); + uint callerPopK1 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3Dump); + uint callerPopLw = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLw, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLwDump); + uint callerPopBeq = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeq, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeqDump); + uint callerPopJr = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJr, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDump); + uint callerPopJrDelay = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelayDump); + if (callerPopLui != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopDump + || callerPopAdd != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop2Dump + || callerPopK1 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop3Dump + || callerPopLw != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopLwDump + || callerPopBeq != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopBeqDump + || callerPopJr != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDump + || callerPopJrDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPopJrDelayDump) + return false; + if (!IsDumpMemAluInsn(callerPopLui) || !IsDumpMemAluInsn(callerPopAdd) + || !IsDumpMemAluInsn(callerPopK1) || !IsMipsLoad(callerPopLw) + || (callerPopBeq >> 26) != 4 || !IsMipsJrRs(callerPopJr, 31) + || !IsDumpMemAluInsn(callerPopJrDelay)) + return false; + if ((callerPopLui & 63) == 0x16 || (callerPopAdd & 63) == 0x16 + || (callerPopK1 & 63) == 0x16 || (callerPopJrDelay & 63) == 0x16) + return false; + if (!TryExecDumpMemAlu(regs, callerPopLui) + || !TryExecDumpMemAlu(regs, callerPopAdd) + || !TryExecDumpMemAlu(regs, callerPopK1)) + return false; + uint callerPopA0 = PeekGpr(regs, 4); + uint callerPopWord = 0; + bool callerPopOk = TryPeekExn15C28CallerWordOrZero(callerPopA0, + out callerPopWord); + PokeGpr(regs, 2, callerPopOk ? callerPopWord : 0); + lwZero = !callerPopOk; + empty = PeekGpr(regs, 2) == 0; + if (!empty) + { + uint callerPopT1 = 0; + TryPeekExn15C28CallerWordOrZero(PeekGpr(regs, 2), out callerPopT1); + PokeGpr(regs, 9, callerPopT1); + } + if (!TryExecDumpMemAlu(regs, callerPopJrDelay)) + return false; + return true; + } + + private static bool TryExecDumpMem15C28CallerIncr(uint[] regs, + out bool lwZero, out bool swSkip) + { + lwZero = true; + swSkip = true; + uint callerIncLui = CoredllDllMainExn15C28OuterJalDestDump; + uint callerIncAdd = CoredllDllMainExn15C28OuterJalDest2Dump; + uint callerIncK1 = CoredllDllMainExn15C28OuterJalDest3Dump; + uint callerIncLw = CoredllDllMainExn15C28OuterJalDestNextDump; + uint callerIncAddiu = CoredllDllMainExn15C28OuterJalDestIncDump; + uint callerIncSw = CoredllDllMainExn15C28OuterJalDestSwDump; + uint callerIncJr = CoredllDllMainExn15C28OuterJalDestJrDump; + uint callerIncJrDelay = CoredllDllMainExn15C28OuterJalDestJrDelayDump; + uint callerIncLuiPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDest, callerIncLui); + uint callerIncAddPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDest2, callerIncAdd); + uint callerIncK1Peek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDest3, callerIncK1); + uint callerIncLwPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDestNext, callerIncLw); + uint callerIncAddiuPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDestInc, callerIncAddiu); + uint callerIncSwPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDestSw, callerIncSw); + uint callerIncJrPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDestJr, callerIncJr); + uint callerIncJrDelayPeek = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalDestJrDelay, callerIncJrDelay); + if (callerIncLuiPeek != callerIncLui || callerIncAddPeek != callerIncAdd + || callerIncK1Peek != callerIncK1 || callerIncLwPeek != callerIncLw + || callerIncAddiuPeek != callerIncAddiu + || callerIncSwPeek != callerIncSw + || callerIncJrPeek != callerIncJr + || callerIncJrDelayPeek != callerIncJrDelay) + return false; + if (!IsDumpMemAluInsn(callerIncLuiPeek) + || !IsDumpMemAluInsn(callerIncAddPeek) + || !IsDumpMemAluInsn(callerIncK1Peek) + || !IsMipsLoad(callerIncLwPeek) + || !IsDumpMemAluInsn(callerIncAddiuPeek) + || !IsMipsStore(callerIncSwPeek) + || !IsMipsJrRs(callerIncJrPeek, 31) + || !IsDumpMemAluInsn(callerIncJrDelayPeek)) + return false; + if ((callerIncLuiPeek & 63) == 0x16 || (callerIncAddPeek & 63) == 0x16 + || (callerIncK1Peek & 63) == 0x16 + || (callerIncAddiuPeek & 63) == 0x16 + || (callerIncJrDelayPeek & 63) == 0x16) + return false; + if (!TryExecDumpMemAlu(regs, callerIncLuiPeek) + || !TryExecDumpMemAlu(regs, callerIncAddPeek) + || !TryExecDumpMemAlu(regs, callerIncK1Peek)) + return false; + uint callerIncA0 = PeekGpr(regs, 4); + uint callerIncWord = 0; + bool callerIncOk = TryPeekExn15C28CallerWordOrZero(callerIncA0, + out callerIncWord); + PokeGpr(regs, 2, callerIncOk ? callerIncWord : 0); + lwZero = !callerIncOk; + if (!TryExecDumpMemAlu(regs, callerIncAddiuPeek)) + return false; + swSkip = IsExn15C28NoInventPage(callerIncA0) + || !TryPeekExn15C28CallerWordOrZero(callerIncA0, out _); + if (!swSkip) + return false; + if (!TryExecDumpMemAlu(regs, callerIncJrDelayPeek)) + return false; + return true; + } + + // Live 29a9913: FIRST-WIN FALL leave + // 0x8003F964 then 9A/99FF after-stk + // spam + TLBL 0x800151A4 + // a0=0xBDFE5B4. Fat dump-true + // caller 0x8003F964–epi: skip 9A + // sw/lw; ALU table 0x8032024C; + // delay a0:=s7+8 then list-pop + // peek-or-zero; skip 3F854 + // re-enter (FALL already logged); + // jr $ra + delay addiu $sp,+32; + // honor sane ra (0x8003F8B4) else + // 0x8003F9E8. Do not fall through + // into twin 0x8003F9E8 when ra is + // sane (TLBS 0x800151D0). Break + // after-stk 3F964 loop. No invent + // 0x8032 / 0x9A / 0x99FF. No MUL + // 0x16. No hop 0x80048190. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCaller(MipsBus bus, + uint[] regs, uint pc, uint insn, bool inDelay, ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetFallLogged) + return false; + if (_exn15C28AfterOuterJalEpiRetCallerLogged) + { + if (inDelay) + return false; + if (!IsExn15C28CallerPc(pc) && !IsExn15C28ListPopPc(pc) + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCaller) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 || IsExn15C28CallerInsaneLeave(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || IsExn15C28CallerPc(capLeave) || IsExn15C28ListPopPc(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFall + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetBneFallNext + || capLeave == CoredllDllMainKdataEpcEa88 + || (capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + && (_exn15C28AfterOuterJalEpiRetCallerNextFnLogged + || IsExn15C28CallerHonoredRaLeave( + _exn15C28AfterOuterJalEpiRetCallerLeave)))) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + && !IsExn15C28CallerPc(pc) && !IsExn15C28ListPopPc(pc)) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint callerAddiuSp = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCaller, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerDump); + uint callerSwRa = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRa, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRaDump); + uint callerSwFp = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFp, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFpDump); + uint callerSwS7 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7Dump); + uint callerV0Imm = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0Dump); + uint callerMult = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMult, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMultDump); + uint callerLui = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLui, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLuiDump); + uint callerAddiuV0 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiu, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiuDump); + uint callerMflo = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMflo, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMfloDump); + uint callerAddu = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddu, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAdduDump); + uint callerJal = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJal, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDump); + uint callerJalDelay = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelayDump); + uint callerOrFp = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRa, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRaDump); + uint callerBne = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBneDump); + uint callerReenter = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenter, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDump); + uint callerLhu = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelayDump); + uint callerOrFp2 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFp, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFpDump); + uint callerBne2 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2Dump); + uint callerGoto = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGoto, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDump); + uint callerGotoDelay = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelayDump); + uint callerIncr16 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Dump); + uint callerIncr16Delay = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Delay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16DelayDump); + uint callerIncr12 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Dump); + uint callerIncr12Delay = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Delay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12DelayDump); + uint callerOrV0 = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0Dump); + uint callerEpiLw = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLw, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLwDump); + uint callerEpiJr = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJr, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDump); + uint callerEpiJrDelay = PeekExn15C28CallerDump( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelay, + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelayDump); + if (callerAddiuSp != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerDump + || callerSwRa != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwRaDump + || callerSwFp != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwFpDump + || callerSwS7 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerSwS7Dump + || callerV0Imm != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerV0Dump + || callerMult != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMultDump + || callerLui != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerLuiDump + || callerAddiuV0 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAddiuDump + || callerMflo != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerMfloDump + || callerAddu != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerAdduDump + || callerJal != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDump + || callerJalDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalDelayDump + || callerOrFp != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJalRaDump + || callerBne != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBneDump + || callerReenter != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDump + || callerLhu != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenterDelayDump + || callerOrFp2 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrFpDump + || callerBne2 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2Dump + || callerGoto != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDump + || callerGotoDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGotoDelayDump + || callerIncr16 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16Dump + || callerIncr16Delay != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16DelayDump + || callerIncr12 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12Dump + || callerIncr12Delay != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12DelayDump + || callerOrV0 != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerOrV0Dump + || callerEpiLw != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLwDump + || callerEpiJr != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDump + || callerEpiJrDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiJrDelayDump) + return false; + if (!IsDumpMemAluInsn(callerAddiuSp) || !IsMipsStore(callerSwRa) + || !IsMipsStore(callerSwFp) || !IsMipsStore(callerSwS7) + || !IsDumpMemAluInsn(callerV0Imm) + || (callerMult >> 26) != 0 || (callerMult & 63) != 0x18 + || (callerMult & 63) == 0x16 + || !IsDumpMemAluInsn(callerLui) || !IsDumpMemAluInsn(callerAddiuV0) + || (callerMflo >> 26) != 0 || (callerMflo & 63) != 0x12 + || !IsDumpMemAluInsn(callerAddu) || (callerJal >> 26) != 3 + || !IsDumpMemAluInsn(callerJalDelay) || !IsDumpMemAluInsn(callerOrFp) + || (callerBne >> 26) != 5 || (callerReenter >> 26) != 3 + || !IsMipsLoad(callerLhu) || !IsDumpMemAluInsn(callerOrFp2) + || (callerBne2 >> 26) != 5 || (callerGoto >> 26) != 4 + || !IsDumpMemAluInsn(callerGotoDelay) || (callerIncr16 >> 26) != 3 + || !IsDumpMemAluInsn(callerIncr16Delay) || (callerIncr12 >> 26) != 3 + || !IsDumpMemAluInsn(callerIncr12Delay) || !IsDumpMemAluInsn(callerOrV0) + || !IsMipsLoad(callerEpiLw) || !IsMipsJrRs(callerEpiJr, 31) + || !IsDumpMemAluInsn(callerEpiJrDelay)) + return false; + if ((callerAddiuSp & 63) == 0x16 || (callerV0Imm & 63) == 0x16 + || (callerLui & 63) == 0x16 || (callerAddiuV0 & 63) == 0x16 + || (callerAddu & 63) == 0x16 || (callerJalDelay & 63) == 0x16 + || (callerOrFp & 63) == 0x16 || (callerOrFp2 & 63) == 0x16 + || (callerGotoDelay & 63) == 0x16 + || (callerIncr16Delay & 63) == 0x16 + || (callerIncr12Delay & 63) == 0x16 + || (callerOrV0 & 63) == 0x16 + || (callerEpiJrDelay & 63) == 0x16) + return false; + uint callerJalDest = (CoredllDllMainExn15C28OuterJalLinkEpiRetCallerJal + & 0xF0000000u) | ((callerJal & 0x03FFFFFFu) << 2); + uint callerReenterDest = (CoredllDllMainExn15C28OuterJalLinkEpiRetCallerReenter + & 0xF0000000u) | ((callerReenter & 0x03FFFFFFu) << 2); + uint callerIncr16Dest = (CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16 + & 0xF0000000u) | ((callerIncr16 & 0x03FFFFFFu) << 2); + uint callerIncr12Dest = (CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12 + & 0xF0000000u) | ((callerIncr12 & 0x03FFFFFFu) << 2); + if (callerJalDest != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerListPop + || callerReenterDest != CoredllDllMainExn15C28OuterJalLinkEpiBeqBneFallJrNext + || callerIncr16Dest != CoredllDllMainExn15C28OuterJalDest + || callerIncr12Dest != CoredllDllMainExn15C28OuterJalDest) + return false; + int callerBneImm = (short)(callerBne & 0xFFFF); + uint callerBneDest = unchecked( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne + 4u + + (uint)(callerBneImm * 4)); + int callerBne2Imm = (short)(callerBne2 & 0xFFFF); + uint callerBne2Dest = unchecked( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerBne2 + 4u + + (uint)(callerBne2Imm * 4)); + int callerGotoImm = (short)(callerGoto & 0xFFFF); + uint callerGotoDest = unchecked( + CoredllDllMainExn15C28OuterJalLinkEpiRetCallerGoto + 4u + + (uint)(callerGotoImm * 4)); + if (callerBneDest != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr12 + || callerBne2Dest != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerIncr16 + || callerGotoDest != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerEpiLw) + return false; + if (insn != 0 && insn != callerAddiuSp && !IsDumpMemAluInsn(insn) + && !IsMipsLoad(insn) && !IsMipsStore(insn) + && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != 0 && insn != callerAddiuSp + && pc == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller) + TryHealDumpInsn(bus, pc, insn, callerAddiuSp); + if (!TryExecDumpMemAlu(regs, callerAddiuSp)) + return false; + if (!TryExecDumpMemAlu(regs, callerV0Imm)) + return false; + uint callerA0In = PeekGpr(regs, 4); + if (IsExn15C28CallerInsaneA0(callerA0In)) + callerA0In = 0; + uint callerMultV0 = PeekGpr(regs, 2); + PokeGpr(regs, 3, unchecked((uint)((ulong)callerA0In * (ulong)callerMultV0))); + if (!TryExecDumpMemAlu(regs, callerLui)) + return false; + if (!TryExecDumpMemAlu(regs, callerAddiuV0)) + return false; + if (PeekGpr(regs, 2) != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerTable) + return false; + if (!TryExecDumpMemAlu(regs, callerAddu)) + return false; + if (!TryExecDumpMemAlu(regs, callerJalDelay)) + return false; + bool callerPopEmpty; + bool callerPopLwZero; + if (!TryExecDumpMem15C28CallerListPop(regs, out callerPopEmpty, + out callerPopLwZero)) + return false; + if (!TryExecDumpMemAlu(regs, callerOrFp)) + return false; + bool callerIncr16Ran = false; + bool callerIncr12Ran = false; + bool callerIncrLwZero = true; + bool callerIncrSwSkip = true; + bool callerReenterSkip = true; + bool callerLhuZero = true; + if (PeekGpr(regs, 30) != 0) + { + if (!TryExecDumpMemAlu(regs, callerIncr12Delay)) + return false; + if (!TryExecDumpMem15C28CallerIncr(regs, out callerIncrLwZero, + out callerIncrSwSkip)) + return false; + callerIncr12Ran = true; + if (!TryExecDumpMemAlu(regs, callerOrV0)) + return false; + } + else + { + PokeGpr(regs, 4, PeekExn15C28CallerHalfOrZero(PeekGpr(regs, 23))); + callerLhuZero = PeekGpr(regs, 4) == 0; + PokeGpr(regs, 2, 0); + callerReenterSkip = true; + if (!TryExecDumpMemAlu(regs, callerOrFp2)) + return false; + if (PeekGpr(regs, 30) != 0) + { + if (!TryExecDumpMemAlu(regs, callerIncr16Delay)) + return false; + if (!TryExecDumpMem15C28CallerIncr(regs, out callerIncrLwZero, + out callerIncrSwSkip)) + return false; + callerIncr16Ran = true; + if (!TryExecDumpMemAlu(regs, callerIncr12Delay)) + return false; + if (!TryExecDumpMem15C28CallerIncr(regs, out callerIncrLwZero, + out callerIncrSwSkip)) + return false; + callerIncr12Ran = true; + if (!TryExecDumpMemAlu(regs, callerOrV0)) + return false; + } + else if (!TryExecDumpMemAlu(regs, callerGotoDelay)) + return false; + } + if (!TryExecDumpMemAlu(regs, callerEpiJrDelay)) + return false; + uint callerRa = PeekGpr(regs, 31); + bool callerRaHonor = IsExn15C28CallerHonoredRaLeave(callerRa); + uint callerLeave = callerRaHonor + ? callerRa + : CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn; + if (!callerRaHonor && IsExn15C28CallerInsaneLeave(callerLeave)) + return false; + if (callerLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = callerLeave; + _exn15C28AfterOuterJalEpiRetFallNextLogged = true; + _exn15C28AfterOuterJalEpiRetCallerLogged = true; + _exn15C28AfterOuterJalEpiRetCallerLeave = callerLeave; + uint callerSp = PeekGpr(regs, 29); + uint callerV0Log = PeekGpr(regs, 2); + uint callerV1 = PeekGpr(regs, 3); + uint callerA0 = PeekGpr(regs, 4); + uint callerS7 = PeekGpr(regs, 23); + uint callerFp = PeekGpr(regs, 30); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-ret-caller"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + callerAddiuSp.ToString("X") + + " dest=0x" + callerLeave.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller" + + " pc=0x" + pc.ToString("X") + + " next=0x" + callerLeave.ToString("X") + + " dump=0x" + callerAddiuSp.ToString("X") + + (insn != 0 && insn != callerAddiuSp + ? " live=0x" + insn.ToString("X") : "") + + " v0=0x" + callerV0Log.ToString("X") + + " v1=0x" + callerV1.ToString("X") + + " a0=0x" + callerA0.ToString("X") + + " s7=0x" + callerS7.ToString("X") + + " fp=0x" + callerFp.ToString("X") + + (callerPopEmpty ? " pop-empty=1" : " pop-empty=0") + + (callerPopLwZero ? " pop-lw=0 zero=1" : " pop-lw=1") + + (callerReenterSkip ? " reenter-skip=1" : " reenter-skip=0") + + (callerLhuZero ? " lhu=0 zero=1" : " lhu=1") + + (callerIncr16Ran ? " incr16=1" : " incr16=0") + + (callerIncr12Ran ? " incr12=1" : " incr12=0") + + (callerIncrLwZero ? " incr-lw=0" : " incr-lw=1") + + (callerIncrSwSkip ? " incr-sw-skip=1" : " incr-sw-skip=0") + + (callerRaHonor ? " ra-honor=1" : " ra-skip=1") + + " ra=0x" + callerRa.ToString("X") + + " sp=0x" + callerSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (fat caller 3F964–epi + list-pop 15198 peek-or-zero + skip 3F854 re-enter;" + + " no invent 0x8032 / SUD / 0x9A / 0x99FF; no jr hop 0x8003F78C;" + + " no hop 0x80048190; no MULT 0x8003F748; break after-stk-sw 3F964 loop)"); + return true; + } + + public static void TryNoteDumpMem15C28AfterOuterJalEpiRetCaller(MipsBus bus, + uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiRetCallerLogged + || _exn15C28AfterOuterJalEpiRetCallerNextLogged) + return; + if (pc != _exn15C28AfterOuterJalEpiRetCallerLeave + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) || IsExn15C28ListPopPc(pc)) + return; + _exn15C28AfterOuterJalEpiRetCallerNextLogged = true; + uint callerNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out callerNoteDump); + uint callerNoteRa = PeekGpr(regs, 31); + uint callerNoteSp = PeekGpr(regs, 29); + uint callerNoteV0 = PeekGpr(regs, 2); + uint callerNoteA0 = PeekGpr(regs, 4); + uint callerNoteS7 = PeekGpr(regs, 23); + string callerNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string callerNoteDumpDis = callerNoteDump != 0 + ? FormatMipsOp(pc, callerNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-ret-caller"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (callerNoteDump != 0 + ? " dump=0x" + callerNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-caller"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-ret-caller" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (callerNoteDump != 0 + ? " dump=0x" + callerNoteDump.ToString("X") : "") + + " dis=" + callerNoteDis + + (callerNoteDump != 0 + ? " dump-dis=" + callerNoteDumpDis : "") + + " v0=0x" + callerNoteV0.ToString("X") + + " a0=0x" + callerNoteA0.ToString("X") + + " s7=0x" + callerNoteS7.ToString("X") + + " ra=0x" + callerNoteRa.ToString("X") + + " sp=0x" + callerNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-caller" + + " (first I-fetch after fat caller / list-pop / epi skip; peek dump, do not invent next word;" + + " no jr hop 0x8003F78C; no hop 0x80048190; no invent 0x8032 / 0x9A / 0x99FF / SUD)"); + } + + // Live 2412828: fat caller honored + // $ra 0x8003F8B4 then STALL on + // beq. Dump-true win: b 0x8003F93C + // + nop; or $v0,$s5; skip 9A epi + // lw 3F940..3F958; jr $ra + delay + // addiu $sp,+48. Honor saved outer + // ra (~0x8003F78C at 3F854 entry), + // not loop 3F8B4 / twin 3F9E8. + // nk.bin B000FF rec 0x80011000: + // 3F8B4/3F93C/3F940..3F960 MATCH + // the 8FBE0010 map. Boot 8cae3af + // silent false was not that map — + // first-take `inDelay` and + // HonoredRaLeave returned false + // before Hive (after-outer Note; + // 0 ret-caller-ra). Take this + // honored land even in a delay + // slot. Skip 9A lw writes. Force + // leave ~0x8003F78C if outer-leave + // gating fails. 3F78C is dump-true + // epi return, not a jr hop. + // Never hop 0x8003F888 / 0x80048190 + // / MULT 0x8003F748. Never MUL 0x16. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRa( + MipsBus bus, uint[] regs, uint pc, uint insn, bool inDelay, + ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetCallerLogged) + return false; + // Boot 8cae3af: Leave is dump- + // true FallJalRa 0x8003F8B4 + // (Hive ra-honor=1). Do not + // also require HonoredRaLeave — + // that helper treats some + // overlay leaves insane and + // aborted before Hive. + if (_exn15C28AfterOuterJalEpiRetCallerLeave + != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa) + return false; + if (IsExn15C28BadABeforeE000()) + return RefuseExn15C28RetCallerRa(pc, insn, "bada-before-e000"); + if (_exn15C28AfterOuterJalEpiRetCallerRaLogged) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi + && !IsExn15C28FallEpiLwPc(pc) + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJr) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || !IsExn15C28FallEpiOuterLeave(capLeave) + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || IsExn15C28CallerPc(capLeave) || IsExn15C28ListPopPc(capLeave) + || capLeave == CoredllDllMainKdataEpcEa88 + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa) + return false; + if (IsExn15C28StkRecurseFrame(PeekGpr(regs, 29))) + return RefuseExn15C28RetCallerRa(pc, insn, "toxic-sp"); + // Honored jr land, not a delay + // we must skip. Boot 8cae3af + // `if (inDelay) return false` + // was silent (Note still fired). + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLw) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return RefuseExn15C28RetCallerRa(pc, insn, + inDelay ? "pc-refuse in-delay" : "pc-refuse"); + uint callerRaDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out callerRaDump) + || callerRaDump == 0) + callerRaDump = CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRaDump; + if (callerRaDump != CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRaDump) + return RefuseExn15C28RetCallerRa(pc, insn, "beq-dump"); + if ((callerRaDump >> 26) != 4 + || (callerRaDump & 63) == 0x18 + || (callerRaDump & 63) == 0x16) + return RefuseExn15C28RetCallerRa(pc, insn, "beq-op"); + int callerRaImm = (short)(callerRaDump & 0xFFFF); + uint callerRaDest = unchecked(pc + 4u + (uint)(callerRaImm * 4)); + if (callerRaDest != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi) + return RefuseExn15C28RetCallerRa(pc, insn, "beq-dest"); + if (insn != callerRaDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn) && (insn >> 26) != 4) + return RefuseExn15C28RetCallerRa(pc, insn, "beq-live"); + if (insn != callerRaDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, callerRaDump); + uint callerRaDelayPeek = 0; + TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallGotoDelay, + out callerRaDelayPeek); + if (callerRaDelayPeek != 0 && callerRaDelayPeek != 0x00000000u) + { + if (!IsDumpMemAluInsn(callerRaDelayPeek) + || (callerRaDelayPeek & 63) == 0x18 + || (callerRaDelayPeek & 63) == 0x16) + return RefuseExn15C28RetCallerRa(pc, insn, "delay"); + if (!TryExecDumpMemAlu(regs, callerRaDelayPeek)) + return RefuseExn15C28RetCallerRa(pc, insn, "delay-exec"); + } + uint callerRaEpiDump = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpi, + out callerRaEpiDump) || callerRaEpiDump == 0) + callerRaEpiDump = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiDump; + if (callerRaEpiDump != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiDump + || !IsDumpMemAluInsn(callerRaEpiDump) + || (callerRaEpiDump & 63) == 0x18 + || (callerRaEpiDump & 63) == 0x16) + return RefuseExn15C28RetCallerRa(pc, insn, "or-dump"); + if (!TryExecDumpMemAlu(regs, callerRaEpiDump)) + return RefuseExn15C28RetCallerRa(pc, insn, "or-exec"); + for (uint lwPc = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLw; + lwPc <= CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiLwRa; + lwPc += 4) + { + uint lwDump = DumpMem15C28RetFallDump(lwPc); + uint lwPeek = 0; + if (!TryPeekLeftoverWait99DumpOnly(lwPc, out lwPeek) + || lwPeek == 0) + lwPeek = lwDump; + if (lwPeek == 0) + continue; + if (!IsExn15C28FallEpiSkipLw(lwPeek)) + return RefuseExn15C28RetCallerRa(pc, insn, + "epi-lw-op pc=0x" + lwPc.ToString("X") + + " word=0x" + lwPeek.ToString("X")); + } + uint callerRaJr = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJr, + out callerRaJr) || callerRaJr == 0) + callerRaJr = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDump; + if (callerRaJr != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDump + || !IsMipsJrRs(callerRaJr, 31)) + return RefuseExn15C28RetCallerRa(pc, insn, "jr-dump"); + uint callerRaJrDelay = 0; + if (!TryPeekLeftoverWait99DumpOnly( + CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelay, + out callerRaJrDelay) || callerRaJrDelay == 0) + callerRaJrDelay = CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelayDump; + if (callerRaJrDelay != CoredllDllMainExn15C28OuterJalLinkEpiRetFallEpiJrDelayDump + || !IsDumpMemAluInsn(callerRaJrDelay) + || (callerRaJrDelay & 63) == 0x18 + || (callerRaJrDelay & 63) == 0x16) + return RefuseExn15C28RetCallerRa(pc, insn, "jr-delay"); + if (!TryExecDumpMemAlu(regs, callerRaJrDelay)) + return RefuseExn15C28RetCallerRa(pc, insn, "jr-delay-exec"); + uint callerRaNext = _exn15C28AfterOuterJalEpiFn854OuterRa; + if (!IsExn15C28FallEpiOuterLeave(callerRaNext) + || callerRaNext == pc + || callerRaNext == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || callerRaNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || callerRaNext == 0x80048190u) + callerRaNext = CoredllDllMainExn15C28OuterJalLink; + // Dump-true lhu land. Do not + // abort the take if a later + // outer-leave helper disagrees. + if (callerRaNext == 0 || (callerRaNext & 3) != 0 + || callerRaNext == pc + || callerRaNext == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || callerRaNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || callerRaNext == 0x80048190u + || IsDumpMemRefuseVa(callerRaNext) + || IsLeftoverDestVa(callerRaNext) + || IsWrapDestSize(callerRaNext) + || IsWrapDestFp50Va(callerRaNext) + || IsExn15C28Na02Frame(callerRaNext)) + callerRaNext = CoredllDllMainExn15C28OuterJalLink; + if (callerRaNext == 0 || (callerRaNext & 3) != 0 + || callerRaNext == pc + || IsDumpMemRefuseVa(callerRaNext) + || IsLeftoverDestVa(callerRaNext)) + return RefuseExn15C28RetCallerRa(pc, insn, + "outer-leave next=0x" + callerRaNext.ToString("X")); + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = callerRaNext; + _exn15C28AfterOuterJalEpiRetCallerNextLogged = true; + _exn15C28AfterOuterJalEpiRetCallerRaLogged = true; + _exn15C28AfterOuterJalEpiRetCallerRaLeave = callerRaNext; + uint callerRaLog = PeekGpr(regs, 31); + uint callerRaV0 = PeekGpr(regs, 2); + uint callerRaS5 = PeekGpr(regs, 21); + uint callerRaSpLog = PeekGpr(regs, 29); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-ret-caller-ra"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + callerRaDump.ToString("X") + + " dest=0x" + callerRaNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-ra" + + " pc=0x" + pc.ToString("X") + + " next=0x" + callerRaNext.ToString("X") + + " dump=0x" + callerRaDump.ToString("X") + + (insn != 0 && insn != callerRaDump + ? " live=0x" + insn.ToString("X") : "") + + " v0=0x" + callerRaV0.ToString("X") + + " s5=0x" + callerRaS5.ToString("X") + + " ra=0x" + callerRaLog.ToString("X") + + " outer=0x" + callerRaNext.ToString("X") + + " sp=0x" + callerRaSpLog.ToString("X") + + (inDelay ? " in-delay=1" : " in-delay=0") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump b 0x8003F93C + or $v0,$s5; skip 9A epi lw;" + + " jr outer ~0x8003F78C; take even if delay-slot fetch;" + + " no loop 3F8B4; no twin 3F9E8; no invent 0x9A / 0x8032 / SUD;" + + " no hop 0x8003F888; no MULT 0x8003F748; no hop 0x80048190)"); + return true; + } + + // Live 8cae3af: after fat FALL epi + // jr, first I-fetch at outer + // 0x8003F78C dump lhu $v0,0($s7). + // 3F78C is dump-true epi return, + // not a leftover jr hop dest. + // Peek *$s7 only. Load $v0 if dest + // peeks; dest-miss skips subu/addu + // that use $v0. PC:=0x8003F798. + // Do not invent $s7 / 0x8033 / dest + // / 0x9A. Never hop 0x8003F888 / + // MULT 0x8003F748 / 0x80048190. + // Never MUL 0x16. Not LoadO32. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaLhu( + MipsBus bus, uint[] regs, uint pc, uint insn, bool inDelay, + ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetCallerRaLogged) + return false; + if (IsExn15C28BadABeforeE000()) + return false; + if (_exn15C28AfterOuterJalEpiRetCallerRaLhuLogged) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLink) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == CoredllDllMainKdataEpcEa88 + || capLeave == 0x80048190u + || !IsExn15C28FallEpiOuterLeave(capLeave) + || IsExn15C28CallerPc(capLeave) + || IsExn15C28ListPopPc(capLeave) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLink) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkAfter) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) + || IsExn15C28ListPopPc(pc)) + return false; + uint lhuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out lhuDump) || lhuDump == 0) + lhuDump = CoredllDllMainExn15C28OuterJalLinkDump; + if (lhuDump != CoredllDllMainExn15C28OuterJalLinkDump) + return false; + if ((lhuDump & 63) == 0x18 || (lhuDump & 63) == 0x16) + return false; + if (insn != lhuDump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != lhuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, lhuDump); + uint lhuS7 = PeekGpr(regs, 23); + uint lhuPeek = 0; + bool destOk = !IsExn15C28NoInventPage(lhuS7) + && TryPeekExn15C28OuterJalLhuDest(bus, lhuS7, out lhuPeek); + if (destOk) + { + PokeGpr(regs, 2, lhuPeek); + uint alu1 = DumpMem15C28AfterWord( + CoredllDllMainExn15C28OuterJalLinkAlu); + uint alu2 = DumpMem15C28AfterWord( + CoredllDllMainExn15C28OuterJalLinkAlu2); + if (alu1 == 0) + alu1 = CoredllDllMainExn15C28OuterJalLinkAluDump; + if (alu2 == 0) + alu2 = CoredllDllMainExn15C28OuterJalLinkAlu2Dump; + if (alu1 != CoredllDllMainExn15C28OuterJalLinkAluDump + || alu2 != CoredllDllMainExn15C28OuterJalLinkAlu2Dump) + return false; + if ((alu1 & 63) == 0x18 || (alu1 & 63) == 0x16 + || (alu2 & 63) == 0x18 || (alu2 & 63) == 0x16) + return false; + if (alu1 != 0 && IsDumpMemAluInsn(alu1)) + TryExecDumpMemAlu(regs, alu1); + if (alu2 != 0 && IsDumpMemAluInsn(alu2)) + TryExecDumpMemAlu(regs, alu2); + } + uint lhuNext = CoredllDllMainExn15C28OuterJalLinkAfter; + if (!IsExn15C28FallEpiOuterLeave(lhuNext) + || lhuNext == pc + || lhuNext == CoredllDllMainExn15C28OuterJalLink + || lhuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || lhuNext == CoredllDllMainKdataEpcEa88 + || lhuNext == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || lhuNext == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || lhuNext == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || lhuNext == 0x80048190u + || IsExn15C28CallerPc(lhuNext) + || IsExn15C28ListPopPc(lhuNext) + || IsDumpMemRefuseVa(lhuNext) + || IsExn15C28Na02Frame(lhuNext) + || IsExn15C28NfffFrame(lhuNext) + || IsExn15C28N9ffFrame(lhuNext) + || IsExn15C28HelperBody(lhuNext) + || IsExn15C28JalRaEpiRange(lhuNext) + || IsLeftoverDestVa(lhuNext) + || IsWrapDestSize(lhuNext) + || IsWrapDestFp50Va(lhuNext)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = lhuNext; + _exn15C28AfterOuterJalEpiRetCallerRaLhuLogged = true; + _exn15C28AfterOuterJalEpiRetCallerRaLeave = lhuNext; + uint lhuRa = PeekGpr(regs, 31); + uint lhuSp = PeekGpr(regs, 29); + uint lhuV0 = PeekGpr(regs, 2); + uint lhuFp = PeekGpr(regs, 30); + uint lhuS6 = PeekGpr(regs, 22); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-ret-caller-ra-lhu" + : "dump-mem-15c28-outer-jal-epi-ret-caller-ra-lhu-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + lhuDump.ToString("X") + + " dest=0x" + lhuS7.ToString("X") + + (destOk ? " *s7=0x" + lhuPeek.ToString("X") : " *s7-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-ra-lhu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + lhuNext.ToString("X") + + " dump=0x" + lhuDump.ToString("X") + + (insn != 0 && insn != lhuDump ? " live=0x" + insn.ToString("X") : "") + + " s7=0x" + lhuS7.ToString("X") + + (destOk ? " *s7=0x" + lhuPeek.ToString("X") : " *s7-miss") + + " v0=0x" + lhuV0.ToString("X") + + " fp=0x" + lhuFp.ToString("X") + + " s6=0x" + lhuS6.ToString("X") + + " ra=0x" + lhuRa.ToString("X") + + " sp=0x" + lhuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lhu $v0,0($s7); peek *$s7 only;" + + " dest miss skips $v0 ALU; 3F78C epi return I-fetch;" + + " no invent $s7 / 0x8033 / dest / 0x9A;" + + " no hop 0x8003F888; no MULT 0x8003F748; no hop 0x80048190)"); + return true; + } + + // Live 4b1d20d: after epi-ret lhu, + // first I-fetch at 0x8003F798 dump + // lw $v0,0($s3). Peek *$s3 only. + // Load $v0 if dest peeks; dest-miss + // leaves $v0. PC:=0x8003F79C. + // Do not invent $s3 / 0x8033 / dest + // / 0x9A. Never hop 0x8003F888 / + // MULT 0x8003F748 / 0x80048190 / + // bne-taken path. Never MUL 0x16. + // Not LoadO32. No leftover-hop. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaS3( + MipsBus bus, uint[] regs, uint pc, uint insn, bool inDelay, + ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetCallerRaLhuLogged) + return false; + if (_exn15C28AfterOuterJalEpiRetCallerRaS3Logged) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkAfter) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28OuterJalLinkAfter + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == CoredllDllMainKdataEpcEa88 + || capLeave == 0x80048190u + || !IsExn15C28FallEpiOuterLeave(capLeave) + || IsExn15C28CallerPc(capLeave) + || IsExn15C28ListPopPc(capLeave) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkAfter) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkT1) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) + || IsExn15C28ListPopPc(pc)) + return false; + uint s3Dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out s3Dump) || s3Dump == 0) + s3Dump = CoredllDllMainExn15C28OuterJalLinkAfterDump; + if (s3Dump != CoredllDllMainExn15C28OuterJalLinkAfterDump) + return false; + if ((s3Dump & 63) == 0x18 || (s3Dump & 63) == 0x16) + return false; + if (insn != s3Dump && insn != 0 && !IsMipsLoad(insn) + && !IsMipsAbsRs0Store(insn) && !IsDumpMemAluInsn(insn)) + return false; + if (insn != s3Dump && insn != 0) + TryHealDumpInsn(bus, pc, insn, s3Dump); + uint s3Base = PeekGpr(regs, 19); + uint s3Peek = 0; + bool destOk = !IsExn15C28NoInventPage(s3Base) + && TryPeekExn15C28OuterJalIncDest(bus, s3Base, out s3Peek); + if (destOk) + PokeGpr(regs, 2, s3Peek); + uint s3Next = CoredllDllMainExn15C28OuterJalLinkT1; + if (!IsExn15C28FallEpiOuterLeave(s3Next) + || s3Next == pc + || s3Next == CoredllDllMainExn15C28OuterJalLink + || s3Next == CoredllDllMainExn15C28OuterJalLinkAfter + || s3Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || s3Next == CoredllDllMainKdataEpcEa88 + || s3Next == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || s3Next == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || s3Next == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || s3Next == 0x80048190u + || IsExn15C28CallerPc(s3Next) + || IsExn15C28ListPopPc(s3Next) + || IsDumpMemRefuseVa(s3Next) + || IsExn15C28Na02Frame(s3Next) + || IsExn15C28NfffFrame(s3Next) + || IsExn15C28N9ffFrame(s3Next) + || IsExn15C28HelperBody(s3Next) + || IsExn15C28JalRaEpiRange(s3Next) + || IsLeftoverDestVa(s3Next) + || IsWrapDestSize(s3Next) + || IsWrapDestFp50Va(s3Next)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = s3Next; + _exn15C28AfterOuterJalEpiRetCallerRaS3Logged = true; + _exn15C28AfterOuterJalEpiRetCallerRaLeave = s3Next; + uint s3Ra = PeekGpr(regs, 31); + uint s3Sp = PeekGpr(regs, 29); + uint s3V0 = PeekGpr(regs, 2); + uint s3S4 = PeekGpr(regs, 20); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = destOk + ? "dump-mem-15c28-outer-jal-epi-ret-caller-ra-s3" + : "dump-mem-15c28-outer-jal-epi-ret-caller-ra-s3-skip"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + s3Dump.ToString("X") + + " dest=0x" + s3Base.ToString("X") + + (destOk ? " *s3=0x" + s3Peek.ToString("X") : " *s3-miss") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-ra-s3" + + " pc=0x" + pc.ToString("X") + + " next=0x" + s3Next.ToString("X") + + " dump=0x" + s3Dump.ToString("X") + + (insn != 0 && insn != s3Dump ? " live=0x" + insn.ToString("X") : "") + + " s3=0x" + s3Base.ToString("X") + + (destOk ? " *s3=0x" + s3Peek.ToString("X") : " *s3-miss") + + " v0=0x" + s3V0.ToString("X") + + " s4=0x" + s3S4.ToString("X") + + " ra=0x" + s3Ra.ToString("X") + + " sp=0x" + s3Sp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump lw $v0,0($s3); peek *$s3 only;" + + " dest miss leaves $v0; no invent $s3 / 0x8033 / dest / 0x9A;" + + " no hop 0x8003F888; no MULT 0x8003F748; no hop 0x80048190)"); + return true; + } + + // Live 5a2878a: after epi-ret lw, + // first I-fetch at 0x8003F79C dump + // addiu $t1,$0,4. Exec dump-true + // ALU (rs=$0). PC:=0x8003F7A0. + // Do not take the bne. Do not + // invent $s4 / taken / 0x9A. + // Never hop 0x8003F888 / MULT + // 0x8003F748 / 0x80048190. + // Never MUL 0x16. Not LoadO32. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaT1( + MipsBus bus, uint[] regs, uint pc, uint insn, bool inDelay, + ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetCallerRaS3Logged) + return false; + if (_exn15C28AfterOuterJalEpiRetCallerRaT1Logged) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkT1) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28OuterJalLinkAfter + || capLeave == CoredllDllMainExn15C28OuterJalLinkT1 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == CoredllDllMainKdataEpcEa88 + || capLeave == 0x80048190u + || !IsExn15C28FallEpiOuterLeave(capLeave) + || IsExn15C28CallerPc(capLeave) + || IsExn15C28ListPopPc(capLeave) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkT1) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBne) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) + || IsExn15C28ListPopPc(pc)) + return false; + uint t1Dump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out t1Dump) || t1Dump == 0) + t1Dump = CoredllDllMainExn15C28OuterJalLinkT1Dump; + if (t1Dump != CoredllDllMainExn15C28OuterJalLinkT1Dump) + return false; + if (!IsDumpMemAluInsn(t1Dump) + || (t1Dump & 63) == 0x18 + || (t1Dump & 63) == 0x16) + return false; + if (insn != t1Dump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsLoad(insn) && !IsMipsAbsRs0Store(insn)) + return false; + if (insn != t1Dump && insn != 0) + TryHealDumpInsn(bus, pc, insn, t1Dump); + if (!TryExecDumpMemAlu(regs, t1Dump)) + return false; + uint t1Next = CoredllDllMainExn15C28OuterJalLinkBne; + if (!IsExn15C28FallEpiOuterLeave(t1Next) + || t1Next == pc + || t1Next == CoredllDllMainExn15C28OuterJalLink + || t1Next == CoredllDllMainExn15C28OuterJalLinkAfter + || t1Next == CoredllDllMainExn15C28OuterJalLinkT1 + || t1Next == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || t1Next == CoredllDllMainKdataEpcEa88 + || t1Next == CoredllDllMainExn15C28OuterJalLinkEpiRetFallJalRa + || t1Next == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || t1Next == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || t1Next == 0x80048190u + || IsExn15C28CallerPc(t1Next) + || IsExn15C28ListPopPc(t1Next) + || IsDumpMemRefuseVa(t1Next) + || IsExn15C28Na02Frame(t1Next) + || IsExn15C28NfffFrame(t1Next) + || IsExn15C28N9ffFrame(t1Next) + || IsExn15C28HelperBody(t1Next) + || IsExn15C28JalRaEpiRange(t1Next) + || IsLeftoverDestVa(t1Next) + || IsWrapDestSize(t1Next) + || IsWrapDestFp50Va(t1Next)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = t1Next; + _exn15C28AfterOuterJalEpiRetCallerRaT1Logged = true; + _exn15C28AfterOuterJalEpiRetCallerRaLeave = t1Next; + uint t1Ra = PeekGpr(regs, 31); + uint t1Sp = PeekGpr(regs, 29); + uint t1V0 = PeekGpr(regs, 2); + uint t1S4 = PeekGpr(regs, 20); + uint t1T1 = PeekGpr(regs, 9); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-ret-caller-ra-t1"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + t1Dump.ToString("X") + + " dest=0x" + t1Next.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-ra-t1" + + " pc=0x" + pc.ToString("X") + + " next=0x" + t1Next.ToString("X") + + " dump=0x" + t1Dump.ToString("X") + + (insn != 0 && insn != t1Dump ? " live=0x" + insn.ToString("X") : "") + + " t1=0x" + t1T1.ToString("X") + + " s4=0x" + t1S4.ToString("X") + + " v0=0x" + t1V0.ToString("X") + + " ra=0x" + t1Ra.ToString("X") + + " sp=0x" + t1Sp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $t1,$0,4; exec ALU rs=$0;" + + " observe bne; do not take bne / sltu / beq MULT;" + + " no invent $s4 / taken / 0x9A;" + + " no hop 0x8003F888; no MULT 0x8003F748; no hop 0x80048190)"); + return true; + } + + // Live 8d9d378: after addiu $t1,$0,4, + // first I-fetch at 0x8003F7A0 dump + // bne $s4,$t1 -> 0x8003F7AC. + // Delay nop (skip). Live $s4 vs + // $t1. Fall 0x8003F7A8 / taken + // 0x8003F7AC. Do not invent $s4 / + // taken. Never hop MULT 0x8003F748 + // / 0x8003F888 / 0x80048190. + // Never MUL 0x16. Not LoadO32. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaBne( + MipsBus bus, uint[] regs, uint pc, uint insn, bool inDelay, + ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetCallerRaT1Logged) + return false; + if (_exn15C28AfterOuterJalEpiRetCallerRaBneLogged) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkBne) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkBne + || capLeave == CoredllDllMainExn15C28OuterJalLink + || capLeave == CoredllDllMainExn15C28OuterJalLinkAfter + || capLeave == CoredllDllMainExn15C28OuterJalLinkT1 + || capLeave == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || capLeave == CoredllDllMainKdataEpcEa88 + || capLeave == 0x80048190u + || (capLeave != CoredllDllMainExn15C28OuterJalLinkBneFall + && capLeave != CoredllDllMainExn15C28OuterJalLinkBneTaken) + || !IsExn15C28FallEpiOuterLeave(capLeave) + || IsExn15C28CallerPc(capLeave) + || IsExn15C28ListPopPc(capLeave) + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkBne) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBneFall) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkBneTaken) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) + || IsExn15C28ListPopPc(pc)) + return false; + uint bneDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out bneDump) || bneDump == 0) + bneDump = CoredllDllMainExn15C28OuterJalLinkBneDump; + if (bneDump != CoredllDllMainExn15C28OuterJalLinkBneDump) + return false; + if ((bneDump >> 26) != 5 + || (bneDump & 63) == 0x18 + || (bneDump & 63) == 0x16) + return false; + if (insn != bneDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsLoad(insn) && !IsMipsAbsRs0Store(insn) + && (insn >> 26) != 5) + return false; + if (insn != bneDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, bneDump); + uint bneS4 = PeekGpr(regs, 20); + uint bneT1 = PeekGpr(regs, 9); + bool taken = bneS4 != bneT1; + uint bneDest = taken + ? CoredllDllMainExn15C28OuterJalLinkBneTaken + : CoredllDllMainExn15C28OuterJalLinkBneFall; + if ((bneDest != CoredllDllMainExn15C28OuterJalLinkBneFall + && bneDest != CoredllDllMainExn15C28OuterJalLinkBneTaken) + || !IsExn15C28FallEpiOuterLeave(bneDest) + || bneDest == pc + || bneDest == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || bneDest == CoredllDllMainKdataEpcEa88 + || bneDest == 0x80048190u + || IsExn15C28CallerPc(bneDest) + || IsExn15C28ListPopPc(bneDest) + || IsDumpMemRefuseVa(bneDest) + || IsExn15C28Na02Frame(bneDest) + || IsExn15C28NfffFrame(bneDest) + || IsExn15C28N9ffFrame(bneDest) + || IsExn15C28HelperBody(bneDest) + || IsExn15C28JalRaEpiRange(bneDest) + || IsLeftoverDestVa(bneDest) + || IsWrapDestSize(bneDest) + || IsWrapDestFp50Va(bneDest)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = bneDest; + _exn15C28AfterOuterJalEpiRetCallerRaBneLogged = true; + _exn15C28AfterOuterJalEpiRetCallerRaLeave = bneDest; + uint bneRa = PeekGpr(regs, 31); + uint bneSp = PeekGpr(regs, 29); + uint bneV0 = PeekGpr(regs, 2); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = taken + ? "dump-mem-15c28-outer-jal-epi-ret-caller-ra-bne-taken" + : "dump-mem-15c28-outer-jal-epi-ret-caller-ra-bne-fall"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + bneDump.ToString("X") + + " dest=0x" + bneDest.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-ra-bne" + + " pc=0x" + pc.ToString("X") + + " next=0x" + bneDest.ToString("X") + + " dump=0x" + bneDump.ToString("X") + + (insn != 0 && insn != bneDump ? " live=0x" + insn.ToString("X") : "") + + " s4=0x" + bneS4.ToString("X") + + " t1=0x" + bneT1.ToString("X") + + (taken ? " taken=1" : " taken=0") + + " v0=0x" + bneV0.ToString("X") + + " ra=0x" + bneRa.ToString("X") + + " sp=0x" + bneSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump bne $s4,$t1; live compare; delay nop skip;" + + " no invent $s4 / taken / 0x9A;" + + " no hop 0x8003F888; no MULT 0x8003F748; no hop 0x80048190)"); + return true; + } + + // Live 8d9d378: after live bne, + // name first I-fetch at fall + // 0x8003F7A8 or taken 0x8003F7AC. + // One-shot. Peek dump only. Do not + // invent $s4 / taken / 0x9A. Do + // not hop sltu/beq MULT / 0x8003F888 + // / 0x80048190. + public static void TryNoteDumpMem15C28AfterOuterJalEpiRetCallerRa( + MipsBus bus, uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiRetCallerRaLogged + || _exn15C28AfterOuterJalEpiRetCallerRaNextLogged) + return; + if (pc != _exn15C28AfterOuterJalEpiRetCallerRaLeave + && pc != CoredllDllMainExn15C28OuterJalLink + && pc != CoredllDllMainExn15C28OuterJalLinkAfter + && pc != CoredllDllMainExn15C28OuterJalLinkT1 + && pc != CoredllDllMainExn15C28OuterJalLinkBne + && pc != CoredllDllMainExn15C28OuterJalLinkBneFall + && pc != CoredllDllMainExn15C28OuterJalLinkBneTaken) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) || IsExn15C28ListPopPc(pc)) + return; + _exn15C28AfterOuterJalEpiRetCallerRaNextLogged = true; + uint callerRaNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out callerRaNoteDump); + uint callerRaNoteRa = PeekGpr(regs, 31); + uint callerRaNoteSp = PeekGpr(regs, 29); + uint callerRaNoteV0 = PeekGpr(regs, 2); + uint callerRaNoteS5 = PeekGpr(regs, 21); + uint callerRaNoteS3 = PeekGpr(regs, 19); + uint callerRaNoteS4 = PeekGpr(regs, 20); + uint callerRaNoteS7 = PeekGpr(regs, 23); + uint callerRaNoteT1 = PeekGpr(regs, 9); + string callerRaNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string callerRaNoteDumpDis = callerRaNoteDump != 0 + ? FormatMipsOp(pc, callerRaNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = _exn15C28AfterOuterJalEpiRetCallerRaBneLogged + ? "dump-mem-15c28-after-outer-jal-epi-ret-caller-ra-bne" + : _exn15C28AfterOuterJalEpiRetCallerRaT1Logged + ? "dump-mem-15c28-after-outer-jal-epi-ret-caller-ra-t1" + : _exn15C28AfterOuterJalEpiRetCallerRaS3Logged + ? "dump-mem-15c28-after-outer-jal-epi-ret-caller-ra-s3" + : _exn15C28AfterOuterJalEpiRetCallerRaLhuLogged + ? "dump-mem-15c28-after-outer-jal-epi-ret-caller-ra-lhu" + : "dump-mem-15c28-after-outer-jal-epi-ret-caller-ra"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (callerRaNoteDump != 0 + ? " dump=0x" + callerRaNoteDump.ToString("X") : "") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 " + + (_exn15C28AfterOuterJalEpiRetCallerRaBneLogged + ? "after-outer-jal-epi-ret-caller-ra-bne" + : _exn15C28AfterOuterJalEpiRetCallerRaT1Logged + ? "after-outer-jal-epi-ret-caller-ra-t1" + : _exn15C28AfterOuterJalEpiRetCallerRaS3Logged + ? "after-outer-jal-epi-ret-caller-ra-s3" + : _exn15C28AfterOuterJalEpiRetCallerRaLhuLogged + ? "after-outer-jal-epi-ret-caller-ra-lhu" + : "after-outer-jal-epi-ret-caller-ra") + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (callerRaNoteDump != 0 + ? " dump=0x" + callerRaNoteDump.ToString("X") : "") + + " dis=" + callerRaNoteDis + + (callerRaNoteDump != 0 + ? " dump-dis=" + callerRaNoteDumpDis : "") + + " v0=0x" + callerRaNoteV0.ToString("X") + + " t1=0x" + callerRaNoteT1.ToString("X") + + " s3=0x" + callerRaNoteS3.ToString("X") + + " s4=0x" + callerRaNoteS4.ToString("X") + + " s5=0x" + callerRaNoteS5.ToString("X") + + " s7=0x" + callerRaNoteS7.ToString("X") + + " ra=0x" + callerRaNoteRa.ToString("X") + + " sp=0x" + callerRaNoteSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (first I-fetch after live bne $s4,$t1;" + + " peek dump fall or $s1 / taken addiu $t2; do not hop sltu / beq MULT;" + + " no invent $s4 / taken / 0x9A;" + + " no hop 0x8003F888; no MULT 0x8003F748; no hop 0x80048190)"); + } + + // Live 749ad1b / d75e3fd: addiu + // $sp,$sp,-24 at 0x8003F9E8 only + // when fat caller did not honor + // jr $ra. Boot 90d6470 honored + // ra 0x8003F8B4: yank off twin, + // do not exec addiu / jal 151C0. + // Else exec dump-true ALU + // $sp:=$sp-24; PC:=0x8003F9EC. + // Refuse leftover / MULT 0x8003F748 + // / jr hop 0x8003F78C / hop + // 0x80048190 / SPECIAL 0x16. + public static bool TryTakeDumpMem15C28AfterOuterJalEpiRetCallerNextFn( + MipsBus bus, uint[] regs, uint pc, uint insn, bool inDelay, + ref uint cpuPc) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return false; + if (!_exn15C28AfterOuterJalEpiRetCallerLogged) + return false; + // Boot 90d6470: honored jr $ra + // 0x8003F8B4. Accidental twin + // 0x8003F9E8 (jal 0x800151C0 / + // 0x80048198) ran with a1=0 → + // TLBS 0x800151D0. Yank to ra; + // do not exec twin addiu. + if (IsExn15C28CallerHonoredRaLeave( + _exn15C28AfterOuterJalEpiRetCallerLeave)) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn) + return false; + cpuPc = _exn15C28AfterOuterJalEpiRetCallerLeave; + return true; + } + if (_exn15C28AfterOuterJalEpiRetCallerNextFnLogged) + { + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn) + return false; + uint capLeave = DumpMem15C28OuterJalProgressLeave(); + if (capLeave == 0 + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn + || capLeave == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || IsExn15C28CallerPc(capLeave) || IsExn15C28ListPopPc(capLeave) + || IsExn15C28CallerInsaneLeave(capLeave) + || capLeave == CoredllDllMainKdataEpcEa88 + || IsDumpMemRefuseVa(capLeave) + || IsExn15C28Na02Frame(capLeave) + || IsExn15C28NfffFrame(capLeave) + || IsExn15C28N9ffFrame(capLeave) + || IsWrapDestSize(capLeave) + || IsWrapDestFp50Va(capLeave)) + return false; + cpuPc = capLeave; + return true; + } + if (inDelay) + return false; + if (pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFn) + return false; + if (IsDumpMemRefuseVa(pc) + || IsDumpMemRefuseVa(CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnNext) + || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) + || IsExn15C28JalRaEpiRange(pc)) + return false; + uint callerAddiuDump = 0; + if (!TryPeekLeftoverWait99DumpOnly(pc, out callerAddiuDump) + || callerAddiuDump == 0) + callerAddiuDump = CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnDump; + if (callerAddiuDump != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnDump) + return false; + if (!IsDumpMemAluInsn(callerAddiuDump) + || (callerAddiuDump & 63) == 0x18 + || (callerAddiuDump & 63) == 0x16) + return false; + if (insn != callerAddiuDump && insn != 0 && !IsDumpMemAluInsn(insn) + && !IsMipsAbsRs0Store(insn) && !IsMipsStore(insn)) + return false; + if (insn != callerAddiuDump && insn != 0) + TryHealDumpInsn(bus, pc, insn, callerAddiuDump); + if (!TryExecDumpMemAlu(regs, callerAddiuDump)) + return false; + uint callerAddiuNext = CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnNext; + if (callerAddiuNext == 0 || (callerAddiuNext & 3) != 0 + || callerAddiuNext == pc + || callerAddiuNext == CoredllDllMainExn15C28OuterJalLink + || callerAddiuNext == CoredllDllMainExn15C28OuterJalLinkBeqTaken + || callerAddiuNext == CoredllDllMainExn15C28JalS1AluNext + || callerAddiuNext == CoredllDllMainExn15C28StkSwNext + || callerAddiuNext == CoredllDllMainKdataEpcEa88 + || callerAddiuNext == CoredllDllMainExn15C28OuterJalLinkEpiRetCaller + || IsExn15C28CallerPc(callerAddiuNext) + || IsExn15C28ListPopPc(callerAddiuNext) + || IsExn15C28CallerInsaneLeave(callerAddiuNext) + || IsDumpMemRefuseVa(callerAddiuNext) + || IsExn15C28Na02Frame(callerAddiuNext) + || IsExn15C28NfffFrame(callerAddiuNext) + || IsExn15C28N9ffFrame(callerAddiuNext) + || IsExn15C28HelperBody(callerAddiuNext) + || IsExn15C28JalRaEpiRange(callerAddiuNext) + || IsLeftoverDestVa(callerAddiuNext) + || IsWrapDestSize(callerAddiuNext) + || IsWrapDestFp50Va(callerAddiuNext)) + return false; + if (bus != null) + { + uint epc = bus.PeekEpc(); + if (epc != 0 && (epc & 3) == 0) + bus.ClearExlIfEpc(epc); + bus.ClearExlIfEpc(pc); + } + cpuPc = callerAddiuNext; + _exn15C28AfterOuterJalEpiRetCallerNextLogged = true; + _exn15C28AfterOuterJalEpiRetCallerNextFnLogged = true; + _exn15C28AfterOuterJalEpiRetCallerNextFnLeave = callerAddiuNext; + uint callerAddiuSp = PeekGpr(regs, 29); + uint callerAddiuRa = PeekGpr(regs, 31); + uint callerAddiuV0 = PeekGpr(regs, 2); + uint callerAddiuFp = PeekGpr(regs, 30); + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-outer-jal-epi-ret-caller-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + callerAddiuDump.ToString("X") + + " dest=0x" + callerAddiuNext.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 outer-jal-epi-ret-caller-addiu" + + " pc=0x" + pc.ToString("X") + + " next=0x" + callerAddiuNext.ToString("X") + + " dump=0x" + callerAddiuDump.ToString("X") + + (insn != 0 && insn != callerAddiuDump + ? " live=0x" + insn.ToString("X") : "") + + " v0=0x" + callerAddiuV0.ToString("X") + + " fp=0x" + callerAddiuFp.ToString("X") + + " ra=0x" + callerAddiuRa.ToString("X") + + " sp=0x" + callerAddiuSp.ToString("X") + + " via=" + _leftoverWait99O32NkChainVia + + " (dump addiu $sp,$sp,-24; ALU only; do not invent 0x9A page / 0x8032 / SUD / E000;" + + " no hop 0x8003F888; no MULT 0x8003F748; no jr hop 0x8003F78C; no hop 0x80048190)"); + return true; + } + + // Live 749ad1b: after NextFn + // addiu, name first I-fetch at + // 0x8003F9EC. One-shot. Peek dump + // only — do not invent next word / + // dest / 0x9A / 0x8032 / SUD. Do + // not hop MUL / jr 0x8003F78C / + // 0x8003F888 / 0x80048190. + public static void TryNoteDumpMem15C28AfterOuterJalEpiRetCallerNextFn( + MipsBus bus, uint[] regs, uint pc, uint insn) + { + if (!_leftoverWait99O32NkCoredllSawEntry || !_exn15C28Left) + return; + if (!_exn15C28AfterOuterJalEpiRetCallerNextFnLogged + || _exn15C28AfterOuterJalEpiRetCallerNextFnNextLogged) + return; + if (pc != _exn15C28AfterOuterJalEpiRetCallerNextFnLeave + && pc != CoredllDllMainExn15C28OuterJalLinkEpiRetCallerNextFnNext) + return; + if (IsDumpMemRefuseVa(pc) || IsExn15C28Na02Frame(pc) + || IsExn15C28HelperBody(pc) || IsExn15C28JalRaEpiRange(pc) + || IsExn15C28CallerPc(pc) || IsExn15C28ListPopPc(pc)) + return; + _exn15C28AfterOuterJalEpiRetCallerNextFnNextLogged = true; + uint callerAddiuNoteDump = 0; + TryPeekLeftoverWait99DumpOnly(pc, out callerAddiuNoteDump); + uint callerAddiuNoteRa = PeekGpr(regs, 31); + uint callerAddiuNoteSp = PeekGpr(regs, 29); + uint callerAddiuNoteV0 = PeekGpr(regs, 2); + uint callerAddiuNoteFp = PeekGpr(regs, 30); + string callerAddiuNoteDis = insn != 0 + ? FormatMipsOp(pc, insn) + : "peek-miss"; + string callerAddiuNoteDumpDis = callerAddiuNoteDump != 0 + ? FormatMipsOp(pc, callerAddiuNoteDump) + : "dump-miss"; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = "dump-mem-15c28-after-outer-jal-epi-ret-caller-addiu"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + insn.ToString("X") + + (callerAddiuNoteDump != 0 + ? " dump=0x" + callerAddiuNoteDump.ToString("X") : "") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-caller-addiu"); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-outer-jal-epi-ret-caller-addiu" + + " pc=0x" + pc.ToString("X") + + " word=0x" + insn.ToString("X") + + (callerAddiuNoteDump != 0 + ? " dump=0x" + callerAddiuNoteDump.ToString("X") : "") + + " dis=" + callerAddiuNoteDis + + (callerAddiuNoteDump != 0 + ? " dump-dis=" + callerAddiuNoteDumpDis : "") + + " v0=0x" + callerAddiuNoteV0.ToString("X") + + " fp=0x" + callerAddiuNoteFp.ToString("X") + + " ra=0x" + callerAddiuNoteRa.ToString("X") + + " sp=0x" + callerAddiuNoteSp.ToString("X") + + " via=dump-mem-15c28-after-outer-jal-epi-ret-caller-addiu" + + " (first I-fetch after 3F9E8 addiu $sp,-24; peek dump, do not invent next word;" + + " no hop 0x8003F888; no jr hop 0x8003F78C; no hop 0x80048190; no invent 0x9A / 0x8032 / SUD)"); + } + + private static void PokeGpr(uint[] regs, int i, uint v) + { + if (regs == null || i <= 0 || i >= regs.Length) + return; + regs[i] = v; + } + + private static void TryLogDumpMemSkip(uint pc, uint live, uint dump, + uint[] regs, string reason, bool site) + { + if (!site || _abs6670DumpSkipLogged || IsDumpMemAlreadyTrue(live)) + return; + _abs6670DumpSkipLogged = true; + uint ra = PeekGpr(regs, 31); + uint v0 = PeekGpr(regs, 2); + uint fp = PeekGpr(regs, 30); + uint rs = (live >> 21) & 31; + uint rt = (live >> 16) & 31; + uint imm = live & 0xFFFF; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-6670 skip" + + " epc=0x" + pc.ToString("X") + + " bad=0x" + imm.ToString("X") + + " word=0x" + live.ToString("X") + + (dump != 0 ? " dump=0x" + dump.ToString("X") : "") + + " dis=" + (live != 0 ? FormatMipsOp(pc, live) : "peek-miss") + + (dump != 0 ? " dump-dis=" + FormatMipsOp(pc, dump) : "") + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " v0=0x" + v0.ToString("X") + + " fp=0x" + fp.ToString("X") + + " ra=0x" + ra.ToString("X") + + " via=dump-mem-skip reason=" + reason + + " (do not invent page 0x6000)"); + } + + private static bool IsStk2470RefuseKseg(uint kseg) + { + if (kseg == 0 || (kseg & 3) != 0) + return true; + if ((kseg & 0x1FFFFFFFu) < 0x00010000u) + return true; + return kseg == LeftoverWait99O32RefuseRa + || kseg == LeftoverWait99GetProcDest + || kseg == LeftoverWait99O32RefuseDump + || kseg == CoredllDllMainKdataWrapRefuse + || IsLeftoverDestVa(kseg) + || IsWrapDestSize(kseg) || IsWrapDestFp50Va(kseg) + || IsHdDllImageBase(kseg) || kseg == WrapDestE32SizeLive + || kseg == WrapDestFp50FillLive; + } + + private static void TryResolveStk2470(MipsBus bus, uint va) + { + if (bus == null || _stk2470Busy || _stk2470Done) + return; + if ((va & ~0xFFFu) != CoredllDllMainStk2470Page) + return; + try + { + _stk2470Busy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + bool pte = sec != 0 + && WalkFirmwarePte(bus, sec, va, out l1, out l2, out pfn, out kseg) + && !IsStk2470RefuseKseg(kseg); + if (!pte) + { + uint sec1 = PeekSection(bus, 1); + if (sec1 != 0 && sec1 != sec) + pte = WalkFirmwarePte(bus, sec1, va, out l1, out l2, out pfn, out kseg) + && !IsStk2470RefuseKseg(kseg); + } + uint destw = 0; + bool destOk = pte && TryPeekWord(bus, + (kseg & ~0xFFFu) | (va & 0xFFFu), out destw); + if (pte && destOk) + { + _stk2470Kseg = kseg & ~0xFFFu; + if (!_stk2470Logged) + { + _stk2470Logged = true; + _stk2470Done = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk stk-2470 map va=0x" + + CoredllDllMainStk2470Page.ToString("X") + + " -> 0x" + _stk2470Kseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + destw.ToString("X") + + " via=pte (dump sw $a2,8($sp); firmware PTE; do not invent dest)"); + } + return; + } + if (!_stk2470Logged) + { + _stk2470Logged = true; + _stk2470Done = true; + uint k0 = 0x80000000u | CoredllDllMainStk2470Bad; + uint k0w = 0; + bool k0ok = TryPeekWord(bus, k0, out k0w); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk stk-2470 map va=0x" + + va.ToString("X") + + " pte-miss sec=0x" + sec.ToString("X") + + (k0ok ? " kseg0=0x" + k0w.ToString("X") : " kseg0-miss") + + " (dump sw $a2,8($sp); page 0x2000 not NK image;" + + " do not invent zero page)"); + } + } + finally + { + _stk2470Busy = false; + } + } + + private static bool IsMipsLoadToZero(uint insn) + { + uint op = insn >> 26; + if (op != 0x20 && op != 0x21 && op != 0x22 && op != 0x23 + && op != 0x24 && op != 0x25 && op != 0x26) + return false; + return ((insn >> 16) & 31) == 0; + } + + // Live 221208f: sud-beq0-skip logged during + // resolve peek then identity F000->F000 + // live-peek dest-word=0 blocked the real + // lw. Refuse identity. Do not skip while + // F000 resolve is busy. Then Read32 returns + // 0 so $v1=0 and PC reaches beq $v1,$0. + // Do not leftover-hop. Do not invent dest. + public static bool TrySkipFfffFe54LoadZero(MipsBus bus, uint va) + { + if (va < CoredllDllMainSudVa || va >= CoredllDllMainSudVa + 4) + return false; + if ((va & ~0xFFFu) != FfffF000Page) + return false; + if (!_leftoverWait99O32NkCoredllSawEntry) + return false; + if (_ffffF000Busy) + return false; + if (_ffffF000Kseg == FfffF000Page) + _ffffF000Kseg = 0; + if (_ffffF000Kseg != 0) + return false; + TryResolveFfffF000(bus, va); + if (_ffffF000Kseg == FfffF000Page) + _ffffF000Kseg = 0; + if (_ffffF000Kseg != 0) + return false; + uint insn = 0; + if (!TryPeekWord(bus, CoredllDllMainSudEpc, out insn) || insn == 0) + insn = CoredllDllMainSudInsn; + uint next = 0; + if (!TryPeekWord(bus, CoredllDllMainSudEpc + 4, out next) || next == 0) + next = CoredllDllMainSudBeq; + bool load0 = IsMipsLoadToZero(insn); + bool beq0 = insn == CoredllDllMainSudInsn + && next == CoredllDllMainSudBeq; + if (!load0 && !beq0) + return false; + if (!_ffffFe54SkipLogged) + { + _ffffFe54SkipLogged = true; + string via = load0 && !beq0 ? "sud-zero-skip" : "sud-beq0-skip"; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-f000 " + via + + " epc=0x" + CoredllDllMainSudEpc.ToString("X") + + " bad=0x" + CoredllDllMainSudVa.ToString("X") + + " word=0x" + insn.ToString("X") + + " dis=" + FormatMipsOp(CoredllDllMainSudEpc, insn) + + " next=0x" + next.ToString("X") + + " ra=0x" + CoredllDllMainKdataRa.ToString("X") + + " v1=0" + + " (NK beq $v1,$0 empty path; never-wired F000; no page; do not invent dest)"); + } + return true; + } + + public static uint MapJalr7eb8Va(MipsBus bus, uint va) + { + if (_jalr7eb8Busy) + return va; + if (!_leftoverWait99O32NkCoredllSawEntry || !_ffffE428SkipLogged) + return va; + if ((va & ~0xFFFu) != CoredllDllMainJalrPage) + return va; + if (_jalr7eb8Kseg != 0) + return _jalr7eb8Kseg | (va & 0xFFFu); + TryResolveJalr7eb8(bus, va); + if (_jalr7eb8Kseg != 0) + return _jalr7eb8Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsMipsLoad(uint insn) + { + uint op = insn >> 26; + return op == 0x20 || op == 0x21 || op == 0x22 || op == 0x23 + || op == 0x24 || op == 0x25 || op == 0x26; + } + + private static void TryResolveJalr7eb8(MipsBus bus, uint va) + { + if (bus == null || _jalr7eb8Busy || _jalr7eb8Done) + return; + if ((va & ~0xFFFu) != CoredllDllMainJalrPage) + return; + try + { + _jalr7eb8Busy = true; + uint destw = 0; + bool destOk = TryPeekWord(bus, CoredllDllMainJalrDest, out destw); + uint rs = destOk ? ((destw >> 21) & 31) : 0xFFu; + bool t9Path = destOk && IsMipsLoad(destw) && rs == 25; + uint kseg0 = t9Path + ? ((CoredllDllMainKdataT9_2 & ~0xFFFu) | (va & 0xFFFu)) + : (0x80000000u | (va & 0x1FFFFFFFu)); + string via = t9Path ? "t9" : "kseg0"; + string destDis = destOk && destw != 0 + ? FormatMipsOp(CoredllDllMainJalrDest, destw) + : "dest-peek-miss"; + uint word = 0; + if (TryPeekWord(bus, kseg0, out word)) + { + _jalr7eb8Kseg = kseg0 & ~0xFFFu; + if (!_jalr7eb8Logged) + { + _jalr7eb8Logged = true; + _jalr7eb8Done = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-7eb8 map va=0x" + + CoredllDllMainJalrPage.ToString("X") + + " -> 0x" + _jalr7eb8Kseg.ToString("X8") + + (destOk ? " dest-word=0x" + destw.ToString("X") : " dest-peek-miss") + + " dis=" + destDis + + " via=" + via + + " (useg 0x7EB8; firmware peek; do not invent dest)"); + } + return; + } + if (!_jalr7eb8Logged) + { + _jalr7eb8Logged = true; + _jalr7eb8Done = true; + uint t9w = 0; + bool t9ok = TryPeekWord(bus, CoredllDllMainKdataT9_2, out t9w); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-7eb8 map va=0x" + + va.ToString("X") + + " pte-miss" + + (destOk ? " dest-word=0x" + destw.ToString("X") : " dest-peek-miss") + + " dis=" + destDis + + (t9ok ? " t9=0x" + t9w.ToString("X") : " t9-unmapped") + + " (data TLBL at jalr dest; not I-fetch; t9-low=0x7EB8; do not invent dest)"); + } + } + finally + { + _jalr7eb8Busy = false; + } + } + + public static uint MapJalr1db0Va(MipsBus bus, uint va) + { + if (_jalr1db0Busy) + return va; + if (!_leftoverWait99O32NkCoredllSawEntry || !_jalr7eb8Logged) + return va; + if ((va & ~0xFFFu) != CoredllDllMainJalrPage2) + return va; + if (_jalr1db0Kseg != 0) + return _jalr1db0Kseg | (va & 0xFFFu); + TryResolveJalr1db0(bus, va); + if (_jalr1db0Kseg != 0) + return _jalr1db0Kseg | (va & 0xFFFu); + return va; + } + + private static void TryResolveJalr1db0(MipsBus bus, uint va) + { + if (bus == null || _jalr1db0Busy || _jalr1db0Done) + return; + if ((va & ~0xFFFu) != CoredllDllMainJalrPage2) + return; + try + { + _jalr1db0Busy = true; + uint destw = 0; + bool destOk = TryPeekWord(bus, CoredllDllMainJalrDest2, out destw); + uint rs = destOk ? ((destw >> 21) & 31) : 0xFFu; + bool t9Path = destOk && IsMipsLoad(destw) && rs == 25; + uint kseg0 = t9Path + ? ((CoredllDllMainKdataT9_2 & ~0xFFFu) | (va & 0xFFFu)) + : (0x80000000u | (va & 0x1FFFFFFFu)); + string via = t9Path ? "t9" : "kseg0"; + string destDis = destOk && destw != 0 + ? FormatMipsOp(CoredllDllMainJalrDest2, destw) + : "dest-peek-miss"; + uint word = 0; + if (TryPeekWord(bus, kseg0, out word)) + { + _jalr1db0Kseg = kseg0 & ~0xFFFu; + if (!_jalr1db0Logged) + { + _jalr1db0Logged = true; + _jalr1db0Done = true; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-1db0 map va=0x" + + CoredllDllMainJalrPage2.ToString("X") + + " -> 0x" + _jalr1db0Kseg.ToString("X8") + + (destOk ? " dest-word=0x" + destw.ToString("X") : " dest-peek-miss") + + " dis=" + destDis + + " rs=" + (destOk ? rs.ToString() : "?") + + " via=" + via + + " (useg 0x1DB0; firmware peek; do not invent dest)"); + } + return; + } + if (!_jalr1db0Logged) + { + _jalr1db0Logged = true; + _jalr1db0Done = true; + uint t9w = 0; + bool t9ok = TryPeekWord(bus, CoredllDllMainKdataT9_2, out t9w); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-1db0 map va=0x" + + va.ToString("X") + + " pte-miss" + + (destOk ? " dest-word=0x" + destw.ToString("X") : " dest-peek-miss") + + " dis=" + destDis + + " rs=" + (destOk ? rs.ToString() : "?") + + (t9ok ? " t9=0x" + t9w.ToString("X") : " t9-unmapped") + + " (data TLBL at sec0; not I-fetch; useg abs; do not invent dest)"); + } + } + finally + { + _jalr1db0Busy = false; + } + } + + private static void TryArmUserKPageAlias(MipsBus bus) + { + if (_userKPageAliasNoted) + return; + _userKPageAliasNoted = true; + uint userWord = 0; + bool userMapped = TryPeekWord(bus, UserKPage, out userWord); + uint kdataWord = 0; + bool kdataMapped = TryPeekWord(bus, KDataBase, out kdataWord); + if (!userMapped) + { + BootLog.Write("[Hive] ExtraROM BindImp-iat FFFF5800-unmapped" + + (kdataMapped + ? " kdata=0x" + kdataWord.ToString("X8") + : " KData-unmapped")); + } + else if (userWord == 0) + { + BootLog.Write("[Hive] ExtraROM BindImp-iat FFFF5800=0" + + (kdataMapped + ? " kdata=0x" + kdataWord.ToString("X8") + : " KData-unmapped")); + } + if (userMapped && userWord != 0) + return; + if (!kdataMapped) + return; + _userKPageAlias = true; + BootLog.Write("[Hive] ExtraROM BindImp-iat alias 0x" + + UserKPage.ToString("X8") + + " -> 0x" + KDataBase.ToString("X8") + + " (KData live; do not invent contents)"); + } + + // Live 19656e2: *(fp+0x1C) / v1 was o32[.data].real + // 0x01F57000. sw 0x80019124 wrote the resolve there, + // not VALLOC IAT 0x01999000. Same class as ddi_nop + // set-valloc. Rewrite dump-real slot to the served + // o32 dest. Do not invent dest or IAT fills. + private static bool TryGetDdiNopIatBases(out uint real, out uint dest, + out uint span) + { + real = _ddiNopIatReal; + dest = _ddiNopIatValloc; + span = _ddiNopIatSpan; + if (real != 0 && dest != 0 && !IsDdiNopDest10Page(dest)) + return true; + int sec; + uint vsize; + uint rva; + uint psize; + uint dataptr; + uint flags; + uint[] blob; + if (!TryFindDdiNopDataO32(out sec, out vsize, out rva, out psize, + out dataptr, out real, out flags, out blob)) + { + dest = 0; + span = 0; + return false; + } + dest = DdiNopVbasePage + (rva != 0 ? rva : DdiNopIatRva); + span = vsize; + if (real == 0 || dest == 0 || IsDdiNopDest10Page(dest)) + return false; + _ddiNopIatReal = real; + _ddiNopIatValloc = dest; + _ddiNopIatSpan = span; + _ddiNopIatPsize = psize; + return true; + } + + private static bool TryMapDumpIatSlot(uint ptr, uint real, uint dest, + uint span, out uint want) + { + want = 0; + if (ptr == 0 || real == 0 || dest == 0) + return false; + if (IsDdiNopDest10Page(ptr) || IsDdiNopDest10Page(dest)) + return false; + uint off; + if (span == 0) + { + if (ptr != real) + return false; + off = 0; + } + else + { + if (ptr < real || ptr >= real + span) + return false; + off = ptr - real; + if ((off & 3u) != 0) + return false; + } + want = dest + off; + return want != 0 && want != ptr; + } + + private static void TryFixBindImpIatSlot(MipsBus bus, uint[] regs, uint pc) + { + if (!_ddiNopAwaitCallDll || !_ddiNopLandedBySig || !_ddiNopIatWatch) + return; + if (bus == null || regs == null || regs.Length <= 3) + return; + if (pc != BindImpOrdJalRet && pc != BindImpIatSlotLw + && pc != BindImpIatNext && pc != BindImpIatNextAfter + && (pc < BindImpIatKdata || pc > BindImpIatAfter)) + return; + uint real; + uint dest; + uint span; + if (!TryGetDdiNopIatBases(out real, out dest, out span)) + return; + uint fp = regs.Length > 30 ? regs[30] : 0; + uint fp1c = 0; + bool fpOk = fp != 0 && TryPeekWord(bus, fp + BindImpFpIatOff, out fp1c); + uint v1 = regs[3]; + uint want; + uint written = 0; + uint was = 0; + if (fpOk && TryMapDumpIatSlot(fp1c, real, dest, span, out want)) + { + was = fp1c; + written = want; + try + { + bus.Write32(fp + BindImpFpIatOff, want); + } + catch + { + return; + } + if (TryMapDumpIatSlot(v1, real, dest, span, out want)) + { + regs[3] = want; + written = want; + } + } + else if (TryMapDumpIatSlot(v1, real, dest, span, out want)) + { + was = v1; + written = want; + regs[3] = want; + } + else + { + TryNoteBindImpIatNext(pc, fp1c, dest, span); + return; + } + if (written == 0) + return; + if (_bindImpIatSlotLog < BindImpObserveMax) + { + _bindImpIatSlotLog++; + BootLog.Write("[Hive] ExtraROM BindImp-iat slot was=0x" + + was.ToString("X8") + + " set-valloc=0x" + written.ToString("X8")); + } + TryNoteBindImpIatNext(pc, written, dest, span); + } + + private static void TryNoteBindImpIatNext(uint pc, uint fp1c, uint dest, + uint span) + { + if (pc != BindImpIatNext && pc != BindImpIatNextAfter) + return; + if (fp1c == _bindImpIatNextLast || _bindImpIatNextLog >= BindImpObserveMax) + return; + _bindImpIatNextLast = fp1c; + _bindImpIatNextLog++; + bool valloc = dest != 0 && fp1c >= dest + && (span == 0 ? fp1c == dest : fp1c < dest + span); + BootLog.Write("[Hive] ExtraROM BindImp-iat next fp1c=0x" + + fp1c.ToString("X8") + + (valloc ? " (valloc)" : " (not-valloc)")); + } + + private static void TryNoteBindImpIatWindow(MipsBus bus, uint[] regs, uint pc) + { + if (!_ddiNopAwaitCallDll || regs == null || regs.Length <= 3) + return; + if (pc < BindImpIatKdata || pc > BindImpIatAfter) + return; + if (pc == BindImpIatSw) + _bindImpIatSwExpect = true; + TryArmUserKPageAlias(bus); + if (pc == _bindImpIatWinLast) + return; + if (_bindImpIatWinLog >= 8) + return; + _bindImpIatWinLast = pc; + _bindImpIatWinLog++; + uint v0 = regs[2]; + uint v1 = regs[3]; + uint fp = regs.Length > 30 ? regs[30] : 0; + uint fp1c = 0; + bool fpOk = fp != 0 && TryPeekWord(bus, fp + BindImpFpIatOff, out fp1c); + uint kdata = 0; + bool kOk = TryPeekWord(bus, UserKPage, out kdata); + uint iat = DdiNopVbasePage + DdiNopIatRva; + bool slot = v1 == iat || fp1c == iat + || (_ddiNopIatDest6 != 0 + && ((v1 & ~0xFFFu) == (_ddiNopIatDest6 & ~0xFFFu) + || (fp1c & ~0xFFFu) == (_ddiNopIatDest6 & ~0xFFFu))); + BootLog.Write("[Hive] ExtraROM BindImp-iat pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " v1=0x" + v1.ToString("X8") + + " fp1c=0x" + fp1c.ToString("X8") + + (fpOk ? "" : " fp1c-unmapped") + + (kOk + ? " FFFF5800=0x" + kdata.ToString("X8") + : " FFFF5800-unmapped") + + (slot ? "" : " (not-IAT-slot)")); + } + + public static void TryNoteBindImpIatSw(uint origVa, uint value) + { + if (!_bindImpIatSwExpect || _ddiNopDestPeekRaw) + return; + _bindImpIatSwExpect = false; + _bindImpIatSwLogged = true; + if (_bindImpIatSwLog >= BindImpObserveMax) + return; + _bindImpIatSwLog++; + uint iat = DdiNopVbasePage + DdiNopIatRva; + bool hit = (origVa & ~0xFFFu) == iat + || (_ddiNopIatDest6 != 0 + && !IsDdiNopDest10Page(_ddiNopIatDest6) + && (origVa & ~0xFFFu) == (_ddiNopIatDest6 & ~0xFFFu)); + BootLog.Write("[Hive] ExtraROM BindImp-iat sw va=0x" + + origVa.ToString("X8") + + " word=0x" + value.ToString("X8") + + (hit ? " (IAT)" : " (not-IAT)")); + } + + private static void TryNoteBindImpIatSwSkipped() + { + if (_bindImpIatSwLogged || _ddiNopOrdGoodV0 == 0) + return; + if (_bindImpIatWinLog == 0 && !_userKPageAliasNoted) + return; + _bindImpIatSwLogged = true; + BootLog.Write("[Hive] ExtraROM BindImp-iat 19124-skipped"); + } + + // Live d19770c: after slot7, exception save at + // 0x8001528C. Name Cause/EPC/BadVAddr. Do not + // invent IAT fills. + public static void TryNoteBindImpException(uint code, uint epc, uint vaddr, + uint vector, uint[] regs) + { + TryNoteBindImpException(code, epc, vaddr, vector, regs, null); + } + + public static void TryNoteBindImpException(uint code, uint epc, uint vaddr, + uint vector, uint[] regs, MipsBus bus) + { + if (!_ddiNopAwaitCallDll || !_ddiNopIatWatch || code == 0) + return; + if (_ddiNopIatStoreN < 7 && !_ddiNopIatStoreLogged) + return; + TryNoteC2SpObserve(regs, epc); + _bindImpExnCode = code; + _bindImpExnEpc = epc; + _bindImpExnVaddr = vaddr; + if (code == 2 + && vaddr >= ProcessInfoPage && vaddr < 0x02000000u + && (_ddiNopIatStoreN >= BindImpObserveMax + || _ddiNopIatStoreLogged + || _ddiNopSawCallDllPc)) + { + _ddiNopInfoDemand = true; + TryResolveDdiNopProcessInfo(bus); + } + if (code == 2 + && epc == vaddr + && (vaddr & ~0xFFFu) == GwesDispFetchPage + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesDispFetchTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc != vaddr + && (vaddr & ~0xFFFu) == GwesDispDataPage + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesDispDataTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc != vaddr + && (vaddr & ~0xFFFu) == GwesTextBasePage + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesTextBaseTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc != vaddr + && (vaddr & ~0xFFFu) == GwesDispData2Page + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesDispData2Tlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc != vaddr + && (vaddr & ~0xFFFu) == GwesDispData3Page + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesDispData3Tlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc == vaddr + && (vaddr & ~0xFFFu) == GwesText2Page + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesText2Tlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && IsDdiNopGwesImageVa(vaddr) + && !IsNamedDdiNopGwesPage(vaddr) + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopGwesImageTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && IsDdiNopCoredllImageVa(vaddr) + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopCoredllImageTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc != vaddr + && IsDdiNopFilesysSlotVa(vaddr) + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopFilesysSlot2Tlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && epc != vaddr + && IsDdiNopFilesys48dVa(vaddr) + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopFilesys48dTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && IsDdiNopVallocDataVa(vaddr) + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteDdiNopVallocDataTlbl(bus, regs, epc, vaddr, vector); + } + if (code == 2 + && IsFfffFce1ObserveVa(epc, vaddr) + && (_ddiNopDllMainLogged || _ddiNopIatStoreN >= BindImpObserveMax)) + { + TryNoteFfffFce1Observe(bus, regs, epc, vaddr, vector); + } + // Live c0347e8: B9 dest0 PTE fills after the + // first TLBL. BindImp-exn on that refill hid + // the next real miss and left Hive quiet. + if (code == 2 && IsGwesDataB9Page(vaddr)) + return; + // Live ddd472a: extra slot-2 pages are + // demand-mapped. Do not consume the + // one-shot on that refill. + if (code == 2 && IsFilesysSlot2ExtraPage(vaddr)) + return; + // Live bb6cdc7: this COREDLL page is now + // demand-mapped. Do not consume the + // one-shot on that refill. + if (code == 2 && IsDdiNopCoredllImageVa(vaddr)) + return; + // Live 98db5d5 / 73486bc: page-0 TLBS/TLBL + // consumed the one-shot and hid later + // real misses. Observe the named sites. + // Do not map VA 0 / page 0. + if (IsNearNullVa(vaddr)) + { + if (code == 3 && epc == GwesNullStoreEpc && vaddr == 0) + TryNoteGwesNullStoreObserve(bus, regs, epc); + else if (code == 2 && epc == NearNullTlblEpc + && vaddr == NearNullTlblVaddr) + TryNoteNearNullTlblObserve(bus, regs, epc, vaddr); + return; + } + // Live f3c2d62 / 3ac5ed9: AdEL consumed + // the one-shot. Observe 0xFFFFFB2A and + // 0xC6FA7C9A. Do not map those VAs. Do + // not invent dest. All AdEL / + // epc==badvaddr unaligned skip the + // one-shot so a later TLBL can name + // itself. + if (IsAdelSkip(code, epc, vaddr)) + { + if (epc == FfffFb2aEpc && vaddr == FfffFb2aVaddr) + TryNoteFfffFb2aAdelObserve(bus, regs, epc, vaddr); + else if (epc == AdelC6FaEpc && vaddr == AdelC6FaVaddr) + TryNoteAdelC6FaObserve(bus, regs, epc, vaddr); + return; + } + // Live 3275fe9: C2* TLBS consumed the + // one-shot. Observe 0xC201FE84. Do not + // invent dest. Do not walk C2 as useg + // (L1 alias). Skip so a later TLBL can + // name itself. + if (IsC2TlbsVa(code, vaddr)) + { + if (epc == C2TlbsEpc && vaddr == C2TlbsVaddr) + TryNoteC2TlbsObserve(bus, regs, epc, vaddr); + return; + } + if (_bindImpExnLogged) + return; + _bindImpExnLogged = true; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint v1 = regs != null && regs.Length > 3 ? regs[3] : 0; + BootLog.Write("[Hive] ExtraROM BindImp-exn cause=" + + code + + " epc=0x" + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " v1=0x" + v1.ToString("X8") + + " stores=" + _ddiNopIatStoreN); + } + + // Live 258ef59: page 0xFFFFF000 / 0xFFFFFCE1 + // or gwes epc 0x000593C8 chasing FFFF*. + // One Hive line. Do not map. Do not invent. + private static bool IsFfffFce1ObserveVa(uint epc, uint vaddr) + { + if ((vaddr & ~0xFFFu) == FfffF000Page) + return true; + return epc == FfffFce1Epc + && (vaddr & 0xFF000000u) == 0xFF000000u; + } + + private static uint PeekGpr(uint[] regs, int i) + { + if (regs == null || i < 0 || i >= regs.Length) + return 0; + return regs[i]; + } + + private static string GprHex(uint[] regs, int i) + { + return "0x" + PeekGpr(regs, i).ToString("X8"); + } + + private static void TryNoteFfffFce1Observe(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + if (_ffffFce1Logged) + return; + _ffffFce1Logged = true; + uint insn = 0; + TryPeekWord(bus, epc, out insn); + string dis = insn != 0 ? FormatMipsOp(epc, insn) : "peek-miss"; + uint op = insn >> 26; + uint rs = (insn >> 21) & 31; + uint rt = (insn >> 16) & 31; + uint uimm = insn & 0xFFFFu; + int simm = (short)uimm; + uint bas = PeekGpr(regs, (int)rs); + uint formed = bas + (uint)simm; + uint uk = 0; + uint kd = 0; + uint pg = 0; + bool ukOk = TryPeekWord(bus, UserKPage, out uk); + bool kdOk = TryPeekWord(bus, KDataBase, out kd); + bool pgOk = TryPeekWord(bus, FfffF000Page, out pg); + uint mapped = MapUserKDataVa(vaddr); + BootLog.Write("[Hive] ExtraROM ddi_nop ffff-fce1 observe epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " insn=0x" + insn.ToString("X8") + + " " + dis + + " op=0x" + op.ToString("X") + + " rs=" + rs + + " rt=" + rt + + " imm=0x" + uimm.ToString("X4") + + " base=0x" + bas.ToString("X8") + + " formed=0x" + formed.ToString("X8") + + " a0=" + GprHex(regs, 4) + + " a1=" + GprHex(regs, 5) + + " a2=" + GprHex(regs, 6) + + " a3=" + GprHex(regs, 7) + + " v0=" + GprHex(regs, 2) + + " v1=" + GprHex(regs, 3) + + " t0=" + GprHex(regs, 8) + + " t1=" + GprHex(regs, 9) + + " t2=" + GprHex(regs, 10) + + " t3=" + GprHex(regs, 11) + + " t4=" + GprHex(regs, 12) + + " t5=" + GprHex(regs, 13) + + " t6=" + GprHex(regs, 14) + + " t7=" + GprHex(regs, 15) + + " t8=" + GprHex(regs, 24) + + " t9=" + GprHex(regs, 25) + + " s0=" + GprHex(regs, 16) + + " s1=" + GprHex(regs, 17) + + " s2=" + GprHex(regs, 18) + + " s3=" + GprHex(regs, 19) + + " s4=" + GprHex(regs, 20) + + " s5=" + GprHex(regs, 21) + + " s6=" + GprHex(regs, 22) + + " s7=" + GprHex(regs, 23) + + " s8=" + GprHex(regs, 30) + + " gp=" + GprHex(regs, 28) + + " sp=" + GprHex(regs, 29) + + " ra=" + GprHex(regs, 31) + + (_userKPageAlias + ? " FFFF5800-alias=on->FFFFD800" + : " FFFF5800-alias=off") + + (ukOk ? " FFFF5800=0x" + uk.ToString("X8") : " FFFF5800-unmapped") + + (kdOk ? " FFFFD800=0x" + kd.ToString("X8") : " FFFFD800-unmapped") + + (pgOk ? " FFFFF000=0x" + pg.ToString("X8") : " FFFFF000-unmapped") + + (mapped != vaddr + ? " map-hit=0x" + mapped.ToString("X8") + : " no-FFFFF000-alias") + + " (page 0xFFFFF000 off=0x" + + (vaddr & 0xFFFu).ToString("X") + + "; not UserKPage/KData; observe only; do not invent dest)"); + TryResolveFfffF000(bus, vaddr); + } + + // Live 98db5d5: gwes 0x00021ABC store miss on + // null. Peek insn / rs / rt / base. One Hive + // line. Do not map VA 0. Do not invent dest. + private static void TryNoteGwesNullStoreObserve(MipsBus bus, uint[] regs, + uint epc) + { + if (_gwesNullStoreLogged) + return; + _gwesNullStoreLogged = true; + uint insn = 0; + string via = "peek-miss"; + if (TryPeekWord(bus, epc, out insn)) + via = "gwes"; + else + { + uint rom = GwesRomTextPage(epc); + if (rom != 0 && TryPeekWord(bus, rom | (epc & 0xFFFu), out insn)) + via = "rom"; + } + string dis = via != "peek-miss" ? FormatMipsOp(epc, insn) : "peek-miss"; + uint rs = (insn >> 21) & 31; + uint rt = (insn >> 16) & 31; + int simm = (short)(insn & 0xFFFFu); + uint bas = PeekGpr(regs, (int)rs); + uint formed = bas + (uint)simm; + string why; + if (rs == 0) + why = "rs0"; + else if (bas == 0) + why = "base0"; + else if (formed == 0) + why = "formed0"; + else + why = "badv=0"; + string extra = via == "gwes" ? "" : " via=" + via; + BootLog.Write("[Hive] ExtraROM ddi_nop null-store epc=0x" + + epc.ToString("X8") + + " insn=0x" + insn.ToString("X8") + + " " + dis + + " rs=" + rs + + " rt=" + rt + + " base=0x" + bas.ToString("X8") + + " formed=0x" + formed.ToString("X8") + + " why=" + why + + extra + + " v0=" + GprHex(regs, 2) + + " (do not map VA 0)"); + } + + private static bool IsNearNullVa(uint va) + { + return va < NearNullPageHi; + } + + // Live 73486bc: kernel 0x80052010 TLBL 0x50. + // Peek insn / rs / rt / base. One Hive line. + // Do not map page 0. Do not invent dest. + private static void TryNoteNearNullTlblObserve(MipsBus bus, uint[] regs, + uint epc, uint vaddr) + { + if (_nearNullTlblLogged) + return; + _nearNullTlblLogged = true; + uint insn = 0; + string via = "peek-miss"; + if (TryPeekWord(bus, epc, out insn)) + via = "kseg"; + string dis = via != "peek-miss" ? FormatMipsOp(epc, insn) : "peek-miss"; + uint rs = (insn >> 21) & 31; + uint rt = (insn >> 16) & 31; + int simm = (short)(insn & 0xFFFFu); + uint bas = PeekGpr(regs, (int)rs); + uint formed = bas + (uint)simm; + string why; + if (rs == 0) + why = "rs0"; + else if (bas == 0) + why = "base0"; + else if (IsNearNullVa(formed)) + why = "formed0"; + else + why = "page0"; + string extra = via == "kseg" ? "" : " via=" + via; + BootLog.Write("[Hive] ExtraROM ddi_nop near-null epc=0x" + + epc.ToString("X8") + + " insn=0x" + insn.ToString("X8") + + " " + dis + + " rs=" + rs + + " rt=" + rt + + " base=0x" + bas.ToString("X8") + + " formed=0x" + formed.ToString("X8") + + " why=" + why + + extra + + " v0=" + GprHex(regs, 2) + + " (do not map page 0)"); + } + + // Live f3c2d62 skipped only FFFF* AdEL. + // Live 3ac5ed9: cause=4 epc=badvaddr= + // 0xC6FA7C9A is also AdEL (unaligned + // corrupt PC). Skip all AdEL and + // epc==badvaddr unaligned. Do not map. + private static bool IsAdelSkip(uint code, uint epc, uint va) + { + if (code == 4) + return true; + return epc == va && (epc & 3) != 0; + } + + // Live f3c2d62: AdEL epc=badvaddr=0xFFFFFB2A. + // Peek insn if mapped. One Hive line. Do not + // map 0xFFFFF000. Do not invent dest. + private static void TryNoteFfffFb2aAdelObserve(MipsBus bus, uint[] regs, + uint epc, uint vaddr) + { + if (_ffffFb2aAdelLogged) + return; + _ffffFb2aAdelLogged = true; + uint insn = 0; + bool peeked = TryPeekWord(bus, epc, out insn); + string dis = peeked ? FormatMipsOp(epc, insn) : "peek-miss"; + string why = (epc & 3) != 0 ? "unaligned" : (peeked ? "adel" : "unmapped"); + BootLog.Write("[Hive] ExtraROM ddi_nop adel-ffff epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " insn=" + (peeked ? "0x" + insn.ToString("X8") : "peek-miss") + + (peeked ? " " + dis : "") + + " why=" + why + + " a1=" + GprHex(regs, 5) + + " v0=" + GprHex(regs, 2) + + " v1=" + GprHex(regs, 3) + + " (AdEL; do not map 0xFFFFF000)"); + } + + // Live 3ac5ed9 / fb58a7e: AdEL epc=badvaddr= + // 0xC6FA7C9A (unaligned I-fetch). Dump: + // leftover 0x800159A8 jal 0x800397B0 returns + // *(0x8033FD50), then 0x80015A08 mtc0 EPC. + // 0xC6FA7C9A = 0x86FA7C9A|0x40000000. Keep + // adel-pc $sp (not C2; nested nest!=1). Do + // not map that VA. Do not invent dest. + private static void TryNoteAdelC6FaObserve(MipsBus bus, uint[] regs, + uint epc, uint vaddr) + { + if (_adelC6FaLogged) + return; + _adelC6FaLogged = true; + _adelPcEpc = epc; + _adelPcSp = PeekGpr(regs, 29); + uint plant = 0; + TryPeekWord(bus, ExnContinueWord, out plant); + _exnContinueWord = plant; + uint insn = 0; + bool peeked = TryPeekWord(bus, epc, out insn); + string dis = peeked ? FormatMipsOp(epc, insn) : "peek-miss"; + string why; + if ((epc & 3) != 0) + why = "unaligned"; + else if (epc == vaddr) + why = "corrupt-pc"; + else + why = peeked ? "adel" : "unmapped"; + BootLog.Write("[Hive] ExtraROM ddi_nop adel-pc epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " insn=" + (peeked ? "0x" + insn.ToString("X8") : "peek-miss") + + (peeked ? " " + dis : "") + + " why=" + why + + " sp=0x" + _adelPcSp.ToString("X8") + + " a1=" + GprHex(regs, 5) + + " v0=" + GprHex(regs, 2) + + " (AdEL; do not map)"); + } + + private static bool IsC2TlbsVa(uint code, uint va) + { + return code == 3 && (va & 0xFF000000u) == C2VaPrefix; + } + + private static bool IsC2Sp(uint sp) + { + return (sp & 0xFF000000u) == C2VaPrefix; + } + + // Live 7827498: $sp=0xC201FE48 at sw ra,60(sp). + // Dump 0x80031D34 is a kernel prologue, not a + // missing page. Log the first C2 $sp (pc/sp/ra + // /a1). Slot 97 image is not a stack. Do not + // map. Do not invent dest. + private static void TryNoteC2SpObserve(uint[] regs, uint pc) + { + if (_c2SpLogged) + return; + if (!_ddiNopAwaitCallDll) + return; + if (!_ddiNopDllMainLogged && _ddiNopIatStoreN < BindImpObserveMax) + return; + uint sp = PeekGpr(regs, 29); + if (!IsC2Sp(sp)) + return; + _c2SpLogged = true; + uint low = sp & 0x01FFFFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop sp-c2 pc=0x" + + pc.ToString("X8") + + " sp=0x" + sp.ToString("X8") + + " low=0x" + low.ToString("X8") + + " ra=" + GprHex(regs, 31) + + " a1=" + GprHex(regs, 5) + + " (NK slot97; not a stack; do not invent dest)"); + } + + private static bool IsC2ImageSp(uint sp) + { + return IsC2Sp(sp) && (sp & 0x01FFFFFFu) < C2SlotImageHi; + } + + private static bool IsAdelPoisonEpc(uint pc) + { + if (pc == AdelC6FaEpc || (pc & 0xFF000000u) == 0xC6000000u) + return true; + return pc != 0 && (pc & 3) != 0; + } + + private static bool IsSaneNkResumePc(uint pc) + { + return (pc & 3) == 0 && pc >= 0x80010000u && pc < NkImageEnd; + } + + // Live 3b847b7 / 695e734: 0x800373C0 is + // mid NK idle (jal 0x80031D34). Live + // ac46757: +5C=0x800356FC is that + // thread's start (dump jal 0x80031D34). + // Not a leftover resume. Do not leftover + // hop. + private static bool IsNkIdleResumePc(uint pc) + { + return pc == NkIdleJal || pc == C2TlbsFunc + || pc == NkIdleStart; + } + + // Live e3cc519: +EC=0x80015B9C is leftover + // mid (ExnAfterFetch2; dump addiu $sp,-304 + // then jal 0x80020FA0), not an adel resume. + // plant-clr of that leftover then later + // +EC idle. leftover dest / adel-pc / + // near-null / NK idle / leftover mid are + // not a resume. Do not invent dest. + private static bool IsSaneAdelResumePc(uint pc) + { + if ((pc & 3) != 0 || IsAdelPoisonEpc(pc) || IsPoisonPlant(pc) + || IsNearNullVa(pc) || IsLeftoverDestVa(pc) + || IsNkIdleResumePc(pc) || pc == ExnAfterFetch + || pc == ExnAfterFetch2) + return false; + if (IsSaneNkResumePc(pc)) + return true; + if (IsC2ImageSp(pc)) + return false; + return pc >= 0x00010000u && pc < 0x80000000u; + } + + private static bool IsSaneReplaySp(uint sp) + { + if (sp == 0 || (sp & 3) != 0) + return false; + if (IsNearNullVa(sp) || IsC2ImageSp(sp)) + return false; + if ((sp & 0xFF000000u) == 0xC6000000u) + return false; + if (sp >= 0xFFFFD000u && sp < 0xFFFFE000u) + return true; + if (sp >= 0x80000000u && sp < 0xC0000000u) + return true; + return sp >= 0x00010000u && sp < 0x80000000u; + } + + // Live 155d918 / fb58a7e: adel-pc then + // 0x80015664 $sp=0xC201FE88 from thread + // +0xD4. Nested AdEL (0x80015488) does + // not update +0xD4, so ERET2 reloads the + // ThreadContextSetup / +0x2C-48 image + // cookie. Replay adel-pc $sp into +0xD4 + // when +0xEC is a sane aligned NK PC + // (firmware's own first-level save at + // 0x80015264). Else refuse ERET. Do not + // hop EPC to 0x80030264. Do not invent + // dest. Do not map 0xC201F000. + // Live cf2477b: after that replay, $sp + // is adel-pc slot-2 (not C2) and live + // PeekEpc is already rewritten. Refuse + // ERET while the adel-pc latch is set, + // even when live EPC is not C6FA. Observe + // latch/live/+EC/pc. Do not leftover hop. + // Live aa0b26c: +D4 is slot-2 (not C2); + // leftover mtc0 / 0x800152CC left + // EPC and +DC as adel-pc. 0x8001563C + // already lw $ra,220($s0). Replay +EC + // into EPC / +DC / $ra when +EC is a + // sane aligned NK/useg PC, then clear + // the latch. Do not invent dest. + // Live 3b847b7: after that clear, later + // C2 $sp sp-fix +EC=0x800373C0 idle. + // Refuse that ERET (idle-halt). Do not + // leftover hop. Do not invent dest. + // Live e3cc519: plant-clr of leftover + // mid 0x80015B9C cleared the latch; + // later +EC idle. Keep latch / epc-halt + // when +EC is leftover mid. Do not + // invent dest. + public static bool TryRefuseC2SpResume(MipsBus bus, uint[] regs, + ref uint programCounter) + { + if (programCounter != C2SpFirstPc + && programCounter != ThreadCtxRestore2 + && programCounter != ThreadCtxEret) + return false; + if (!_ddiNopAwaitCallDll) + return false; + if (!_ddiNopDllMainLogged && _ddiNopIatStoreN < BindImpObserveMax) + return false; + if (_adelPcEpc == 0 && !_adelC6FaLogged + && !_nearNullTlblLogged && !_c2SpLogged) + return false; + uint sp = PeekGpr(regs, 29); + bool c2 = IsC2ImageSp(sp); + if (!c2 && _adelPcEpc == 0) + return false; + uint d4 = 0; + uint t24 = 0; + uint t2c = 0; + uint ec = 0; + uint dc = 0; + uint plant = _exnContinueWord; + uint thr = 0; + if (bus != null) + { + try + { + thr = bus.Read32(ThreadPtr); + if (thr != 0) + { + d4 = bus.Read32(thr + ThreadCtxSp); + t24 = bus.Read32(thr + ThreadStack); + t2c = bus.Read32(thr + ThreadStackAlt); + ec = bus.Read32(thr + ThreadCtxPc); + dc = bus.Read32(thr + ThreadCtxRa); + } + uint word; + if (TryPeekWord(bus, ExnContinueWord, out word)) + plant = word; + } + catch + { + } + } + if (!_thrSpLogged) + { + _thrSpLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop thr-sp +D4=0x" + + d4.ToString("X8") + + " +24=0x" + t24.ToString("X8") + + " +2C=0x" + t2c.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " adel-sp=0x" + _adelPcSp.ToString("X8") + + " plant=0x" + plant.ToString("X8")); + } + bool fixedSp = false; + if (c2 && thr != 0 && bus != null + && IsSaneReplaySp(_adelPcSp) && IsSaneNkResumePc(ec)) + { + try + { + bus.Write32(thr + ThreadCtxSp, _adelPcSp); + if (regs != null && regs.Length > 29) + regs[29] = _adelPcSp; + fixedSp = true; + } + catch + { + if (!_c2EretHaltLogged) + { + _c2EretHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop eret-c2-halt pc=0x" + + programCounter.ToString("X8") + + " sp=0x" + sp.ToString("X8") + + " ra=" + GprHex(regs, 31) + + " +EC=0x" + ec.ToString("X8") + + " (refuse ERET after adel-pc; do not invent dest)"); + } + return true; + } + if (!_spFixLogged) + { + _spFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop sp-fix +D4=0x" + + sp.ToString("X8") + + " to=0x" + _adelPcSp.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " (replay adel-pc $sp; do not invent dest)"); + } + } + if (_adelPcEpc != 0) + { + uint live = 0; + if (bus != null) + live = bus.PeekEpc(); + if (IsSaneAdelResumePc(ec)) + { + bool cleared = true; + if (bus != null) + bus.PokeEpc(ec); + if (thr != 0 && bus != null && IsAdelPoisonEpc(dc)) + { + try + { + bus.Write32(thr + ThreadCtxRa, ec); + } + catch + { + cleared = false; + } + } + if (cleared && regs != null && regs.Length > 31 + && IsAdelPoisonEpc(regs[31])) + regs[31] = ec; + if (cleared) + { + if (!_adelPlantClrLogged) + { + _adelPlantClrLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop plant-clr latch=0x" + + _adelPcEpc.ToString("X8") + + " live=0x" + live.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " (replay +EC; do not invent dest)"); + } + _adelPcEpc = 0; + return false; + } + } + if (!_epcHaltLogged) + { + _epcHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop epc-halt latch=0x" + + _adelPcEpc.ToString("X8") + + " live=0x" + live.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " pc=0x" + programCounter.ToString("X8") + + " (refuse ERET; adel-pc latch; do not invent dest)"); + } + return true; + } + if (IsNkIdleResumePc(ec)) + { + if (!_idleHaltLogged) + { + _idleHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop idle-halt +EC=0x" + + ec.ToString("X8") + + " pc=0x" + programCounter.ToString("X8") + + " (refuse ERET; NK idle poll; do not invent dest)"); + } + return true; + } + if (fixedSp || !c2) + return false; + if (!_c2EretHaltLogged) + { + _c2EretHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop eret-c2-halt pc=0x" + + programCounter.ToString("X8") + + " sp=0x" + sp.ToString("X8") + + " ra=" + GprHex(regs, 31) + + " +EC=0x" + ec.ToString("X8") + + " (refuse ERET after adel-pc; do not invent dest)"); + } + return true; + } + + private static bool IsDdiNopDestLive() + { + return _ddiNopDllMainLogged || _ddiNopDestWordLogged; + } + + private static bool IsPoisonPlant(uint pc) + { + if (pc == 0 || pc == 0xFFFFFFFFu) + return true; + if ((pc & 3) != 0) + return true; + return (pc & 0xFF000000u) == 0xC6000000u; + } + + private static bool IsLeftoverDestVa(uint pc) + { + return pc >= LeftoverDestLo && pc < LeftoverDestHi; + } + + // Live 8d10132: +EC mid 0x80038294 / +DC + // mid 0x8003B04C. plant-fix $ra to that + // PC then jr $ra spins. Not a leftover + // resume. Do not invent dest. + private static bool IsPoisonMidPlantResume(uint pc) + { + if (pc >= HandleLookupJal && pc < HandleLookupEnd) + return true; + if (pc >= HandleLookupRet && pc < HandleLookupRetEnd) + return true; + return pc >= MemsetJal && pc < MemsetEnd; + } + + private static bool IsJalInsn(uint word, uint pc, out uint target) + { + uint op = (word >> 26) & 63; + target = (pc & 0xF0000000u) | ((word & 0x3FFFFFFu) << 2); + return op == 2 || op == 3; + } + + // Live 78866b8 plant-fix +EC=0x80038D7C +DC= + // 0x800399E8 hung. Dump +DC-8 is jal + // 0x80038CCC; +EC is that callee jr $ra, + // not entry. Live 1f83cb1 / 8d10132: + // +DC-8 jal T, +EC mid T. Refuse when + // +EC != T or +EC is jr $ra. Do not + // leftover hop. Do not invent dest. + private static bool IsJalCalleeMid(MipsBus bus, uint ec, uint dc) + { + if (bus == null || (dc & 3) != 0 || dc < 8) + return false; + uint jr = 0; + if (TryPeekWord(bus, ec, out jr) && IsFirmwareJrRa(jr)) + return true; + uint w = 0; + if (!TryPeekWord(bus, dc - 8, out w)) + return false; + uint t; + if (!IsJalInsn(w, dc - 8, out t)) + return false; + return ec != t; + } + + // Live f919479 leftover-cstk-fix stores dest + // leftover-syscall jalr+8 0x8009573C. leftover + // 0x800397B0 returns that as $v0; or $ra,$v0; + // leftover-skip does not fire (not leftover + // dest). ERET to dest wrapper mid: nop then + // lw $a2,0($fp) with leftover $fp. Poison. + // leftover-halt that dest stub resume. + // Live 8ac997b leftover-halt dest jalr+8 + // +EC=0x800382F8. Dump leftover wait99 + // 0x8001597C sw $ra,40($sp); ObjectCall + // 0x800391C4 lw $t3,16($fp) is leftover + // wait99 $ra (leftover dest leftover- + // syscall site). leftover dest leftover- + // syscall $ra live 0x03F71740 dest + // 0x80089740 mid-hash addu, not leftover + // dest leftover-syscall jalr+8 0x03F7D73C + // of dest wrapper 0x800956F0. +EC is + // handle-lookup mid jal 0x80038294. + // leftover dest leftover-syscall return + // is leftover dest leftover-syscall $ra. + // leftover hop forbidden. leftover-halt + // dest stub stays. Name leftover wait99 + // $ra / dest / leftover dest leftover- + // syscall jalr+8. Do not leftover hop. + // Do not invent dest. + private static bool IsLeftoverSyscallStubRet(MipsBus bus, uint pc) + { + if (bus == null || (pc & 3) != 0) + return false; + if (pc < LeftoverDestKseg + || pc >= LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo) + || pc >= NkImageEnd) + return false; + uint jalrPc = 0; + uint w = 0; + uint rs; + if (TryPeekWord(bus, pc - 4, out w) && IsJalrInsn(w, out rs)) + jalrPc = pc - 4; + else if (TryPeekWord(bus, pc - 8, out w) && IsJalrInsn(w, out rs)) + jalrPc = pc - 8; + else + return false; + for (uint off = 4; off <= 32; off += 4) + { + uint aw = 0; + uint rt; + if (!TryPeekWord(bus, jalrPc - off, out aw)) + break; + if (IsAddiuZeroNeg(aw, out rt) && rt == rs) + return true; + } + return false; + } + + private static bool IsSanePlantResumePc(uint pc) + { + if ((pc & 3) != 0 || IsPoisonPlant(pc) || IsNearNullVa(pc)) + return false; + if (IsLeftoverDestVa(pc) || IsNkIdleResumePc(pc) + || IsPoisonMidPlantResume(pc)) + return false; + if (pc == LeftoverOrRa || pc == LeftoverMtc0Epc + || pc == LeftoverJrRa || pc == LeftoverEret + || pc == LeftoverJalRet + || pc == ExnAfterFetch || pc == ExnAfterFetch2 + || pc == ThreadCtxRestore || pc == ThreadCtxRestore2 + || pc == C2SpFirstPc + || (pc >= LeftoverResumePlant && pc < LeftoverResumePlantEnd)) + return false; + if (pc >= 0x80010000u && pc < NkImageEnd) + return true; + return pc >= 0x00010000u && pc < 0x80000000u; + } + + private static bool TryPeekThreadCtxPc(MipsBus bus, out uint thr, out uint ec, + out uint dc, out uint plant) + { + thr = 0; + ec = 0; + dc = 0; + plant = _exnContinueWord; + if (bus == null) + return false; + try + { + thr = bus.Read32(ThreadPtr); + if (thr != 0) + { + ec = bus.Read32(thr + ThreadCtxPc); + dc = bus.Read32(thr + ThreadCtxRa); + } + uint word; + if (TryPeekWord(bus, ExnContinueWord, out word)) + plant = word; + return thr != 0; + } + catch + { + return false; + } + } + + private static void ApplyPlantResume(uint[] regs, uint pc, uint dest) + { + if (regs == null || regs.Length <= 31) + return; + if (pc == LeftoverOrRa || pc == LeftoverEret) + regs[2] = dest; + if (pc == LeftoverMtc0Epc || pc == LeftoverEret || pc == LeftoverJrRa) + { + regs[12] = dest; + regs[31] = dest; + } + if (pc == LeftoverEret) + regs[2] = dest; + } + + // Live f66919d: adel-pc gone; ddi_nop dest live; + // leftover eret-restore was=0xFFFFFFFF. Dump + // 0x800397B0 returns $s3; 0x800399A4 load of + // *(0x8033FD50) is skipped by beq/bne to + // 0x800399A8 so $s3 stays -1. leftover hop to + // dest-live then ~2.8M Code-10. Replay + // thread+0xEC when that is a sane aligned PC. + // Else refuse leftover ERET. Do not leftover + // dest hop. Do not invent dest. + // Live 77ba8c0: adel-pc then epc-halt; +EC + // leftover mid is not a resume. Dump wait99: + // 0x800159B4 or $ra,$v0; 0x80015A08 mtc0 + // $t4,$14; user ERET / kernel jr $ra plants + // that return. This Boot plant=0x03F74844 + // (leftover dest). ERET there then unaligned + // I-fetch 0xC6FA7C9A (0x86FA7C9A|0x40000000). + // +EC leftover mid / idle are not a resume. + // Refuse leftover ERET when $v0/$t4/$ra is + // leftover dest unless thread+0xEC is a + // sane aligned NK/useg PC. Live 0332c87: + // leftover-halt was=0x03F71740 +EC= + // 0x800382F8 during NK coredll LoadO32. + // Live 8d10132: plant-fix to that +EC + // hung (jr $ra loop). Dump: +EC is mid + // jal 0x80038294; +DC=0x8003B05C is the + // jal return. Neither is a leftover + // resume. leftover-halt when +EC is that + // poison mid. Live 3d6387d: leftover-halt + // again; plant=0x03F74844 leftover dest. + // Dump leftover 0x800159A4 sw $v0,16($sp) + // then jal 0x800397B0; 0x800397F8 lw + // $s3,4(thread+0x18); 0x800399A4 may + // skip FD50; 0x8001597C sw $ra,40($sp). + // Observe those slots. Live ac46757: + // leftover-frame +5C=0x800356FC is NK + // idle start (jal 0x80031D34), not a + // LoadO32 continue. +18/v016=0; + // FD50/ra40 leftover dest. leftover-halt + // stays. Live ee3e1af: leftover dest + // $v0 at wait99 or $ra,$v0 plants + // coredll mid-hash (0x03F71740). Dump + // 0x800397B0 returns $s3 from frame+4. + // Skip that or; leave $ra. Live 7607343: + // leftover-skip then jr $ra to leftover + // mid 0x800159B0 hung. leftover-halt that + // mid. Do not leftover hop. Do not invent + // dest. + public static bool TryRefuseMinusOnePlant(MipsBus bus, uint[] regs, + ref uint programCounter) + { + uint pc = programCounter; + if (pc != LeftoverOrRa && pc != LeftoverMtc0Epc + && pc != LeftoverJrRa && pc != LeftoverEret) + return false; + if (regs == null || regs.Length <= 31) + return false; + uint was = pc == LeftoverOrRa || pc == LeftoverEret + ? regs[2] + : (pc == LeftoverMtc0Epc ? regs[12] : regs[31]); + bool adel = IsAdelPoisonEpc(was); + bool destPlant = IsLeftoverDestVa(was); + bool destStub = IsLeftoverSyscallStubRet(bus, was); + bool leftoverMid = was == LeftoverJalRet + || (pc == LeftoverEret && regs[12] == LeftoverJalRet); + if (!adel && !destPlant && !leftoverMid && !destStub + && !(IsDdiNopDestLive() && IsPoisonPlant(was))) + return false; + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + if (adel) + { + if (!_epcHaltLogged) + { + _epcHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop epc-halt was=0x" + + was.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (refuse leftover ERET adel-pc; do not invent dest)"); + } + return true; + } + if (pc == LeftoverOrRa && destPlant) + { + programCounter = pc + 4; + if (!_leftoverSkipLogged) + { + _leftoverSkipLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-skip was=0x" + + was.ToString("X8") + + " ra=0x" + regs[31].ToString("X8") + + " (leave $ra; refuse leftover dest)"); + } + return true; + } + bool api78 = _leftoverCstkApi == LeftoverApi78; + bool api54 = _leftoverCstkApi == LeftoverApi54; + if (api78) + TryPlantLeftoverApi78Method(bus); + if (api54) + TryPlantLeftoverApi54Method(bus); + bool api78Cont = api78 && IsLeftoverApiContPc(bus, ec, + LeftoverApi78Ec, LeftoverApi78Meth); + uint api54Dest = 0; + bool api54Cont = api54 && TryLeftoverApi54ContDest(bus, out api54Dest); + bool apiCont = api78Cont || api54Cont; + if ((destStub && !apiCont) + || ((destPlant || leftoverMid) && !apiCont + && (IsJalCalleeMid(bus, ec, dc) || !IsSanePlantResumePc(ec)))) + { + TryNoteLeftoverFrameObserve(bus, regs, plant); + uint mid = leftoverMid && !destPlant + ? (was == LeftoverJalRet ? was : regs[12]) + : was; + uint waitRa = PeekGpr(regs, 31); + uint destOfRa = 0; + if (IsLeftoverDestVa(waitRa)) + destOfRa = LeftoverDestKseg + (waitRa - LeftoverDestLo); + uint leftoverJalr8 = 0; + if (destStub + && mid >= LeftoverDestKseg + && mid < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo)) + leftoverJalr8 = LeftoverDestLo + (mid - LeftoverDestKseg); + if (api54) + TryNoteLeftoverApi54Halt(bus, mid, ec, dc); + else if (!_leftoverHaltLogged) + { + _leftoverHaltLogged = true; + if (api78) + { + uint m = 0; + uint jalr8 = 0; + TryPeekLeftoverWait99Method(bus, LeftoverApi78Meth, out m); + TryResolveLeftoverCstkFromApi(bus, LeftoverApi78, out jalr8); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-78-halt api=0x" + + LeftoverApi78.ToString("X8") + + " imm=" + LeftoverApi78Imm + + " jalr8=0x" + jalr8.ToString("X8") + + " m78=0x" + m.ToString("X8") + + " was=0x" + mid.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8")); + } + else + { + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-halt was=0x" + + mid.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + (destStub + ? " ra=0x" + waitRa.ToString("X8") + + " dest=0x" + destOfRa.ToString("X8") + + " leftover-jalr8=0x" + leftoverJalr8.ToString("X8") + + " (refuse leftover dest leftover-syscall jalr+8; leftover dest $ra mid-hash not leftover dest leftover-syscall stub; do not leftover dest)" + : leftoverMid && !destPlant + ? " (refuse leftover mid $ra; do not invent dest)" + : " (refuse leftover ERET dest; do not invent dest)")); + } + } + return true; + } + if (apiCont + || (IsSanePlantResumePc(ec) && !IsJalCalleeMid(bus, ec, dc))) + { + uint resume = api54Cont ? api54Dest : ec; + ApplyPlantResume(regs, pc, resume); + if (api54Cont) + TryNoteLeftoverApi54Cont(bus, was, ec, dc, resume); + else if (!_plantFixLogged) + { + _plantFixLogged = true; + if (api78) + { + uint m = 0; + TryPeekLeftoverWait99Method(bus, LeftoverApi78Meth, out m); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-78-cont api=0x" + + LeftoverApi78.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " was=0x" + was.ToString("X8") + + " m78=0x" + m.ToString("X8")); + } + else + { + BootLog.Write("[Hive] ExtraROM ddi_nop plant-fix was=0x" + + was.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (replay thread+0xEC; do not leftover dest)"); + } + } + return false; + } + if (!_plantHaltLogged) + { + _plantHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop plant-halt was=0x" + + was.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (refuse leftover ERET; do not invent dest)"); + } + return true; + } + + // Live 3d6387d leftover-halt during NK + // coredll LoadO32. Dump leftover: + // 0x800158D4 lw thread+0x18; 0x800397F8 + // lw $s3,4($a0); 0x800399A4 lw FD50; + // 0x800159A4 sw $v0,16($sp); 0x8001597C + // sw $ra,40($sp). +5C startip. +F0 is + // 3 kernel / 0x13 user. One Hive line. + // Do not leftover hop. Do not invent dest. + private static void TryNoteLeftoverFrameObserve(MipsBus bus, uint[] regs, + uint plant) + { + if (_leftoverFrameLogged) + return; + _leftoverFrameLogged = true; + uint frame = 0; + uint frame4 = 0; + uint fd50 = plant; + uint ra40 = 0; + uint v016 = 0; + uint startip = 0; + uint sr = 0; + uint thr = 0; + if (TryPeekWord(bus, ThreadPtr, out thr) && thr != 0 + && thr != 0xFFFFFFFFu) + { + TryPeekWord(bus, thr + ThreadSyscallFrame, out frame); + TryPeekWord(bus, thr + ThreadStartip, out startip); + TryPeekWord(bus, thr + ThreadCtxSr, out sr); + if (frame != 0 && frame != 0xFFFFFFFFu) + TryPeekWord(bus, frame + 4, out frame4); + } + uint word; + if (TryPeekWord(bus, ExnContinueWord, out word)) + fd50 = word; + uint sp = PeekGpr(regs, 29); + if (sp != 0 && sp != 0xFFFFFFFFu) + { + TryPeekWord(bus, sp + 16, out v016); + TryPeekWord(bus, sp + 40, out ra40); + } + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-frame +18=0x" + + frame.ToString("X8") + + " +4=0x" + frame4.ToString("X8") + + " FD50=0x" + fd50.ToString("X8") + + " ra40=0x" + ra40.ToString("X8") + + " v016=0x" + v016.ToString("X8") + + " +5C=0x" + startip.ToString("X8") + + " +F0=0x" + sr.ToString("X8") + + " (do not invent dest)"); + } + + // Live 7ecd04b leftover-halt dest leftover- + // syscall jalr+8. leftover dest leftover- + // syscall return is leftover dest leftover- + // syscall $ra, not dest leftover-syscall + // jalr+8 / poison +EC. Live a6102f2 dest- + // live continue leftover dest leftover- + // syscall $ra dest=0x80089740 mid-hash + // then leftover-wait99-spin pc=0x80015368 + // v0=0 a0=1 ra=0x80015360. Dump 0x80015358 + // jalr $a1; 0x80015360 mfc0 Status; + // 0x80015368 xori IE; 0x80015380 beq + // $v0,$0, restore/ERET. dest-live continue + // leftover dest leftover-syscall $ra + // I-fetches leftover dest mid-hash; + // exception ERET storm. leftover dest + // leftover-syscall $ra mid-hash is not a + // LoadO32 resume. Live 2239756 leftover- + // wait99-halt then leftover-cstk +4 + // leftover dest api=0xFFFFFF68 leftover- + // cstk-fix jalr+8 leftover-halt dest stub + // +EC=0x800382F8. leftover-wait99-halt + // logged and returned false so firmware + // sw $ra / jal ObjectCall 0x80015980 + // still ran. Dump 0x80015980 jal + // 0x80039148. dest leftover-syscall + // jalr+8 / leftover dest leftover-syscall + // $ra are not a LoadO32 continue past + // wait99/-1630. Halt at wait99 plant + // root (leave PC; do not execute sw $ra + // / jal ObjectCall). dest leftover- + // syscall stub / dest wrapper jalr+8 stay + // leftover-halt. Live 0161c2e leftover- + // wait99-tick-halt word=0x1300000A is + // OEM tick beq $t8,$0,+10, not LoadO32. + // Dump leftover dest leftover-syscall $ra + // dest 0x80089740 mid-hash addu. leftover + // dest leftover-syscall -1630 jalr+8 + // leftover dest is 0x03F7D73C, not live + // $ra 0x03F71740. leftover-frame +5C idle + // is not a LoadO32 resume. No dest-live + // LoadO32 continue in PE/hive/dest-word. + // leftover-wait99-need names that missing + // dest-live LoadO32 resume. Live 98463a8 + // leftover-wait99-wrap-cont then leftover- + // wait99-halt ra=0x03F70B94 dest=0x80088B94 + // dest-word=0x01495825 (or $t3,$t2,$t1 mid- + // hash) leftover-wait99-spin pc=0x80055814. + // leftover dest leftover-syscall $ra dest + // mid-hash is not a LoadO32 continue. + // leftover-wait99-tick-halt dump OEM tick + // mid after leftover-wait99-halt stays. + // leftover dest GetProc dest leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. + public static bool TryFixWait99PlantRa(MipsBus bus, uint[] regs, + ref uint programCounter) + { + if (programCounter != LeftoverWait99RaSw) + return false; + if (regs == null || regs.Length <= 31) + return false; + uint ra = PeekGpr(regs, 31); + if (!IsLeftoverDestVa(ra) || (ra & 3) != 0) + return false; + uint destOfRa = LeftoverDestKseg + (ra - LeftoverDestLo); + if (IsLeftoverSyscallStubRet(bus, destOfRa)) + return false; + uint wrapperDest; + if (TryResolveLeftoverCstkFromDestWrapper(bus, ra, out wrapperDest)) + return false; + uint o32 = 0; + if (TryLeftoverWait99O32Resume(bus, ra, destOfRa, out o32)) + { + programCounter = o32; + TryNoteLeftoverWait99O32Cont(bus, ra, destOfRa, o32); + return true; + } + if (!_wait99PlantFixLogged) + { + _wait99PlantFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-halt was=0x" + + LeftoverWait99RaSw.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dest=0x" + destOfRa.ToString("X8") + + " (refuse leftover dest leftover-syscall $ra dest mid-hash dest-live continue; refuse leftover dest GetProc dest leftover hop; dump 0x80015980 jal ObjectCall; do not leftover dest)"); + TryNoteLeftoverWait99Need(bus, ra, destOfRa); + TryNoteLeftoverWait99O32Halt(bus, ra, destOfRa); + } + return true; + } + + // Live 0161c2e leftover-wait99-halt then leftover- + // wait99-tick-halt. Dump shows no dest-live + // LoadO32 continue past wait99/-1630: leftover + // dest leftover-syscall $ra dest 0x80089740 is + // mid-hash addu; leftover dest leftover-syscall + // -1630 jalr+8 leftover dest is 0x03F7D73C; + // leftover-frame +5C idle / plant-fix +EC hung. + // Name dest-word / leftover dest word / +5C / + // +EC / LoadO32-watch vs leftover dest leftover- + // syscall -1630 jalr+8. Missing prerequisite is + // dest-live LoadO32 resume at leftover dest + // leftover-syscall $ra. Do not leftover hop. + // Do not invent dest. + private static void TryNoteLeftoverWait99Need(MipsBus bus, uint ra, + uint destOfRa) + { + uint destWord = 0; + uint raWord = 0; + TryPeekWord(bus, destOfRa, out destWord); + TryPeekWord(bus, ra, out raWord); + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + uint startip = 0; + if (thr != 0 && thr != 0xFFFFFFFFu) + TryPeekWord(bus, thr + ThreadStartip, out startip); + uint jalr8Ra = LeftoverDestLo + (LeftoverApi1630Ret - LeftoverDestKseg); + string lo32 = string.IsNullOrEmpty(_nkLoadO32Name) ? "-" : _nkLoadO32Name; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-need ra=0x" + + ra.ToString("X8") + + " dest=0x" + destOfRa.ToString("X8") + + " dest-word=0x" + destWord.ToString("X8") + + " ra-word=0x" + raWord.ToString("X8") + + " +5C=0x" + startip.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " jalr8=0x" + jalr8Ra.ToString("X8") + + " lo32=" + lo32 + + " entered=" + _nkLoadO32Entered + + " dest0=0x" + _nkLoadO32Toc.ToString("X8") + + " (dump dest mid-hash; leftover dest leftover-syscall $ra != leftover dest leftover-syscall -1630 jalr+8; no dest-live LoadO32 resume; do not leftover dest)"); + TryNoteLeftoverWait99Why(bus, plant, ra, destWord, raWord); + } + + // Live 0c21f53 leftover-wait99-wrap-cont then + // leftover-wait99-halt ra=0x03F70B94 dest= + // 0x80088B94 dest-word=0x01495825 +5C= + // 0x03FBF69C +EC=0x03F74B5C +DC=0x03F71618 + // plant=0x03F74844 leftover-wait99-tick-halt + // pc=0x800557F4. dest dest-word is or $t3, + // $t2,$t1 mid-hash, not LoadO32. +5C is + // coredll ThreadExceptionExit CreateThread + // start (0x03F74B18 worker). +EC leftover + // dest dest-wrapper / leftover dest GetProc + // dest neighborhood. +DC leftover dest mid- + // hash dest 0x80089618. plant leftover dest + // GetProc dest 0x8008C844 leftover hop + // forbidden. leftover-wait99-o32-cont only + // dest-live NK LoadO32 / BindImp / wrap- + // copy dest-fp50 / wrap-copy-ret. dest-e32 + // 0x1B0C is SIZE not dest-live hop. + // leftover-wrap-after-copy is leftover jal + // INTO wrap residue after CopyO32 dest + // fill. after dest-live GetProc wrap-cont + // (0x800165DC–0x8001E538 / 0x8001E6E0– + // 0x8001E758 / BindImp 0x80019098). leftover- + // wait99-o32-halt +5C/+EC/+DC / leftover dest + // dest-wrapper / leftover dest GetProc dest + // 0x8008C844 / leftover-api-54 methods[54] + // are not a LoadO32 continue. leftover dest + // leftover-syscall $ra dest mid-hash is not + // a LoadO32 continue. leftover dest GetProc + // dest leftover hop forbidden. Do not leftover + // hop. Do not invent dest. + private static bool TryLeftoverWait99O32Resume(MipsBus bus, uint ra, + uint destOfRa, out uint resume) + { + resume = 0; + if (destOfRa == LeftoverWait99GetProcDest + || destOfRa == LeftoverWait99NeedDest) + return false; + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + if (ec == LeftoverWait99O32HaltEc || dc == LeftoverWait99O32HaltDc) + return false; + if (TryLeftoverWait99O32DestLive(ec, out resume)) + return true; + if (TryLeftoverWait99O32DestLive(dc, out resume)) + return true; + return false; + } + + private static bool TryLeftoverWait99O32DestLive(uint pc, out uint dest) + { + dest = 0; + if (!IsLeftoverWait99O32Caller(pc)) + return false; + dest = pc; + return true; + } + + private static void TryNoteLeftoverWait99O32Cont(MipsBus bus, uint ra, + uint destOfRa, uint resume) + { + if (_leftoverWait99O32ContLogged) + return; + _leftoverWait99O32ContLogged = true; + _wait99PlantFixLogged = true; + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-cont ra=0x" + + ra.ToString("X8") + + " dest=0x" + destOfRa.ToString("X8") + + " resume=0x" + resume.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (dump dest-live NK LoadO32; refuse leftover dest leftover-syscall $ra dest mid-hash / leftover dest GetProc dest leftover hop; do not leftover dest)"); + } + + private static void TryNoteLeftoverWait99O32Halt(MipsBus bus, uint ra, + uint destOfRa) + { + if (_leftoverWait99O32HaltLogged) + return; + _leftoverWait99O32HaltLogged = true; + uint destWord = 0; + TryPeekWord(bus, destOfRa, out destWord); + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + uint startip = 0; + if (thr != 0 && thr != 0xFFFFFFFFu) + TryPeekWord(bus, thr + ThreadStartip, out startip); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-halt ra=0x" + + ra.ToString("X8") + + " dest=0x" + destOfRa.ToString("X8") + + " dest-word=0x" + destWord.ToString("X8") + + " +5C=0x" + startip.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (refuse leftover dest leftover-syscall $ra dest mid-hash 0x80088B94 / leftover dest dest-wrapper +EC/+DC / leftover dest GetProc dest 0x8008C844 / ThreadExceptionExit +5C; no dest-live NK LoadO32; leftover-wait99-halt stays; do not leftover dest)"); + } + + // Live a77cd06 leftover dest leftover-syscall $ra + // dest wrapper mid lw $a2,0($fp); plant leftover + // dest GetProc. leftover dest GetProc leftover + // dest dest-wrapper jalr leftover-syscall -1630 + // is why wait99 is entered. leftover dest dest- + // wrapper mid leftover $fp is poison. leftover + // dest GetProc dest leftover hop forbidden. + // leftover-wait99-wrap-halt leftover dest dest- + // wrapper so leftover-syscall -1630 is never + // entered. Do not leftover hop. Do not invent dest. + public static bool TryRefuseLeftoverWait99Wrap(MipsBus bus, uint[] regs, + ref uint pc) + { + if (TryLeftoverWait99O32RaSrc(bus, regs, ref pc)) + return true; + if (TryLeftoverWait99O32FirstSwRa(bus, regs, ref pc)) + return true; + if (pc < LeftoverWait99Wrap || pc > LeftoverWait99WrapRa + || (pc & 3) != 0) + return false; + uint word = 0; + TryPeekWord(bus, pc, out word); + uint rs; + uint rt; + bool jalr = IsJalrInsn(word, out rs); + bool addiu1630 = IsAddiuZeroNeg(word, out rt) + && (short)(word & 0xFFFF) == -1630; + bool wrapMid = pc == LeftoverWait99WrapRa + && word == LeftoverWait99WrapRaWord; + bool wrapLoad = pc == LeftoverWait99Wrap + && word == LeftoverWait99WrapWord; + bool wrapBeq = pc == LeftoverWait99WrapBeq + && word == LeftoverWait99WrapBeqWord; + bool wrapSkip = pc == LeftoverWait99WrapSkip + && word == LeftoverWait99WrapSkipWord; + bool wrapGetProcLw = pc == LeftoverWait99WrapGetProcLw + && word == LeftoverWait99WrapGetProcLwWord; + bool wrapJalr = pc == LeftoverWait99WrapJalr + && word == LeftoverWait99WrapJalrWord; + uint v0 = PeekGpr(regs, 2); + if (wrapLoad) + TryPlantLeftoverWait99GetProc(bus, regs); + if (wrapLoad || wrapBeq || wrapSkip || wrapGetProcLw + || (wrapJalr && IsDumpWait99GetProcDest(v0))) + { + TryNoteLeftoverWait99WrapCont(bus, regs, pc, word); + return false; + } + if (wrapMid && TryContinueLeftoverWait99WrapRa(bus, regs)) + { + uint o32 = 0; + string via = ""; + if (TryLeftoverWait99O32ResumeFromWrap(bus, regs, out o32, + out via)) + { + pc = o32; + TryNoteLeftoverWait99O32ContFromWrap(bus, regs, o32, via); + return true; + } + TryNoteLeftoverWait99O32HaltFromWrap(bus, regs, via); + return true; + } + if ((addiu1630 || (pc == LeftoverWait99WrapSyscall + && word == LeftoverWait99WrapSyscallWord)) + && TryContinueLeftoverWait99GetProc(bus, regs, ref pc)) + return false; + if (!jalr && !addiu1630 && !wrapMid) + return false; + if (!_leftoverWait99WrapLogged) + { + _leftoverWait99WrapLogged = true; + uint destWord = 0; + uint raWord = 0; + TryPeekWord(bus, LeftoverWait99GetProcDest, out destWord); + TryPeekWord(bus, LeftoverWait99WrapRa, out raWord); + uint plant = 0; + TryPeekWord(bus, ExnContinueWord, out plant); + uint cache = 0; + uint getproc = 0; + uint meth = 0; + TryPeekLeftoverWait99WrapGetProcLive(bus, out cache, out getproc, + out meth); + uint fp = PeekGpr(regs, 30); + TryNoteLeftoverWait99Why(bus, plant, LeftoverWait99WrapRa, + destWord, raWord); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-wrap-halt pc=0x" + + pc.ToString("X8") + + " word=0x" + word.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " cache=0x" + cache.ToString("X8") + + " getproc=0x" + getproc.ToString("X8") + + " meth=0x" + meth.ToString("X8") + + " fp=0x" + fp.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " (refuse leftover dest leftover-syscall -1630 / missing dest-live GetProc; dump dest leftover-syscall wrapper jalr+8 wrap-cont after wrap-plant dest-live methods[152]; leftover dest GetProc dest leftover hop forbidden; do not leftover dest)"); + } + return true; + } + + // Dump dest leftover-syscall wrapper success + // after leftover dest GetProc lw $v0,0($s6): + // $s6=0x01FFFCA4 (lui 0x200 + addiu -860). + // $v0=*0x01FFFCA4 is GetProc cache. dest-live + // 0x03F7172C b +2 / 0x03F71730 lw $v0,608($v0) + // / 0x03F71738 jalr $v0. leftover dest leftover- + // syscall -1630 wrap-halt stays when cache is + // 0 / dest-live words miss dump. Live 2b0bcf3 + // leftover-wait99-wrap-plant via=ptr now= + // 0x8005D400 gp=0x8003EABC leftover-wait99- + // wrap-cont pc=0x03F7172C cache=0x8005D400 + // getproc=0x8003EABC then leftover-wait99- + // wrap-halt pc=0x03F71740 (missing dest-live + // GetProc). *0x01FFFCA4 at GetProc-wrapper + // $ra is not the plant table. leftover-wait99- + // wrap-cont at $ra peeks plant table + // 0x8005D400 / KData 0xFFFFDCA4 when the + // slot is cleared. leftover dest leftover- + // syscall -1630 / missing GetProc wrap-halt + // stays. leftover dest GetProc dest 0x8008C844 + // leftover hop forbidden. Do not leftover hop. + // Do not invent dest. + + // Live 2b0bcf3 leftover-wait99-wrap-halt + // pc=0x03F71740 after wrap-plant dest-live + // GetProc gp=0x8003EABC / wrap-cont + // cache=0x8005D400. ProcessInfoFaultVa peek + // at $ra missed dest-live methods[152]. + // dump dest leftover-syscall wrapper plant + // table 0x8005D400 methods[152] 0x8003EABC + // still dest-live. leftover-wait99-wrap-cont + // at GetProc-wrapper $ra when plant table / + // KData / slot still dest-live. leftover dest + // leftover-syscall -1630 / missing GetProc + // wrap-halt stays. leftover dest GetProc dest + // leftover hop forbidden. Do not leftover hop. + // Do not invent dest. + private static bool TryContinueLeftoverWait99WrapRa(MipsBus bus, + uint[] regs) + { + uint cache = 0; + uint getproc = 0; + uint meth = 0; + return TryPeekLeftoverWait99WrapGetProcLive(bus, out cache, + out getproc, out meth); + } + + // Live db3d277 leftover-wait99-o32-sw-halt + // pc=0x03F716F4 ra leftover dest 0x03F74DEC + // dest=0x8008CDEC dump-sp1c=0. $ra is + // leftover before AFBF001C. Implied source + // is jal/jalr/lw $ra at $ra-8 0x03F74DE4 + // (leftover dest 0x8008CDE4 / coredll dump + // 0x80098DE4). Observe that prior jalr + // word/dest. Live 0ab1b68 leftover-wait99- + // o32-ra-src pc=0x03F74DE4 word=0x0CFDC5BC + // dest=0x03F716F0 via=jal. leftover jal + // INTO wrap. leftover→wrap loop, NOT + // LoadO32. Do not continue via that jal + // dest. leftover-wait99-o32-nk-call + // observes who jal's LoadO32 with a good + // $ra. leftover-wait99-o32-cont only + // dump-true dest-live NK LoadO32 / BindImp + // / wrap-copy dest-fp50 / wrap-copy-ret. + // dest-e32=0x1B0C is SIZE not dest-live + // hop. leftover-wrap-after-copy is leftover + // jal INTO wrap residue after CopyO32 dest + // fill. leftover dest 0x03F74DEC / + // leftover dest GetProc dest 0x8008C844 + // leftover hop forbidden. Do not leftover + // hop. Do not invent dest. Do not hop + // dest-e32 size. + private static bool TryLeftoverWait99O32RaSrc(MipsBus bus, + uint[] regs, ref uint pc) + { + if (_leftoverWait99O32RaSrcLogged) + { + if (_leftoverWait99O32HaltLogged + && IsLeftoverWait99O32RaSrcSite(pc)) + return true; + return false; + } + if ((pc & 3) != 0 || !IsLeftoverWait99O32RaSrcSite(pc)) + return false; + uint word = 0; + if (!TryPeekLeftoverWait99O32RaSrcWord(bus, pc, out word)) + TryPeekWord(bus, pc, out word); + uint dest; + string via; + if (!TryDecodeLeftoverWait99O32RaSrc(word, pc, regs, bus, + out dest, out via)) + return false; + // Live 7bb467b leftover jal INTO wrap + // residue during BindImp of hd.dll. + // Do not leftover-hop wrap. Resume + // dump-true BindImp so the IAT march + // can finish. + if (IsLeftoverWait99O32WrapLoopDest(dest) + && (_leftoverWait99O32NkBindLogged + || _leftoverWait99O32NkIatStubLog > 0)) + { + uint resume = _leftoverWait99O32NkBindLastPc; + if (resume == 0 || !IsLeftoverWait99O32NkBindPc(resume)) + resume = BindImpOrdJalRet; + if (IsLeftoverWait99O32Caller(resume) + && !IsLeftoverBindRefuse(resume) + && !IsWrapDestSize(resume) + && resume != dest + && resume != WrapDestE32SizeLive + && !IsWrapDestFp50Va(resume) + && !IsHdDllImageBase(resume) + && resume != HdDllEntryVa + && resume != HdDllInitVa + && resume != HdDllEntryRva) + { + uint src = pc; + pc = resume; + _leftoverWait99O32RaSrcLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-bind-refuse-wrap pc=0x" + + src.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " resume=0x" + resume.ToString("X8") + + " via=bind-refuse-wrap"); + TryNoteLeftoverWait99O32ContFromNkWrap(bus, resume, resume, + "bind-refuse-wrap"); + return true; + } + } + if (dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || dest == LeftoverWait99GetProc + || dest == LeftoverWait99O32RefuseDumpJalr + || dest == LeftoverWait99O32RefuseCoredllJalr + || dest == LeftoverWait99O32RefuseDump + || dest == LeftoverWait99O32RefusePrologue + || dest == LeftoverWait99O32RefuseJalr + || IsLeftoverWait99O32WrapLoopDest(dest) + || IsWrapDestSize(dest) + || dest == WrapDestE32SizeLive + || IsWrapDestFp50Va(dest) + || dest == WrapDestFp50FillLive + || IsHdDllImageBase(dest) + || dest == HdDllEntryVa || dest == HdDllInitVa + || dest == HdDllEntryRva + || IsLeftoverBindRefuse(dest) + || !IsLeftoverWait99O32Caller(dest)) + { + string haltVia = via; + if (IsWrapDestSize(dest) || dest == WrapDestE32SizeLive + || dest == HdDllEntryRva) + haltVia = "size-e32"; + else if (IsWrapDestFp50Va(dest) || dest == WrapDestFp50FillLive + || IsHdDllImageBase(dest)) + haltVia = "dest-fp50"; + else if (dest == HdDllEntryVa || dest == HdDllInitVa) + haltVia = "dump-true"; + else if (IsLeftoverBindRefuse(dest)) + haltVia = "leftover-getproc"; + else if (IsLeftoverWait99O32WrapLoopDest(dest)) + haltVia = LeftoverWrapAfterCopyVia(); + else if (dest == 0 || dest == 0xFFFFFFFFu) + haltVia = "miss-dest"; + TryNoteLeftoverWait99O32RaSrcHalt(bus, pc, word, dest, haltVia); + return true; + } + pc = dest; + TryNoteLeftoverWait99O32ContFromSw(dest, via + "-src"); + _leftoverWait99O32RaSrcLogged = true; + return true; + } + + private static bool IsLeftoverWait99O32RaSrcSite(uint pc) + { + if (pc == LeftoverWait99O32RefuseJalr + || pc == LeftoverWait99O32RefuseDumpJalr + || pc == LeftoverWait99O32RefuseCoredllJalr) + return true; + if (pc >= LeftoverWait99O32RefusePrologue + && pc < LeftoverWait99O32RefusePrologue + 0x20) + return true; + uint destLo = LeftoverWait99DestOf(LeftoverWait99O32RefusePrologue); + if (destLo != 0 && pc >= destLo && pc < destLo + 0x20) + return true; + if (pc >= LeftoverWait99O32RefuseCoredllJalr - 4 + && pc < LeftoverWait99O32RefuseCoredllJalr - 4 + 0x20) + return true; + return false; + } + + private static bool TryPeekLeftoverWait99O32RaSrcWord(MipsBus bus, + uint va, out uint word) + { + if (TryPeekLeftoverWait99WrapWord(bus, va, out word)) + return true; + uint dest = LeftoverWait99DestOf(va); + if (dest != 0 && dest != va + && TryPeekLeftoverWait99WrapWord(bus, dest, out word)) + return true; + if (va >= 0x03F70000u && va < 0x03F80000u) + { + uint ck = 0x80094000u + (va - 0x03F70000u); + if (TryPeekLeftoverWait99DumpOnly(ck, out word)) + return true; + if (TryPeekWord(bus, ck, out word)) + return true; + } + word = 0; + return false; + } + + private static bool TryDecodeLeftoverWait99O32RaSrc(uint word, uint pc, + uint[] regs, MipsBus bus, out uint dest, out string via) + { + dest = 0; + via = ""; + uint rs; + if (IsJalrInsn(word, out rs)) + { + dest = PeekGpr(regs, (int)rs); + via = "jalr"; + return true; + } + uint target; + uint op = (word >> 26) & 63; + if (op == 3 && IsJalInsn(word, pc, out target)) + { + dest = target; + via = "jal"; + return true; + } + if (op == 2 && IsJalInsn(word, pc, out target)) + { + dest = target; + via = "j"; + return true; + } + if (((word >> 26) & 63) == 0x23 && ((word >> 16) & 31) == 31) + { + uint baseReg = PeekGpr(regs, (int)((word >> 21) & 31)); + int imm = (short)(word & 0xFFFF); + TryPeekWord(bus, baseReg + (uint)imm, out dest); + via = "lw-ra"; + return true; + } + if (((word >> 26) & 63) == 0 && ((word >> 11) & 31) == 31) + { + uint funct = word & 63; + if (funct == 37 || funct == 33 || funct == 36 || funct == 32 + || funct == 35 || funct == 34) + { + dest = PeekGpr(regs, (int)((word >> 16) & 31)); + if (dest == 0) + dest = PeekGpr(regs, (int)((word >> 21) & 31)); + via = "move-ra"; + return true; + } + } + return false; + } + + private static string LeftoverWait99O32RaSrcViaOf(uint word) + { + uint rs; + if (IsJalrInsn(word, out rs)) + return "jalr"; + uint op = (word >> 26) & 63; + if (op == 3) + return "jal"; + if (op == 2) + return "j"; + if (op == 0x23 && ((word >> 16) & 31) == 31) + return "lw-ra"; + if (op == 0 && ((word >> 11) & 31) == 31) + { + uint funct = word & 63; + if (funct == 37 || funct == 33 || funct == 36 || funct == 32 + || funct == 35 || funct == 34) + return "move-ra"; + } + return "srcw"; + } + + private static bool IsLeftoverWait99O32WrapLoopDest(uint dest) + { + return dest == LeftoverWait99WrapPrologue + || dest == LeftoverWait99WrapSw + || dest == LeftoverWait99WrapDumpPrologue + || dest == LeftoverWait99WrapDumpSw + || dest == LeftoverWait99WrapRa + || dest == LeftoverWait99WrapDumpRa + || dest == LeftoverWait99WrapDump; + } + + // Live 84dd0ca ra-src leftover-wrap-after-copy + // while nk-next next=0x8001E9D4 via=bindimp. + // leftover jal INTO wrap residue after + // CopyO32 dest fill. Wrapper is already + // at BindImp LoadLib. leftover dest + // 0x03F74DEC / GetProc dest 0x8008C844 + // leftover hop forbidden. Not CopyO32 + // fail. Do not hop dest-fp50 as PC. + private static string LeftoverWrapAfterCopyVia() + { + if (!_leftoverWait99O32NkWrapCopyLogged) + return "leftover-wrap"; + if (_leftoverWait99O32NkNextLogged + || _leftoverWait99O32NkBindLogged + || _leftoverWait99O32NkImpLogged) + return "leftover-wrap-during-bind"; + return "leftover-wrap-after-copy"; + } + + private static void TryNoteLeftoverWait99O32RaSrcHalt(MipsBus bus, + uint pc, uint word, uint dest, string via) + { + _leftoverWait99O32RaSrcLogged = true; + _leftoverWait99O32SwLogged = true; + if (_leftoverWait99O32HaltLogged) + { + TryNoteLeftoverWait99O32NkCallDump(bus); + return; + } + _leftoverWait99O32HaltLogged = true; + _leftoverWait99WrapRaContLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-ra-src pc=0x" + + pc.ToString("X8") + + " word=0x" + word.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " via=" + via); + if (_leftoverWait99O32NkWrapCopyLogged) + { + TryNoteLeftoverWait99O32NkE32(bus, null, pc); + TryNoteLeftoverWait99O32NkNext(bus, null, pc); + TryNoteLeftoverWait99O32NkImp(bus, null, pc); + } + TryNoteLeftoverWait99O32NkCallDump(bus); + } + + // Live 183c8f4 leftover-wait99-o32-nk-call + // is dump-true NK LoadO32 ($ra= + // LoadO32RomRet). leftover-wait99-o32- + // nk-ret dest-word=2 skip200=y via=dest- + // set was the byte-out at fp+0xCE, not + // dest-set. dest-sp20 there is LoadO32 + // frame 0x20(sp), not wrapper dest-e32. + // Live fbfeebf leftover-wait99-o32-nk- + // wrap pc=0x800283FC v0=0x80340040 s5=0 + // is shared VALLOC, not wrapper jal + // 0x8001E444. leftover-wait99-o32-nk- + // wrap-after names 0x8001E428 s5 dest- + // e32 dest-fp50. Live 0be2cb9 dest-e32= + // 0x1B0C is SIZE not dest-live hop; + // dest-fp50 0x8006C000 is CopyO32 dest + // fill. leftover-wait99-o32-nk-wrap- + // copy-ret names post-CopyO32 BindImp / + // CallDLL. leftover-wrap-during-bind is + // leftover jal INTO wrap residue after + // CopyO32 while BindImp LoadLib is next. + // leftover dest 0x03F74DEC / leftover dest + // GetProc dest 0x8008C844 leftover hop + // forbidden. + // Do not leftover hop. Do not invent dest. + // Do not hop dest-e32 size. Do not set + // 0x200. Do not set s5. + private static void TryLeftoverWait99O32NkObserve(MipsBus bus, + uint[] regs, uint pc) + { + if ((pc & 3) != 0) + return; + TryFeedCoredllStartipBeforeCallDll(bus, regs, pc); + TryNoteLeftoverWait99O32NkJalr(bus, regs, pc); + TryNoteLeftoverWait99O32NkAfter(bus, regs, pc); + TryNoteLeftoverWait99O32NkChain(bus, regs, pc); + TryNoteLeftoverWait99O32NkCoredllJal(bus, regs, pc); + TryNoteLeftoverWait99O32NkCoredllPc0(bus, regs, pc); + TryNoteLeftoverWait99O32NkCoredllAfter(bus, regs, pc); + TryNoteJalrT9MsecScale(bus, regs, pc); + if (pc == LoadO32WrapJalO32 || pc == LoadO32Rom) + { + if (pc == LoadO32WrapJalO32) + TrySaveLeftoverWait99O32NkWrapFrame(regs); + uint word = 0; + TryPeekLeftoverWait99O32NkWord(bus, pc, out word); + uint dest = LoadO32Rom; + string via = "entry"; + uint target; + if (pc == LoadO32WrapJalO32 && IsJalInsn(word, pc, out target)) + { + dest = target; + via = "jal"; + } + uint ra = pc == LoadO32WrapJalO32 ? pc + 8 : PeekGpr(regs, 31); + if (pc == LoadO32Rom && (ra & 3) == 0 && ra >= 8) + { + uint srcw = 0; + if (TryPeekLeftoverWait99O32NkWord(bus, ra - 8, out srcw) + && IsJalInsn(srcw, ra - 8, out target)) + { + word = srcw; + dest = target; + via = "jal-ra"; + } + } + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || IsLeftoverWait99O32WrapLoopDest(dest) + || IsLeftoverWait99O32WrapLoopDest(ra)) + via = "refuse-ra"; + TryNoteLeftoverWait99O32NkCall(bus, regs, pc, ra, dest, word, via); + return; + } + if (pc == LoadO32SkipValloc) + _leftoverWait99O32NkSkip200 = true; + if (pc == LoadO32OkRet) + { + TryNoteLeftoverWait99O32NkRet(bus, regs, pc); + return; + } + if (pc == LoadO32WrapAfter) + { + TrySaveLeftoverWait99O32NkWrapFrame(regs); + TryNoteLeftoverWait99O32NkWrapAfter(bus, regs, pc); + return; + } + if (pc == LoadO32WrapValloc) + { + TryNoteLeftoverWait99O32NkWrapValloc(bus, regs, pc); + return; + } + if (pc == LoadO32WrapS5Hi) + { + TryNoteLeftoverWait99O32NkWrapS5(bus, regs, pc); + return; + } + if (pc == LoadO32WrapCopy || pc == LoadO32WrapCopyJal) + { + TryNoteLeftoverWait99O32NkWrapCopy(bus, regs, pc); + return; + } + if (pc == LoadO32WrapCopyRet || pc == LoadO32RomRet) + { + if (pc == LoadO32WrapCopyRet) + TryNoteLeftoverWait99O32NkWrapCopyRet(bus, regs, pc); + if (_leftoverWait99O32NkWrapCopyLogged) + TryNoteLeftoverWait99O32NkPostCopy(bus, regs, pc); + return; + } + if (_leftoverWait99O32NkWrapCopyLogged + && pc >= LoadO32RomRet && pc <= LoadO32WrapS5Hi) + TryNoteLeftoverWait99O32NkPostCopy(bus, regs, pc); + if (pc == BindImpHdr || pc == BindImpDllName + || pc == BindImpLoadLib) + TryNoteLeftoverWait99O32NkIat(bus, regs, pc); + if (IsLeftoverWait99O32NkBindPc(pc)) + TryNoteLeftoverWait99O32NkIatStub(bus, regs, pc); + if (pc == CallDllStartip || pc == XipDllCallDllJal + || pc == LoadO32WrapStartip || pc == BindImpLoadLibRet + || pc == BindImpIatSw || pc == BindImpOrdJalRet) + TryNoteLeftoverWait99O32NkEntry(bus, regs, pc); + } + + private static bool TryPeekLeftoverWait99O32NkWord(MipsBus bus, + uint va, out uint word) + { + if (TryPeekWord(bus, va, out word)) + return true; + return TryPeekLeftoverWait99DumpOnly(va, out word); + } + + private static void TryNoteLeftoverWait99O32NkCallDump(MipsBus bus) + { + if (_leftoverWait99O32NkCallLogged) + return; + uint site = LoadO32WrapJalO32; + uint word = 0; + uint dest = 0; + string via = "dump-miss"; + for (uint pc = LoadE32WrapJal; pc < LoadO32RomRet; pc += 4) + { + uint w; + if (!TryPeekLeftoverWait99O32NkWord(bus, pc, out w)) + continue; + uint target; + if (!IsJalInsn(w, pc, out target) || target != LoadO32Rom) + continue; + site = pc; + word = w; + dest = target; + via = "dump-jal"; + break; + } + if (via == "dump-miss" + && TryPeekLeftoverWait99O32NkWord(bus, LoadO32WrapJalO32, out word)) + via = "dump-word"; + uint ra = dest == LoadO32Rom ? site + 8 : 0; + if (IsLeftoverWait99O32WrapLoopDest(dest) + || dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest) + via = "refuse-ra"; + TryNoteLeftoverWait99O32NkCall(bus, null, site, ra, dest, word, via); + } + + private static void TryNoteLeftoverWait99O32NkCall(MipsBus bus, + uint[] regs, uint pc, uint ra, uint dest, uint word, string via) + { + if (_leftoverWait99O32NkCallLogged) + return; + _leftoverWait99O32NkCallLogged = true; + _leftoverWait99O32NkRa = ra; + uint a0 = PeekGpr(regs, 4); + uint a2 = PeekGpr(regs, 6); + uint a3 = PeekGpr(regs, 7); + _leftoverWait99O32NkA0 = a0; + _leftoverWait99O32NkA2 = a2; + _leftoverWait99O32NkA3 = a3; + uint destWord = 0; + if (a2 != 0) + destWord = PeekDestWord(bus, a2); + if (destWord == 0 && _loadE32OkDest0 != 0) + destWord = PeekDestWord(bus, _loadE32OkDest0); + if (destWord == 0 && _nkLoadO32Toc != 0) + destWord = PeekDestWord(bus, _nkLoadO32Toc); + _leftoverWait99O32NkDestWord = destWord; + uint live0 = _nkLoadO32Word0; + if (live0 == 0 && a0 != 0) + { + uint toc = PeekDestWord(bus, a0); + live0 = toc != 0 ? PeekDestWord(bus, toc) : 0; + } + _leftoverWait99O32NkLive0 = live0; + _leftoverWait99O32NkBit200 = (live0 & LoadO32VallocBit) != 0; + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || dest == LeftoverWait99WrapPrologue + || IsLeftoverWait99O32WrapLoopDest(dest) + || IsLeftoverWait99O32WrapLoopDest(ra)) + via = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-call pc=0x" + + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " word=0x" + word.ToString("X8") + + " via=" + via); + } + + private static void TryNoteLeftoverWait99O32NkRet(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkRetLogged) + return; + _leftoverWait99O32NkRetLogged = true; + uint v0 = PeekGpr(regs, 2); + uint ra = PeekGpr(regs, 31); + if (ra == 0) + ra = _leftoverWait99O32NkRa; + uint destCe = _leftoverWait99O32NkA2; + if (destCe == 0) + destCe = PeekGpr(regs, 21); + uint destA3 = _leftoverWait99O32NkA3; + if (destA3 == 0) + destA3 = PeekGpr(regs, 20); + uint destWord = destCe != 0 + ? PeekDestWord(bus, destCe) : _leftoverWait99O32NkDestWord; + uint destByte = PeekDestByte(bus, destCe); + uint destSp20 = PeekSpWord(bus, regs, 0x20); + uint destAddr = destA3 != 0 ? PeekDestWord(bus, destA3) : 0; + uint live0 = _leftoverWait99O32NkLive0; + if (live0 == 0) + live0 = _nkLoadO32Word0; + bool bit200 = _leftoverWait99O32NkBit200 + || (live0 & LoadO32VallocBit) != 0 + || _loadE32OkBit200; + bool skip200 = _leftoverWait99O32NkSkip200 || _loadE32OkSkip200 + || !bit200; + string why; + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || destAddr == LeftoverWait99O32RefuseRa + || destAddr == LeftoverWait99GetProcDest) + why = "refuse-ra"; + else if (destAddr != 0) + why = "dest-set"; + else if (skip200 && (destWord == LoadO32DestCeInit + || destByte == LoadO32DestCeInit)) + why = "skip200-ce2"; + else if (skip200) + why = "skip200"; + else + why = "dest-word-0"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-ret pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X") + + " dest-word=0x" + destWord.ToString("X") + + " dest-a3=0x" + destA3.ToString("X") + + " dest-ce=0x" + destByte.ToString("X") + + " dest-sp20=0x" + destSp20.ToString("X") + + " ra=0x" + ra.ToString("X8") + + " skip200=" + (skip200 ? "y" : "n") + + " bit200=" + (bit200 ? "y" : "n") + + " via=" + why); + } + + // Live 183c8f4 LoadO32 skip200 dest-a3=0 dest-word=2 + // is dump wrapper sb 2 at fp+0xCE. dest-sp20 on + // that ret is LoadO32 frame, not wrapper dest- + // e32. Dump-true dest-e32 is wrapper 0x20(sp) + // after LoadE32 (a3=&sp+0x20). If dest-e32 is + // 0, ori s5,3 so bit2 takes VALLOC jal + // 0x8001E444 $ra=0x8001E44C; dest is sw v0, + // 80(fp) then 0x8001E6E0 CopyO32. o32walk + // 0x8001E45C is bit2-clear. Live 0be2cb9 + // dest-e32=0x1B0C is SIZE not dest-live + // hop; dest-fp50 0x8006C000 is CopyO32 + // dest fill. leftover-wait99-o32-nk-wrap- + // copy-ret names post-CopyO32 BindImp / + // CallDLL. leftover-wrap-after-copy is + // leftover jal INTO wrap residue. Observe + // only. leftover dest 0x03F74DEC / + // leftover dest GetProc dest 0x8008C844 + // leftover hop forbidden. Do not leftover + // hop. Do not invent dest. Do not hop + // dest-e32 size. Do not set 0x200. Do + // not set s5. + private static void TrySaveLeftoverWait99O32NkWrapFrame(uint[] regs) + { + uint sp = PeekGpr(regs, 29); + uint fp = PeekGpr(regs, 30); + if (sp != 0) + _leftoverWait99O32NkWrapSp = sp; + if (fp != 0) + _leftoverWait99O32NkWrapFp = fp; + } + + private static uint PeekWrapDestE32(MipsBus bus, uint[] regs) + { + uint sp = _leftoverWait99O32NkWrapSp; + if (sp == 0) + sp = PeekGpr(regs, 29); + if (sp == 0) + return 0; + return PeekDestWord(bus, sp + 0x20); + } + + private static uint PeekWrapDestFp50(MipsBus bus, uint[] regs) + { + uint fp = _leftoverWait99O32NkWrapFp; + if (fp == 0) + fp = PeekGpr(regs, 30); + if (fp == 0) + return 0; + return PeekDestWord(bus, fp + LoadO32WrapDestFpOff); + } + + private static uint PeekWrapFlags(MipsBus bus, uint[] regs) + { + uint fp = _leftoverWait99O32NkWrapFp; + if (fp == 0) + fp = PeekGpr(regs, 30); + if (fp != 0) + { + uint w = PeekDestWord(bus, fp + LoadO32WrapFlagsFpOff); + if (w != 0) + return w & 0xFFFF; + } + uint sp = _leftoverWait99O32NkWrapSp; + if (sp == 0) + sp = PeekGpr(regs, 29); + if (sp == 0) + return 0; + return PeekDestWord(bus, sp + LoadO32WrapFlagsSpOff) & 0xFFFF; + } + + private static void TryNoteLeftoverWait99O32NkWrapAfter(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkWrapAfterLogged) + return; + _leftoverWait99O32NkWrapAfterLogged = true; + _leftoverWait99O32NkWrapLogged = true; + uint s5 = PeekS5(regs); + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = PeekWrapDestFp50(bus, regs); + uint flags = PeekWrapFlags(bus, regs); + bool bit2 = (s5 & WrapS5Bit2) != 0; + bool bit8000 = (s5 & WrapS5CallDll) != 0; + string why; + if (IsWrapDestSize(destE32)) + why = "size-e32"; + else if (IsDumpTrueWrapDestFill(destE32)) + why = "dest-e32"; + else if (bit2 || (s5 & WrapS5Ori3) == WrapS5Ori3) + why = "ori3"; + else + why = "s5-0"; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest) + why = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-wrap-after pc=0x" + + pc.ToString("X8") + + " s5=0x" + s5.ToString("X") + + " bit2=" + (bit2 ? "y" : "n") + + " bit8000=" + (bit8000 ? "y" : "n") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " flags=0x" + flags.ToString("X") + + " via=" + why); + if (IsDumpTrueWrapDestFill(destFp50) && !IsWrapDestFp50Va(destFp50) + && !IsWrapDestSize(destFp50)) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, destFp50, + "dest-fp50"); + } + + private static void TryNoteLeftoverWait99O32NkWrapValloc(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkWrapVallocLogged) + return; + _leftoverWait99O32NkWrapVallocLogged = true; + uint v0 = PeekGpr(regs, 2); + uint ra = PeekGpr(regs, 31); + uint s5 = PeekS5(regs); + uint destFp50 = PeekWrapDestFp50(bus, regs); + bool wrapJal = ra == LoadO32WrapVallocRa; + string why = wrapJal ? "wrap-jal" : "shared-valloc"; + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest) + why = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-wrap-valloc pc=0x" + + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " v0=0x" + v0.ToString("X") + + " s5=0x" + s5.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " via=" + why); + } + + private static void TryNoteLeftoverWait99O32NkWrapS5(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkWrapS5Logged) + return; + _leftoverWait99O32NkWrapS5Logged = true; + uint s5 = PeekS5(regs); + bool bit8000 = (s5 & WrapS5CallDll) != 0; + string why = bit8000 ? "o32walk" : "skip-o32walk"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-wrap-s5 pc=0x" + + pc.ToString("X8") + + " s5=0x" + s5.ToString("X") + + " bit8000=" + (bit8000 ? "y" : "n") + + " dest-e32=0x" + PeekWrapDestE32(bus, regs).ToString("X") + + " dest-fp50=0x" + PeekWrapDestFp50(bus, regs).ToString("X") + + " via=" + why); + } + + private static void TryNoteLeftoverWait99O32NkWrapCopy(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkWrapCopyLogged) + return; + _leftoverWait99O32NkWrapCopyLogged = true; + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = PeekWrapDestFp50(bus, regs); + uint a3 = PeekGpr(regs, 7); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-wrap-copy pc=0x" + + pc.ToString("X8") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " a3=0x" + a3.ToString("X") + + " via=copyo32"); + if (IsDumpTrueWrapDestFill(destFp50)) + _leftoverWait99O32NkWrapDestFp50 = destFp50; + } + + // Live 0be2cb9 leftover-wait99-o32-nk-wrap- + // copy dest-fp50=0x8006C000 then leftover- + // wait99-o32-ra-src via leftover-wrap. + // dest-e32=0x1B0C is SIZE. dest-fp50 is + // CopyO32 dest fill. leftover-wait99-o32- + // nk-wrap-copy-ret names the next dump- + // true jal after CopyO32 (BindImp / + // CallDLL / copy-fail). leftover-wrap- + // after-copy is leftover jal INTO wrap + // residue, not dump-true next. leftover + // dest 0x03F74DEC / leftover dest GetProc + // dest 0x8008C844 leftover hop forbidden. + // Do not hop dest-e32 size. Do not hop + // dest-fp50 as PC. + private static void TryNoteLeftoverWait99O32NkWrapCopyRet(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkWrapCopyRetLogged) + return; + _leftoverWait99O32NkWrapCopyRetLogged = true; + uint v0 = PeekGpr(regs, 2); + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = PeekWrapDestFp50(bus, regs); + uint sect = PeekGpr(regs, 16); + uint destFill = destFp50 != 0 ? PeekDestWord(bus, destFp50) : 0; + uint next = 0; + string why = PeekWrapCopyRetNext(bus, pc, out next); + if (next == LoadO32WrapCopy || next == LoadO32WrapCopyJal + || next == CopyO32Rom || next == LoadO32WrapO32Walk) + why = "sect-next"; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest) + why = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-wrap-copy-ret pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " fill=0x" + destFill.ToString("X") + + " sect=0x" + sect.ToString("X") + + " next=0x" + next.ToString("X") + + " via=" + why); + if (IsLeftoverWait99O32Caller(next) + && next != LeftoverWait99O32RefuseRa + && next != LeftoverWait99GetProcDest + && !IsWrapDestSize(next) + && !IsLeftoverWait99O32WrapLoopDest(next)) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, next, + "copy-ret"); + TryNoteLeftoverWait99O32NkE32(bus, regs, pc); + TryNoteLeftoverWait99O32NkNext(bus, regs, pc); + TryNoteLeftoverWait99O32NkImp(bus, regs, pc); + } + + private static string PeekWrapCopyRetNext(MipsBus bus, uint pc, + out uint next) + { + next = 0; + uint lo = pc != 0 ? pc : LoadO32WrapCopyRet; + uint hi = lo + 0x40; + for (uint va = lo; va < hi; va += 4) + { + uint word; + if (!TryPeekLeftoverWait99O32NkWord(bus, va, out word)) + continue; + uint target; + if (!IsJalInsn(word, va, out target)) + continue; + if (IsWrapCopyLoopJal(target) || IsWrapDestSize(target) + || target == LeftoverWait99O32RefuseRa + || target == LeftoverWait99GetProcDest + || target == WrapDestFp50FillLive + || IsLeftoverWait99O32WrapLoopDest(target)) + continue; + next = target; + return WrapCopyRetViaOf(target); + } + return PeekWrapTailJal(bus, out next); + } + + // Live 0be2cb9 leftover-wait99-o32-nk-wrap- + // copy dest-fp50=0x8006C000 then leftover- + // wrap. +0x40 from wrap-copy-ret 0x8001E758 + // misses startip 0x8001E960 and BindImp + // LoadLib 0x8001E9D4. Scan that wrap tail + // for dump-true jal. Skip CopyO32 loop / + // dest-e32 size / dest-fp50 / leftover dest. + private static string PeekWrapTailJal(MipsBus bus, out uint next) + { + next = 0; + string via = "copy-ret"; + uint pick = 0; + int rank = 0; + for (uint va = LoadO32WrapCopyRet; va < WrapCopyRetScanHi; va += 4) + { + uint word; + if (!TryPeekLeftoverWait99O32NkWord(bus, va, out word)) + continue; + uint target; + if (!IsJalInsn(word, va, out target)) + continue; + if (IsWrapCopyLoopJal(target) + || target == LoadO32WrapValloc + || IsWrapDestSize(target) + || target == WrapDestE32SizeLive + || target == WrapDestFp50FillLive + || target == LeftoverWait99O32RefuseRa + || target == LeftoverWait99GetProcDest + || IsLeftoverWait99O32WrapLoopDest(target) + || IsLeftoverDestVa(target)) + continue; + string why = WrapCopyRetViaOf(target); + int n = WrapCopyRetRank(why); + if (n > rank) + { + rank = n; + pick = target; + via = why; + } + } + next = pick; + return via; + } + + private static bool IsWrapCopyLoopJal(uint dest) + { + return dest == LoadO32WrapCopy || dest == LoadO32WrapCopyJal + || dest == CopyO32Rom || dest == LoadO32WrapO32Walk; + } + + private static int WrapCopyRetRank(string via) + { + if (via == "bindimp") + return 4; + if (via == "calldll") + return 3; + if (via == "startip") + return 2; + if (via == "dest-live") + return 1; + return 0; + } + + private static string WrapCopyRetViaOf(uint dest) + { + if (dest == BindImpHdr || dest == BindImpLoadLib + || dest == BindImpLoadLibRet || dest == BindImpOrdJalRet + || dest == BindImpWalk || dest == BindImpDllName) + return "bindimp"; + if (dest == CallDllEntry || dest == CallDllStartip + || dest == XipDllCallDllJal || dest == CallDllAfterJalr + || dest == XipExeCallDllJal) + return "calldll"; + if (dest == LoadO32WrapStartip) + return "startip"; + if (dest == LoadE32WrapFail) + return "copy-fail"; + if (IsWrapDestSize(dest)) + return "size-e32"; + if (IsLeftoverWait99O32WrapLoopDest(dest) + || dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest) + return "leftover-wrap"; + if (IsLeftoverWait99O32Caller(dest)) + return "dest-live"; + return "copy-ret"; + } + + private static bool IsWrapDestSize(uint dest) + { + return dest != 0 && dest < WrapDestSizeMax; + } + + private static bool IsDumpTrueWrapDestFill(uint dest) + { + if ((dest & 3) != 0 || dest == 0 || dest == 0xFFFFFFFFu) + return false; + if (IsWrapDestSize(dest) || dest == WrapDestE32SizeLive) + return false; + if (dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || dest == LeftoverWait99GetProc + || IsLeftoverWait99O32WrapLoopDest(dest) + || IsLeftoverDestVa(dest)) + return false; + if (dest >= 0x80000000u && dest < NkImageEnd) + return true; + if (dest >= 0x01000000u && dest < 0x80000000u) + return true; + return false; + } + + // dest-fp50 0x8006C000 is CopyO32 dest fill, + // not a code VA. Do not hop it as PC. + private static bool IsWrapDestFp50Va(uint dest) + { + if (dest == 0 || dest == 0xFFFFFFFFu) + return false; + if (dest == WrapDestFp50FillLive) + return true; + if (_leftoverWait99O32NkWrapDestFp50 != 0 + && dest == _leftoverWait99O32NkWrapDestFp50) + return true; + return false; + } + + private static void TryNoteLeftoverWait99O32ContFromNkWrap(MipsBus bus, + uint pc, uint dest, string via) + { + if (_leftoverWait99O32ContLogged) + return; + if (pc == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || pc == LeftoverWait99GetProcDest + || IsLeftoverBindRefuse(pc) + || IsLeftoverBindRefuse(dest) + || IsWrapDestSize(dest) + || dest == WrapDestE32SizeLive + || IsWrapDestFp50Va(dest) + || dest == WrapDestFp50FillLive + || IsHdDllImageBase(dest) + || dest == HdDllEntryVa || dest == HdDllInitVa + || dest == HdDllEntryRva + || IsLeftoverWait99O32WrapLoopDest(dest) + || dest == LeftoverWait99GetProc) + return; + if (!IsDumpTrueWrapDestFill(dest) + && !IsLeftoverWait99O32Caller(dest) + && dest != 0) + return; + if (!IsLeftoverWait99O32Caller(pc) + && pc != LoadO32WrapAfter && pc != LoadO32WrapCopy + && pc != LoadO32WrapCopyJal && pc != LoadO32WrapCopyRet + && pc != LoadO32RomRet) + return; + _leftoverWait99O32ContLogged = true; + _leftoverWait99WrapRaContLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-cont ra=0x" + + pc.ToString("X8") + + " dest=0x" + dest.ToString("X") + + " via=" + via + + " (dump dest-live wrap-copy dest-fp50 / wrap-copy-ret; refuse dest-e32 size / leftover dest / GetProc dest)"); + } + + private static void TryNoteLeftoverWait99O32NkPostCopy(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkPostCopyLogged) + return; + if (!_leftoverWait99O32NkWrapCopyLogged) + return; + _leftoverWait99O32NkPostCopyLogged = true; + uint ra = PeekGpr(regs, 31); + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = ResolveWrapDestFp50(bus, regs); + uint a3 = PeekGpr(regs, 7); + uint next = 0; + string why = PeekWrapCopyRetNext(bus, pc, out next); + if (next == LoadO32WrapCopy || next == LoadO32WrapCopyJal + || next == CopyO32Rom || next == LoadO32WrapO32Walk) + why = "loop"; + else if (why == "copy-ret" && next == 0) + why = PeekWrapCopyRetNext(bus, LoadO32WrapCopyRet, out next); + if (pc == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || ra == LeftoverWait99GetProcDest) + why = "refuse-ra"; + else if (next != 0 + && (next == destFp50 + || next == WrapDestFp50FillLive + || next == HdDllEntryVa + || next == HdDllInitVa + || next == HdDllEntryRva + || IsHdDllImageBase(next) + || IsLeftoverBindRefuse(next))) + why = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-postcopy pc=0x" + + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " a3=0x" + a3.ToString("X") + + " next=0x" + next.ToString("X") + + " via=" + why); + if (IsLeftoverWait99O32Caller(next) + && next != LeftoverWait99O32RefuseRa + && next != LeftoverWait99GetProcDest + && !IsLeftoverBindRefuse(next) + && !IsWrapDestSize(next) + && !IsLeftoverWait99O32WrapLoopDest(next) + && next != destFp50 + && next != WrapDestFp50FillLive + && next != HdDllEntryVa + && next != HdDllInitVa + && next != HdDllEntryRva + && !IsHdDllImageBase(next)) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, next, + "postcopy"); + TryNoteLeftoverWait99O32NkE32(bus, regs, pc); + TryNoteLeftoverWait99O32NkNext(bus, regs, pc); + TryNoteLeftoverWait99O32NkImp(bus, regs, pc); + } + + // Live 84dd0ca leftover-wait99-o32-nk-e32 + // via=empty w0=0 at dest-fp50+0. Header + // is not at +0. Scan dest-fp50 +0x1000 / + // dest-fp50-0x1000 / e32_lite / dump TOC + // e32 so Boot names hdr-off / fill-off / + // entryrva / Target_VA. leftover-wrap- + // during-bind is leftover jal INTO wrap + // residue after CopyO32 while BindImp + // LoadLib is the dump-true next. Do not + // invent dest from +0x10 COM/stackmax. + // Do not hop dest-e32 size. Do not hop + // dest-fp50 as PC. leftover dest + // 0x03F74DEC / leftover dest GetProc dest + // 0x8008C844 leftover hop forbidden. + private static void TryNoteLeftoverWait99O32NkE32(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkE32Logged) + return; + if (!_leftoverWait99O32NkWrapCopyLogged) + return; + if (pc == LoadO32WrapCopy || pc == LoadO32WrapCopyJal) + return; + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = ResolveWrapDestFp50(bus, regs); + if (!IsDumpTrueWrapDestFill(destFp50)) + return; + uint a3 = PeekGpr(regs, 7); + if (a3 == 0) + a3 = WrapCopySectCount; + uint hdr; + int hdrOff; + uint w0; + uint entryRva; + uint vbase; + uint vsize; + uint imp; + uint fillOff; + string why = PeekWrapE32Hdr(bus, regs, destFp50, destE32, a3, + out hdr, out hdrOff, out w0, out entryRva, out vbase, + out vsize, out imp, out fillOff); + // Live 29bdcf2 hdr-off=0x1010 w0=0x52 + // is dest-fp50+.text+0x10, not e32_rom. + // dest-e32 0x1B0C is SIZE. Keep that + // entryrva only when objcnt is e32- + // proven (1..16). + bool proven = IsWrapE32ProvenWhy(why); + if (!proven && (entryRva == destE32 + || entryRva == WrapDestE32SizeLive + || IsHdDllEntryRva(entryRva) || (w0 & 0xFFFF) > 16)) + entryRva = 0; + _leftoverWait99O32NkE32Logged = true; + _leftoverWait99O32NkHdr = hdr; + _leftoverWait99O32NkHdrOff = (uint)hdrOff; + uint objcnt = w0 & 0xFFFF; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest) + why = "refuse-ra"; + string stub = IatStubNameOf(imp); + if (stub.Length != 0) + why = stub; + uint targetVa = WrapEntryTargetVa(destFp50, destE32, hdr, + entryRva, vbase, proven); + uint e32Rva = PeekWrapE32Rva(bus, hdr); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-e32 pc=0x" + + pc.ToString("X8") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " hdr-off=" + FormatWrapHdrOff(hdrOff) + + " fill-off=0x" + fillOff.ToString("X") + + " w0=0x" + w0.ToString("X") + + " objcnt=0x" + objcnt.ToString("X") + + " e32_entryrva=0x" + entryRva.ToString("X") + + " e32_vbase=0x" + vbase.ToString("X") + + " e32_vsize=0x" + vsize.ToString("X") + + " e32_rva=0x" + e32Rva.ToString("X") + + " entryrva=0x" + entryRva.ToString("X") + + " vbase=0x" + vbase.ToString("X") + + " vsize=0x" + vsize.ToString("X") + + " imp=0x" + imp.ToString("X") + + " target=0x" + targetVa.ToString("X") + + " via=" + why); + if (why == "e32-rom" + && targetVa != 0 + && !IsWrapDestFp50Va(targetVa) + && !IsWrapDestSize(targetVa) + && !IsHdDllImageBase(targetVa) + && targetVa != HdDllEntryVa && targetVa != HdDllInitVa + && !IsLeftoverBindRefuse(targetVa) + && IsDumpTrueWrapDestFill(targetVa) + && targetVa != LeftoverWait99O32RefuseRa + && targetVa != LeftoverWait99GetProcDest) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, targetVa, + "e32-entry"); + TryNoteLeftoverWait99O32NkNext(bus, regs, pc); + } + + // Live 0be2cb9 leftover-wait99-o32-nk-wrap- + // copy dest-fp50=0x8006C000 then leftover- + // wrap-after-copy. dest-e32=0x1B0C is SIZE. + // leftover-wait99-o32-nk-next names the + // dump-true wrap-tail jal after CopyO32 + // (BindImp / CallDLL / startip). Do not + // hop dest-e32 size. Do not hop dest-fp50 + // as PC. leftover dest 0x03F74DEC / + // leftover dest GetProc dest 0x8008C844 + // leftover hop forbidden. + private static void TryNoteLeftoverWait99O32NkNext(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkNextLogged) + return; + if (!_leftoverWait99O32NkWrapCopyLogged) + return; + if (pc == LoadO32WrapCopy || pc == LoadO32WrapCopyJal) + return; + _leftoverWait99O32NkNextLogged = true; + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = ResolveWrapDestFp50(bus, regs); + uint next = 0; + string why = PeekWrapTailJal(bus, out next); + if (next != 0 + && (next == LeftoverWait99O32RefuseRa + || next == LeftoverWait99GetProcDest + || next == WrapDestE32SizeLive + || next == destE32 + || next == destFp50 + || next == WrapDestFp50FillLive + || next == HdDllEntryVa + || next == HdDllInitVa + || next == HdDllEntryRva + || IsHdDllImageBase(next) + || IsLeftoverBindRefuse(next) + || IsWrapDestSize(next) + || IsLeftoverWait99O32WrapLoopDest(next) + || IsLeftoverDestVa(next))) + { + next = 0; + why = "refuse-ra"; + } + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest) + why = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-next pc=0x" + + pc.ToString("X8") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " next=0x" + next.ToString("X") + + " via=" + why); + if (next != 0 + && IsLeftoverWait99O32Caller(next) + && next != LeftoverWait99O32RefuseRa + && next != LeftoverWait99GetProcDest + && !IsLeftoverBindRefuse(next) + && !IsWrapDestSize(next) + && !IsLeftoverWait99O32WrapLoopDest(next) + && next != destFp50 + && next != WrapDestFp50FillLive + && next != HdDllEntryVa + && next != HdDllInitVa + && next != HdDllEntryRva + && !IsHdDllImageBase(next)) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, next, + "next"); + TryNoteLeftoverWait99O32NkImp(bus, regs, pc); + } + + // Live 84dd0ca leftover-wait99-o32-nk-imp + // via=miss at dest-fp50+0. Live 26cbe16 + // nk-iat name=hd.dll via=bindlib; nk-imp + // still via=miss. Header is not at +0. + // Peek IMP from scanned hdr-off / + // e32_lite / dump TOC e32, first DLL name + // at dest-fp50+NameRVA or BindImp LoadLib + // a0 UTF-16, first IAT thunk. leftover- + // wait99-o32-nk-iat-stub peeks hd.dll + // IAT stubs dump-true after LoadLib. + // Do not invent the DLL. Do not hop + // dest-e32 size. Do not hop dest-fp50 + // as PC. leftover dest 0x03F74DEC / + // leftover dest GetProc dest 0x8008C844 + // leftover hop forbidden. + private static void TryNoteLeftoverWait99O32NkImp(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkImpLogged) + return; + if (!_leftoverWait99O32NkWrapCopyLogged) + return; + if (pc == LoadO32WrapCopy || pc == LoadO32WrapCopyJal) + return; + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = ResolveWrapDestFp50(bus, regs); + if (!IsDumpTrueWrapDestFill(destFp50)) + return; + _leftoverWait99O32NkImpLogged = true; + uint a3 = PeekGpr(regs, 7); + if (a3 == 0) + a3 = WrapCopySectCount; + uint hdr; + int hdrOff; + uint w0; + uint entryRva; + uint vbase; + uint vsize; + uint impRva; + uint fillOff; + PeekWrapE32Hdr(bus, regs, destFp50, destE32, a3, + out hdr, out hdrOff, out w0, out entryRva, out vbase, + out vsize, out impRva, out fillOff); + uint nameRva = 0; + uint iatRva = 0; + uint iat = 0; + string name = "-"; + string why = "miss"; + uint image = destFp50; + if (IsDumpTrueWrapDestFill(hdr) && hdr != destFp50) + image = hdr; + if (IsWrapImpRva(impRva, destE32)) + { + uint desc = image + impRva; + nameRva = PeekDestWord(bus, desc + E32ImpNameOff); + iatRva = PeekDestWord(bus, desc + E32ImpIatOff); + if (IsWrapImpRva(nameRva, destE32)) + { + string peek = PeekWrapBindName(bus, image + nameRva); + if (peek.Length != 0) + name = peek; + } + if (IsWrapImpRva(iatRva, destE32)) + iat = PeekDestWord(bus, image + iatRva); + why = "imp"; + } + if (name.Length <= 1) + { + string bind = PeekWrapBindLibName(bus, regs, pc); + if (bind.Length != 0) + { + name = bind; + why = "bindlib"; + } + } + if (name.Length <= 1) + { + string scan = PeekWrapDllNameScan(bus, destFp50, destE32); + if (scan.Length != 0) + { + name = scan; + why = "scan"; + } + } + string stub = IatStubNameOf(iat); + if (stub.Length != 0) + why = stub; + else if (name.Length > 1 && why != "bindlib" && why != "scan") + why = "name"; + else if (why == "imp" && iat == 0 && nameRva == 0) + why = "empty"; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest) + why = "refuse-ra"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-imp pc=0x" + + pc.ToString("X8") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " hdr-off=" + FormatWrapHdrOff(hdrOff) + + " imp=0x" + impRva.ToString("X") + + " name=" + name + + " iat=0x" + iat.ToString("X") + + " stub=" + (stub.Length != 0 ? stub : "-") + + " via=" + why); + if (stub.Length == 0 + && why != "refuse-ra" && why != "miss" && why != "empty" + && IsLeftoverWait99O32Caller(BindImpHdr)) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, BindImpHdr, + BindImpHdr, "imp"); + } + + private static uint PeekWrapImpRva(MipsBus bus, uint destFp50, + uint destE32) + { + uint rom = PeekDestWord(bus, destFp50 + E32RomImpRvaOff); + if (IsWrapImpRva(rom, destE32)) + return rom; + uint lite = PeekDestWord(bus, destFp50 + E32LiteImpRvaOff); + if (IsWrapImpRva(lite, destE32)) + return lite; + return 0; + } + + private static bool IsWrapImpRva(uint rva, uint destE32) + { + if ((rva & 3) != 0 || rva == 0 || rva == 0xFFFFFFFFu) + return false; + if (rva == destE32 || rva == WrapDestE32SizeLive) + return false; + if (IsLeftoverDestVa(rva) || rva == LeftoverWait99O32RefuseRa + || rva == LeftoverWait99GetProcDest + || IsLeftoverWait99O32WrapLoopDest(rva)) + return false; + if (destE32 != 0 && destE32 < WrapDestSizeMax) + return rva < destE32; + return rva < WrapDestSizeMax; + } + + private static string PeekWrapImpName(MipsBus bus, uint va) + { + if (bus == null || va == 0 || IsLeftoverDestVa(va) + || va == LeftoverWait99O32RefuseRa + || va == LeftoverWait99GetProcDest + || IsWrapDestSize(va)) + return ""; + System.Text.StringBuilder sb = new System.Text.StringBuilder(); + for (int i = 0; i < E32ImpNameMax; i++) + { + uint b = PeekDestByte(bus, va + (uint)i); + if (b == 0) + break; + if (b < 0x2D || b > 0x7A) + return ""; + char c = (char)b; + if ((c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') + || (c >= '0' && c <= '9') || c == '.' || c == '_' + || c == '-') + sb.Append(c); + else + return ""; + } + return sb.ToString(); + } + + private static void TryNoteLeftoverWait99O32NkIat(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkBindLogged) + return; + _leftoverWait99O32NkBindLogged = true; + uint ra = PeekGpr(regs, 31); + uint a0 = PeekGpr(regs, 4); + uint destFp50 = ResolveWrapDestFp50(bus, regs); + uint destE32 = PeekWrapDestE32(bus, regs); + uint a3 = PeekGpr(regs, 7); + if (a3 == 0) + a3 = WrapCopySectCount; + uint hdr; + int hdrOff; + uint w0; + uint entryRva; + uint vbase; + uint vsize; + uint impRva; + uint fillOff; + string hdrWhy = PeekWrapE32Hdr(bus, regs, destFp50, destE32, a3, + out hdr, out hdrOff, out w0, out entryRva, out vbase, + out vsize, out impRva, out fillOff); + uint iat = 0; + uint image = destFp50; + if (IsDumpTrueWrapDestFill(hdr) && hdr != destFp50) + image = hdr; + if (IsWrapImpRva(impRva, destE32)) + { + uint iatRva = PeekDestWord(bus, image + impRva + E32ImpIatOff); + if (IsWrapImpRva(iatRva, destE32)) + iat = PeekDestWord(bus, image + iatRva); + } + string name = PeekWrapBindLibName(bus, regs, pc); + if (name.Length == 0 && a0 != 0 && a0 != LeftoverWait99O32RefuseRa + && a0 != LeftoverWait99GetProcDest && !IsWrapDestSize(a0)) + name = PeekWrapBindName(bus, a0); + // Live 84dd0ca iat=0x640068 at BindImp LoadLib + // is *a0 UTF-16 first word, not an IAT thunk. + if (pc == BindImpLoadLib) + iat = 0; + if (name.Length > 1) + _leftoverWait99O32NkBindName = name; + string stub = IatStubNameOf(iat); + string why; + if (stub.Length != 0) + why = stub; + else if (name.Length > 1) + why = "bindlib"; + else + why = "bindimp"; + if (name.Length == 0) + name = "-"; + uint targetVa = WrapEntryTargetVa(destFp50, destE32, hdr, + entryRva, vbase, IsWrapE32ProvenWhy(hdrWhy)); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-iat pc=0x" + + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dest-e32=0x" + destE32.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " hdr-off=" + FormatWrapHdrOff(hdrOff) + + " name=" + name + + " iat=0x" + iat.ToString("X") + + " stub=" + (stub.Length != 0 ? stub : "-") + + " target=0x" + targetVa.ToString("X") + + " via=" + why); + if (IsLeftoverWait99O32Caller(pc) + && pc != LeftoverWait99O32RefuseRa + && pc != LeftoverWait99GetProcDest + && !IsLeftoverBindRefuse(pc) + && !IsWrapDestSize(pc) + && !IsWrapDestFp50Va(pc) + && stub.Length == 0) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, pc, "bindimp"); + } + + private static string IatStubNameOf(uint thunk) + { + if (thunk == 0 || thunk == 0xFFFFFFFFu) + return ""; + if (thunk == HdDllGetProcInV0) + return "leftover-in"; + if (thunk == HdDllModExpRvaLive) + return "exprva"; + if (IsMipsLuiWord(thunk) || thunk == NkLuiV1Word) + return "lui-v1"; + if (IsWrapDestSize(thunk) || thunk == WrapDestE32SizeLive + || thunk == HdDllEntryRva) + return ""; + string hd = HdDllExportName(thunk); + if (hd.Length != 0) + return hd; + if (IsLeftoverWait99O32WrapLoopDest(thunk) + || thunk == LeftoverWait99O32RefuseRa + || thunk == LeftoverWait99O32RefusePrologue + || thunk == LeftoverWait99O32RefuseJalr) + return "leftover-wrap"; + if (IsLeftoverBindRefuse(thunk) + || thunk == LeftoverWait99GetProcDest + || thunk == LeftoverWait99GetProc) + return "leftover-getproc"; + uint destOf = LeftoverWait99DestOf(thunk); + if (destOf == LeftoverWait99GetProcDest + || destOf == LeftoverWait99O32RefuseRa + || destOf == LeftoverWait99O32RefuseDump) + return "leftover-getproc"; + if (IsLeftoverDestVa(thunk)) + return "leftover-dest"; + return ""; + } + + // Live fb2d4b3 GetProc 0x8001F7BC v0= + // 0x87000000 is incoming leftover, not + // leftover dest 0x03F74DEC / GetProc + // dest 0x8008C844. 0x8001F7D0 v0= + // 0x7FFA0 is lw MODULE+0x8C ExpRva, + // not dest-e32 size. Dump hd.dll + // exports: ord=1 HdstubDLLEntry + // 0x8006DB0C rva=0x1B0C; ord=2 + // HdstubInit 0x8006D9D0 rva=0x19D0. + // 0x3C038034 is NK lui $v1,0x8034 at + // 0x800370E8, not an IAT thunk. + private static bool IsMipsLuiWord(uint word) + { + return ((word >> 26) & 0x3F) == 0xF; + } + + private static bool IsNkGetProcStoreSlot(uint va) + { + if ((va & 3) != 0) + return false; + return va >= NkGetProcStoreSlot && va < NkGetProcStoreHi; + } + + private static bool IsHdDllImageBase(uint dest) + { + return dest == HdDllImageBase || dest == WrapDestFp50FillLive; + } + + private static bool IsHdDllEntryRva(uint rva) + { + return rva == HdDllEntryRva || rva == WrapDestE32SizeLive; + } + + private static bool IsHdDllBindName(string name) + { + return !string.IsNullOrEmpty(name) + && NamesMatchRom(name, "hd.dll"); + } + + private static string HdDllExportName(uint ordOrVa) + { + if (ordOrVa == 2 || ordOrVa == HdDllInitVa) + return "HdstubInit"; + if (ordOrVa == 1 || ordOrVa == HdDllEntryVa) + return "HdstubDLLEntry"; + return ""; + } + + // Decode GetProc/bind v0 into dump-true + // hd.dll export stubs. leftover-in / + // exprva / lui-v1 are not leftover- + // getproc hops. When bind name is + // hd.dll, write stub=HdstubDLLEntry + // (ord 1 / entry) or HdstubInit (ord 2). + private static string HdDllStubNameOf(uint v0, uint a1, + uint destFp50, string name) + { + if (IsLeftoverBindRefuse(v0) || IsLeftoverBindRefuse(a1) + || IsLeftoverBindRefuse(destFp50)) + return "leftover-getproc"; + string fromV0 = IatStubNameOf(v0); + if (fromV0 == "HdstubDLLEntry" || fromV0 == "HdstubInit") + return fromV0; + string fromA1 = HdDllExportName(a1); + if (fromA1.Length != 0 + && (IsHdDllBindName(name) || IsHdDllImageBase(destFp50))) + return fromA1; + if (IsHdDllBindName(name) || IsHdDllImageBase(destFp50)) + return "HdstubDLLEntry"; + return fromV0; + } + + private static uint HdDllStubVaOf(string stub) + { + if (stub == "HdstubInit") + return HdDllInitVa; + if (stub == "HdstubDLLEntry") + return HdDllEntryVa; + return 0; + } + + // Plant dump-true hd.dll export VA into + // the live BindImp IAT slot (fp+0x1C / + // $v1). Do not plant dest-e32 SIZE + // 0x1B0C / dest-fp50 / leftover dest as + // the slot or as the thunk. + private static void TryPlantHdDllIatStub(MipsBus bus, uint slot, + string stub) + { + uint va = HdDllStubVaOf(stub); + if (bus == null || va == 0 || slot == 0 || (slot & 3) != 0) + return; + if (!IsDumpTrueIatSlot(slot)) + return; + if (slot == WrapDestE32SizeLive || slot == HdDllEntryRva + || IsWrapDestSize(slot) || IsWrapDestFp50Va(slot) + || IsHdDllImageBase(slot) || slot == HdDllEntryVa + || slot == HdDllInitVa || IsLeftoverBindRefuse(slot) + || IsLeftoverDestVa(slot)) + return; + uint cur = PeekDestWord(bus, slot); + if (cur == va || IsLeftoverBindRefuse(cur)) + return; + try + { + bus.Write32(slot, va); + } + catch + { + } + } + + // CallDLL 0x80018B34 jalrs MODULE+0x5C. + // Wrapper 0x8001E960 skips that store when + // 32($sp) entryrva is 0. Live 2b02f4e named + // Target_VA=HdstubDLLEntry only. Write the + // dump export VA into startip so the guest + // jalr can run. Do not leftover-hop dest. + // Do not write dest-e32 SIZE / dest-fp50. + private static uint PeekHdDllModule(MipsBus bus, uint[] regs, + uint destFp50) + { + uint a0 = PeekGpr(regs, 4); + uint[] mods = new uint[] { _leftoverWait99O32NkBindMod, a0 }; + for (int i = 0; i < mods.Length; i++) + { + uint mod = mods[i]; + if (mod == 0 || (mod & 3) != 0 + || IsLeftoverBindRefuse(mod) + || IsWrapDestSize(mod) || IsWrapDestFp50Va(mod) + || IsHdDllImageBase(mod) || IsLeftoverDestVa(mod) + || mod == HdDllEntryVa || mod == HdDllInitVa + || mod == HdDllEntryRva) + continue; + uint p50 = 0; + if (TryPeekWord(bus, mod + ProcModule, out p50) + && (IsHdDllImageBase(p50) || (destFp50 != 0 + && p50 == destFp50))) + return mod; + if (IsHdDllBindName(_leftoverWait99O32NkBindName) + && mod == _leftoverWait99O32NkBindMod) + return mod; + } + return 0; + } + + private static bool IsHdDllStartipKeep(uint cur) + { + if (cur == 0) + return false; + if (IsLeftoverBindRefuse(cur) || IsWrapDestSize(cur) + || cur == WrapDestE32SizeLive || cur == HdDllEntryRva + || IsWrapDestFp50Va(cur) || IsHdDllImageBase(cur) + || IsLeftoverDestVa(cur)) + return false; + return true; + } + + private static uint TryPlantHdDllStartip(MipsBus bus, uint[] regs, + uint targetVa) + { + if (bus == null || targetVa == 0) + return 0; + if (targetVa != HdDllEntryVa && targetVa != HdDllInitVa) + return 0; + if (IsWrapDestSize(targetVa) || targetVa == HdDllEntryRva + || IsWrapDestFp50Va(targetVa) || IsHdDllImageBase(targetVa) + || IsLeftoverBindRefuse(targetVa) || IsLeftoverDestVa(targetVa)) + return 0; + uint destFp50 = ResolveWrapDestFp50(bus, regs); + if (!IsHdDllImageBase(destFp50) + && !IsHdDllBindName(_leftoverWait99O32NkBindName)) + return 0; + uint mod = PeekHdDllModule(bus, regs, destFp50); + if (mod == 0) + return 0; + uint cur = 0; + if (!TryPeekWord(bus, mod + ModuleStartip, out cur)) + return 0; + if (cur == targetVa) + return cur; + if (IsHdDllStartipKeep(cur)) + return cur; + try + { + bus.Write32(mod + ModuleStartip, targetVa); + } + catch + { + return 0; + } + return targetVa; + } + + // Live b52708e FIRST-WIN plant + // startip=0x03F57A00 word=0x27BDFFD8 + // via=startip at wrap 0x8001E960. No + // coredll via=calldll/entry/ret. 0x80061CA0 + // is osaxst0. Feed MODULE+0x5C before + // CallDLL 0x80018B34 like Hdstub. Do not + // plant osaxst0. Do not leftover-hop dest. + // Do not name entryrva=0x1B0C. + private static bool IsCoredllStartipVa(uint va) + { + if (va == 0 || (va & 3) != 0) + return false; + if (va == HdDllEntryVa || va == HdDllInitVa + || va == HdDllEntryRva || va == ChainCallVaLive + || va == WrapDestE32SizeLive || IsWrapDestSize(va) + || IsWrapDestFp50Va(va) || IsHdDllImageBase(va) + || IsLeftoverBindRefuse(va) || IsLeftoverDestVa(va)) + return false; + return va >= CoredllSharedLo && va < CoredllSharedHi; + } + + private static bool IsDumpTrueCoredllStartip(MipsBus bus, uint va) + { + if (!IsCoredllStartipVa(va)) + return false; + if (va == CoredllDllMainVa) + return true; + if (_leftoverWait99O32NkCoredllStartip != 0 + && va == _leftoverWait99O32NkCoredllStartip) + return true; + if (bus == null) + return false; + bool threw; + uint word = PeekDestWordRaw(bus, va, out threw); + if (threw || word == 0) + return false; + if (word == CoredllDllMainWord) + return true; + return (word & 0xFFFF0000u) == 0x27BD0000u; + } + + private static uint AcceptCoredllEntry(uint vbase, uint entryRva) + { + if (entryRva == 0 || IsHdDllEntryRva(entryRva)) + return 0; + if (entryRva >= (CoredllSharedHi - CoredllSharedLo)) + return 0; + uint baseVa = CoredllSharedLo; + if (IsCoredllBasePtr(vbase)) + baseVa = vbase; + uint va = baseVa + entryRva; + if (!IsCoredllStartipVa(va)) + return 0; + return va; + } + + private static uint PeekE32CoredllStartip(MipsBus bus, uint e32) + { + if (bus == null || e32 == 0 || (e32 & 3) != 0) + return 0; + uint entryRva = 0; + uint vbase = 0; + if (!TryPeekWord(bus, e32 + E32RomEntryRvaOff, out entryRva)) + return 0; + TryPeekWord(bus, e32 + E32RomVbaseOff, out vbase); + return AcceptCoredllEntry(vbase, entryRva); + } + + private static uint PeekCoredllDllMainFromE32(MipsBus bus, uint e32, + uint o32) + { + if (bus == null || e32 == 0 || (e32 & 3) != 0 + || o32 == 0 || (o32 & 3) != 0) + return 0; + try + { + uint objcnt = bus.Read32(e32) & 0xFFFF; + uint expRva = bus.Read32(e32 + E32RomExpRva); + uint expSize = bus.Read32(e32 + E32RomExpRva + 4); + if (expRva == 0 || expSize < 0x28 || expSize > 0x20000) + return 0; + if (!TryPackedFromRva(bus, o32, objcnt, expRva, out uint expPacked)) + return 0; + uint nFuncs = bus.Read32(expPacked + 0x14); + uint nNames = bus.Read32(expPacked + 0x18); + uint addrFuncs = bus.Read32(expPacked + 0x1C); + uint addrNames = bus.Read32(expPacked + 0x20); + uint addrOrds = bus.Read32(expPacked + 0x24); + if (nNames == 0 || nNames > 2048 || nFuncs == 0 + || nFuncs > 2048) + return 0; + if (!TryPackedFromRva(bus, o32, objcnt, addrNames, + out uint namesPacked) + || !TryPackedFromRva(bus, o32, objcnt, addrFuncs, + out uint funcsPacked) + || !TryPackedFromRva(bus, o32, objcnt, addrOrds, + out uint ordsPacked)) + return 0; + uint vbase = 0; + TryPeekWord(bus, e32 + E32RomVbaseOff, out vbase); + for (uint n = 0; n < nNames; n++) + { + uint nameRva = bus.Read32(namesPacked + n * 4); + if (!TryPackedFromRva(bus, o32, objcnt, nameRva, + out uint namePacked)) + continue; + if (!NamesEqual(ReadAscii(bus, namePacked), "DllMain")) + continue; + uint ordWord = bus.Read32((ordsPacked + n * 2) & ~3u); + uint ord = ((ordsPacked + n * 2) & 2) == 0 + ? (ordWord & 0xFFFF) : (ordWord >> 16); + if (ord >= nFuncs) + return 0; + uint funcRva = bus.Read32(funcsPacked + ord * 4); + return AcceptCoredllEntry(vbase, funcRva); + } + } + catch + { + } + return 0; + } + + private static uint PeekCoredllPeDllMain(MipsBus bus) + { + if (bus == null) + return 0; + uint baseVa = CoredllSharedLo; + uint mz = 0; + if (!TryPeekWord(bus, baseVa, out mz) + || (mz & 0xFFFF) != E32MzMagic) + return 0; + uint lfanew = 0; + if (!TryPeekWord(bus, baseVa + 0x3C, out lfanew) + || lfanew < 0x40 || lfanew > 0x400) + return 0; + uint pe = baseVa + lfanew; + uint sig = 0; + if (!TryPeekWord(bus, pe, out sig) || sig != 0x00004550) + return 0; + uint magic = 0; + if (!TryPeekWord(bus, pe + 0x18, out magic) + || (magic & 0xFFFF) != 0x10B) + return 0; + uint expRva = 0; + if (!TryPeekWord(bus, pe + 0x78, out expRva) || expRva == 0 + || expRva >= (CoredllSharedHi - CoredllSharedLo)) + return 0; + uint exp = baseVa + expRva; + uint nFuncs = 0; + uint nNames = 0; + if (!TryPeekWord(bus, exp + 0x14, out nFuncs) + || !TryPeekWord(bus, exp + 0x18, out nNames)) + return 0; + if (nNames == 0 || nNames > 2048 || nFuncs == 0 + || nFuncs > 2048) + return 0; + uint addrFuncs = 0; + uint addrNames = 0; + uint addrOrds = 0; + if (!TryPeekWord(bus, exp + 0x1C, out addrFuncs) + || !TryPeekWord(bus, exp + 0x20, out addrNames) + || !TryPeekWord(bus, exp + 0x24, out addrOrds) + || addrFuncs == 0 || addrNames == 0 || addrOrds == 0) + return 0; + uint namesVa = baseVa + addrNames; + uint funcsVa = baseVa + addrFuncs; + uint ordsVa = baseVa + addrOrds; + for (uint n = 0; n < nNames; n++) + { + uint nameRva = 0; + if (!TryPeekWord(bus, namesVa + n * 4, out nameRva) + || nameRva == 0) + continue; + string nm = ""; + try + { + nm = ReadAscii(bus, baseVa + nameRva); + } + catch + { + continue; + } + if (!NamesEqual(nm, "DllMain")) + continue; + uint ordWord = 0; + uint ordAddr = ordsVa + n * 2; + if (!TryPeekWord(bus, ordAddr & ~3u, out ordWord)) + return 0; + uint ord = (ordAddr & 2) == 0 + ? (ordWord & 0xFFFF) : (ordWord >> 16); + if (ord >= nFuncs) + return 0; + uint funcRva = 0; + if (!TryPeekWord(bus, funcsVa + ord * 4, out funcRva)) + return 0; + return AcceptCoredllEntry(baseVa, funcRva); + } + return 0; + } + + private static uint PeekModuleCoredllStartip(MipsBus bus, uint module) + { + if (bus == null || module == 0 || (module & 3) != 0) + return 0; + uint obj = 0; + if (!TryPeekWord(bus, module + ModuleFileObj, out obj) || obj == 0 + || (obj & 3) != 0) + return 0; + try + { + if (bus.Read8(obj + 4) != TocAttachType) + return 0; + uint toc = bus.Read32(obj); + if (toc == 0 || (toc & 3) != 0) + return 0; + uint np = bus.Read32(toc + 0x10); + string name = ReadAscii(bus, np); + if (!NamesMatchRom(name, "coredll.dll")) + return 0; + uint e32 = bus.Read32(toc + 0x14); + uint o32 = bus.Read32(toc + 0x18); + uint va = PeekE32CoredllStartip(bus, e32); + if (va != 0) + return va; + return PeekCoredllDllMainFromE32(bus, e32, o32); + } + catch + { + } + return 0; + } + + private static uint PeekTocCoredllStartip(MipsBus bus, uint tocOrZero) + { + if (bus == null) + return 0; + try + { + uint toc = tocOrZero; + if (toc == 0) + toc = bus.Read32(EcecTocPtr); + if (toc == 0) + return 0; + uint nmods = bus.Read32(toc + RomHdrNumMods); + if (nmods == 0 || nmods > 128) + return 0; + for (uint i = 0; i < nmods; i++) + { + uint entry = toc + TocFirst + i * TocEntrySize; + uint np = bus.Read32(entry + 0x10); + string name = ReadAscii(bus, np); + if (!NamesMatchRom(name, "coredll.dll")) + continue; + uint e32 = bus.Read32(entry + 0x14); + uint o32 = bus.Read32(entry + 0x18); + if (e32 == 0 || (e32 & 3) != 0) + return 0; + uint va = PeekE32CoredllStartip(bus, e32); + if (va != 0) + return va; + va = PeekCoredllDllMainFromE32(bus, e32, o32); + if (va != 0) + return va; + return 0; + } + } + catch + { + } + return 0; + } + + private static uint PeekDumpCoredllStartip(MipsBus bus) + { + if (_leftoverWait99O32NkCoredllStartip != 0 + && IsCoredllStartipVa(_leftoverWait99O32NkCoredllStartip)) + return _leftoverWait99O32NkCoredllStartip; + uint live = 0; + if (NamesMatchRom(_nkLoadE32Name, "coredll.dll") + && _nkLoadE32E32 != 0) + live = PeekE32CoredllStartip(bus, _nkLoadE32E32); + if (live == 0 && NamesMatchRom(_nkLoadO32Name, "coredll.dll") + && _nkLoadO32Toc != 0) + { + uint e32 = 0; + if (TryPeekWord(bus, _nkLoadO32Toc + 0x14, out e32)) + live = PeekE32CoredllStartip(bus, e32); + } + if (IsCoredllStartipVa(live)) + { + _leftoverWait99O32NkCoredllStartip = live; + return live; + } + ExtraRomTocMod slot = FindCachedExtraRomToc("coredll.dll"); + if (slot != null && slot.E32Words != null + && slot.E32Words.Length > 2) + { + uint va = AcceptCoredllEntry(slot.E32Words[2], + slot.E32Words.Length > 1 ? slot.E32Words[1] : 0); + if (va != 0) + { + _leftoverWait99O32NkCoredllStartip = va; + return va; + } + } + uint toc = PeekTocCoredllStartip(bus, 0); + if (toc == 0) + toc = PeekTocCoredllStartip(bus, ExtraRomToc(bus)); + if (toc == 0) + toc = PeekCoredllPeDllMain(bus); + if (toc == 0 && IsDumpTrueCoredllStartip(bus, CoredllDllMainVa)) + toc = CoredllDllMainVa; + if (toc != 0) + _leftoverWait99O32NkCoredllStartip = toc; + return toc; + } + + private static uint TryPlantCoredllStartip(MipsBus bus, uint module) + { + if (bus == null || module == 0 || (module & 3) != 0 + || IsLeftoverBindRefuse(module) || IsWrapDestSize(module) + || IsWrapDestFp50Va(module) || IsHdDllImageBase(module) + || IsLeftoverDestVa(module) || module == HdDllEntryVa) + return 0; + uint p50 = 0; + if (!TryPeekWord(bus, module + ProcModule, out p50)) + return 0; + if (!IsCoredllBasePtr(p50) && module != _coredllModule) + return 0; + uint want = PeekModuleCoredllStartip(bus, module); + if (!IsCoredllStartipVa(want)) + want = PeekDumpCoredllStartip(bus); + if (!IsCoredllStartipVa(want)) + return 0; + uint cur = 0; + if (!TryPeekWord(bus, module + ModuleStartip, out cur)) + return 0; + if (cur == want) + { + if (_leftoverWait99O32NkCoredllStartip == 0) + _leftoverWait99O32NkCoredllStartip = cur; + return cur; + } + if (cur != 0 && IsCoredllStartipVa(cur)) + { + if (_leftoverWait99O32NkCoredllStartip == 0) + _leftoverWait99O32NkCoredllStartip = cur; + return cur; + } + if (cur != 0 && IsHdDllStartipKeep(cur) + && !IsCoredllStartipVa(cur)) + return 0; + try + { + bus.Write32(module + ModuleStartip, want); + } + catch + { + return 0; + } + if (_leftoverWait99O32NkCoredllStartip == 0) + _leftoverWait99O32NkCoredllStartip = want; + return want; + } + + private static bool IsCoredllCallDllModule(MipsBus bus, uint module) + { + if (bus == null || module == 0 || (module & 3) != 0 + || IsLeftoverBindRefuse(module) || IsWrapDestSize(module) + || IsWrapDestFp50Va(module) || IsHdDllImageBase(module) + || IsLeftoverDestVa(module) || module == HdDllEntryVa) + return false; + if (module == _coredllModule) + return true; + uint p50 = 0; + if (TryPeekWord(bus, module + ProcModule, out p50) + && IsCoredllBasePtr(p50)) + return true; + string name = PeekNkModuleName(bus, module); + return NamesMatchRom(name, "coredll.dll"); + } + + private static uint PeekCoredllCallDllModule(MipsBus bus, uint[] regs) + { + if (bus == null) + return 0; + uint a0 = PeekGpr(regs, 4); + uint fp = PeekGpr(regs, 30); + uint s7 = PeekGpr(regs, 23); + uint[] mods = new uint[] { a0, fp, s7, _coredllModule }; + for (int i = 0; i < mods.Length; i++) + { + if (IsCoredllCallDllModule(bus, mods[i])) + return mods[i]; + } + return 0; + } + + // Live b52708e planted 0x03F57A00 at wrap + // 0x8001E960 via=startip; CallDLL 0x80018B34 + // never jalr'd. Same feed as Hdstub: + // MODULE+0x5C before CallDLL sites. 32($sp) + // is entryrva, not VA — do not write the + // startip VA there. Do not leftover-hop. + private static void TryFeedCoredllStartipBeforeCallDll(MipsBus bus, + uint[] regs, uint pc) + { + if (pc != CallDllEntry && pc != CallDllStartip + && pc != XipDllCallDllJal && pc != XipCallDllUsegChk + && pc != LoadO32WrapStartip) + return; + uint mod = PeekCoredllCallDllModule(bus, regs); + if (mod != 0) + { + if (_coredllModule == 0) + _coredllModule = mod; + TryPlantCoredllStartip(bus, mod); + } + if (_coredllModule != 0 && _coredllModule != mod) + TryPlantCoredllStartip(bus, _coredllModule); + } + + public static void TryFeedCoredllCallDllStartip(MipsBus bus, uint[] regs) + { + TryFeedCoredllStartipBeforeCallDll(bus, regs, CallDllStartip); + } + + // Live b51fa7d wrap 0x8001E960 via=startip + // then hd.dll iat-stub; CallDLL never + // entered. $fp at wrap is the frame, $a0 + // is the MODULE. Plant at LoadO32-ret. + // At wrap, CallDLL 0x80018B34 (a1=1) and + // resume wrap+8. At 0x8001DD6C, firmware + // jal 0x8001DD94 when $fp is coredll. + // Do not leftover-hop dest. + public static bool TryFeedCoredllCallDll(MipsBus bus, uint[] regs, + ref uint programCounter) + { + if (bus == null || regs == null || regs.Length <= 30) + return false; + bool atUseg = programCounter == XipCallDllUsegChk; + bool atWrap = programCounter == LoadO32WrapStartip; + if (!atUseg && !atWrap) + return false; + uint module; + if (atUseg) + { + module = PeekGpr(regs, 30); + if (!IsCoredllCallDllModule(bus, module)) + return false; + } + else + { + module = PeekCoredllCallDllModule(bus, regs); + if (module == 0) + return false; + } + TryPlantCoredllStartip(bus, module); + uint p50 = 0; + uint ip = 0; + if (!TryPeekWord(bus, module + ProcModule, out p50) + || !TryPeekWord(bus, module + ModuleStartip, out ip)) + return false; + if (!IsDumpTrueCoredllStartip(bus, ip)) + return false; + if (!IsCallDllSkipUseg(p50)) + return false; + if (IsLeftoverBindRefuse(ip) || IsWrapDestSize(ip) + || IsWrapDestFp50Va(ip) || IsHdDllImageBase(ip) + || IsLeftoverDestVa(ip) || ip == HdDllEntryVa + || ip == HdDllInitVa || ip == HdDllEntryRva) + return false; + regs[4] = module; + regs[5] = 1; + if (atWrap) + { + regs[31] = programCounter + 8; + programCounter = CallDllEntry; + } + else + programCounter = XipDllCallDllJal; + _leftoverWait99O32NkCoredllSawCall = true; + return true; + } + + // Live 26cbe16 leftover dest 0x03F74DEC / + // GetProc dest 0x8008C844 leftover hop + // forbidden during BindImp of hd.dll. + private static bool IsLeftoverBindRefuse(uint dest) + { + if (dest == 0 || dest == 0xFFFFFFFFu) + return false; + if (dest == LeftoverWait99O32RefuseRa + || dest == LeftoverWait99GetProcDest + || dest == LeftoverWait99GetProc + || dest == LeftoverWait99O32RefusePrologue + || dest == LeftoverWait99O32RefuseJalr + || dest == LeftoverWait99O32RefuseDump + || dest == LeftoverWait99O32RefuseDumpJalr + || dest == LeftoverWait99O32RefuseCoredllJalr) + return true; + uint destOf = LeftoverWait99DestOf(dest); + return destOf == LeftoverWait99GetProcDest + || destOf == LeftoverWait99O32RefuseRa + || destOf == LeftoverWait99O32RefuseDump; + } + + private static bool IsLeftoverWait99O32NkBindPc(uint pc) + { + return pc == BindImpLoadLibRet || pc == BindImpIatSw + || pc == BindImpIatSlotLw || pc == BindImpIatNext + || pc == BindImpIatNextAfter || pc == BindImpOrdJalRet + || pc == BindImpOrdLookup || pc == BindImpOrdBaseLw + || pc == BindImpIatKdata || pc == BindImpIatAfter + || pc == BindImpWalk; + } + + // Live fb2d4b3 leftover-wait99-o32-nk-iat-stub + // name=hd.dll GetProc 0x8001F7BC v0= + // 0x87000000 leftover-in; 0x8001F7D0 + // v0=0x7FFA0 exprva; dest-fp50 leaked + // coredll 0x03F50000; slot=0x800370E8 + // iat=0x3C038034 lui-v1; stub=-. + // Live 7bb467b named stub=HdstubDLLEntry + // but rewrote iat/entry to dest+0x1B0C + // (SIZE) and UNIQUE_SLOTS=0. Decode v0 + // into stub= without rewriting iat. + // Keep BindImp fp+0x1C / $v1 slot march. + // Plant dump-true export VA into the + // live slot. dest-e32 0x1B0C is SIZE; + // do not name entryrva / Target_VA / + // IAT base. Latch dest-fp50 to CopyO32 + // 0x8006C000. leftover dest 0x03F74DEC + // / GetProc dest 0x8008C844 leftover + // hop forbidden. Do not hop dest-e32 + // 0x1B0C or dest-fp50 as PC. FILE[26] + // unchanged. Display ddi_nop.dll. + private static void TryNoteCoredllMissCallDll(uint pc) + { + if (_leftoverWait99O32NkCoredllMissLog) + return; + if (!_leftoverWait99O32NkCoredllSawStartip + || _leftoverWait99O32NkCoredllSawCall) + return; + if (_leftoverWait99O32NkCoredllStartip == 0) + return; + _leftoverWait99O32NkCoredllMissLog = true; + uint startip = _leftoverWait99O32NkCoredllStartip; + _leftoverWait99O32NkChainLast = pc ^ startip; + _leftoverWait99O32NkChainVia = "miss-calldll"; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + startip.ToString("X") + + " word=0x0" + + " via=miss-calldll"); + } + + private static void TryNoteLeftoverWait99O32NkIatStub(MipsBus bus, + uint[] regs, uint pc) + { + TryNoteCoredllMissCallDll(pc); + if (!_leftoverWait99O32NkBindLogged) + return; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || IsLeftoverBindRefuse(pc) + || IsWrapDestFp50Va(pc) + || IsHdDllImageBase(pc) + || pc == HdDllEntryVa || pc == HdDllInitVa + || IsWrapDestSize(pc) + || pc == WrapDestE32SizeLive + || pc == HdDllEntryRva) + return; + if (_leftoverWait99O32NkIatStubLog >= BindImpObserveMax) + return; + if (IsLeftoverWait99O32NkBindPc(pc)) + _leftoverWait99O32NkBindLastPc = pc; + uint v0 = PeekGpr(regs, 2); + uint a1 = PeekGpr(regs, 5); + uint destE32 = PeekWrapDestE32(bus, regs); + uint destFp50 = ResolveWrapDestFp50(bus, regs); + uint slot; + string slotVia; + uint iat = PeekWrapIatStubLive(bus, regs, destFp50, destE32, + out slot, out slotVia); + if (pc == BindImpIatSw && v0 != 0 + && !IsLeftoverBindRefuse(v0) + && !IsWrapDestSize(v0) + && v0 != WrapDestE32SizeLive + && v0 != HdDllEntryRva) + iat = v0; + if (pc == BindImpLoadLibRet) + { + if (v0 != 0 && !IsLeftoverBindRefuse(v0) + && !IsWrapDestSize(v0) && !IsWrapDestFp50Va(v0) + && !IsHdDllImageBase(v0) + && _leftoverWait99O32NkBindMod == 0) + _leftoverWait99O32NkBindMod = v0; + } + string name = _leftoverWait99O32NkBindName; + if (name.Length == 0) + name = PeekWrapBindLibName(bus, regs, pc); + if (name.Length == 0) + name = "-"; + string stub = IatStubNameOf(iat); + if (stub.Length == 0) + stub = IatStubDumpTrueName(iat, destE32); + string hd = HdDllStubNameOf(v0, a1, destFp50, name); + if (hd == "HdstubDLLEntry" || hd == "HdstubInit") + stub = hd; + else if (stub.Length == 0) + stub = hd; + TryPlantHdDllIatStub(bus, slot, stub); + if (stub.Length == 0 && pc == BindImpLoadLibRet && v0 == 0) + stub = "loadlib-0"; + string why; + if (IsLeftoverBindRefuse(iat) || IsLeftoverBindRefuse(v0) + || stub == "leftover-getproc") + why = "leftover-getproc"; + else if (stub == "HdstubDLLEntry" || stub == "HdstubInit") + why = "dump-true"; + else if (v0 == HdDllGetProcInV0) + why = "leftover-in"; + else if (v0 == HdDllModExpRvaLive || pc == BindImpOrdBaseLw) + why = "exprva"; + else if (pc == BindImpLoadLibRet) + why = v0 == 0 ? "loadlib-0" : "loadlib-ret"; + else if (pc == BindImpIatSw) + why = stub.Length != 0 ? stub : "iat-sw"; + else if (pc == BindImpOrdJalRet || pc == BindImpOrdLookup + || pc == BindImpOrdBaseLw) + why = stub.Length != 0 ? stub : "ord"; + else if (slotVia.Length != 0 && slotVia != "miss") + why = slotVia; + else if (stub.Length != 0) + why = stub; + else + why = "bind"; + uint key = iat ^ slot ^ v0 ^ pc; + if (key == _leftoverWait99O32NkIatStubLast && why == _leftoverWait99O32NkIatStubVia) + return; + _leftoverWait99O32NkIatStubLast = key; + _leftoverWait99O32NkIatStubVia = why; + _leftoverWait99O32NkIatStubLog++; + uint hdr; + int hdrOff; + uint entryRva; + uint vbase; + uint targetVa; + PeekWrapEntryNow(bus, regs, destFp50, destE32, + out hdr, out hdrOff, out entryRva, out vbase, out targetVa); + if (entryRva != 0) + _leftoverWait99O32NkEntryRva = entryRva; + if (entryRva == 0 + && (targetVa == HdDllEntryVa || targetVa == HdDllInitVa + || IsHdDllBindName(name) || IsHdDllImageBase(destFp50))) + { + if (targetVa == 0) + targetVa = HdDllEntryVa; + TryPlantHdDllStartip(bus, regs, targetVa); + } + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-iat-stub pc=0x" + + pc.ToString("X8") + + " name=" + name + + " v0=0x" + v0.ToString("X") + + " dest-fp50=0x" + destFp50.ToString("X") + + " slot=0x" + slot.ToString("X") + + " iat=0x" + iat.ToString("X") + + " stub=" + (stub.Length != 0 ? stub : "-") + + " entryrva=0x" + entryRva.ToString("X") + + " Target_VA=0x" + targetVa.ToString("X") + + " via=" + why); + if (entryRva != 0 && targetVa != 0) + TryNoteLeftoverWait99O32NkEntry(bus, regs, pc); + } + + private static uint PeekWrapIatStubLive(MipsBus bus, uint[] regs, + uint destFp50, uint destE32, out uint slot, out string via) + { + slot = 0; + via = "miss"; + uint fp = PeekGpr(regs, 30); + uint fp1c = 0; + if (fp != 0 && TryPeekWord(bus, fp + BindImpFpIatOff, out fp1c) + && IsDumpTrueIatSlot(fp1c)) + { + slot = fp1c; + uint stub = PeekDestWord(bus, fp1c); + if (stub != 0 && !IsLeftoverBindRefuse(stub) + && stub != WrapDestE32SizeLive + && stub != HdDllEntryRva + && !IsWrapDestSize(stub)) + { + via = "fp1c"; + return stub; + } + } + uint v1 = PeekGpr(regs, 3); + if (IsDumpTrueIatSlot(v1)) + { + slot = v1; + uint stub = PeekDestWord(bus, v1); + if (stub != 0 && !IsLeftoverBindRefuse(stub) + && stub != WrapDestE32SizeLive + && stub != HdDllEntryRva + && !IsWrapDestSize(stub)) + { + via = "v1"; + return stub; + } + } + uint scan = PeekWrapIatStubScan(bus, destFp50, destE32, out slot); + if (scan != 0) + { + via = "scan"; + return scan; + } + return 0; + } + + private static bool IsDumpTrueIatSlot(uint va) + { + if ((va & 3) != 0 || va == 0 || va == 0xFFFFFFFFu) + return false; + if (IsWrapDestSize(va) || va == WrapDestE32SizeLive + || va == HdDllEntryRva) + return false; + if (IsWrapDestFp50Va(va) && va == WrapDestFp50FillLive) + return false; + if (va == CoredllSharedLo) + return false; + if (IsLeftoverBindRefuse(va) || IsLeftoverDestVa(va) + || IsLeftoverWait99O32WrapLoopDest(va)) + return false; + return IsDumpTrueWrapDestFill(va); + } + + private static uint PeekWrapIatStubScan(MipsBus bus, uint destFp50, + uint destE32, out uint slot) + { + slot = 0; + if (!IsDumpTrueWrapDestFill(destFp50)) + return 0; + if (IsWrapDestFp50Va(destFp50) && destFp50 == WrapDestFp50FillLive) + return 0; + uint lim = destE32 != 0 && destE32 < WrapE32ScanMax + ? destE32 : WrapE32ScanMax; + for (uint off = 0; off + 4 < lim; off += 4) + { + uint va = destFp50 + off; + if (IsWrapDestFp50Va(va) && off == 0) + continue; + uint w = PeekDestWord(bus, va); + if (w == 0 || w == 0xFFFFFFFFu) + continue; + string named = IatStubNameOf(w); + if (named == "lui-v1" || named == "leftover-in" + || named == "exprva" || named == "leftover-getproc" + || named == "leftover-wrap" || named == "leftover-dest") + continue; + if (named.Length != 0) + { + slot = va; + return w; + } + string dump = IatStubDumpTrueName(w, destE32); + if (dump == "dump-true" || dump == "ord" || dump == "hint" + || dump == "HdstubDLLEntry" || dump == "HdstubInit") + { + slot = va; + return w; + } + } + return 0; + } + + private static string IatStubDumpTrueName(uint thunk, uint destE32) + { + if (thunk == 0 || thunk == 0xFFFFFFFFu) + return ""; + if (IsLeftoverBindRefuse(thunk) || IsWrapDestFp50Va(thunk) + || IsHdDllImageBase(thunk) || thunk == HdDllGetProcInV0) + return ""; + if (IsMipsLuiWord(thunk) || thunk == NkLuiV1Word) + return "lui-v1"; + if (IsWrapDestSize(thunk) || thunk == WrapDestE32SizeLive + || thunk == HdDllEntryRva) + return ""; + string hd = HdDllExportName(thunk); + if (hd.Length != 0) + return hd; + if (thunk == HdDllModExpRvaLive) + return "exprva"; + if ((thunk & 0x80000000u) != 0 + && (thunk & 0x7FFFFFFFu) < 0x10000u) + return "ord"; + if (IsWrapImpRva(thunk, destE32)) + return "hint"; + if (IsDumpTrueWrapDestFill(thunk) + && !IsLeftoverDestVa(thunk) + && !IsLeftoverWait99O32WrapLoopDest(thunk) + && IsLeftoverWait99O32Caller(thunk)) + return "dump-true"; + if (IsDumpTrueWrapDestFill(thunk) + && !IsLeftoverDestVa(thunk) + && !IsLeftoverWait99O32WrapLoopDest(thunk) + && thunk >= 0x80010000u && thunk < NkImageEnd) + return "dump-true"; + if (thunk >= ExtraRomPhysFirst && thunk < ExtraRomPhysLast + && !IsLeftoverDestVa(thunk) + && !IsLeftoverWait99O32WrapLoopDest(thunk)) + return "dump-true"; + return ""; + } + + private static void PeekWrapEntryNow(MipsBus bus, uint[] regs, + uint destFp50, uint destE32, out uint hdr, out int hdrOff, + out uint entryRva, out uint vbase, out uint targetVa) + { + hdr = 0; + hdrOff = 0; + entryRva = 0; + vbase = 0; + targetVa = 0; + uint a3 = PeekGpr(regs, 7); + if (a3 == 0) + a3 = WrapCopySectCount; + uint w0; + uint vsize; + uint imp; + uint fillOff; + string why = PeekWrapE32Hdr(bus, regs, destFp50, destE32, a3, + out hdr, out hdrOff, out w0, out entryRva, out vbase, + out vsize, out imp, out fillOff); + bool proven = IsWrapE32ProvenWhy(why); + if (!proven && (entryRva == destE32 + || entryRva == WrapDestE32SizeLive + || IsHdDllEntryRva(entryRva) || (w0 & 0xFFFF) > 16)) + entryRva = 0; + uint live = PeekWrapSp32Entry(bus, regs, destE32); + if (live != 0) + entryRva = live; + uint mod = _leftoverWait99O32NkBindMod; + uint startip = 0; + if (mod != 0 && !IsLeftoverBindRefuse(mod) + && !IsWrapDestSize(mod) && !IsWrapDestFp50Va(mod) + && TryPeekWord(bus, mod + ModuleStartip, out startip) + && startip != 0 && !IsLeftoverBindRefuse(startip) + && !IsWrapDestSize(startip) && !IsWrapDestFp50Va(startip)) + { + uint baseVa = destFp50; + if (IsDumpTrueWrapDestFill(vbase) && !IsWrapDestFp50Va(vbase) + && !IsWrapDestSize(vbase)) + baseVa = vbase; + else if (IsDumpTrueWrapDestFill(hdr) && !IsWrapDestFp50Va(hdr) + && !IsWrapDestSize(hdr)) + baseVa = hdr; + if (baseVa != 0 && startip > baseVa + && startip - baseVa < WrapDestSizeMax + && (proven + || (startip - baseVa != WrapDestE32SizeLive + && startip - baseVa != HdDllEntryRva))) + entryRva = startip - baseVa; + } + targetVa = WrapEntryTargetVa(destFp50, destE32, hdr, entryRva, + vbase, proven); + if (targetVa == 0 && startip != 0 + && !IsLeftoverBindRefuse(startip) + && !IsWrapDestSize(startip) + && !IsWrapDestFp50Va(startip) + && !IsLeftoverDestVa(startip)) + targetVa = startip; + // Dump hd.dll e32_rom is not in the CopyO32 + // PE fill; PE OptionalHeader+0x10 is 0x1B0C + // SIZE. If e32_entryrva is genuinely 0, + // launch via dump export HdstubDLLEntry + // (no HD_Init/Open). Do not name entryrva + // 0x1B0C. Feed MODULE+0x5C startip so + // CallDLL jalrs Target_VA. Do not + // leftover-hop dest. + if (targetVa == 0 && entryRva == 0 + && (IsHdDllImageBase(destFp50) + || IsHdDllBindName(_leftoverWait99O32NkBindName))) + targetVa = HdDllEntryVa; + } + + // Wrapper 0x20(sp) is dest-e32 SIZE 0x1B0C + // after CopyO32. Do not treat SIZE as + // entryrva. A later nonzero 32($sp) that + // is not dest-e32 / leftover is live + // entryrva for Target_VA=base+entryrva. + private static uint PeekWrapSp32Entry(MipsBus bus, uint[] regs, + uint destE32) + { + uint sp = _leftoverWait99O32NkWrapSp; + if (sp == 0) + sp = PeekGpr(regs, 29); + if (sp == 0) + return 0; + uint w = PeekDestWord(bus, sp + 0x20); + if (w == 0 || w == destE32 || w == WrapDestE32SizeLive + || IsHdDllEntryRva(w) + || w >= WrapDestSizeMax || IsLeftoverDestVa(w) + || IsLeftoverBindRefuse(w) || IsWrapDestFp50Va(w)) + return 0; + return w; + } + + private static uint ResolveWrapDestFp50(MipsBus bus, uint[] regs) + { + uint destFp50 = PeekWrapDestFp50(bus, regs); + uint latched = _leftoverWait99O32NkWrapDestFp50; + if (latched == 0 && _leftoverWait99O32NkWrapCopyLogged) + latched = WrapDestFp50FillLive; + // Live fb2d4b3 GetProc $fp+0x50 leaked + // coredll ImageBase 0x03F50000. Latch + // CopyO32 dest-fp50 0x8006C000 during + // bind. Do not hop dest-fp50 as PC. + if (IsHdDllImageBase(latched) + && (destFp50 == CoredllSharedLo || destFp50 == 0 + || !IsHdDllImageBase(destFp50))) + destFp50 = latched; + if (!IsDumpTrueWrapDestFill(destFp50)) + destFp50 = latched; + if (!IsDumpTrueWrapDestFill(destFp50) + && IsDumpTrueWrapDestFill(WrapDestFp50FillLive) + && _leftoverWait99O32NkWrapCopyLogged) + destFp50 = WrapDestFp50FillLive; + return destFp50; + } + + private static string FormatWrapHdrOff(int hdrOff) + { + if (hdrOff < 0) + return "-0x" + (-hdrOff).ToString("X"); + return "0x" + hdrOff.ToString("X"); + } + + // Target_VA = dest-fp50+entryrva (or vbase+ + // entryrva) only when entryrva is nonzero + // and not dest-e32 size. Do not hop + // dest-fp50 or leftover dest as PC. + private static bool IsWrapE32Objcnt(uint objcnt) + { + return objcnt >= 1 && objcnt <= 16; + } + + private static bool IsWrapE32ProvenWhy(string why) + { + return why == "e32-rom" || why == "dump-e32" + || why == "module-e32" || why == "mz"; + } + + private static uint WrapEntryTargetVa(uint destFp50, uint destE32, + uint hdr, uint entryRva, uint vbase, bool e32Proven) + { + if (entryRva == 0 || IsLeftoverDestVa(entryRva) + || entryRva >= WrapDestSizeMax) + return 0; + if (!e32Proven && (entryRva == destE32 + || entryRva == WrapDestE32SizeLive + || IsHdDllEntryRva(entryRva))) + return 0; + uint baseVa = destFp50; + if (IsDumpTrueWrapDestFill(vbase) && !IsWrapDestFp50Va(vbase) + && !IsWrapDestSize(vbase)) + baseVa = vbase; + else if (IsDumpTrueWrapDestFill(hdr) && !IsWrapDestFp50Va(hdr) + && !IsWrapDestSize(hdr)) + baseVa = hdr; + if (!IsDumpTrueWrapDestFill(baseVa)) + return 0; + uint target = baseVa + entryRva; + if (target == LeftoverWait99O32RefuseRa + || target == LeftoverWait99GetProcDest + || target == destE32 + || target == destFp50 + || IsWrapDestFp50Va(target) + || IsWrapDestSize(target) + || IsLeftoverWait99O32WrapLoopDest(target) + || IsLeftoverDestVa(target)) + return 0; + return target; + } + + private static string PeekWrapE32Hdr(MipsBus bus, uint[] regs, + uint destFp50, uint destE32, uint a3, out uint hdr, + out int hdrOff, out uint w0, out uint entryRva, out uint vbase, + out uint vsize, out uint imp, out uint fillOff) + { + hdr = destFp50; + hdrOff = 0; + w0 = PeekDestWord(bus, destFp50); + entryRva = PeekDestWord(bus, destFp50 + E32RomEntryRvaOff); + vbase = PeekDestWord(bus, destFp50 + E32RomVbaseOff); + vsize = PeekDestWord(bus, destFp50 + E32RomVsizeOff); + imp = PeekWrapImpRva(bus, destFp50, destE32); + fillOff = PeekWrapFillOff(bus, destFp50, destE32); + string why = WrapE32Why(w0, entryRva, vbase, vsize, destE32, a3); + if (why == "e32-rom" || why == "mz") + return why; + uint scan = PeekWrapE32RomScan(bus, destFp50, destE32, a3, + out w0, out entryRva, out vbase, out vsize, out imp, out why); + if (scan != 0) + { + hdr = scan; + hdrOff = (int)(scan - destFp50); + return why; + } + int[] offs = new int[] + { + (int)WrapO32RvaLive, -(int)WrapO32RvaLive, 0x40, 0x80, + 0x100, 0x200, 0x400, 0x800, 0x10, 0x1C, 0x20, 0x24, + 0x5C + }; + for (int i = 0; i < offs.Length; i++) + { + uint va = destFp50 + (uint)offs[i]; + if (offs[i] < 0) + va = destFp50 - (uint)(-offs[i]); + if ((va & 3) != 0 || va == destFp50) + continue; + if (TryAcceptWrapE32At(bus, va, destE32, a3, out w0, + out entryRva, out vbase, out vsize, out imp, out why)) + { + hdr = va; + hdrOff = offs[i]; + return why; + } + } + uint lite = PeekWrapE32Lite(bus, regs, destE32, a3, out w0, + out entryRva, out vbase, out vsize, out imp, out why); + if (lite != 0) + { + hdr = lite; + hdrOff = (int)(lite - destFp50); + return why; + } + uint modHdr = PeekWrapModuleE32(bus, regs, destE32, a3, destFp50, + out w0, out entryRva, out vbase, out vsize, out imp, out why); + if (modHdr != 0) + { + hdr = modHdr; + hdrOff = (int)(modHdr - destFp50); + return why; + } + ExtraRomTocMod slot = FindWrapDumpSlot(destE32, destFp50, a3); + if (slot != null && slot.E32Words != null + && slot.E32Words.Length > 10 + && IsWrapE32Objcnt(slot.E32Words[0] & 0xFFFF)) + { + w0 = slot.E32Words[0]; + entryRva = slot.E32Words.Length > 1 ? slot.E32Words[1] : 0; + vbase = slot.E32Words.Length > 2 ? slot.E32Words[2] : 0; + vsize = slot.E32Words.Length > 5 ? slot.E32Words[5] : 0; + imp = slot.E32Words[10]; + if (!IsWrapImpRva(imp, destE32) + && slot.E32Words.Length > 11) + imp = slot.E32Words[11]; + hdr = destFp50; + hdrOff = 0; + return "dump-e32"; + } + w0 = PeekDestWord(bus, destFp50); + entryRva = 0; + vbase = 0; + vsize = destE32; + imp = 0; + if (fillOff != 0) + { + uint fill = destFp50 + fillOff; + uint fw = PeekDestWord(bus, fill); + // Live 29bdcf2 dest-fp50+0x1010 w0=0x52 + // is dump hd.dll .text+0x10, not e32_rom. + if (!IsWrapE32Objcnt(fw & 0xFFFF)) + { + hdr = destFp50; + hdrOff = 0; + return fillOff == WrapO32RvaLive + 0x10 + ? "text-1010" : "text-fill"; + } + w0 = fw; + hdr = fill; + hdrOff = (int)fillOff; + return "fill"; + } + return w0 == 0 ? "empty" : "fill"; + } + + private static bool TryAcceptWrapE32At(MipsBus bus, uint va, + uint destE32, uint a3, out uint w0, out uint entryRva, + out uint vbase, out uint vsize, out uint imp, out string why) + { + w0 = PeekDestWord(bus, va); + entryRva = PeekDestWord(bus, va + E32RomEntryRvaOff); + vbase = PeekDestWord(bus, va + E32RomVbaseOff); + vsize = PeekDestWord(bus, va + E32RomVsizeOff); + imp = PeekWrapImpRva(bus, va, destE32); + why = WrapE32Why(w0, entryRva, vbase, vsize, destE32, a3); + return why == "e32-rom" || why == "mz"; + } + + private static string WrapE32Why(uint w0, uint entryRva, uint vbase, + uint vsize, uint destE32, uint a3) + { + uint objcnt = w0 & 0xFFFF; + if ((w0 & 0xFFFF) == E32MzMagic) + return "mz"; + if (w0 == 0) + return "empty"; + if (!IsWrapE32Objcnt(objcnt)) + return "fill"; + if (entryRva == 0 || entryRva >= WrapDestSizeMax + || IsLeftoverDestVa(entryRva)) + return "fill"; + // dest-e32 0x1B0C is SIZE. Same word may + // also be e32_entryrva when objcnt is + // dump-true (1..16). Do not reject that. + if (objcnt == a3 || objcnt == WrapCopySectCount) + return "e32-rom"; + if (destE32 != 0 && (vsize == destE32 || vsize == 0 + || IsWrapDestSize(vsize))) + return "e32-rom"; + if (vbase != 0 && (IsDumpTrueWrapDestFill(vbase) + || IsHdDllImageBase(vbase))) + return "e32-rom"; + return "fill"; + } + + // Scan CopyO32 dest-fp50 for WinCE e32_rom + // (e32_entryrva +4, e32_vbase +8, e32_vsize + // +0x14, e32_rva unit[0] +0x20/+0x24). Do + // not treat PE OptionalHeader+0x10 0x1B0C + // as entry. Skip dest+.text+0x10 w0=0x52. + private static uint PeekWrapE32RomScan(MipsBus bus, uint destFp50, + uint destE32, uint a3, out uint w0, out uint entryRva, + out uint vbase, out uint vsize, out uint imp, out string why) + { + w0 = 0; + entryRva = 0; + vbase = 0; + vsize = 0; + imp = 0; + why = "empty"; + if (!IsDumpTrueWrapDestFill(destFp50)) + return 0; + uint lim = destE32 != 0 && destE32 < WrapE32ScanMax + ? destE32 : WrapE32ScanMax; + if (lim < 0x80) + lim = 0x80; + bool mz = PeekDestWord(bus, destFp50) == E32MzMagic; + for (uint off = 0; off + 0x28 < lim; off += 4) + { + if (off == WrapO32RvaLive + 0x10) + continue; + uint va = destFp50 + off; + uint live0 = PeekDestWord(bus, va); + if (!IsWrapE32Objcnt(live0 & 0xFFFF)) + continue; + uint liveEntry = PeekDestWord(bus, va + E32RomEntryRvaOff); + uint liveVbase = PeekDestWord(bus, va + E32RomVbaseOff); + uint liveVsize = PeekDestWord(bus, va + E32RomVsizeOff); + if (mz && liveEntry == WrapDestE32SizeLive + && liveVbase != destFp50 && !IsHdDllImageBase(liveVbase)) + continue; + if (liveVbase != destFp50 && !IsHdDllImageBase(liveVbase) + && liveVbase != 0) + continue; + if (liveVbase == 0 && liveVsize == 0 && liveEntry == 0) + continue; + if (liveVsize == 0x52) + continue; + if (TryAcceptWrapE32At(bus, va, destE32, a3, out w0, + out entryRva, out vbase, out vsize, out imp, out why) + && why == "e32-rom") + return va; + if ((IsHdDllImageBase(liveVbase) || liveVbase == destFp50) + && liveEntry < WrapDestSizeMax + && !IsLeftoverDestVa(liveEntry) + && (liveVsize == 0 || IsWrapDestSize(liveVsize) + || liveVsize == destE32 || liveVsize == 0x6000u)) + { + w0 = live0; + entryRva = liveEntry; + vbase = liveVbase; + vsize = liveVsize; + imp = PeekWrapImpRva(bus, va, destE32); + why = "e32-rom"; + return va; + } + } + return 0; + } + + private static uint PeekWrapE32Rva(MipsBus bus, uint hdr) + { + if (hdr == 0 || IsWrapDestSize(hdr) || IsLeftoverDestVa(hdr)) + return 0; + uint u20 = PeekDestWord(bus, hdr + E32RomRvaOff); + uint u24 = PeekDestWord(bus, hdr + E32RomExpRva); + if (u20 == HdDllExpRva) + return u20; + if (u24 == HdDllExpRva) + return u24; + if (u20 != 0 && u20 < WrapDestSizeMax && !IsLeftoverDestVa(u20) + && u20 != WrapDestE32SizeLive && u20 != HdDllEntryRva) + return u20; + if (u24 != 0 && u24 < WrapDestSizeMax && !IsLeftoverDestVa(u24) + && u24 != WrapDestE32SizeLive && u24 != HdDllEntryRva) + return u24; + return 0; + } + + private static uint PeekWrapFillOff(MipsBus bus, uint destFp50, + uint destE32) + { + uint lim = destE32 != 0 && destE32 < WrapE32ScanMax + ? destE32 : WrapE32ScanMax; + if (lim < WrapO32RvaLive) + lim = WrapO32RvaLive + 0x10; + for (uint off = 0; off < lim; off += 0x10) + { + uint w = PeekDestWord(bus, destFp50 + off); + if (w != 0) + return off; + } + uint back = PeekDestWord(bus, destFp50 - WrapO32RvaLive); + if (back != 0) + return 0xFFFFF000u; + return 0; + } + + private static uint PeekWrapE32Lite(MipsBus bus, uint[] regs, + uint destE32, uint a3, out uint w0, out uint entryRva, + out uint vbase, out uint vsize, out uint imp, out string why) + { + w0 = 0; + entryRva = 0; + vbase = 0; + vsize = 0; + imp = 0; + why = "empty"; + uint sp = _leftoverWait99O32NkWrapSp; + if (sp == 0) + sp = PeekGpr(regs, 29); + uint fp = _leftoverWait99O32NkWrapFp; + if (fp == 0) + fp = PeekGpr(regs, 30); + uint[] bases = new uint[] { sp, fp }; + uint[] offs = new uint[] + { + 0, 0x10, 0x1C, 0x20, 0x24, 0x28, 0x2C, 0x40, 0x5C, 0x70, + 0x80 + }; + for (int b = 0; b < bases.Length; b++) + { + if (bases[b] == 0) + continue; + for (int i = 0; i < offs.Length; i++) + { + uint va = bases[b] + offs[i]; + if (TryAcceptWrapE32At(bus, va, destE32, a3, out w0, + out entryRva, out vbase, out vsize, out imp, out why)) + return va; + } + } + return 0; + } + + private static uint PeekWrapModuleE32(MipsBus bus, uint[] regs, + uint destE32, uint a3, uint destFp50, out uint w0, + out uint entryRva, out uint vbase, out uint vsize, + out uint imp, out string why) + { + w0 = 0; + entryRva = 0; + vbase = 0; + vsize = 0; + imp = 0; + why = "empty"; + uint a0 = PeekGpr(regs, 4); + uint[] mods = new uint[] { _leftoverWait99O32NkBindMod, a0 }; + for (int i = 0; i < mods.Length; i++) + { + uint mod = mods[i]; + if (mod == 0 || IsLeftoverBindRefuse(mod) + || IsWrapDestSize(mod) || IsWrapDestFp50Va(mod) + || IsHdDllImageBase(mod) || IsLeftoverDestVa(mod)) + continue; + uint[] ptrs = new uint[] { 0, 4 }; + for (int p = 0; p < ptrs.Length; p++) + { + uint e32 = 0; + if (!TryPeekWord(bus, mod + ptrs[p], out e32) + || e32 == 0 || (e32 & 3) != 0 + || IsLeftoverBindRefuse(e32) + || IsWrapDestSize(e32) || IsWrapDestFp50Va(e32) + || e32 == destFp50) + continue; + if (TryAcceptWrapE32At(bus, e32, destE32, a3, out w0, + out entryRva, out vbase, out vsize, out imp, out why) + && why == "e32-rom") + { + why = "module-e32"; + return e32; + } + } + } + return 0; + } + + private static ExtraRomTocMod FindWrapDumpSlot(uint destE32, + uint destFp50, uint a3) + { + ExtraRomTocMod named = FindCachedExtraRomToc( + _leftoverWait99O32NkBindName); + if (named == null && IsHdDllImageBase(destFp50)) + named = FindCachedExtraRomToc("hd.dll"); + if (named != null && named.E32Words != null + && named.E32Words.Length >= 6 + && IsWrapE32Objcnt(named.E32Words[0] & 0xFFFF)) + return named; + if (_romTocMods == null) + return null; + ExtraRomTocMod best = null; + for (int i = 0; i < _romTocCount; i++) + { + ExtraRomTocMod slot = _romTocMods[i]; + if (slot == null || slot.E32Words == null + || slot.E32Words.Length < 6) + continue; + uint objcnt = slot.E32Words[0] & 0xFFFF; + uint vsize = slot.E32Words[5]; + uint vbase = slot.E32Words.Length > 2 ? slot.E32Words[2] : 0; + bool sizeMatch = destE32 != 0 && vsize == destE32 + && destE32 != WrapDestE32SizeLive + && destE32 != HdDllEntryRva; + bool destMatch = destFp50 != 0 + && (slot.Dest == destFp50 || slot.Vbase == destFp50 + || vbase == destFp50 + || (slot.Dest & SlotMask) == (destFp50 & SlotMask)); + if (sizeMatch || destMatch) + return slot; + if (best == null && destE32 != 0 + && destE32 != WrapDestE32SizeLive + && destE32 != HdDllEntryRva + && (objcnt == a3 || objcnt == WrapCopySectCount)) + best = slot; + } + return best; + } + + private static string PeekWrapBindLibName(MipsBus bus, uint[] regs, + uint pc) + { + if (pc != BindImpLoadLib && pc != BindImpDllName + && pc != BindImpHdr) + return ""; + uint a0 = PeekGpr(regs, 4); + if (pc == BindImpDllName) + a0 = PeekGpr(regs, 3); + if (a0 == 0 || a0 == LeftoverWait99O32RefuseRa + || a0 == LeftoverWait99GetProcDest || IsWrapDestSize(a0) + || IsLeftoverDestVa(a0)) + return ""; + return PeekWrapBindName(bus, a0); + } + + private static string PeekWrapBindName(MipsBus bus, uint va) + { + if (bus == null || va == 0 || IsLeftoverDestVa(va) + || va == LeftoverWait99O32RefuseRa + || va == LeftoverWait99GetProcDest + || IsWrapDestSize(va)) + return ""; + string utf = ""; + try + { + utf = ReadUtf16Name(bus, va); + } + catch + { + } + if (IsWrapDllName(utf)) + return utf; + string ascii = PeekWrapImpName(bus, va); + if (IsWrapDllName(ascii)) + return ascii; + return utf.Length != 0 ? utf : ascii; + } + + private static bool IsWrapDllName(string name) + { + if (string.IsNullOrEmpty(name) || name.Length < 5) + return false; + int n = name.Length; + return name[n - 4] == '.' + && (name[n - 3] == 'd' || name[n - 3] == 'D') + && (name[n - 2] == 'l' || name[n - 2] == 'L') + && (name[n - 1] == 'l' || name[n - 1] == 'L'); + } + + private static string PeekWrapDllNameScan(MipsBus bus, uint destFp50, + uint destE32) + { + if (!IsDumpTrueWrapDestFill(destFp50)) + return ""; + uint lim = destE32 != 0 && destE32 < WrapE32ScanMax + ? destE32 : WrapE32ScanMax; + for (uint off = 0; off + 8 < lim; off += 2) + { + string ascii = PeekWrapImpName(bus, destFp50 + off); + if (IsWrapDllName(ascii)) + return ascii; + string utf = ""; + try + { + utf = ReadUtf16Name(bus, destFp50 + off); + } + catch + { + } + if (IsWrapDllName(utf)) + return utf; + } + return ""; + } + + private static void TryNoteLeftoverWait99O32NkEntry(MipsBus bus, + uint[] regs, uint pc) + { + // dest-e32 0x1B0C is SIZE. Live + // 7bb467b named entryrva=0x1B0C + // Target_VA=0x8006DB0C without e32_rom + // EntryPoint (hdr w0=0x52). Do not + // name that. leftover dest 0x03F74DEC + // / GetProc dest 0x8008C844 leftover + // hop forbidden. Do not hop dest-e32 + // 0x1B0C or dest-fp50 as PC. + if (_leftoverWait99O32NkCallDllLogged + && _leftoverWait99O32NkEntryTarget != 0) + return; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || IsLeftoverBindRefuse(pc) + || IsWrapDestFp50Va(pc) + || IsHdDllImageBase(pc) + || pc == HdDllEntryVa || pc == HdDllInitVa + || IsWrapDestSize(pc) + || pc == WrapDestE32SizeLive + || pc == HdDllEntryRva) + return; + uint destFp50 = ResolveWrapDestFp50(bus, regs); + uint destE32 = PeekWrapDestE32(bus, regs); + uint hdr; + int hdrOff; + uint entryRva; + uint vbase; + uint targetVa; + PeekWrapEntryNow(bus, regs, destFp50, destE32, + out hdr, out hdrOff, out entryRva, out vbase, out targetVa); + if (_leftoverWait99O32NkCallDllLogged && entryRva == 0 + && targetVa == 0) + return; + if (_leftoverWait99O32NkCallDllLogged && entryRva != 0 + && entryRva == _leftoverWait99O32NkEntryRva) + return; + _leftoverWait99O32NkCallDllLogged = true; + if (entryRva != 0) + _leftoverWait99O32NkEntryRva = entryRva; + if (targetVa != 0) + _leftoverWait99O32NkEntryTarget = targetVa; + TryNoteLeftoverWait99O32NkE32(bus, regs, pc); + string why = entryRva != 0 && targetVa != 0 ? "entry" : "entryrva-0"; + if (entryRva == 0 && targetVa == HdDllEntryVa) + why = "HdstubDLLEntry"; + else if (entryRva == 0 && targetVa == HdDllInitVa) + why = "HdstubInit"; + if (targetVa == destFp50 || (targetVa == destE32 && entryRva == 0)) + why = "entryrva-0"; + if (IsLeftoverBindRefuse(pc) || IsLeftoverBindRefuse(targetVa)) + why = "leftover-getproc"; + uint startip = 0; + if (entryRva == 0 + && (targetVa == HdDllEntryVa || targetVa == HdDllInitVa)) + startip = TryPlantHdDllStartip(bus, regs, targetVa); + if (startip == 0) + { + uint mod = PeekHdDllModule(bus, regs, destFp50); + if (mod != 0) + TryPeekWord(bus, mod + ModuleStartip, out startip); + } + // HiveLineMax 180: drop dest-e32 / target / + // ra / hdr-off so via= is not truncated. + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-entry pc=0x" + + pc.ToString("X8") + + " dest-fp50=0x" + destFp50.ToString("X") + + " hdr-off=" + FormatWrapHdrOff(hdrOff) + + " entryrva=0x" + entryRva.ToString("X") + + " Target_VA=0x" + targetVa.ToString("X") + + " startip=0x" + startip.ToString("X") + + " via=" + why); + if (targetVa != 0 + && !IsWrapDestFp50Va(targetVa) + && !IsWrapDestSize(targetVa) + && !IsHdDllImageBase(targetVa) + && targetVa != HdDllEntryVa && targetVa != HdDllInitVa + && !IsLeftoverBindRefuse(targetVa) + && IsDumpTrueWrapDestFill(targetVa) + && targetVa != LeftoverWait99O32RefuseRa + && targetVa != LeftoverWait99GetProcDest) + TryNoteLeftoverWait99O32ContFromNkWrap(bus, pc, targetVa, + "entry"); + } + + // Live 2b02f4e named Target_VA but never + // jalr'd HdstubDLLEntry. leftover-wait99- + // o32-nk-jalr names guest dispatch into + // that VA, or why CallDLL / startip skip. + // Live a273e3a FIRST-WIN via=calldll at + // 0x80018B34 / 0x80018BAC; cap 2 burned + // before PC at 0x8006DB0C. Keep calldll + // lines; always name PC-at/near export. + // Peek live word at Target_VA (kseg0 fill; + // not TLB). Do not leftover-hop dest. + // Do not force CallDLL. Do not hop dest- + // e32 SIZE / dest-fp50 as PC. + private static bool IsHdDllTargetPc(uint pc, uint targetVa) + { + if (pc == HdDllEntryVa || pc == HdDllInitVa) + return true; + if (targetVa == 0 || targetVa == HdDllEntryRva + || IsWrapDestSize(targetVa) || IsWrapDestFp50Va(targetVa) + || IsHdDllImageBase(targetVa) || IsLeftoverDestVa(targetVa) + || IsLeftoverBindRefuse(targetVa)) + return false; + return pc >= targetVa && pc < targetVa + 0x20; + } + + private static uint PeekHdDllTargetWord(MipsBus bus, uint targetVa, + out bool mapped) + { + mapped = false; + if (targetVa != HdDllEntryVa && targetVa != HdDllInitVa) + return 0; + bool threw; + uint w = PeekDestWordRaw(bus, targetVa, out threw); + mapped = !threw; + return w; + } + + private static void TryNoteLeftoverWait99O32NkJalr(MipsBus bus, + uint[] regs, uint pc) + { + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || IsLeftoverBindRefuse(pc) + || IsWrapDestFp50Va(pc) + || IsHdDllImageBase(pc) + || IsWrapDestSize(pc) + || pc == WrapDestE32SizeLive + || pc == HdDllEntryRva) + return; + uint targetVa = _leftoverWait99O32NkEntryTarget; + if (targetVa == 0 + && (IsHdDllBindName(_leftoverWait99O32NkBindName) + || IsHdDllImageBase(ResolveWrapDestFp50(bus, regs)))) + targetVa = HdDllEntryVa; + bool atTarget = IsHdDllTargetPc(pc, targetVa); + bool atCall = pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal + || pc == XipCallDllUsegChk || pc == LoadO32WrapStartip; + if (!atTarget && !atCall) + return; + if (atTarget && _leftoverWait99O32NkJalrSawTarget) + return; + if (!atTarget && _leftoverWait99O32NkJalrLog >= 2) + return; + if (targetVa != HdDllEntryVa && targetVa != HdDllInitVa + && !atTarget) + return; + uint destFp50 = ResolveWrapDestFp50(bus, regs); + uint destE32 = PeekWrapDestE32(bus, regs); + if (atCall && (targetVa == HdDllEntryVa || targetVa == HdDllInitVa)) + TryPlantHdDllStartip(bus, regs, targetVa); + uint mod = PeekHdDllModule(bus, regs, destFp50); + uint startip = 0; + uint p50 = 0; + if (mod != 0) + { + TryPeekWord(bus, mod + ModuleStartip, out startip); + TryPeekWord(bus, mod + ProcModule, out p50); + } + uint callMod = PeekGpr(regs, 4); + if (callMod == 0) + callMod = PeekGpr(regs, 30); + bool thisHd = mod != 0 && (callMod == mod + || IsHdDllImageBase(destFp50) + || IsHdDllBindName(_leftoverWait99O32NkBindName)); + uint jalrDest = 0; + uint insn = 0; + uint rs; + if (TryPeekWord(bus, pc, out insn) && IsJalrInsn(insn, out rs)) + jalrDest = PeekGpr(regs, (int)rs); + if (jalrDest == 0) + jalrDest = startip; + uint sp32 = PeekSpWord(bus, regs, 0x20); + uint s5 = PeekS5(regs); + bool mapped; + uint word = PeekHdDllTargetWord(bus, targetVa, out mapped); + string why; + if (atTarget) + { + if (!mapped) + why = "unmap"; + else if (word == 0) + why = "empty"; + else + why = pc == HdDllInitVa ? "HdstubInit" : "HdstubDLLEntry"; + _leftoverWait99O32NkJalrSawTarget = true; + } + else if (!thisHd && jalrDest != targetVa + && jalrDest != HdDllEntryVa && jalrDest != HdDllInitVa) + return; + else if (pc == XipCallDllUsegChk && mod != 0 + && IsCallDllSkipUseg(p50)) + why = "useg-skip"; + else if (pc == LoadO32WrapStartip + && (startip == 0 || startip != targetVa) + && (sp32 == 0 || sp32 == destE32 + || sp32 == WrapDestE32SizeLive + || IsHdDllEntryRva(sp32))) + why = "startip-skip-0"; + else if (pc == LoadO32WrapStartip + && (startip == targetVa || startip == HdDllEntryVa)) + return; + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && (jalrDest == targetVa || jalrDest == HdDllEntryVa + || jalrDest == HdDllInitVa)) + { + why = "calldll"; + _leftoverWait99O32NkJalrSawCall = true; + } + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && jalrDest == 0 && thisHd) + why = "startip-0"; + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && thisHd && (s5 & WrapS5CallDll) == 0) + why = "s5-skip"; + else + return; + if (!atTarget) + _leftoverWait99O32NkJalrLog++; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-jalr pc=0x" + + pc.ToString("X8") + + " dest-fp50=0x" + destFp50.ToString("X") + + " startip=0x" + startip.ToString("X") + + " word=0x" + word.ToString("X") + + " Target_VA=0x" + targetVa.ToString("X") + + " via=" + why); + } + + // Live a273e3a CallDLL jalr dest was + // HdstubDLLEntry; no hive PC at Target_VA + // then NK LoadE32 osaxst0/coredll. Name + // CallDLL return, miss-pc, next module, or + // unmap/empty fill. Do not leftover-hop. + private static void TryNoteLeftoverWait99O32NkAfter(MipsBus bus, + uint[] regs, uint pc) + { + if (_leftoverWait99O32NkCoredllSawEntry && pc == CallDllAfterJalr + && !_leftoverWait99O32NkCoredllRetLog) + { + _leftoverWait99O32NkCoredllRetLog = true; + uint coredllV0 = PeekGpr(regs, 2); + bool threw; + uint coredllWord = PeekDestWordRaw(bus, CoredllDllMainVa, out threw); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-after pc=0x" + + pc.ToString("X8") + + " v0=0x" + coredllV0.ToString("X") + + " word=0x" + coredllWord.ToString("X") + + " saw=y" + + " next=coredll.dll" + + " Target_VA=0x" + CoredllDllMainVa.ToString("X") + + " via=ret"); + } + if (!_leftoverWait99O32NkJalrSawCall) + return; + if (_leftoverWait99O32NkAfterLog >= 2) + return; + if (pc != CallDllAfterJalr) + return; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || IsLeftoverBindRefuse(pc) + || IsWrapDestFp50Va(pc) + || IsHdDllImageBase(pc) + || IsWrapDestSize(pc) + || pc == HdDllEntryRva) + return; + uint targetVa = _leftoverWait99O32NkEntryTarget; + if (targetVa == 0) + targetVa = HdDllEntryVa; + if (targetVa != HdDllEntryVa && targetVa != HdDllInitVa) + return; + bool mapped; + uint word = PeekHdDllTargetWord(bus, targetVa, out mapped); + uint v0 = PeekGpr(regs, 2); + string why; + if (!mapped) + why = "unmap"; + else if (_leftoverWait99O32NkJalrSawTarget) + why = "ret"; + else if (word == 0) + why = "empty"; + else + why = "miss-pc"; + WriteLeftoverWait99O32NkAfter(pc, v0, word, why, "-"); + } + + private static void TryNoteLeftoverWait99O32NkAfterLoad(MipsBus bus, + string name) + { + if (!_leftoverWait99O32NkJalrSawCall) + return; + if (_leftoverWait99O32NkAfterLog >= 2) + return; + if (string.IsNullOrEmpty(name) || IsHdDllBindName(name)) + return; + uint targetVa = _leftoverWait99O32NkEntryTarget; + if (targetVa == 0) + targetVa = HdDllEntryVa; + bool mapped; + uint word = PeekHdDllTargetWord(bus, targetVa, out mapped); + string why; + if (_leftoverWait99O32NkJalrSawTarget) + why = "next"; + else if (!mapped) + why = "unmap"; + else if (word == 0) + why = "empty"; + else + why = "miss-pc"; + WriteLeftoverWait99O32NkAfter(0, 0, word, why, name); + } + + private static void WriteLeftoverWait99O32NkAfter(uint pc, uint v0, + uint word, string why, string next) + { + _leftoverWait99O32NkAfterLog++; + string saw = _leftoverWait99O32NkJalrSawTarget ? "y" : "n"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-after pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X") + + " word=0x" + word.ToString("X") + + " saw=" + saw + + " next=" + (string.IsNullOrEmpty(next) ? "-" : next) + + " Target_VA=0x" + + (_leftoverWait99O32NkEntryTarget != 0 + ? _leftoverWait99O32NkEntryTarget : HdDllEntryVa) + .ToString("X") + + " via=" + why); + } + + // Live c7dd951 FIRST-WIN rich naming: + // via=entry 0x03F57A00, via=body + // 0x03F57A04, leftover-refuse 0x03F6EE0C + // word=0x27BDFFE0. leftover dest RANGE + // misnamed a live DllMain callee. Dump- + // true $ra / next jal at 0x03F6EE0C. + // Plant dest-live GetProc only when that + // dest is leftover 0x03F74DEC / GetProc + // dest 0x8008C844. Do not leftover-hop. + private static bool TryPeekCoredllDumpWord(MipsBus bus, uint va, + out uint word) + { + word = 0; + if ((va & 3) != 0) + return false; + if (va >= CoredllSharedLo && va < CoredllSharedHi) + { + uint dump = CoredllDumpBase + (va - CoredllSharedLo); + if (TryPeekLeftoverWait99DumpOnly(dump, out word)) + return true; + } + if (va >= 0x03F70000u && va < 0x03F80000u) + { + uint ck = 0x80094000u + (va - 0x03F70000u); + if (TryPeekLeftoverWait99DumpOnly(ck, out word)) + return true; + } + return bus != null && TryPeekWord(bus, va, out word); + } + + private static bool TryDecodeCoredllDllMainJal(MipsBus bus, uint[] regs, + uint pc, out uint jalDest, out uint apiImm, out string via) + { + jalDest = 0; + apiImm = 0; + via = "miss-jal"; + bool sawJalr = false; + for (uint off = 0; off < 0x80; off += 4) + { + uint va = pc + off; + uint word; + if (!TryPeekCoredllDumpWord(bus, va, out word)) + continue; + uint target; + uint rs; + uint rt; + if (IsJalInsn(word, va, out target) && ((word >> 26) & 63) == 3) + { + jalDest = target; + via = "jal"; + return true; + } + if (IsJalrInsn(word, out rs)) + { + // GPR dest is only live at the jalr PC. + // Ahead-scan from the prologue would + // name a stale $t9/$v0 leftover dest. + if (va == pc) + jalDest = PeekGpr(regs, (int)rs); + sawJalr = true; + } + if (IsAddiuZeroNeg(word, out rt) && rt == 2 && apiImm == 0) + apiImm = (uint)(short)(word & 0xFFFF); + } + if (apiImm != 0) + { + via = "api"; + return true; + } + if (sawJalr) + { + via = "jalr"; + return true; + } + return false; + } + + private static void TryNoteLeftoverWait99O32NkCoredllJal(MipsBus bus, + uint[] regs, uint pc) + { + if (!_leftoverWait99O32NkCoredllSawEntry) + return; + if (pc != CoredllDllMainJalVa) + return; + if (_leftoverWait99O32NkCoredllJalLog) + return; + _leftoverWait99O32NkCoredllJalLog = true; + uint ra = PeekGpr(regs, 31); + bool threw; + uint word = PeekDestWordRaw(bus, pc, out threw); + if (word == 0) + TryPeekCoredllDumpWord(bus, pc, out word); + uint jalDest; + uint apiImm; + string how; + TryDecodeCoredllDllMainJal(bus, regs, pc, out jalDest, out apiImm, + out how); + string why = "dllmain-jal"; + if (IsLeftoverBindRefuse(jalDest) + || jalDest == LeftoverWait99O32RefuseRa + || jalDest == LeftoverWait99GetProcDest) + { + why = "leftover-thunk"; + TryResolveDdiNopProcessInfo(bus); + TryPlantLeftoverWait99GetProc(bus, regs); + } + else if (how == "api") + { + why = "api"; + TryResolveDdiNopProcessInfo(bus); + TryPlantLeftoverWait99GetProc(bus, regs); + _coredllImageDemand = true; + TryResolveDdiNopCoredllImage(bus, CoredllDllMainPageVa); + } + else if (how == "miss-jal") + why = "miss-jal"; + if (IsLeftoverBindRefuse(ra) || ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || IsWrapDestSize(ra) || IsWrapDestFp50Va(ra) + || ra == HdDllEntryRva) + ra = 0; + if (ra != 0 && (ra & 3) == 0 + && ra >= CoredllSharedLo && ra < CoredllSharedHi) + _leftoverWait99O32NkCoredllJalRa = ra; + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = why; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " word=0x" + word.ToString("X") + + " ra=0x" + ra.ToString("X") + + " jal=0x" + jalDest.ToString("X") + + " via=" + why); + } + + // Live 4d62343 FIRST-WIN coredll-page maps + // then I-fetch TLBL epc=0 bad=0. wrap-plant + // slot=0. Dump-true who jalr/jr'd 0 + // ($v0/$t9/$ra). Plant dest-live GetProc + // into $v0/$t9 only. Restore latched + // DllMain ra 0x03F57A44 on jr $ra,0. + // Do not leftover-hop dest. Do not invent + // heap / PTE / page 0. + private static uint PeekCoredllDumpTrueGetProc() + { + uint gp = _leftoverWait99WrapPlantGp; + if (!IsDumpWait99GetProcDest(gp)) + gp = LeftoverWait99WrapPlantGp; + if (!IsDumpWait99GetProcDest(gp)) + return 0; + if (IsLeftoverBindRefuse(gp) || gp == LeftoverWait99GetProcDest + || IsLeftoverDestVa(gp) || IsWrapDestSize(gp) + || IsWrapDestFp50Va(gp) || gp == HdDllEntryRva) + return 0; + return gp; + } + + private static void TryNoteLeftoverWait99O32NkCoredllPc0(MipsBus bus, + uint[] regs, uint pc) + { + if (!_leftoverWait99O32NkCoredllSawEntry) + return; + if (_leftoverWait99O32NkCoredllPc0Log) + return; + if (pc == 0 || IsLeftoverBindRefuse(pc) + || pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || IsWrapDestSize(pc) || IsWrapDestFp50Va(pc) + || pc == HdDllEntryRva) + return; + uint insn = 0; + if (!TryPeekWord(bus, pc, out insn) && !TryPeekCoredllDumpWord(bus, pc, out insn)) + return; + uint rs; + bool jalr = IsJalrInsn(insn, out rs); + bool jr = ((insn >> 26) & 63) == 0 && (insn & 63) == 8; + if (!jalr && !jr) + return; + if (jr) + rs = (insn >> 21) & 31; + uint dest = PeekGpr(regs, (int)rs); + if (dest != 0) + return; + _leftoverWait99O32NkCoredllPc0Log = true; + uint v0 = PeekGpr(regs, 2); + uint t9 = PeekGpr(regs, 25); + uint ra = PeekGpr(regs, 31); + uint slot = 0; + TryPeekWord(bus, ProcessInfoFaultVa, out slot); + string why = jalr ? "jalr-0" : (rs == 31 ? "jr-ra-0" : "jr-0"); + if (jalr && (rs == 2 || rs == 25)) + { + uint gp = PeekCoredllDumpTrueGetProc(); + if (gp != 0 && regs != null && regs.Length > (int)rs) + { + regs[rs] = gp; + why = "jalr-0-plant"; + } + } + else if (jr && rs == 31) + { + uint ret = _leftoverWait99O32NkCoredllJalRa; + if (ret != 0 && (ret & 3) == 0 + && ret >= CoredllSharedLo && ret < CoredllSharedHi + && !IsLeftoverBindRefuse(ret) + && regs != null && regs.Length > 31) + { + regs[31] = ret; + why = "jr-ra-ret"; + } + } + _leftoverWait99O32NkChainLast = pc ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = why; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " v0=0x" + v0.ToString("X") + + " t9=0x" + t9.ToString("X") + + " ra=0x" + ra.ToString("X") + + " slot=0x" + slot.ToString("X") + + " via=" + why); + } + + // Live e728aa2 FIRST-WIN via=exn at + // 0x80000180 word=0x3C1A8001 before + // DllMain; nk-after via=ret was early + // (osaxst0 ChainSawEntry). Later + // CallDLL/entry at 0x03F57A00, no ret. + // Latch real coredll entry. Enrich exn + // with Cause/EPC/BadVAddr. Observe + // body/ret only after 0x03F57A00. Do + // not leftover-hop dest 0x03F74DEC. + private static string CoredllExnWhy(uint code) + { + if (code == 2) + return "exn-tlbl"; + if (code == 3) + return "exn-tlbs"; + if (code == 4) + return "exn-adel"; + if (code == 5) + return "exn-ades"; + if (code == 8) + return "exn-sys"; + if (code == 10) + return "exn-ri"; + if (code == 0) + return "exn-int"; + return "exn"; + } + + public static void TryNoteLeftoverWait99O32NkCoredllExn(uint code, + uint epc, uint vaddr, uint vector, uint[] regs, MipsBus bus) + { + if (!_leftoverWait99O32NkJalrSawTarget) + return; + if (code == 0) + return; + if (IsWrapDestSize(epc) || epc == HdDllEntryRva + || IsWrapDestFp50Va(epc) || IsHdDllImageBase(epc) + || IsLeftoverBindRefuse(epc) || epc == LeftoverWait99GetProcDest + || epc == LeftoverWait99O32RefuseRa + || epc == CoredllDllMainJalRaVa) + return; + // Early e728aa2 via=exn was genex + // 0x80000180. Do not burn the one + // pre-DllMain slot on an unrelated + // TLB refill. After entry, any + // Cause/EPC (useg TLB/AdEL). + if (!_leftoverWait99O32NkCoredllSawEntry + && vector != 0x80000180u && vector != 0x80000000u) + return; + if (!_leftoverWait99O32NkCoredllSawEntry + && _leftoverWait99O32NkCoredllExnLog) + return; + bool slot = _leftoverWait99O32NkCoredllSawEntry + && vaddr >= ProcessInfoPage && vaddr < 0x02000000u + && (code == 2 || code == 3); + bool page = _leftoverWait99O32NkCoredllSawEntry + && code == 2 && epc == vaddr + && IsDdiNopCoredllImageVa(epc); + bool kdata = _leftoverWait99O32NkCoredllSawEntry + && (vaddr & ~0xFFFu) == FfffE000Page + && (code == 2 || code == 3); + bool sud = _leftoverWait99O32NkCoredllSawEntry + && (vaddr & ~0xFFFu) == FfffF000Page + && (code == 2 || code == 3); + bool jalr = _leftoverWait99O32NkCoredllSawEntry + && (epc == CoredllDllMainJalrDest + || (vaddr & ~0xFFFu) == CoredllDllMainJalrPage) + && (code == 2 || code == 3); + bool jalr1db0 = _leftoverWait99O32NkCoredllSawEntry + && _jalr7eb8Logged + && !jalr + && (epc == CoredllDllMainJalrDest2 + || vaddr == CoredllDllMainJalrBad2 + || (vaddr & ~0xFFFu) == CoredllDllMainJalrPage2) + && (code == 2 || code == 3); + bool ri = _leftoverWait99O32NkCoredllSawEntry + && _jalr1db0Logged + && code == 10 + && (epc == CoredllDllMainRiEpc + || epc == CoredllDllMainRiEpc + 4 + || epc == CoredllDllMainRiEpc - 4); + bool stk2470 = _leftoverWait99O32NkCoredllSawEntry + && _jalrE478JrLogged + && !_stk2470ExnLogged + && !_stk2470SwLogged + && (code == 2 || code == 3) + && (epc == CoredllDllMainStk2470Epc + || vaddr == CoredllDllMainStk2470Bad + || ((vaddr & ~0xFFFu) == CoredllDllMainStk2470Page + && epc == CoredllDllMainStk2470Epc)); + bool stk1670 = _leftoverWait99O32NkCoredllSawEntry + && _stk2470SwLogged + && !_stk1670Logged + && !_stk1670SbLogged + && (code == 2 || code == 3) + && (epc == CoredllDllMainStk1670Epc + || vaddr == CoredllDllMainStk1670Bad); + bool abs1828 = _leftoverWait99O32NkCoredllSawEntry + && _stk1670SbLogged + && !_abs1828ExnLogged + && (code == 2 || code == 3) + && (epc == CoredllDllMainAbs1828Epc + || vaddr == CoredllDllMainAbs1828Bad); + uint live6670 = 0; + if (epc == CoredllDllMainAbs6670Epc) + TryPeekWord(bus, epc, out live6670); + bool abs6670 = _leftoverWait99O32NkCoredllSawEntry + && _stk1670SbLogged + && !_abs6670ExnLogged + && (code == 2 || code == 3) + && !IsDumpMemAlreadyTrue(live6670) + && (vaddr == CoredllDllMainAbs6670Bad + || (epc == CoredllDllMainAbs6670Epc + && IsMipsAbsRs0Store(live6670))); + bool c000 = _leftoverWait99O32NkCoredllSawEntry + && _stk1670SbLogged + && !_c000ExnLogged + && (code == 2 || code == 3) + && (epc == CoredllDllMainC000Epc + || vaddr == CoredllDllMainC000Bad + || vaddr == CoredllDllMainC0001070 + || vaddr == CoredllDllMainC1000070 + || vaddr == CoredllDllMainD0000028 + || vaddr == CoredllDllMainE0000688 + || vaddr == CoredllDllMainF0000288 + || vaddr == CoredllDllMainFfff0288 + || IsC000StoreSkipVa(vaddr)); + bool exn15 = _leftoverWait99O32NkCoredllSawEntry + && _stk1670SbLogged + && !_exn15C28Logged + && (code == 2 || code == 3) + && (epc == CoredllDllMainExn15C28Epc + || epc == CoredllDllMainExn15C28Epc + 4); + bool destJal = _leftoverWait99O32NkCoredllSawEntry + && _abs6670JalTakenLogged + && !_abs6670DestExnLogged + && (code == 2 || code == 3) + && (epc == CoredllDllMainAbs6670Dest + || epc == CoredllDllMainStk2470Epc); + bool bada = _leftoverWait99O32NkCoredllSawEntry + && _abs6670JalTakenLogged + && !_badAExnLogged + && (code == 2 || code == 3) + && (epc == CoredllDllMainBadAEpc + || vaddr == CoredllDllMainBadABad); + // Live e7f0f37: after 15c28 leave, + // AfterLog>=2 dropped the next + // unclassified TLBL/TLBS. Name + // that miss once. Do not invent + // dest / 0x9A02 / ckseg. + bool exn15After = _leftoverWait99O32NkCoredllSawEntry + && _exn15C28Left + && !_exn15C28AfterExnLogged + && (code == 2 || code == 3) + && !exn15 && !c000 && !bada && !destJal + && !kdata && !sud && !jalr && !jalr1db0 + && !ri && !stk2470 && !stk1670 + && !abs1828 && !abs6670 + && !IsDumpMemRefuseVa(epc) + && !IsDumpMemRefuseVa(vaddr) + && epc != LeftoverWait99O32RefuseRa + && epc != LeftoverWait99GetProcDest + && vaddr != LeftoverWait99O32RefuseRa + && vaddr != LeftoverWait99GetProcDest; + if (slot) + { + TryResolveDdiNopProcessInfo(bus); + TryPlantLeftoverWait99GetProc(bus, regs); + } + if (page) + { + _coredllImageDemand = true; + TryResolveDdiNopCoredllImage(bus, epc); + } + if (kdata) + TryResolveFfffE000(bus, vaddr); + if (sud) + TryResolveFfffF000(bus, vaddr); + if (jalr) + TryResolveJalr7eb8(bus, vaddr); + if (jalr1db0) + TryResolveJalr1db0(bus, vaddr); + if (stk2470) + TryResolveStk2470(bus, vaddr); + if (c000) + TryResolveC0000088(bus, vaddr, regs); + if (bada) + TryResolveBadA(bus, vaddr, regs); + if (ri && _jalrRiLogged) + return; + if (_leftoverWait99O32NkCoredllSawEntry + && _leftoverWait99O32NkCoredllAfterLog >= 2 + && !kdata && !sud && !jalr && !jalr1db0 && !ri && !stk2470 + && !stk1670 && !abs1828 && !abs6670 && !c000 && !exn15 + && !exn15After && !destJal && !bada) + return; + string why = CoredllExnWhy(code); + uint slotWord = 0; + if (slot) + { + why = "exn-tlbl-slot"; + TryPeekCoredllDumpWord(bus, epc, out slotWord); + if (slotWord == 0 && epc == CoredllDllMainJalLwVa) + slotWord = CoredllDllMainJalLwWord; + } + else if (page) + { + why = "exn-tlbl-page"; + TryPeekCoredllDumpWord(bus, epc, out slotWord); + uint kseg = LookupCoredllImageKseg(epc); + if (slotWord == 0 && kseg != 0) + TryPeekWord(bus, kseg | (epc & 0xFFFu), out slotWord); + } + else if (kdata) + { + why = code == 3 ? "exn-tlbs-kdata" : "exn-tlbl-kdata"; + if (!TryPeekWord(bus, epc, out slotWord) && epc == CoredllDllMainKdataEpc) + slotWord = CoredllDllMainKdataInsn; + } + else if (sud) + { + why = code == 3 ? "exn-tlbs-sud" : "exn-tlbl-sud"; + TryPeekWord(bus, epc, out slotWord); + } + else if (jalr) + { + why = code == 2 && epc != vaddr ? "exn-tlbl-jalr" : CoredllExnWhy(code) + "-jalr"; + TryPeekWord(bus, epc, out slotWord); + } + else if (jalr1db0) + { + why = code == 2 && epc != vaddr ? "exn-tlbl-1db0" : CoredllExnWhy(code) + "-1db0"; + TryPeekWord(bus, epc, out slotWord); + } + else if (ri) + { + why = "exn-ri"; + if (!TryPeekWord(bus, epc, out slotWord)) + TryPeekWord(bus, epc - 4, out slotWord); + } + else if (stk2470) + { + why = code == 3 ? "exn-tlbs-stk" : "exn-tlbl-stk"; + if (!TryPeekWord(bus, epc, out slotWord) || slotWord == 0) + slotWord = CoredllDllMainStk2470Insn; + } + else if (stk1670) + { + why = code == 3 ? "exn-tlbs-1670" : "exn-tlbl-1670"; + if (!TryPeekWord(bus, epc, out slotWord)) + slotWord = 0; + } + else if (abs1828) + { + why = code == 3 ? "exn-tlbs-1828" : "exn-tlbl-1828"; + if (!TryPeekWord(bus, epc, out slotWord)) + slotWord = 0; + } + else if (abs6670) + { + why = code == 3 ? "exn-tlbs-6670" : "exn-tlbl-6670"; + if (!TryPeekWord(bus, epc, out slotWord)) + slotWord = 0; + } + else if (c000) + { + why = code == 3 ? "exn-tlbs-c000" : "exn-tlbl-c000"; + if (!TryPeekWord(bus, epc, out slotWord)) + slotWord = 0; + } + else if (exn15) + { + why = code == 3 ? "exn-tlbs-15c28" : "exn-tlbl-15c28"; + if (!TryPeekWord(bus, epc, out slotWord) || slotWord == 0) + slotWord = CoredllDllMainExn15C28Dump; + } + else if (exn15After) + { + why = code == 3 ? "exn-tlbs-15c28-after" : "exn-tlbl-15c28-after"; + if (!TryPeekWord(bus, epc, out slotWord)) + slotWord = 0; + } + else if (destJal) + { + why = code == 3 ? "exn-tlbs-4326c" : "exn-tlbl-4326c"; + if (!TryPeekWord(bus, epc, out slotWord) || slotWord == 0) + { + slotWord = epc == CoredllDllMainAbs6670Dest + ? CoredllDllMainStk2470Prev + : CoredllDllMainStk2470Insn; + } + } + else if (bada) + { + why = code == 3 ? "exn-tlbs-a" : "exn-tlbl-a"; + if (!TryPeekWord(bus, epc, out slotWord) || slotWord == 0) + slotWord = CoredllDllMainBadADump; + } + else if (_leftoverWait99O32NkCoredllSawEntry + && code == 2 && epc == 0 && vaddr == 0) + { + why = "exn-tlbl-pc0"; + } + uint pc0V0 = 0; + uint pc0T9 = 0; + uint pc0Ra = 0; + uint kdataPrev = 0; + uint kdataNext = 0; + string kdataDis = ""; + if (why == "exn-tlbl-pc0" || kdata || sud || jalr || jalr1db0 || ri || stk2470 || stk1670 || abs1828 || abs6670 || c000 || exn15 || exn15After || destJal || bada) + { + pc0V0 = PeekGpr(regs, 2); + pc0T9 = PeekGpr(regs, 25); + pc0Ra = PeekGpr(regs, 31); + } + if (kdata || sud || jalr || jalr1db0 || ri || stk2470 || stk1670 || abs1828 || abs6670 || c000 || exn15 || exn15After || destJal || bada) + { + kdataDis = slotWord != 0 + ? FormatMipsOp(epc, slotWord) + : "peek-miss"; + TryPeekWord(bus, epc - 4, out kdataPrev); + TryPeekWord(bus, epc + 4, out kdataNext); + if (ri && slotWord == 0 && kdataPrev != 0) + { + slotWord = kdataPrev; + kdataDis = FormatMipsOp(epc - 4, kdataPrev); + } + } + if (_leftoverWait99O32NkCoredllSawEntry) + _leftoverWait99O32NkCoredllAfterLog++; + else + _leftoverWait99O32NkCoredllExnLog = true; + _leftoverWait99O32NkChainLast = vector ^ CoredllDllMainVa; + _leftoverWait99O32NkChainVia = why; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + vector.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + CoredllDllMainVa.ToString("X") + + " cause=" + code + + " epc=0x" + epc.ToString("X") + + " bad=0x" + vaddr.ToString("X") + + (slot || page || kdata || sud || jalr || jalr1db0 || ri || stk2470 || stk1670 || abs1828 || abs6670 || c000 || exn15 || exn15After || destJal || bada ? " word=0x" + slotWord.ToString("X") : "") + + ((why == "exn-tlbl-pc0" || kdata || sud || jalr || jalr1db0 || ri || stk2470 || stk1670 || abs1828 || abs6670 || c000 || exn15 || exn15After || destJal || bada) + ? " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + : "") + + (jalr1db0 && slotWord != 0 + ? " rs=" + ((slotWord >> 21) & 31).ToString() + : "") + + (ri ? " cause=ri" : "") + + " via=" + why); + if (kdata) + { + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-e000 sb" + + " dis=" + kdataDis + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + + (pc0V0 == 0 ? " sb-zero" : "") + + (pc0T9 == CoredllDllMainKdataT9 ? " t9-tlbr" : "") + + " (l2=0; NK wired KData pair C000/D000; never wired E000/F000; do not invent dest)"); + } + if (sud) + { + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk ffff-f000 load" + + " dis=" + kdataDis + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + + " (SharedUserData+0xE54; never-wired F000 pair; no alias; do not invent dest)"); + } + if (jalr) + { + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-7eb8 load" + + " dis=" + kdataDis + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + + " (data TLBL bad=0x7EB8 at jalr dest; t9-low=0x7EB8; not I-fetch; do not invent dest)"); + } + if (jalr1db0) + { + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-1db0 load" + + " dis=" + kdataDis + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + + (slotWord != 0 ? " rs=" + ((slotWord >> 21) & 31).ToString() : "") + + " (data TLBL bad=0x1DB0 at sec0; useg abs; not I-fetch; do not invent dest)"); + } + if (stk2470) + { + uint rs = slotWord != 0 ? ((slotWord >> 21) & 31) : 0; + uint rt = slotWord != 0 ? ((slotWord >> 16) & 31) : 0; + int off = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint bas = PeekGpr(regs, (int)rs); + uint a2 = PeekGpr(regs, 6); + uint sp = PeekGpr(regs, 29); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk stk-2470 store" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " off=" + off.ToString() + + " base=0x" + bas.ToString("X") + + " sp=0x" + sp.ToString("X") + + " a2=0x" + a2.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + + (IsMipsStore(slotWord) ? " store" : "") + + " (live sb $a0,0x2470($0); dump sw $a2,8($sp); once; do not invent dest)"); + _stk2470ExnLogged = true; + } + if (stk1670) + { + uint rs = slotWord != 0 ? ((slotWord >> 21) & 31) : 0; + uint rt = slotWord != 0 ? ((slotWord >> 16) & 31) : 0; + int off = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint bas = PeekGpr(regs, (int)rs); + uint a3 = PeekGpr(regs, 7); + uint fp = PeekGpr(regs, 30); + bool liveAbs = IsMipsStore(slotWord) && rs == 0 + && (off & 0xFFFF) == (CoredllDllMainStk1670Bad & 0xFFFF); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk nest-1670 store" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + CoredllDllMainStk1670Insn.ToString("X") + + " dump-dis=sb a3,443(v0)" + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " off=" + off.ToString() + + " base=0x" + bas.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " a3=0x" + a3.ToString("X") + + " fp=0x" + fp.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + (liveAbs ? " live-abs" : "") + + (slotWord == CoredllDllMainStk1670Insn ? " dump-match" : "") + + " (dump sb $a3,443($v0) not stack-rel; no rewrite;" + + " do not invent page 0x1000)"); + _stk1670Logged = true; + } + if (abs1828) + { + uint rs = slotWord != 0 ? ((slotWord >> 21) & 31) : 0; + uint rt = slotWord != 0 ? ((slotWord >> 16) & 31) : 0; + int off = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint bas = PeekGpr(regs, (int)rs); + uint fp = PeekGpr(regs, 30); + uint dumpw = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out dumpw) || dumpw == 0) + dumpw = CoredllDllMainAbs1828Dump; + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-1828 store" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + dumpw.ToString("X") + + " dump-dis=" + FormatMipsOp(epc, dumpw) + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " off=" + off.ToString() + + " base=0x" + bas.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " fp=0x" + fp.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " (dump lw $t4,0($fp); live abs rs=0; via=dump-mem;" + + " do not invent page 0x1000)"); + _abs1828ExnLogged = true; + } + if (abs6670) + { + uint rs = slotWord != 0 ? ((slotWord >> 21) & 31) : 0; + uint rt = slotWord != 0 ? ((slotWord >> 16) & 31) : 0; + int off = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint bas = PeekGpr(regs, (int)rs); + uint fp = PeekGpr(regs, 30); + uint dumpw = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out dumpw) || dumpw == 0) + dumpw = CoredllDllMainAbs6670Dump; + bool liveAbs = IsMipsStore(slotWord) && rs == 0 + && (off & 0xFFFF) == (CoredllDllMainAbs6670Bad & 0xFFFF); + string whySkip = !IsMipsStore(slotWord) ? "not-a-memop" + : (rs != 0 ? "rs!=0" + : (slotWord == dumpw ? "dump-already-matches" + : "dump-mem-miss")); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-6670 store" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + dumpw.ToString("X") + + " dump-dis=" + FormatMipsOp(epc, dumpw) + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " off=" + off.ToString() + + " base=0x" + bas.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " fp=0x" + fp.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + (liveAbs ? " live-abs" : "") + + (slotWord == dumpw ? " dump-match" : "") + + " via=exn-tlbs-6670 reason=" + whySkip + + " (dump jal 0x" + CoredllDllMainAbs6670Dest.ToString("X") + + "; no page 0x6000 invent)"); + _abs6670ExnLogged = true; + } + if (c000) + { + uint rs = slotWord != 0 ? ((slotWord >> 21) & 31) : 0; + uint rt = slotWord != 0 ? ((slotWord >> 16) & 31) : 0; + int off = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint bas = PeekGpr(regs, (int)rs); + uint a0 = PeekGpr(regs, 4); + uint a1 = PeekGpr(regs, 5); + uint dumpw = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out dumpw) || dumpw == 0) + dumpw = CoredllDllMainC000Dump; + uint a0w = 0; + bool a0ok = a0 != 0 && TryPeekWord(bus, a0, out a0w); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk c000-0088 store" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + dumpw.ToString("X") + + " dump-dis=" + FormatMipsOp(epc, dumpw) + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " off=" + off.ToString() + + " base=0x" + bas.ToString("X") + + " a0=0x" + a0.ToString("X") + + " a1=0x" + a1.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + (a0ok ? " *a0=0x" + a0w.ToString("X") : " *a0-miss") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + (slotWord == dumpw ? " dump-match" : "") + + " via=exn-tlbs-c000" + + " (dump sw $v0,0($a1); no invent 0xC0000000)"); + _c000ExnLogged = true; + } + if (exn15) + { + uint dumpw = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out dumpw) || dumpw == 0) + dumpw = CoredllDllMainExn15C28Dump; + uint sp = PeekGpr(regs, 29); + uint fp = PeekGpr(regs, 30); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk genex-15c28" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + dumpw.ToString("X") + + " dump-dis=" + FormatMipsOp(epc, dumpw) + + " sp=0x" + sp.ToString("X") + + " fp=0x" + fp.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + (slotWord == dumpw ? " dump-match" : "") + + " via=exn-tlbs-15c28" + + " (dump sw $ra,284($sp); fallthrough; no invent dest)"); + _exn15C28Logged = true; + } + if (exn15After) + { + uint afterDumpW = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out afterDumpW)) + afterDumpW = 0; + uint afterSp2 = PeekGpr(regs, 29); + uint afterFp = PeekGpr(regs, 30); + uint afterRs2 = slotWord != 0 ? ((slotWord >> 21) & 31) : 0; + uint afterRt2 = slotWord != 0 ? ((slotWord >> 16) & 31) : 0; + int afterOff2 = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint afterBas2 = PeekGpr(regs, (int)afterRs2); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-15c28 after-exn" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + (afterDumpW != 0 ? " dump=0x" + afterDumpW.ToString("X") : "") + + (afterDumpW != 0 ? " dump-dis=" + FormatMipsOp(epc, afterDumpW) : "") + + " rs=" + afterRs2.ToString() + + " rt=" + afterRt2.ToString() + + " off=" + afterOff2.ToString() + + " base=0x" + afterBas2.ToString("X") + + " sp=0x" + afterSp2.ToString("X") + + " fp=0x" + afterFp.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " via=" + why + + " (first TLB after leave; honor ra; no invent dest)"); + _exn15C28AfterExnLogged = true; + } + if (destJal) + { + uint dumpw = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out dumpw) || dumpw == 0) + { + dumpw = epc == CoredllDllMainAbs6670Dest + ? CoredllDllMainStk2470Prev + : CoredllDllMainStk2470Insn; + } + uint sp = PeekGpr(regs, 29); + uint a1 = PeekGpr(regs, 5); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk abs-6670 dest-exn" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + dumpw.ToString("X") + + " dump-dis=" + FormatMipsOp(epc, dumpw) + + " sp=0x" + sp.ToString("X") + + " a1=0x" + a1.ToString("X") + + " v0=0x" + pc0V0.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + (slotWord == dumpw ? " dump-match" : "") + + " via=exn-tlbs-4326c" + + " (dump sw $a1,4($sp); after jal; no invent dest)"); + _abs6670DestExnLogged = true; + } + if (bada) + { + uint dumpw = 0; + if (!TryPeekLeftoverWait99DumpOnly(epc, out dumpw) || dumpw == 0) + dumpw = CoredllDllMainBadADump; + uint rs = slotWord != 0 ? ((slotWord >> 21) & 31) : 5; + uint rt = slotWord != 0 ? ((slotWord >> 16) & 31) : 3; + int off = slotWord != 0 ? (short)(slotWord & 0xFFFF) : 0; + uint bas = PeekGpr(regs, (int)rs); + uint a0 = PeekGpr(regs, 4); + uint a1 = PeekGpr(regs, 5); + uint sp = PeekGpr(regs, 29); + uint basew = 0; + bool baseOk = bas != 0 && (bas & 3) == 0 + && !IsC000RefuseKseg(bas & ~0xFFFu) + && TryPeekWord(bus, bas, out basew); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk bad-a load" + + " dis=" + kdataDis + + " word=0x" + slotWord.ToString("X") + + " dump=0x" + dumpw.ToString("X") + + " dump-dis=" + FormatMipsOp(epc, dumpw) + + " rs=" + rs.ToString() + + " rt=" + rt.ToString() + + " off=" + off.ToString() + + " base=0x" + bas.ToString("X") + + (baseOk ? " *base=0x" + basew.ToString("X") : " *base-miss") + + " v0=0x" + pc0V0.ToString("X") + + " a0=0x" + a0.ToString("X") + + " a1=0x" + a1.ToString("X") + + " sp=0x" + sp.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + (slotWord == dumpw ? " dump-match" : "") + + " via=exn-tlbl-a" + + " (dump lhu $v1,0($a1); VA=0xA; no invent page 0)"); + _badAExnLogged = true; + } + if (ri) + { + _jalrRiLogged = true; + uint caller = 0; + TryPeekWord(bus, CoredllDllMainRiRa, out caller); + uint at = PeekGpr(regs, 1); + uint s0 = PeekGpr(regs, 16); + uint fp = PeekGpr(regs, 30); + uint s2 = PeekGpr(regs, 18); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-ri" + + " dis=" + kdataDis + + " prev=0x" + kdataPrev.ToString("X") + + " next=0x" + kdataNext.ToString("X") + + " ra=0x" + pc0Ra.ToString("X") + + " caller=0x" + CoredllDllMainRiRa.ToString("X") + + (caller != 0 ? " caller-word=0x" + caller.ToString("X") + + " caller-dis=" + FormatMipsOp(CoredllDllMainRiRa, caller) : "") + + " v0=0x" + pc0V0.ToString("X") + + " t9=0x" + pc0T9.ToString("X") + + " at=0x" + at.ToString("X") + + " s0=0x" + s0.ToString("X") + + " s2=0x" + s2.ToString("X") + + " fp=0x" + fp.ToString("X") + + " cause=ri" + + " (fn=0x16 reserved not MUL; not ri-nop; no cache)"); + uint thr = 0; + uint s0w = 0; + uint s0w4 = 0; + uint s0stk = 0; + uint fpw = 0; + uint s7 = PeekGpr(regs, 23); + bool s2Thr = s2 == ThreadPtr; + bool s2ok = TryPeekWord(bus, s2, out thr); + bool s2s0 = s2ok && thr == s0 && s0 != 0; + bool s0ok = TryPeekWord(bus, s0, out s0w); + bool s0ok4 = s0 != 0 && TryPeekWord(bus, s0 + 4, out s0w4); + bool s0stkOk = s0 != 0 && TryPeekWord(bus, s0 + ThreadStack, out s0stk); + bool fpok = TryPeekWord(bus, fp, out fpw); + uint prev8 = 0; + uint next8 = 0; + TryPeekWord(bus, epc - 8, out prev8); + TryPeekWord(bus, epc + 8, out next8); + BootLog.Write("[Hive] ExtraROM leftover-wait99-o32-nk jalr-ri regs" + + (s2Thr ? " s2=ThreadPtr" : " s2=0x" + s2.ToString("X")) + + (s2s0 ? " s2=s0-thr" : "") + + (s2ok ? " *s2=0x" + thr.ToString("X") : " *s2-miss") + + (s0ok ? " *s0=0x" + s0w.ToString("X") : " *s0-miss") + + (s0ok && s0w == CoredllDllMainRiThrW0 ? " thr-w0=0x40" : "") + + (s0ok4 ? " *s0+4=0x" + s0w4.ToString("X") : "") + + (s0stkOk ? " *s0+24=0x" + s0stk.ToString("X") : "") + + (fpok ? " *fp=0x" + fpw.ToString("X") : " *fp-miss") + + " s7=0x" + s7.ToString("X") + + " prev8=0x" + prev8.ToString("X") + + " next8=0x" + next8.ToString("X") + + " (I-fetch dest-data; caller lw *s2; not helper; not MUL; not ri-nop)"); + } + } + + private static void TryNoteLeftoverWait99O32NkCoredllAfter(MipsBus bus, + uint[] regs, uint pc) + { + if (!_leftoverWait99O32NkCoredllSawEntry) + return; + if (pc == CallDllAfterJalr) + { + if (_leftoverWait99O32NkCoredllRetLog) + return; + _leftoverWait99O32NkCoredllRetLog = true; + uint v0 = PeekGpr(regs, 2); + bool threw; + uint word = PeekDestWordRaw(bus, CoredllDllMainVa, out threw); + WriteCoredllAfterChain(pc, CoredllDllMainVa, word, "ret"); + return; + } + if (_leftoverWait99O32NkCoredllAfterLog >= 2) + return; + if (pc == CallDllEntry || pc == CallDllStartip + || pc == XipDllCallDllJal || pc == LoadO32WrapStartip + || pc == CoredllDllMainVa || pc == CoredllDllMainJalVa) + return; + string why; + uint peekVa = pc; + if (pc == LeftoverWait99GetProcDest) + why = "leftover-getproc"; + else if (pc == LeftoverWait99O32RefuseRa + || IsLeftoverBindRefuse(pc)) + why = "leftover-refuse"; + else if (pc >= CoredllSharedLo && pc < CoredllSharedHi) + { + if (pc == _leftoverWait99O32NkCoredllBodyPc) + { + _leftoverWait99O32NkCoredllSpin++; + if (_leftoverWait99O32NkCoredllSpin != 64) + return; + why = "spin"; + } + else + { + _leftoverWait99O32NkCoredllSpin = 0; + _leftoverWait99O32NkCoredllBodyPc = pc; + if (_leftoverWait99O32NkCoredllAfterLog != 0) + return; + why = "body"; + } + } + else + return; + bool threwWord = false; + uint word2 = 0; + if (peekVa != 0 && (peekVa & 3) == 0 + && peekVa != LeftoverWait99GetProcDest) + word2 = PeekDestWordRaw(bus, peekVa, out threwWord); + if (why == "body") + { + if (threwWord) + why = "unmap"; + else if (word2 == 0) + why = "empty"; + } + WriteCoredllAfterChain(pc, CoredllDllMainVa, word2, why); + } + + private static void WriteCoredllAfterChain(uint pc, uint startip, + uint word, string why) + { + if (why == "ret") + _leftoverWait99O32NkCoredllSawCall = true; + _leftoverWait99O32NkCoredllAfterLog++; + _leftoverWait99O32NkChainLast = pc ^ startip; + _leftoverWait99O32NkChainVia = why; + _leftoverWait99O32NkChainName = "coredll.dll"; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=coredll.dll" + + " startip=0x" + startip.ToString("X") + + " word=0x" + word.ToString("X") + + " via=" + why); + } + + // Live e65e45c named 0x80061CA0 osaxst0 + // (MODULE+8), not coredll. Live b52708e + // planted 0x03F57A00 via=startip; CallDLL + // never jalr'd. Feed MODULE+0x5C before + // 0x80018B34 like Hdstub. Do not plant + // osaxst0/osaxst1/kd/kcover. Do not + // leftover-hop dest. Keep Hdstub + // jalr+after. Do not reattribute + // 0x80061CA0. + private static bool IsNkChainName(string name) + { + return NamesMatchRom(name, "osaxst0.dll") + || NamesMatchRom(name, "coredll.dll") + || NamesMatchRom(name, "filesys.exe") + || NamesMatchRom(name, "filesys.dll") + || NamesMatchRom(name, "fsdmgr.dll"); + } + + private static bool IsHonestTocMissName(string name) + { + return NamesMatchRom(name, "osaxst1.dll") + || NamesMatchRom(name, "kd.dll") + || NamesMatchRom(name, "kcover.dll"); + } + + private static bool IsChainCallVa(uint va) + { + if (va == 0 || va == HdDllEntryVa || va == HdDllInitVa + || va == HdDllEntryRva || IsWrapDestSize(va) + || IsWrapDestFp50Va(va) || IsHdDllImageBase(va) + || IsLeftoverBindRefuse(va) || IsLeftoverDestVa(va)) + return false; + if (va == ChainCallVaLive) + return true; + if (_leftoverWait99O32NkChainCallVa != 0 + && va == _leftoverWait99O32NkChainCallVa) + return true; + if (_leftoverWait99O32NkCoredllStartip != 0 + && va == _leftoverWait99O32NkCoredllStartip) + return true; + if (va == CoredllDllMainVa) + return true; + return false; + } + + private static bool IsCoredllBasePtr(uint p50) + { + if (p50 == CoredllSharedLo) + return true; + return p50 >= CoredllSharedLo && p50 < CoredllSharedHi; + } + + private static string PeekNkModuleName(MipsBus bus, uint mod) + { + if (bus == null || mod == 0 || (mod & 3) != 0 + || IsLeftoverBindRefuse(mod) || IsWrapDestSize(mod) + || IsWrapDestFp50Va(mod) || IsHdDllImageBase(mod) + || IsLeftoverDestVa(mod) || mod == HdDllEntryVa) + return ""; + uint np = 0; + if (TryPeekWord(bus, mod + ModuleLpszName, out np) && np != 0 + && (np & 1) == 0 && !IsLeftoverBindRefuse(np) + && !IsWrapDestSize(np) && !IsLeftoverDestVa(np)) + { + string utf = ""; + try + { + utf = ReadUtf16Name(bus, np); + } + catch + { + } + if (IsWrapDllName(utf) || IsNkChainName(utf) + || NamesMatchRom(utf, "filesys.exe")) + return utf; + } + string inline = ""; + try + { + inline = ReadUtf16Name(bus, mod + ModuleLpszName); + } + catch + { + } + if (IsWrapDllName(inline) || IsNkChainName(inline) + || NamesMatchRom(inline, "filesys.exe")) + return inline; + return ""; + } + + private static string PeekNkChainName(MipsBus bus, uint[] regs, + uint pc, uint mod, uint p50, uint startip) + { + string fromMod = PeekNkModuleName(bus, mod); + if (fromMod.Length > 1) + return fromMod; + if (mod != 0 && _coredllModule != 0 && mod == _coredllModule) + return "coredll.dll"; + if (IsCoredllBasePtr(p50) + || (IsChainCallVa(startip) && IsCoredllBasePtr(p50))) + return "coredll.dll"; + string bind = PeekWrapBindLibName(bus, regs, pc); + if (IsNkChainName(bind) || IsHonestTocMissName(bind) + || IsWrapDllName(bind)) + return bind; + if (IsNkChainName(_nkLoadO32Name)) + return _nkLoadO32Name; + if (IsNkChainName(_nkLoadE32Name)) + return _nkLoadE32Name; + if (IsHdDllBindName(_leftoverWait99O32NkBindName)) + return ""; + return bind; + } + + private static void TryNoteLeftoverWait99O32NkChain(MipsBus bus, + uint[] regs, uint pc) + { + if (!_leftoverWait99O32NkJalrSawTarget) + return; + if (pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99GetProcDest + || IsLeftoverBindRefuse(pc) + || IsWrapDestFp50Va(pc) + || IsHdDllImageBase(pc) + || pc == HdDllEntryVa || pc == HdDllInitVa + || IsWrapDestSize(pc) + || pc == HdDllEntryRva) + return; + bool atTarget = IsChainCallVa(pc); + bool atCall = pc == CallDllStartip || pc == CallDllEntry + || pc == CallDllAfterJalr || pc == XipDllCallDllJal + || pc == XipCallDllUsegChk || pc == LoadO32WrapStartip; + bool atBind = pc == BindImpHdr || pc == BindImpDllName + || pc == BindImpLoadLib || pc == BindImpLoadLibRet; + if (!atTarget && !atCall && !atBind) + return; + uint mod = PeekGpr(regs, 4); + if (mod == 0 || IsHdDllImageBase(mod) || IsLeftoverBindRefuse(mod) + || IsWrapDestSize(mod) || IsWrapDestFp50Va(mod) + || IsLeftoverDestVa(mod) || mod == HdDllEntryVa) + mod = PeekGpr(regs, 30); + uint startip = 0; + uint p50 = 0; + if (mod != 0 && !IsHdDllImageBase(mod) + && !IsLeftoverBindRefuse(mod) && !IsWrapDestSize(mod) + && !IsWrapDestFp50Va(mod) && !IsLeftoverDestVa(mod) + && mod != HdDllEntryVa && mod != HdDllInitVa) + { + TryPeekWord(bus, mod + ModuleStartip, out startip); + TryPeekWord(bus, mod + ProcModule, out p50); + } + if (!atTarget && startip == 0 && mod != 0 + && (IsCoredllBasePtr(p50) || mod == _coredllModule)) + { + uint planted = TryPlantCoredllStartip(bus, mod); + if (IsCoredllStartipVa(planted)) + startip = planted; + } + if (atTarget) + startip = pc; + if (startip == HdDllEntryVa || startip == HdDllInitVa + || IsHdDllImageBase(startip) || IsLeftoverBindRefuse(startip) + || IsWrapDestSize(startip) || startip == HdDllEntryRva) + { + if (atCall && !atTarget) + return; + startip = 0; + } + if (IsChainCallVa(startip) && _leftoverWait99O32NkChainCallVa == 0) + _leftoverWait99O32NkChainCallVa = startip; + string name = PeekNkChainName(bus, regs, pc, mod, p50, startip); + if (IsHdDllBindName(name) + && !(pc == XipCallDllUsegChk + && _leftoverWait99O32NkCoredllStartip != 0)) + return; + string fromMod = PeekNkModuleName(bus, mod); + if (mod != 0 && !IsHdDllImageBase(mod) + && !IsLeftoverBindRefuse(mod) && !IsWrapDestSize(mod) + && !IsLeftoverDestVa(mod) + && (NamesMatchRom(fromMod, "coredll.dll") + || (NamesMatchRom(name, "coredll.dll") + && IsCoredllBasePtr(p50)))) + { + if (_coredllModule == 0) + _coredllModule = mod; + if (!atTarget && startip == 0) + { + uint planted = TryPlantCoredllStartip(bus, mod); + if (IsCoredllStartipVa(planted)) + startip = planted; + } + } + uint jalrDest = 0; + uint insn = 0; + uint rs; + if (TryPeekWord(bus, pc, out insn) && IsJalrInsn(insn, out rs)) + jalrDest = PeekGpr(regs, (int)rs); + if (jalrDest == HdDllEntryVa || jalrDest == HdDllInitVa) + return; + if (IsChainCallVa(jalrDest) && _leftoverWait99O32NkChainCallVa == 0) + _leftoverWait99O32NkChainCallVa = jalrDest; + uint s5 = PeekS5(regs); + bool mapped = true; + uint word = 0; + uint peekVa = atTarget ? pc : (IsChainCallVa(startip) ? startip : 0); + if (peekVa != 0) + { + bool threw; + word = PeekDestWordRaw(bus, peekVa, out threw); + mapped = !threw; + } + string why; + if (atTarget) + { + if (!mapped) + why = "unmap"; + else if (word == 0) + why = "empty"; + else + why = "entry"; + } + else if (IsHonestTocMissName(name)) + why = "toc-miss"; + else if (pc == XipCallDllUsegChk + && (_leftoverWait99O32NkCoredllStartip != 0 + || NamesMatchRom(name, "coredll.dll"))) + { + uint fp = PeekGpr(regs, 30); + if (!IsCoredllCallDllModule(bus, fp)) + why = "fp-miss"; + else if (IsCallDllSkipUseg(p50)) + why = "useg-skip"; + else if ((s5 & WrapS5CallDll) == 0) + why = "s5-skip"; + else + why = "useg"; + } + else if (pc == XipCallDllUsegChk && mod != 0 + && IsCallDllSkipUseg(p50)) + why = "useg-skip"; + else if (pc == LoadO32WrapStartip && startip == 0) + why = "startip-skip-0"; + else if (pc == LoadO32WrapStartip) + why = "startip"; + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && (IsChainCallVa(jalrDest) || IsChainCallVa(startip))) + why = "calldll"; + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && (jalrDest != 0 || startip != 0) + && (IsNkChainName(name) || name.Length > 1)) + why = "calldll"; + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && startip == 0 && jalrDest == 0) + why = "startip-0"; + else if (pc == CallDllAfterJalr + && (IsChainCallVa(startip) || _leftoverWait99O32NkChainSawEntry)) + { + if (NamesMatchRom(name, "coredll.dll") + && !_leftoverWait99O32NkCoredllSawEntry) + return; + why = "ret"; + } + else if (atBind && name.Length > 1) + why = "bindlib"; + else if ((pc == CallDllStartip || pc == CallDllEntry + || pc == XipDllCallDllJal) + && (s5 & WrapS5CallDll) == 0) + why = "s5-skip"; + else + return; + if (why == "fp-miss" || why == "miss-calldll") + name = "coredll.dll"; + bool keep = atTarget || why == "calldll" || why == "ret" + || why == "entry" || why == "empty" || why == "unmap" + || why == "fp-miss" || why == "useg-skip" || why == "s5-skip" + || why == "miss-calldll" + || NamesMatchRom(name, "coredll.dll") + || NamesMatchRom(name, "filesys.exe") + || NamesMatchRom(name, "filesys.dll") + || NamesMatchRom(name, "fsdmgr.dll"); + if (!keep && _leftoverWait99O32NkChainLog >= 4) + return; + if (!keep && NamesMatchRom(name, "osaxst0.dll") + && startip == 0 && (why == "bindlib" || why == "loade32" + || why == "startip-0")) + return; + if (!IsNkChainName(name) && !IsHonestTocMissName(name) + && !atTarget && why != "calldll" && why != "startip-0" + && why != "ret" && why != "startip" && why != "entry" + && why != "fp-miss" && why != "useg-skip" + && why != "s5-skip" && why != "miss-calldll") + return; + if (name.Length == 0) + name = "-"; + uint key = pc ^ startip; + if (key == _leftoverWait99O32NkChainLast + && why == _leftoverWait99O32NkChainVia + && name == _leftoverWait99O32NkChainName) + return; + if (atTarget) + _leftoverWait99O32NkChainSawEntry = true; + if (atTarget && NamesMatchRom(name, "coredll.dll") + && IsCoredllStartipVa(pc)) + { + _leftoverWait99O32NkCoredllSawEntry = true; + _leftoverWait99O32NkCoredllRetLog = false; + _leftoverWait99O32NkCoredllAfterLog = 0; + _leftoverWait99O32NkCoredllBodyPc = 0; + _leftoverWait99O32NkCoredllSpin = 0; + } + if (NamesMatchRom(name, "coredll.dll") && why == "startip") + _leftoverWait99O32NkCoredllSawStartip = true; + if (why == "calldll" || why == "entry" + || (why == "ret" && _leftoverWait99O32NkCoredllSawEntry)) + _leftoverWait99O32NkCoredllSawCall = true; + _leftoverWait99O32NkChainLast = key; + _leftoverWait99O32NkChainVia = why; + _leftoverWait99O32NkChainName = name; + if (!keep) + _leftoverWait99O32NkChainLog++; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x" + + pc.ToString("X8") + + " name=" + name + + " startip=0x" + startip.ToString("X") + + " word=0x" + word.ToString("X") + + " via=" + why); + } + + private static void TryNoteLeftoverWait99O32NkChainLoad(MipsBus bus, + string name) + { + if (!_leftoverWait99O32NkJalrSawTarget) + return; + if (string.IsNullOrEmpty(name) || IsHdDllBindName(name)) + return; + if (NamesMatchRom(name, "coredll.dll") && _coredllModule != 0) + TryPlantCoredllStartip(bus, _coredllModule); + string why; + if (IsHonestTocMissName(name)) + why = "toc-miss"; + else if (NamesMatchRom(name, "coredll.dll") + || NamesMatchRom(name, "filesys.exe") + || NamesMatchRom(name, "filesys.dll") + || NamesMatchRom(name, "fsdmgr.dll")) + why = "loade32"; + else if (IsNkChainName(name)) + why = "loade32"; + else + return; + bool keep = NamesMatchRom(name, "coredll.dll") + || NamesMatchRom(name, "filesys.exe") + || NamesMatchRom(name, "filesys.dll") + || NamesMatchRom(name, "fsdmgr.dll"); + if (!keep && _leftoverWait99O32NkChainLog >= 4) + return; + if (!keep && NamesMatchRom(name, "osaxst0.dll")) + return; + uint key = 0xE32u ^ (uint)name.Length; + if (key == _leftoverWait99O32NkChainLast + && why == _leftoverWait99O32NkChainVia + && name == _leftoverWait99O32NkChainName) + return; + _leftoverWait99O32NkChainLast = key; + _leftoverWait99O32NkChainVia = why; + _leftoverWait99O32NkChainName = name; + if (!keep) + _leftoverWait99O32NkChainLog++; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-nk-chain pc=0x0" + + " name=" + name + + " startip=0x0" + + " word=0x0" + + " via=" + why); + } + + // Live 92eb906 leftover-wait99-o32-halt + // dump-sp1c leftover dest 0x03F74DEC via + // refuse. wrap $ra frame already leftover. + // Observe the first dump-true AFBF001C + // sw $ra,0x1C($sp) at wrap entry + // 0x03F716F4 / dump 0x800956F4, and + // leftover dest 0x03F74DE0 neighborhood + // when that word is AFBF001C. Incoming + // $ra is the original saved return before + // residue overwrites $sp+0x1C. + // leftover-wait99-o32-cont only dest-live + // NK LoadO32 / BindImp / wrap-copy dest- + // fp50 / wrap-copy-ret. dest-e32=0x1B0C + // is SIZE not dest-live hop. leftover- + // wrap-after-copy is leftover jal INTO + // wrap residue after CopyO32 dest fill. + // leftover dest 0x03F74DEC / leftover dest + // GetProc dest 0x8008C844 leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. Do not hop dest-e32 size. + // Live db3d277 first AFBF001C already + // leftover $ra; dump-sp1c=0. Prefer + // leftover-wait99-o32-ra-src at $ra-8. + private static bool TryLeftoverWait99O32FirstSwRa(MipsBus bus, + uint[] regs, ref uint pc) + { + if (_leftoverWait99O32SwLogged) + { + if (_leftoverWait99O32HaltLogged + && IsLeftoverWait99O32FirstSwSite(pc)) + return true; + return false; + } + if ((pc & 3) != 0 || !IsLeftoverWait99O32FirstSwSite(pc)) + return false; + uint word = 0; + if (!TryPeekLeftoverWait99WrapWord(bus, pc, out word)) + TryPeekWord(bus, pc, out word); + int off; + if (word != LeftoverWait99WrapSwRaWord + && (!IsSwRaSp(word, out off) + || off != LeftoverWait99WrapRaOff)) + return false; + uint ra = PeekGpr(regs, 31); + uint destOfRa = LeftoverWait99DestOf(ra); + if (ra == LeftoverWait99O32RefuseRa + || ra == LeftoverWait99GetProcDest + || destOfRa == LeftoverWait99GetProcDest + || destOfRa == LeftoverWait99O32RefuseRa + || !IsLeftoverWait99O32Caller(ra)) + { + string via = "refuse-0x" + ra.ToString("X8"); + if (ra == 0 || ra == 0xFFFFFFFFu) + via = "miss-ra"; + TryNoteLeftoverWait99O32SwHalt(bus, regs, pc, ra, destOfRa, + via); + return true; + } + TryLeftoverWait99O32PopWrapFrame(bus, regs, pc); + if (regs != null && regs.Length > 31) + regs[31] = ra; + uint dest = ra; + pc = dest; + TryNoteLeftoverWait99O32ContFromSw(dest, "sw-1c"); + return true; + } + + private static bool IsLeftoverWait99O32FirstSwSite(uint pc) + { + if (pc == LeftoverWait99WrapSw + || pc == LeftoverWait99WrapDumpSw) + return true; + if (pc >= LeftoverWait99O32RefusePrologue + && pc < LeftoverWait99O32RefusePrologue + 0x20) + return true; + uint destLo = LeftoverWait99DestOf(LeftoverWait99O32RefusePrologue); + if (destLo != 0 && pc >= destLo && pc < destLo + 0x20) + return true; + return false; + } + + private static void TryLeftoverWait99O32PopWrapFrame(MipsBus bus, + uint[] regs, uint pc) + { + if (regs == null || regs.Length <= 29) + return; + uint prev = 0; + if (!TryPeekLeftoverWait99WrapWord(bus, pc - 4, out prev) + && !TryPeekWord(bus, pc - 4, out prev)) + return; + int n; + if (!IsAddiuSpNeg(prev, out n) || n != LeftoverWait99WrapFrame) + return; + uint sp = PeekGpr(regs, 29); + if (!IsLeftoverWait99WrapStackVa(sp)) + return; + regs[29] = sp + (uint)LeftoverWait99WrapFrame; + } + + private static void TryNoteLeftoverWait99O32ContFromSw(uint dest, + string via) + { + if (_leftoverWait99O32ContLogged) + return; + _leftoverWait99O32SwLogged = true; + _leftoverWait99O32ContLogged = true; + _leftoverWait99WrapRaContLogged = true; + _wait99PlantFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-cont ra=0x" + + LeftoverWait99WrapSw.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " via=" + via + + " (dump dest-live NK LoadO32 / BindImp $ra first AFBF001C; refuse leftover dest GetProc dest leftover hop)"); + } + + private static void TryNoteLeftoverWait99O32SwHalt(MipsBus bus, + uint[] regs, uint pc, uint ra, uint destOfRa, string via) + { + _leftoverWait99O32SwLogged = true; + if (_leftoverWait99O32HaltLogged) + return; + _leftoverWait99O32HaltLogged = true; + _leftoverWait99WrapRaContLogged = true; + uint src = 0; + uint srcw = 0; + string srcVia = via; + if ((ra & 3) == 0 && ra >= 8) + { + src = ra - 8; + if (TryPeekLeftoverWait99O32RaSrcWord(bus, src, out srcw) + || TryPeekWord(bus, src, out srcw)) + srcVia = LeftoverWait99O32RaSrcViaOf(srcw); + } + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-sw-halt pc=0x" + + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " src=0x" + src.ToString("X8") + + " srcw=0x" + srcw.ToString("X8") + + " dest=0x" + destOfRa.ToString("X8") + + " via=" + srcVia); + } + + // Live 0142875 leftover-wait99-o32-halt + // ra=0x03F71740 dump-pro=0x27BDFFE0 + // dump-sw=useg-sw=0xAFBF001C via=refuse- + // 0x03F74DEC dest=0. dump-pro is addiu + // $sp,-32. dump-sw is sw $ra,0x1C($sp). + // $sp+0x1C is leftover dest, not LoadO32. + // Live 92eb906 wrap $ra frame already + // leftover dest. leftover-wait99-o32-cont + // prefers first AFBF001C incoming $ra. + // leftover dest GetProc dest leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. + private static bool TryLeftoverWait99O32ResumeFromWrap(MipsBus bus, + uint[] regs, out uint dest, out string via) + { + dest = 0; + via = ""; + if (!TryPeekLeftoverWait99O32FrameDest(bus, regs, out dest, out via)) + return false; + if (regs != null && regs.Length > 31) + regs[31] = dest; + if (regs != null && regs.Length > 29) + { + uint sp = PeekGpr(regs, 29); + if (IsLeftoverWait99WrapStackVa(sp)) + regs[29] = sp + (uint)LeftoverWait99WrapFrame; + } + int fpOff = 0; + uint fpSaved = 0; + if (TryPeekLeftoverWait99WrapSavedFp(bus, regs, out fpSaved, + out fpOff) + && IsLeftoverWait99O32FpLive(fpSaved) + && regs != null && regs.Length > 30) + regs[30] = fpSaved; + return true; + } + + private static bool IsLeftoverWait99O32Caller(uint pc) + { + if ((pc & 3) != 0 || pc == 0 || pc == 0xFFFFFFFFu) + return false; + if (IsWrapDestSize(pc) || pc == WrapDestE32SizeLive + || IsHdDllEntryRva(pc)) + return false; + if (IsWrapDestFp50Va(pc) || pc == WrapDestFp50FillLive + || IsHdDllImageBase(pc) + || pc == HdDllEntryVa || pc == HdDllInitVa + || IsNkGetProcStoreSlot(pc)) + return false; + if (IsLeftoverBindRefuse(pc)) + return false; + if (IsLeftoverDestVa(pc) || pc == LeftoverWait99GetProcDest + || pc == LeftoverWait99NeedDest || pc == LeftoverWait99GetProc + || pc == LeftoverWait99O32RefuseRa + || pc == LeftoverWait99WrapRaWord + || pc == LeftoverWait99O32Halt5C + || pc == LeftoverWait99O32HaltEc + || pc == LeftoverWait99O32HaltDc + || pc == LeftoverApi54MethLive || pc == LeftoverApi78Ec + || pc == LeftoverApi54Ret || pc == LeftoverApi1630Ret + || pc == LeftoverWait99Tick || pc == LeftoverWait99TickMid + || pc == OemTickDelta || IsNearNullVa(pc) + || IsNkIdleResumePc(pc) || IsPoisonMidPlantResume(pc) + || !IsSanePlantResumePc(pc)) + return false; + if (pc >= CoredllSharedLo && pc < CoredllSharedHi) + return false; + if (pc >= LeftoverDestKseg + && pc < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo)) + return false; + if (pc >= LoadO32Rom && pc <= LoadE32WrapFail) + return true; + if (pc >= LoadO32WrapCopy && pc <= LoadO32WrapCopyRet) + return true; + if (pc >= LoadO32WrapCopyRet && pc <= BindImpLoadLib) + return true; + if (pc == LoadO32WrapStartip || pc == CallDllEntry) + return true; + if (pc >= BindImpHdr && pc <= BindImpIatNextAfter) + return true; + if (pc >= BindImpOrdLookup && pc < BindImpOrdLookup + 0xC0) + return true; + if (pc == BindImpOrdJalRet || pc == BindImpLoadLibRet + || pc == BindImpLoadLib || pc == CallDllStartip + || pc == XipDllCallDllJal || pc == CallDllAfterJalr) + return true; + return false; + } + + private static bool IsLeftoverWait99O32FpLive(uint fp) + { + if ((fp & 3) != 0 || fp == 0 || fp == 0xFFFFFFFFu) + return false; + if (IsLeftoverDestVa(fp) || fp == LeftoverWait99GetProc + || fp == LeftoverWait99GetProcDest + || fp == LeftoverWait99O32Halt5C + || fp == LeftoverWait99O32HaltEc + || fp == LeftoverWait99O32HaltDc) + return false; + return true; + } + + private static bool IsLeftoverWait99WrapStackVa(uint va) + { + if ((va & 3) != 0 || va == 0 || va == 0xFFFFFFFFu) + return false; + if (IsLeftoverDestVa(va) || va == LeftoverWait99GetProc + || va == LeftoverWait99GetProcDest + || va == LeftoverWait99O32Halt5C + || va == LeftoverWait99O32HaltEc + || va == LeftoverWait99O32HaltDc) + return false; + if (va >= LeftoverDestKseg + && va < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo)) + return false; + return true; + } + + // Live 0142875 dump-sw=0xAFBF001C sw $ra, + // 0x1C($sp). Frame 32. $sp+0x1C was leftover + // dest 0x03F74DEC. Peek that imm slot first, + // then the 32-byte frame, for dest-live NK + // LoadO32 / BindImp. leftover dest GetProc + // dest leftover hop forbidden. Do not leftover + // hop. Do not invent dest. + private static bool TryPeekLeftoverWait99O32FrameDest(MipsBus bus, + uint[] regs, out uint dest, out string via) + { + dest = 0; + via = ""; + uint swWord = 0; + if (!TryPeekLeftoverWait99UsegText(bus, LeftoverWait99WrapSw, + out swWord)) + TryPeekLeftoverWait99DumpOnly(LeftoverWait99WrapDumpSw, + out swWord); + int raOff = -1; + bool useFp = false; + int off; + if (IsSwRaSp(swWord, out off) || IsLwRaSp(swWord, out off)) + raOff = off; + else if (IsSwRaFp(swWord, out off) || IsLwRaFp(swWord, out off)) + { + raOff = off; + useFp = true; + } + uint sp = PeekGpr(regs, 29); + uint fp = PeekGpr(regs, 30); + uint baseVa = 0; + if (useFp && IsLeftoverWait99WrapStackVa(fp)) + baseVa = fp; + else if (IsLeftoverWait99WrapStackVa(sp)) + baseVa = sp; + else if (IsLeftoverWait99WrapStackVa(fp)) + baseVa = fp; + if (baseVa == 0) + { + via = "leftover-sp"; + return false; + } + if (raOff >= 0 && raOff < LeftoverWait99WrapFrame) + { + uint slot = 0; + if (TryPeekWord(bus, baseVa + (uint)raOff, out slot) + && IsLeftoverWait99O32Caller(slot)) + { + dest = slot; + via = "sw-" + raOff.ToString("X"); + return true; + } + if (slot == LeftoverWait99O32RefuseRa || IsLeftoverDestVa(slot) + || slot == LeftoverWait99WrapRaWord) + via = "refuse-0x" + slot.ToString("X8"); + } + for (int slotOff = 0; slotOff < LeftoverWait99WrapFrame; + slotOff += 4) + { + uint slot = 0; + if (!TryPeekWord(bus, baseVa + (uint)slotOff, out slot)) + continue; + if (!IsLeftoverWait99O32Caller(slot)) + continue; + dest = slot; + via = "slot-" + slotOff.ToString("X"); + return true; + } + if (baseVa != fp && IsLeftoverWait99WrapStackVa(fp)) + { + for (int slotOff = 0; slotOff < LeftoverWait99WrapFrame; + slotOff += 4) + { + uint slot = 0; + if (!TryPeekWord(bus, fp + (uint)slotOff, out slot)) + continue; + if (!IsLeftoverWait99O32Caller(slot)) + continue; + dest = slot; + via = "fp-slot-" + slotOff.ToString("X"); + return true; + } + } + if (string.IsNullOrEmpty(via)) + via = "miss-slot"; + return false; + } + + private static bool TryPeekLeftoverWait99WrapSavedFp(MipsBus bus, + uint[] regs, out uint saved, out int fpOff) + { + saved = 0; + fpOff = 0; + uint sp = PeekGpr(regs, 29); + if (!IsLeftoverWait99WrapStackVa(sp)) + return false; + for (uint i = 1; i <= 32; i++) + { + uint word = 0; + if (!TryPeekLeftoverWait99UsegText(bus, + LeftoverWait99Wrap - (i * 4), out word) + && !TryPeekLeftoverWait99DumpOnly( + LeftoverWait99WrapDumpPrologue + (i * 4), out word)) + continue; + int off; + if (!IsSwFpSp(word, out off)) + continue; + if (!TryPeekWord(bus, sp + (uint)off, out saved)) + return false; + fpOff = off; + return true; + } + return false; + } + + private static bool IsSwRaSp(uint word, out int off) + { + return IsStoreRaBase(word, 29, out off); + } + + private static bool IsLwRaSp(uint word, out int off) + { + return IsLoadRaBase(word, 29, out off); + } + + private static bool IsSwRaFp(uint word, out int off) + { + return IsStoreRaBase(word, 30, out off); + } + + private static bool IsLwRaFp(uint word, out int off) + { + return IsLoadRaBase(word, 30, out off); + } + + private static bool IsStoreRaBase(uint word, int rs, out int off) + { + off = 0; + if (((word >> 26) & 63) != 0x2B) + return false; + if (((word >> 21) & 31) != (uint)rs) + return false; + if (((word >> 16) & 31) != 31) + return false; + off = (short)(word & 0xFFFF); + return (off & 3) == 0 && off >= 0 && off <= 0x80; + } + + private static bool IsLoadRaBase(uint word, int rs, out int off) + { + off = 0; + if (((word >> 26) & 63) != 0x23) + return false; + if (((word >> 21) & 31) != (uint)rs) + return false; + if (((word >> 16) & 31) != 31) + return false; + off = (short)(word & 0xFFFF); + return (off & 3) == 0 && off >= 0 && off <= 0x80; + } + + private static bool IsSwFpSp(uint word, out int off) + { + off = 0; + if ((word & 0xFFFF0000u) != 0xAFBE0000u) + return false; + off = (short)(word & 0xFFFF); + return (off & 3) == 0 && off >= 0 && off <= 0x80; + } + + private static bool IsAddiuSpNeg(uint word, out int n) + { + n = 0; + if ((word & 0xFFFF0000u) != 0x27BD0000u) + return false; + int imm = (short)(word & 0xFFFF); + if (imm >= 0 || (imm & 3) != 0) + return false; + n = -imm; + return n > 0 && n <= 0x100; + } + + private static bool TryPeekLeftoverWait99WrapWord(MipsBus bus, uint va, + out uint word) + { + if (IsLeftoverWait99WrapDumpKseg(va)) + return TryPeekLeftoverWait99DumpOnly(va, out word); + if (TryPeekWord(bus, va, out word)) + return true; + return TryPeekLeftoverWait99DumpOnly(va, out word); + } + + private static bool IsLeftoverWait99WrapDumpKseg(uint va) + { + return va >= LeftoverDestKseg + && va < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + } + + private static bool TryPeekLeftoverWait99UsegText(MipsBus bus, uint va, + out uint word) + { + word = 0; + if ((va & 3) != 0 || va < LeftoverWait99WrapPrologue - 0x80 + || va > LeftoverWait99WrapRa + 0x80) + return false; + return TryPeekWord(bus, va, out word); + } + + private static bool TryPeekLeftoverWait99DumpOnly(uint va, out uint word) + { + return TryDumpPeekWait99(Wait99DumpRecs(), va, out word); + } + + private static List Wait99DumpRecs() + { + if (_leftoverWait99DumpRecsTried) + return _leftoverWait99DumpRecs; + _leftoverWait99DumpRecsTried = true; + _leftoverWait99DumpRecs = new List(); + string path = TryWait99NkBinPath(); + if (string.IsNullOrEmpty(path)) + return _leftoverWait99DumpRecs; + byte[] data; + try { data = System.IO.File.ReadAllBytes(path); } + catch { return _leftoverWait99DumpRecs; } + if (data == null || data.Length < 0x2000) + return _leftoverWait99DumpRecs; + TryLoadWait99DumpRecs(data, _leftoverWait99DumpRecs); + return _leftoverWait99DumpRecs; + } + + private static void TryNoteLeftoverWait99O32ContFromWrap(MipsBus bus, + uint[] regs, uint dest, string via) + { + if (_leftoverWait99O32ContLogged) + return; + _leftoverWait99O32ContLogged = true; + _leftoverWait99WrapRaContLogged = true; + _wait99PlantFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-cont ra=0x" + + LeftoverWait99WrapRa.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " via=" + via + + " (dump dest-live NK LoadO32 / BindImp $ra after dest-live GetProc; refuse leftover dest GetProc dest leftover hop)"); + } + + // Live 0142875 dump-sw=0xAFBF001C known. HiveLineMax + // 180: drop dump-pro/dump-sw/useg-sw/dest so the + // halt line can name dump-sp10/14/18/1c. dest=0 + // is the halt. leftover dest 0x03F74DEC / leftover + // dest GetProc dest leftover hop forbidden. Do not + // leftover hop. Do not invent dest. + private static void TryNoteLeftoverWait99O32HaltFromWrap(MipsBus bus, + uint[] regs, string via) + { + if (_leftoverWait99O32HaltLogged) + return; + _leftoverWait99O32HaltLogged = true; + _leftoverWait99WrapRaContLogged = true; + string peekVia = ""; + TryPeekLeftoverWait99O32FrameDest(bus, regs, out _, out peekVia); + if (string.IsNullOrEmpty(via)) + via = peekVia; + uint sp10 = 0; + uint sp14 = 0; + uint sp18 = 0; + uint sp1c = 0; + TryPeekLeftoverWait99O32FrameSlots(bus, PeekGpr(regs, 29), + out sp10, out sp14, out sp18, out sp1c); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-halt ra=0x" + + LeftoverWait99WrapRa.ToString("X8") + + " dump-sp10=0x" + sp10.ToString("X8") + + " dump-sp14=0x" + sp14.ToString("X8") + + " dump-sp18=0x" + sp18.ToString("X8") + + " dump-sp1c=0x" + sp1c.ToString("X8") + + " via=" + via); + TryNoteLeftoverWait99O32HaltFp(bus, regs); + } + + private static void TryPeekLeftoverWait99O32FrameSlots(MipsBus bus, + uint baseVa, out uint w10, out uint w14, out uint w18, out uint w1c) + { + w10 = 0; + w14 = 0; + w18 = 0; + w1c = 0; + if (!IsLeftoverWait99WrapStackVa(baseVa)) + return; + TryPeekWord(bus, baseVa + 0x10, out w10); + TryPeekWord(bus, baseVa + 0x14, out w14); + TryPeekWord(bus, baseVa + 0x18, out w18); + TryPeekWord(bus, baseVa + (uint)LeftoverWait99WrapRaOff, out w1c); + } + + private static void TryNoteLeftoverWait99O32HaltFp(MipsBus bus, + uint[] regs) + { + uint fp = PeekGpr(regs, 30); + if (!IsLeftoverWait99WrapStackVa(fp)) + return; + uint fp10 = 0; + uint fp14 = 0; + uint fp18 = 0; + uint fp1c = 0; + TryPeekLeftoverWait99O32FrameSlots(bus, fp, out fp10, out fp14, + out fp18, out fp1c); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-o32-halt-fp fp=0x" + + fp.ToString("X8") + + " dump-fp10=0x" + fp10.ToString("X8") + + " dump-fp14=0x" + fp14.ToString("X8") + + " dump-fp18=0x" + fp18.ToString("X8") + + " dump-fp1c=0x" + fp1c.ToString("X8")); + } + + private static void RememberLeftoverWait99WrapPlant(uint methods, + uint getproc) + { + if (IsDumpWait99GetProcTable(methods)) + _leftoverWait99WrapPlantMeth = methods; + if (IsDumpWait99GetProcDest(getproc)) + _leftoverWait99WrapPlantGp = getproc; + } + + private static bool TryPeekLeftoverWait99WrapGetProcLive(MipsBus bus, + out uint cache, out uint getproc, out uint meth) + { + cache = 0; + getproc = 0; + meth = 0; + uint slot = 0; + uint kdata = 0; + TryPeekWord(bus, ProcessInfoFaultVa, out slot); + TryPeekWord(bus, LeftoverWait99CacheKdata, out kdata); + cache = slot; + if (TryAcceptLeftoverWait99GetProcTable(bus, slot, out getproc)) + { + meth = slot; + RememberLeftoverWait99WrapPlant(slot, getproc); + return true; + } + if (TryAcceptLeftoverWait99GetProcTable(bus, kdata, out getproc)) + { + meth = kdata; + RememberLeftoverWait99WrapPlant(kdata, getproc); + return true; + } + uint plant = _leftoverWait99WrapPlantMeth != 0 + ? _leftoverWait99WrapPlantMeth + : LeftoverWait99WrapPlantMeth; + if (TryAcceptLeftoverWait99GetProcTable(bus, plant, out getproc)) + { + meth = plant; + RememberLeftoverWait99WrapPlant(plant, getproc); + return true; + } + uint methods = 0; + uint viaWn32 = 0; + uint hop = 0; + string via = ""; + if (TryResolveLeftoverWait99GetProcTable(bus, out methods, + out getproc, out via, out viaWn32, out hop)) + { + meth = methods; + RememberLeftoverWait99WrapPlant(methods, getproc); + return true; + } + meth = plant; + if (plant != 0) + TryPeekWord(bus, plant + LeftoverWait99GetProcOff, out getproc); + return false; + } + + private static void TryNoteLeftoverWait99WrapRaCont(MipsBus bus, + uint[] regs, uint word) + { + if (_leftoverWait99WrapRaContLogged) + return; + _leftoverWait99WrapRaContLogged = true; + uint fp = PeekGpr(regs, 30); + uint cache = 0; + uint getproc = 0; + uint meth = 0; + TryPeekLeftoverWait99WrapGetProcLive(bus, out cache, out getproc, + out meth); + uint plant = 0; + TryPeekWord(bus, ExnContinueWord, out plant); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-wrap-cont pc=0x" + + LeftoverWait99WrapRa.ToString("X8") + + " word=0x" + word.ToString("X8") + + " fp=0x" + fp.ToString("X8") + + " cache=0x" + cache.ToString("X8") + + " getproc=0x" + getproc.ToString("X8") + + " meth=0x" + meth.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (dump dest leftover-syscall wrapper jalr+8 GetProc-wrapper $ra dest-live plant table methods[152]; leftover dest leftover-syscall -1630 / missing GetProc wrap-halt stays; leftover dest GetProc dest leftover hop forbidden; do not leftover dest)"); + } + + private static bool TryContinueLeftoverWait99GetProc(MipsBus bus, + uint[] regs, ref uint pc) + { + uint s6 = PeekGpr(regs, 22); + uint cache = PeekGpr(regs, 2); + if (s6 != ProcessInfoFaultVa) + return false; + if (cache == 0 || cache == 0xFFFFFFFFu) + return false; + uint skipWord = 0; + uint lwWord = 0; + uint jalrWord = 0; + if (!TryPeekWord(bus, LeftoverWait99WrapSkip, out skipWord) + || !TryPeekWord(bus, LeftoverWait99WrapGetProcLw, out lwWord) + || !TryPeekWord(bus, LeftoverWait99WrapJalr, out jalrWord)) + return false; + if (lwWord != LeftoverWait99WrapGetProcLwWord + || jalrWord != LeftoverWait99WrapJalrWord) + return false; + uint getproc = 0; + if (!TryPeekWord(bus, cache + LeftoverWait99GetProcOff, out getproc) + || !IsDumpWait99GetProcDest(getproc)) + return false; + uint dest; + uint destWord; + if (skipWord == LeftoverWait99WrapSkipWord) + { + dest = LeftoverWait99WrapSkip; + destWord = skipWord; + } + else + { + if (regs == null || regs.Length <= 2) + return false; + regs[2] = getproc; + dest = LeftoverWait99WrapJalr; + destWord = jalrWord; + } + if (dest == pc) + return false; + pc = dest; + TryNoteLeftoverWait99WrapCont(bus, regs, dest, destWord, cache, + getproc); + return true; + } + + private static bool IsDumpWait99GetProcDest(uint va) + { + if ((va & 3) != 0 || va == 0 || va == 0xFFFFFFFFu) + return false; + if (va == 0xFFFFF9A2u || va == LeftoverWait99GetProcDest) + return false; + if (va == ProcessInfoFaultVa) + return false; + if (IsLeftoverDestVa(va)) + return false; + if (va >= LeftoverDestKseg + && va < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo)) + return false; + if (IsFirmwareUserOrCoredllVa(va)) + return true; + return va >= 0x80010000u && va < NkImageEnd; + } + + private static bool IsDumpWait99GetProcTable(uint va) + { + if ((va & 3) != 0 || va == 0 || va == 0xFFFFFFFFu) + return false; + if (IsLeftoverDestVa(va)) + return false; + if (va >= LeftoverDestKseg + && va < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo)) + return false; + if (va == ProcessInfoFaultVa || va == LeftoverWait99GetProcDest) + return false; + return true; + } + + // Live 394f3fd *0x01FFFCA4=0 during NK coredll + // LoadO32 so dest-wrapper beq takes leftover- + // syscall -1630. Peek dest-live cache (slot / + // KData 0xFFFFDCA4 / firmware PTE) or dump + // Win32 ahSys[0] CINFO+8 ppfnMethods. Plant + // dest-live methods table at the slot the lw + // reads. leftover dest GetProc dest leftover + // hop forbidden. Do not leftover hop. Do not + // invent dest. + private static void TryPlantLeftoverWait99GetProc(MipsBus bus, uint[] regs) + { + uint methods; + uint getproc; + uint wn32; + uint hop; + string via; + if (!TryResolveLeftoverWait99GetProcTable(bus, out methods, + out getproc, out via, out wn32, out hop)) + { + TryNoteLeftoverWait99WrapNeed(bus, regs, methods, getproc, via, + wn32, hop); + return; + } + uint slot = 0; + TryPeekWord(bus, ProcessInfoFaultVa, out slot); + RememberLeftoverWait99WrapPlant(methods, getproc); + if (slot == methods) + return; + try + { + bus.Write32(ProcessInfoFaultVa, methods); + } + catch + { + TryNoteLeftoverWait99WrapNeed(bus, regs, methods, getproc, + "write-" + via, wn32, hop); + return; + } + uint kdata = 0; + if (TryPeekWord(bus, LeftoverWait99CacheKdata, out kdata) + && kdata == 0) + { + try { bus.Write32(LeftoverWait99CacheKdata, methods); } + catch { } + } + if (!_leftoverWait99WrapPlantLogged) + { + _leftoverWait99WrapPlantLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-wrap-plant via=" + + via + + " now=0x" + methods.ToString("X8") + + " gp=0x" + getproc.ToString("X8") + + " wn32=0x" + wn32.ToString("X8") + + " slot=0x" + slot.ToString("X8")); + } + TryPlantLeftoverApi78Method(bus); + TryPlantLeftoverApi54Method(bus); + } + + private static bool TryResolveLeftoverWait99GetProcTable(MipsBus bus, + out uint methods, out uint getproc, out string via, out uint wn32, + out uint hop) + { + methods = 0; + getproc = 0; + via = "empty"; + wn32 = 0; + hop = 0; + uint slot = 0; + uint kdata = 0; + TryPeekWord(bus, ProcessInfoFaultVa, out slot); + TryPeekWord(bus, LeftoverWait99CacheKdata, out kdata); + if (TryAcceptLeftoverWait99GetProcTable(bus, slot, out getproc)) + { + methods = slot; + via = "slot"; + return true; + } + if (TryAcceptLeftoverWait99GetProcTable(bus, kdata, out getproc)) + { + methods = kdata; + via = "kdata"; + return true; + } + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfnWord = 0; + uint kseg = 0; + uint pte = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, ProcessInfoFaultVa, + out l1, out l2, out pfnWord, out kseg) + && TryPeekWord(bus, kseg | (ProcessInfoFaultVa & 0xFFFu), + out pte) + && TryAcceptLeftoverWait99GetProcTable(bus, pte, out getproc)) + { + methods = pte; + via = "pte"; + return true; + } + uint ahM = 0; + uint ahG = 0; + uint ahW = 0; + uint ahH = 0; + if (TryWalkAhSysWn32(bus, out ahM, out ahG, out ahW, out ahH)) + { + methods = ahM; + getproc = ahG; + wn32 = ahW; + hop = ahH; + via = "ahsys"; + return true; + } + if (TryScanDumpWn32Methods(bus, out methods, out getproc, out wn32, + out hop)) + { + via = string.IsNullOrEmpty(_leftoverWait99ScanVia) + ? "wn32" + : _leftoverWait99ScanVia; + return true; + } + NoteWait99Wn32Hit(ahW, ahH, ahM, ahG, ref wn32, ref hop, + ref methods, ref getproc); + if (hop != 0) + via = "wn32-hop"; + else if (wn32 != 0) + via = "wn32-miss"; + else + { + uint ib = 0; + uint c0 = 0; + bool ibOk = TryPeekWord(bus, LeftoverWait99NkImage, out ib); + bool c0Ok = TryPeekWord(bus, NkCopy0Dst, out c0); + if (!ibOk && !c0Ok) + via = "wn32-unmapped"; + else + via = "wn32-miss"; + } + return false; + } + + // Live f316d35 ahSys[0]=0; scan missed dump nk.exe + // ImageBase 0x80010000. Walk ahSys[32], PE data, + // then ImageBase..copy dest. acName "WN32" +8 + // ppfnMethods. Do not scan leftover dest kseg. + // leftover dest GetProc dest leftover hop + // forbidden. Do not invent dest. + private static bool TryScanDumpWn32Methods(MipsBus bus, out uint methods, + out uint getproc, out uint wn32, out uint hop) + { + methods = 0; + getproc = 0; + wn32 = 0; + hop = 0; + _leftoverWait99ScanVia = ""; + _leftoverWait99Cf = 0; + _leftoverWait99Sk = 0; + if (bus == null) + return false; + uint peM = 0; + uint peG = 0; + uint peW = 0; + uint peH = 0; + if (TryScanDumpNkPeWn32(bus, out peM, out peG, out peW, out peH)) + { + methods = peM; + getproc = peG; + wn32 = peW; + hop = peH; + _leftoverWait99ScanVia = "wn32"; + return true; + } + NoteWait99Wn32Hit(peW, peH, peM, peG, ref wn32, ref hop, + ref methods, ref getproc); + uint nkHi = NkCopy0Dst + NkCopy0DestLen; + uint linM = 0; + uint linG = 0; + uint linW = 0; + uint linH = 0; + if (TryScanDumpWn32Range(bus, LeftoverWait99NkImage, nkHi, + out linM, out linG, out linW, out linH)) + { + methods = linM; + getproc = linG; + wn32 = linW; + hop = linH; + _leftoverWait99ScanVia = "wn32"; + return true; + } + NoteWait99Wn32Hit(linW, linH, linM, linG, ref wn32, ref hop, + ref methods, ref getproc); + uint ptrM = 0; + uint ptrG = 0; + uint ptrW = 0; + uint ptrH = 0; + if (TryScanDumpWin32PtrMethods(bus, out ptrM, out ptrG, out ptrW, + out ptrH)) + { + methods = ptrM; + getproc = ptrG; + wn32 = ptrW; + hop = ptrH; + _leftoverWait99ScanVia = "ptr"; + return true; + } + NoteWait99Wn32Hit(ptrW, ptrH, ptrM, ptrG, ref wn32, ref hop, + ref methods, ref getproc); + if (TryScanDumpNkBinWin32Methods(bus, out ptrM, out ptrG, out ptrW, + out ptrH)) + { + methods = ptrM; + getproc = ptrG; + wn32 = ptrW; + hop = ptrH; + _leftoverWait99ScanVia = "dump"; + return true; + } + NoteWait99Wn32Hit(ptrW, ptrH, ptrM, ptrG, ref wn32, ref hop, + ref methods, ref getproc); + return false; + } + + // Live 0e57fb6: no WN32 acName on dest-live ImageBase / + // copy dest. Dump Win32CreateFile 0x8003D700 and + // KernelReadFile 0x8003D7E0 differ by 0xE0 (56 + // slots). Walk those thunks; accept a table only + // when methods[152] is dest-live GetProc and the + // ReadFile/CreateFile pair (or a second dump-named + // 0x8003Dxxx thunk) sits in the same array. + // leftover dest GetProc dest leftover hop + // forbidden. Do not invent dest. + private static bool TryScanDumpWin32PtrMethods(MipsBus bus, + out uint methods, out uint getproc, out uint wn32, out uint hop) + { + methods = 0; + getproc = 0; + wn32 = 0; + hop = 0; + if (bus == null) + return false; + uint destLo = LeftoverDestKseg; + uint destHi = LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + uint nkHi = NkCopy0Dst + NkCopy0DestLen; + for (uint va = LeftoverWait99NkImage; va + 4 < nkHi; va += 4) + { + if (va >= destLo && va < destHi) + { + va = destHi - 4; + continue; + } + uint word = 0; + if (!TryPeekWord(bus, va, out word)) + { + _leftoverWait99Sk++; + uint next = (va & ~0xFFFu) + 0x1000; + if (next <= va) + break; + va = next - 4; + continue; + } + if (!IsDumpWait99Win32Thunk(word)) + continue; + if (word == Win32CreateFile) + _leftoverWait99Cf++; + uint m = 0; + uint g = 0; + uint h = 0; + if (TryGuessWait99TableFromHit(bus, va, word, out m, out g, + out h)) + { + methods = m; + getproc = g; + wn32 = va; + hop = h; + return true; + } + NoteWait99Wn32Hit(va, h, m, g, ref wn32, ref hop, ref methods, + ref getproc); + } + return false; + } + + private static bool IsDumpWait99Win32Thunk(uint va) + { + if (va == Win32CreateFile || va == KernelReadFile + || va == KernelCreateFileMapping) + return true; + if (va == HostHardDisk.KernelRegOpen + || va == HostHardDisk.KernelRegQuery) + return true; + return false; + } + + private static bool TryGuessWait99TableFromHit(MipsBus bus, uint hitVa, + uint hitWord, out uint methods, out uint getproc, out uint hop) + { + methods = 0; + getproc = 0; + hop = 0; + if (bus == null || (hitVa & 3) != 0) + return false; + for (uint idx = 0; idx <= 220; idx++) + { + uint table = hitVa - (idx * 4); + if (table > hitVa) + break; + if (!IsDumpWait99GetProcTable(table)) + continue; + uint raw = 0; + TryPeekWord(bus, table + LeftoverWait99GetProcOff, out raw); + if (raw == LeftoverWait99GetProcDest) + { + hop = raw; + continue; + } + uint gp = 0; + if (!TryAcceptLeftoverWait99GetProcTable(bus, table, out gp)) + continue; + if (!Wait99TableHasDumpPair(bus, table, hitVa, hitWord)) + continue; + methods = table; + getproc = gp; + return true; + } + return false; + } + + private static bool Wait99TableHasDumpPair(MipsBus bus, uint table, + uint hitVa, uint hitWord) + { + uint other = 0; + if (hitWord == Win32CreateFile) + { + if (TryPeekWord(bus, hitVa + LeftoverWait99ReadFileDelta, + out other) && other == KernelReadFile) + return true; + } + else if (hitWord == KernelReadFile) + { + if (hitVa >= LeftoverWait99ReadFileDelta + && TryPeekWord(bus, hitVa - LeftoverWait99ReadFileDelta, + out other) && other == Win32CreateFile) + return true; + } + else if (hitWord == HostHardDisk.KernelRegOpen) + { + if (TryPeekWord(bus, hitVa + LeftoverWait99ReadFileDelta, + out other) && other == HostHardDisk.KernelRegQuery) + return true; + } + else if (hitWord == HostHardDisk.KernelRegQuery) + { + if (hitVa >= LeftoverWait99ReadFileDelta + && TryPeekWord(bus, hitVa - LeftoverWait99ReadFileDelta, + out other) && other == HostHardDisk.KernelRegOpen) + return true; + } + for (uint i = 0; i < 256; i++) + { + uint w = 0; + if (!TryPeekWord(bus, table + (i * 4), out w)) + continue; + if (w != hitWord && IsDumpWait99Win32Thunk(w)) + return true; + } + return false; + } + + private static bool TryScanDumpNkBinWin32Methods(MipsBus bus, + out uint methods, out uint getproc, out uint wn32, out uint hop) + { + methods = 0; + getproc = 0; + wn32 = 0; + hop = 0; + string path = TryWait99NkBinPath(); + if (string.IsNullOrEmpty(path)) + return false; + byte[] data; + try { data = System.IO.File.ReadAllBytes(path); } + catch { return false; } + if (data == null || data.Length < 0x2000) + return false; + List recs = new List(); + if (!TryLoadWait99DumpRecs(data, recs) || recs.Count == 0) + return false; + uint destLo = LeftoverDestKseg; + uint destHi = LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + for (int r = 0; r < recs.Count; r++) + { + Wait99DumpRec rec = recs[r]; + if (rec.Data == null || rec.Data.Length < 4) + continue; + int max = rec.Data.Length - 3; + for (int off = 0; off < max; off += 4) + { + uint word = (uint)(rec.Data[off] + | (rec.Data[off + 1] << 8) + | (rec.Data[off + 2] << 16) + | (rec.Data[off + 3] << 24)); + if (!IsDumpWait99Win32Thunk(word)) + continue; + if (word == Win32CreateFile) + _leftoverWait99Cf++; + uint hitVa = rec.Va + (uint)off; + if (hitVa >= destLo && hitVa < destHi) + continue; + uint m = 0; + uint g = 0; + uint h = 0; + if (!TryGuessWait99TableFromDump(recs, hitVa, word, out m, + out g, out h)) + { + NoteWait99Wn32Hit(hitVa, h, m, g, ref wn32, ref hop, + ref methods, ref getproc); + continue; + } + if (g == LeftoverWait99GetProcDest) + { + hop = g; + continue; + } + if (!IsDumpWait99GetProcDest(g) + || !IsDumpWait99GetProcTable(m)) + continue; + if (!TryEnsureWait99DumpTableLive(bus, recs, m)) + { + NoteWait99Wn32Hit(hitVa, h, m, g, ref wn32, ref hop, + ref methods, ref getproc); + continue; + } + uint live = 0; + if (!TryAcceptLeftoverWait99GetProcTable(bus, m, out live)) + { + NoteWait99Wn32Hit(hitVa, h, m, g, ref wn32, ref hop, + ref methods, ref getproc); + continue; + } + methods = m; + getproc = live; + wn32 = hitVa; + hop = h; + return true; + } + } + return false; + } + + private static string TryWait99NkBinPath() + { + string root = HostHardDisk.Root; + if (string.IsNullOrEmpty(root)) + return ""; + string p = System.IO.Path.Combine(root, "nk.bin"); + try + { + if (System.IO.File.Exists(p) + && new System.IO.FileInfo(p).Length >= 0x2000) + return p; + } + catch + { + } + return ""; + } + + private static bool TryLoadWait99DumpRecs(byte[] data, + List recs) + { + if (data == null || recs == null || data.Length < 15) + return false; + int pos = 0; + if (data.Length >= 7 + && data[0] == (byte)'B' && data[1] == (byte)'0' + && data[2] == (byte)'0' && data[3] == (byte)'0' + && data[4] == (byte)'F' && data[5] == (byte)'F' + && data[6] == (byte)'\n') + pos = 7; + if (pos + 8 > data.Length) + return false; + uint imageLength = (uint)(data[pos + 4] | (data[pos + 5] << 8) + | (data[pos + 6] << 16) | (data[pos + 7] << 24)); + pos += 8; + while (pos + 12 <= data.Length) + { + uint addr = (uint)(data[pos] | (data[pos + 1] << 8) + | (data[pos + 2] << 16) | (data[pos + 3] << 24)); + uint len = (uint)(data[pos + 4] | (data[pos + 5] << 8) + | (data[pos + 6] << 16) | (data[pos + 7] << 24)); + pos += 12; + if (addr == 0 && len == 0) + break; + if (len == 0 || len > imageLength || pos + (int)len > data.Length) + break; + byte[] rec = new byte[len]; + System.Buffer.BlockCopy(data, pos, rec, 0, (int)len); + pos += (int)len; + recs.Add(new Wait99DumpRec { Va = addr, Data = rec }); + if (recs.Count > 512) + break; + } + return recs.Count > 0; + } + + private static bool TryDumpPeekWait99(List recs, uint va, + out uint word) + { + word = 0; + if (recs == null || (va & 3) != 0) + return false; + for (int i = 0; i < recs.Count; i++) + { + Wait99DumpRec rec = recs[i]; + if (rec.Data == null || va < rec.Va) + continue; + uint off = va - rec.Va; + if (off + 4 > (uint)rec.Data.Length) + continue; + int o = (int)off; + word = (uint)(rec.Data[o] | (rec.Data[o + 1] << 8) + | (rec.Data[o + 2] << 16) | (rec.Data[o + 3] << 24)); + return true; + } + return false; + } + + private static bool TryGuessWait99TableFromDump(List recs, + uint hitVa, uint hitWord, out uint methods, out uint getproc, + out uint hop) + { + methods = 0; + getproc = 0; + hop = 0; + if (recs == null || (hitVa & 3) != 0) + return false; + for (uint idx = 0; idx <= 220; idx++) + { + uint table = hitVa - (idx * 4); + if (table > hitVa) + break; + if (!IsDumpWait99GetProcTable(table)) + continue; + uint raw = 0; + TryDumpPeekWait99(recs, table + LeftoverWait99GetProcOff, + out raw); + if (raw == LeftoverWait99GetProcDest) + { + hop = raw; + continue; + } + if (!IsDumpWait99GetProcDest(raw)) + continue; + if (!Wait99DumpTableHasPair(recs, table, hitVa, hitWord)) + continue; + methods = table; + getproc = raw; + return true; + } + return false; + } + + private static bool Wait99DumpTableHasPair(List recs, + uint table, uint hitVa, uint hitWord) + { + uint other = 0; + if (hitWord == Win32CreateFile) + { + if (TryDumpPeekWait99(recs, hitVa + LeftoverWait99ReadFileDelta, + out other) && other == KernelReadFile) + return true; + } + else if (hitWord == KernelReadFile) + { + if (hitVa >= LeftoverWait99ReadFileDelta + && TryDumpPeekWait99(recs, + hitVa - LeftoverWait99ReadFileDelta, out other) + && other == Win32CreateFile) + return true; + } + for (uint i = 0; i < 256; i++) + { + uint w = 0; + if (!TryDumpPeekWait99(recs, table + (i * 4), out w)) + continue; + if (w != hitWord && IsDumpWait99Win32Thunk(w)) + return true; + } + return false; + } + + private static bool TryEnsureWait99DumpTableLive(MipsBus bus, + List recs, uint table) + { + if (bus == null || recs == null || !IsDumpWait99GetProcTable(table)) + return false; + uint live = 0; + if (TryPeekWord(bus, table + LeftoverWait99GetProcOff, out live) + && IsDumpWait99GetProcDest(live)) + return true; + for (uint i = 0; i <= 160; i++) + { + uint va = table + (i * 4); + uint dump = 0; + if (!TryDumpPeekWait99(recs, va, out dump) || dump == 0) + continue; + uint cur = 0; + bool poked = TryPeekWord(bus, va, out cur); + if (poked && cur != 0 && cur != dump) + continue; + try { bus.Write32(va, dump); } + catch { return false; } + } + return TryPeekWord(bus, table + LeftoverWait99GetProcOff, out live) + && IsDumpWait99GetProcDest(live); + } + + private sealed class Wait99DumpRec + { + public uint Va; + public byte[] Data; + } + + private static bool TryWalkAhSysWn32(MipsBus bus, out uint methods, + out uint getproc, out uint wn32, out uint hop) + { + methods = 0; + getproc = 0; + wn32 = 0; + hop = 0; + if (bus == null) + return false; + for (int i = 0; i < LeftoverWait99AhCount; i++) + { + uint cinfo = 0; + if (!TryPeekWord(bus, KDataBase + 4 + (uint)(i * 4), out cinfo)) + continue; + if (!IsDumpWait99CinfoVa(cinfo)) + continue; + uint name = 0; + if (!TryPeekWord(bus, cinfo, out name) + || name != LeftoverWait99Wn32Name) + continue; + uint m = 0; + uint g = 0; + uint h = 0; + if (TryReadDumpWn32Cinfo(bus, cinfo, out m, out g, out h)) + { + wn32 = cinfo; + methods = m; + getproc = g; + return true; + } + NoteWait99Wn32Hit(cinfo, h, m, g, ref wn32, ref hop, + ref methods, ref getproc); + } + return false; + } + + private static bool TryScanDumpNkPeWn32(MipsBus bus, out uint methods, + out uint getproc, out uint wn32, out uint hop) + { + methods = 0; + getproc = 0; + wn32 = 0; + hop = 0; + uint mz = 0; + if (!TryPeekWord(bus, LeftoverWait99NkImage, out mz) + || (mz & 0xFFFF) != 0x5A4D) + return false; + uint lfanew = 0; + if (!TryPeekWord(bus, LeftoverWait99NkImage + 0x3C, out lfanew) + || lfanew < 0x40 || lfanew > 0x400) + return false; + uint pe = LeftoverWait99NkImage + lfanew; + uint sig = 0; + if (!TryPeekWord(bus, pe, out sig) || sig != 0x00004550) + return false; + uint coff = 0; + uint opt = 0; + if (!TryPeekWord(bus, pe + 4, out coff) + || !TryPeekWord(bus, pe + 20, out opt)) + return false; + uint nsec = (coff >> 16) & 0xFFFF; + uint optSize = opt & 0xFFFF; + if (nsec == 0 || nsec > 16 || optSize > 0x200) + return false; + uint secOff = pe + 24 + optSize; + for (uint i = 0; i < nsec; i++) + { + uint ch = 0; + uint vs = 0; + uint rva = 0; + if (!TryPeekWord(bus, secOff + 36, out ch) + || !TryPeekWord(bus, secOff + 8, out vs) + || !TryPeekWord(bus, secOff + 12, out rva)) + { + secOff += 40; + continue; + } + secOff += 40; + if ((ch & 0x40) == 0) + continue; + if (vs == 0) + TryPeekWord(bus, secOff - 40 + 16, out vs); + if (vs < 12 || vs > 0x400000) + continue; + uint lo = rva >= LeftoverWait99NkImage + ? rva + : LeftoverWait99NkImage + rva; + if ((lo & 3) != 0) + continue; + uint hi = lo + vs; + uint m = 0; + uint g = 0; + uint w = 0; + uint h = 0; + if (TryScanDumpWn32Range(bus, lo, hi, out m, out g, out w, + out h)) + { + methods = m; + getproc = g; + wn32 = w; + hop = h; + return true; + } + NoteWait99Wn32Hit(w, h, m, g, ref wn32, ref hop, ref methods, + ref getproc); + } + return false; + } + + private static bool TryScanDumpWn32Range(MipsBus bus, uint lo, uint hi, + out uint methods, out uint getproc, out uint wn32, out uint hop) + { + methods = 0; + getproc = 0; + wn32 = 0; + hop = 0; + if (bus == null || lo >= hi || (lo & 3) != 0) + return false; + uint destLo = LeftoverDestKseg; + uint destHi = LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + uint nkHi = NkCopy0Dst + NkCopy0DestLen; + if (hi > nkHi) + hi = nkHi; + for (uint va = lo; va + 12 < hi; va += 4) + { + if (va >= destLo && va < destHi) + { + va = destHi - 4; + continue; + } + uint name = 0; + if (!TryPeekWord(bus, va, out name)) + { + uint next = (va & ~0xFFFu) + 0x1000; + if (next <= va) + break; + va = next - 4; + continue; + } + if (name != LeftoverWait99Wn32Name) + continue; + uint m = 0; + uint g = 0; + uint h = 0; + if (TryReadDumpWn32Cinfo(bus, va, out m, out g, out h)) + { + wn32 = va; + methods = m; + getproc = g; + return true; + } + NoteWait99Wn32Hit(va, h, m, g, ref wn32, ref hop, ref methods, + ref getproc); + } + return false; + } + + private static bool TryReadDumpWn32Cinfo(MipsBus bus, uint cinfo, + out uint methods, out uint getproc, out uint hop) + { + methods = 0; + getproc = 0; + hop = 0; + uint name = 0; + if (!TryPeekWord(bus, cinfo, out name) + || name != LeftoverWait99Wn32Name) + return false; + uint pfn = 0; + if (!TryPeekWord(bus, cinfo + LeftoverWait99CinfoPfn, out pfn)) + return false; + uint gp = 0; + uint alt = 0; + TryPeekWord(bus, pfn + LeftoverWait99GetProcOff, out gp); + TryPeekWord(bus, pfn + LeftoverWait99GetProcOffAlt, out alt); + methods = pfn; + getproc = gp; + if (gp == LeftoverWait99GetProcDest + || alt == LeftoverWait99GetProcDest) + { + hop = gp != 0 ? gp : alt; + return false; + } + if (!TryAcceptLeftoverWait99GetProcTable(bus, pfn, out gp)) + return false; + if (alt != 0 && !IsDumpWait99GetProcDest(alt)) + return false; + getproc = gp; + return true; + } + + private static void NoteWait99Wn32Hit(uint wn32Hit, uint hopHit, + uint methodsHit, uint getprocHit, ref uint wn32, ref uint hop, + ref uint methods, ref uint getproc) + { + if (wn32Hit == 0) + return; + if (wn32 == 0) + wn32 = wn32Hit; + if (hop == 0) + hop = hopHit; + if (methods == 0) + methods = methodsHit; + if (getproc == 0) + getproc = getprocHit; + } + + private static bool IsDumpWait99CinfoVa(uint va) + { + if ((va & 3) != 0 || va == 0 || va == 0xFFFFFFFFu) + return false; + if (IsLeftoverDestVa(va)) + return false; + uint destLo = LeftoverDestKseg; + uint destHi = LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + if (va >= destLo && va < destHi) + return false; + return va >= LeftoverWait99NkImage + && va < NkCopy0Dst + NkCopy0DestLen; + } + + private static bool TryAcceptLeftoverWait99GetProcTable(MipsBus bus, + uint table, out uint getproc) + { + getproc = 0; + if (!IsDumpWait99GetProcTable(table)) + return false; + if (!TryPeekWord(bus, table + LeftoverWait99GetProcOff, out getproc)) + return false; + return IsDumpWait99GetProcDest(getproc); + } + + // Live 509dd8f leftover-api-78-halt +EC= + // 0x8003FD04 destPlant leftover dest. Dump- + // true thread+0xEC is sane NK. leftover- + // dispatch +DC jal is not the jal that + // entered +EC. Live 11cf70a leftover-api- + // 54-halt +EC=0x8005950C leftover mid + // 0x800159B0. That +EC is dump memset mid + // (0x800593F0–0x80059588 / + // IsPoisonMidPlantResume). Live f0cb076 + // leftover-api-54-cont namedEc / memset + // range accepted that +EC then silent + // freeze. leftover hop plant-fix to memset + // hung. leftover-api-54-cont after refuse + // leftover hop ObjectCall jalr dest-live + // methods[54]. Refuse leftover dest / + // leftover hop GetProc dest / idle / + // poison mid. Do not leftover hop. Do not + // invent dest. + private static bool IsLeftoverApiContPc(MipsBus bus, uint ec, + uint namedEc, uint meth) + { + if ((ec & 3) != 0 || IsPoisonPlant(ec) || IsNearNullVa(ec) + || IsLeftoverDestVa(ec) || IsNkIdleResumePc(ec) + || IsPoisonMidPlantResume(ec) + || ec == LeftoverWait99GetProcDest) + return false; + if (!IsSanePlantResumePc(ec)) + return false; + uint w = 0; + if (!TryPeekWord(bus, ec, out w) || !IsFirmwareJrRa(w)) + return true; + if (ec == namedEc) + return true; + uint fn = 0; + return TryPeekLeftoverWait99Method(bus, meth, out fn) + && fn == ec && IsDumpWait99GetProcDest(fn); + } + + // Live f0cb076 leftover-api-54-need refuse + // 0x80095EBC m54=0x8005A6D0 dest-live then + // silent freeze: leftover-api-54-cont + // replayed dump memset mid +EC=0x8005950C + // without leftover-api-54-cont log + // (_plantFixLogged leftover-api-78-cont). + // leftover hop plant-fix to memset hung. + // leftover-api-54-cont after refuse leftover + // hop ObjectCall jalr dest-live methods[54] + // already present. Do not replay memset mid. + // leftover dest GetProc dest leftover hop + // forbidden. Do not leftover hop. Do not + // invent dest. + private static bool TryLeftoverApi54ContDest(MipsBus bus, out uint dest) + { + dest = 0; + uint m54 = 0; + if (!TryPeekLeftoverWait99Method(bus, LeftoverApi54Meth, out m54)) + return false; + if (!IsDumpWait99GetProcDest(m54) || !IsSanePlantResumePc(m54) + || IsPoisonMidPlantResume(m54) + || m54 == LeftoverWait99GetProcDest) + return false; + dest = m54; + return true; + } + + private static void TryNoteLeftoverApi54Cont(MipsBus bus, uint was, + uint ec, uint dc, uint dest) + { + if (_leftoverApi54ContLogged) + return; + _leftoverApi54ContLogged = true; + _plantFixLogged = true; + uint m54 = 0; + TryPeekLeftoverWait99Method(bus, LeftoverApi54Meth, out m54); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-54-cont api=0x" + + LeftoverApi54.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " was=0x" + was.ToString("X8") + + " m54=0x" + m54.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " (ObjectCall jalr dest-live methods[54]; refuse memset mid +EC; do not leftover dest)"); + } + + private static void TryNoteLeftoverApi54Halt(MipsBus bus, uint was, + uint ec, uint dc) + { + if (_leftoverApi54HaltLogged) + return; + _leftoverApi54HaltLogged = true; + _leftoverHaltLogged = true; + uint m54 = 0; + uint jalr8 = 0; + TryPeekLeftoverWait99Method(bus, LeftoverApi54Meth, out m54); + TryResolveLeftoverCstkFromApi(bus, LeftoverApi54, out jalr8); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-54-halt api=0x" + + LeftoverApi54.ToString("X8") + + " imm=" + LeftoverApi54Imm + + " jalr8=0x" + jalr8.ToString("X8") + + " m54=0x" + m54.ToString("X8") + + " was=0x" + was.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " (refuse memset mid +EC / leftover dest; do not leftover dest)"); + } + + // Live 509dd8f wrap-plant via=ptr now= + // 0x8005D400 gp=0x8003EABC. methods[78] at + // +0x138 stayed 0: TryEnsureWait99DumpTableLive + // returns once GetProc is dest-live and never + // copies slot 78. Dump nk.bin B000FF at the + // same table, or a second dump-pair table + // with dest-live GetProc, holds the Win32 + // entry. Do not plant leftover dest / leftover + // hop GetProc dest / +EC. leftover dest + // GetProc dest leftover hop forbidden. Do + // not leftover hop. Do not invent dest. + private static bool TryPlantLeftoverApi78Method(MipsBus bus) + { + return TryPlantLeftoverWait99ApiMethod(bus, LeftoverApi78Meth, + "78", LeftoverApi78Off, ref _leftoverApi78PlantLogged); + } + + private static bool TryPlantLeftoverApi54Method(MipsBus bus) + { + return TryPlantLeftoverWait99ApiMethod(bus, LeftoverApi54Meth, + "54", LeftoverApi54Off, ref _leftoverApi54PlantLogged); + } + + private static bool TryPlantLeftoverWait99ApiMethod(MipsBus bus, + uint index, string tag, uint off, ref bool plantLogged) + { + uint table = 0; + if (!TryResolveLeftoverApi78Table(bus, out table)) + return false; + uint live = 0; + if (TryPeekWord(bus, table + off, out live) + && IsDumpWait99GetProcDest(live)) + return true; + uint dump = 0; + string via = ""; + if (TryDumpPeekLeftoverWait99Api(table, off, out dump) + && IsDumpWait99GetProcDest(dump)) + via = "dump"; + else if (TryScanLeftoverWait99Api(bus, table, off, out dump) + && IsDumpWait99GetProcDest(dump)) + via = "scan"; + else + return false; + try { bus.Write32(table + off, dump); } + catch { return false; } + if (!plantLogged) + { + plantLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-" + + tag + "-plant via=" + + via + + " now=0x" + dump.ToString("X8") + + " meth=0x" + table.ToString("X8") + + " (dump methods[" + index + "] ppfnMethods+0x" + + off.ToString("X") + + "; leftover dest GetProc dest leftover hop forbidden; do not leftover dest)"); + } + return true; + } + + private static bool TryResolveLeftoverApi78Table(MipsBus bus, + out uint table) + { + table = 0; + if (bus == null) + return false; + uint slot = 0; + uint kdata = 0; + uint gp; + TryPeekWord(bus, ProcessInfoFaultVa, out slot); + TryPeekWord(bus, LeftoverWait99CacheKdata, out kdata); + if (TryAcceptLeftoverWait99GetProcTable(bus, slot, out gp)) + table = slot; + else if (TryAcceptLeftoverWait99GetProcTable(bus, kdata, out gp)) + table = kdata; + else + return false; + return IsDumpWait99GetProcTable(table); + } + + private static bool TryDumpPeekLeftoverWait99Api(uint table, uint off, + out uint fn) + { + fn = 0; + string path = TryWait99NkBinPath(); + if (string.IsNullOrEmpty(path)) + return false; + byte[] data; + try { data = System.IO.File.ReadAllBytes(path); } + catch { return false; } + List recs = new List(); + if (!TryLoadWait99DumpRecs(data, recs) || recs.Count == 0) + return false; + return TryDumpPeekWait99(recs, table + off, out fn) + && IsDumpWait99GetProcDest(fn); + } + + private static bool TryScanLeftoverWait99Api(MipsBus bus, uint table, + uint slotOff, out uint fn) + { + fn = 0; + if (bus == null || !IsDumpWait99GetProcTable(table)) + return false; + uint getproc = 0; + if (!TryPeekWord(bus, table + LeftoverWait99GetProcOff, out getproc) + || !IsDumpWait99GetProcDest(getproc)) + return false; + string path = TryWait99NkBinPath(); + if (!string.IsNullOrEmpty(path)) + { + byte[] data; + try { data = System.IO.File.ReadAllBytes(path); } + catch { data = null; } + List recs = new List(); + if (data != null && TryLoadWait99DumpRecs(data, recs)) + { + uint destLo = LeftoverDestKseg; + uint destHi = LeftoverDestKseg + + (LeftoverDestHi - LeftoverDestLo); + for (int r = 0; r < recs.Count; r++) + { + Wait99DumpRec rec = recs[r]; + if (rec.Data == null || rec.Data.Length < 4) + continue; + int max = rec.Data.Length - 3; + for (int off = 0; off < max; off += 4) + { + uint word = (uint)(rec.Data[off] + | (rec.Data[off + 1] << 8) + | (rec.Data[off + 2] << 16) + | (rec.Data[off + 3] << 24)); + if (!IsDumpWait99Win32Thunk(word)) + continue; + uint hitVa = rec.Va + (uint)off; + if (hitVa >= destLo && hitVa < destHi) + continue; + uint m = 0; + uint g = 0; + uint h = 0; + if (!TryGuessWait99TableFromDump(recs, hitVa, word, + out m, out g, out h)) + continue; + if (g != getproc || m == table) + continue; + uint slot = 0; + if (!TryDumpPeekWait99(recs, m + slotOff, + out slot) + || !IsDumpWait99GetProcDest(slot)) + continue; + fn = slot; + return true; + } + } + } + } + uint nkHi = NkCopy0Dst + NkCopy0DestLen; + uint destLo2 = LeftoverDestKseg; + uint destHi2 = LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + for (uint va = LeftoverWait99NkImage; va + 4 < nkHi; va += 4) + { + if (va >= destLo2 && va < destHi2) + { + va = destHi2 - 4; + continue; + } + uint word = 0; + if (!TryPeekWord(bus, va, out word)) + { + uint next = (va & ~0xFFFu) + 0x1000; + if (next <= va) + break; + va = next - 4; + continue; + } + if (!IsDumpWait99Win32Thunk(word)) + continue; + uint m = 0; + uint g = 0; + uint h = 0; + if (!TryGuessWait99TableFromHit(bus, va, word, out m, out g, + out h)) + continue; + if (g != getproc || m == table) + continue; + uint slot = 0; + if (!TryPeekWord(bus, m + slotOff, out slot) + || !IsDumpWait99GetProcDest(slot)) + continue; + fn = slot; + return true; + } + return false; + } + + // Live f99af0d leftover-wait99-wrap-plant + // via=ptr now=0x8005D400. methods[78] is + // *(ppfnMethods+0x138). Peek only; do not + // invent dest from an empty slot. + private static bool TryPeekLeftoverWait99Method(MipsBus bus, uint index, + out uint fn) + { + fn = 0; + if (bus == null || index > 255) + return false; + uint table = 0; + uint slot = 0; + uint kdata = 0; + uint gp; + TryPeekWord(bus, ProcessInfoFaultVa, out slot); + TryPeekWord(bus, LeftoverWait99CacheKdata, out kdata); + if (TryAcceptLeftoverWait99GetProcTable(bus, slot, out gp)) + table = slot; + else if (TryAcceptLeftoverWait99GetProcTable(bus, kdata, out gp)) + table = kdata; + else if (slot != 0 && slot != 0xFFFFFFFFu) + table = slot; + else + return false; + if (!TryPeekWord(bus, table + index * 4, out fn)) + { + fn = 0; + return false; + } + if (fn == 0 || fn == 0xFFFFFFFFu) + return false; + return true; + } + + private static void TryNoteLeftoverApi78Need(MipsBus bus, uint leftoverRa, + uint refuse) + { + if (_leftoverApi78NeedLogged) + return; + _leftoverApi78NeedLogged = true; + TryPlantLeftoverApi78Method(bus); + uint m78 = 0; + TryPeekLeftoverWait99Method(bus, LeftoverApi78Meth, out m78); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-78-need api=0x" + + LeftoverApi78.ToString("X8") + + " imm=" + LeftoverApi78Imm + + " ra=0x" + leftoverRa.ToString("X8") + + " refuse=0x" + refuse.ToString("X8") + + " m78=0x" + m78.ToString("X8")); + } + + private static void TryNoteLeftoverApi54Need(MipsBus bus, uint leftoverRa, + uint refuse) + { + if (_leftoverApi54NeedLogged) + return; + _leftoverApi54NeedLogged = true; + TryPlantLeftoverApi54Method(bus); + uint m54 = 0; + TryPeekLeftoverWait99Method(bus, LeftoverApi54Meth, out m54); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-api-54-need api=0x" + + LeftoverApi54.ToString("X8") + + " imm=" + LeftoverApi54Imm + + " ra=0x" + leftoverRa.ToString("X8") + + " refuse=0x" + refuse.ToString("X8") + + " m54=0x" + m54.ToString("X8")); + } + + private static void TryNoteLeftoverWait99WrapNeed(MipsBus bus, uint[] regs, + uint methods, uint getproc, string via, uint wn32, uint hop) + { + if (_leftoverWait99WrapNeedLogged) + return; + _leftoverWait99WrapNeedLogged = true; + uint ib = 0; + uint c0 = 0; + bool ibOk = TryPeekWord(bus, LeftoverWait99NkImage, out ib); + bool c0Ok = TryPeekWord(bus, NkCopy0Dst, out c0); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-wrap-need via=" + + (via ?? "empty") + + " wn32=0x" + wn32.ToString("X8") + + " hop=0x" + hop.ToString("X8") + + " meth=0x" + methods.ToString("X8") + + " gp=0x" + getproc.ToString("X8") + + " cf=" + _leftoverWait99Cf + + " sk=" + _leftoverWait99Sk + + " ib=" + (ibOk ? "y" : "n") + + " c0=" + (c0Ok ? "y" : "n")); + } + + private static void TryNoteLeftoverWait99WrapCont(MipsBus bus, + uint[] regs, uint pc, uint word) + { + uint cache = PeekGpr(regs, 2); + if (pc == LeftoverWait99Wrap) + TryPeekWord(bus, ProcessInfoFaultVa, out cache); + uint getproc = 0; + if (cache != 0 && cache != 0xFFFFFFFFu) + TryPeekWord(bus, cache + LeftoverWait99GetProcOff, out getproc); + TryNoteLeftoverWait99WrapCont(bus, regs, pc, word, cache, getproc); + } + + private static void TryNoteLeftoverWait99WrapCont(MipsBus bus, + uint[] regs, uint pc, uint word, uint cache, uint getproc) + { + bool getprocCont = pc == LeftoverWait99WrapSkip + || pc == LeftoverWait99WrapJalr + || pc == LeftoverWait99WrapGetProcLw; + if (getprocCont) + { + if (_leftoverWait99WrapGetProcLogged) + return; + _leftoverWait99WrapGetProcLogged = true; + } + else if (_leftoverWait99WrapContLogged) + return; + else + _leftoverWait99WrapContLogged = true; + RememberLeftoverWait99WrapPlant(cache, getproc); + uint destWord = 0; + uint raWord = 0; + uint s6 = PeekGpr(regs, 22); + TryPeekWord(bus, LeftoverWait99GetProcDest, out destWord); + TryPeekWord(bus, LeftoverWait99WrapRa, out raWord); + uint plant = 0; + TryPeekWord(bus, ExnContinueWord, out plant); + TryNoteLeftoverWait99Why(bus, plant, LeftoverWait99WrapRa, + destWord, raWord); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-wrap-cont pc=0x" + + pc.ToString("X8") + + " word=0x" + word.ToString("X8") + + " s6=0x" + s6.ToString("X8") + + " cache=0x" + cache.ToString("X8") + + " getproc=0x" + getproc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + (getprocCont + ? " (dump dest leftover-syscall wrapper success b +2 / lw $v0,608($v0) real GetProc / jalr; leftover dest leftover-syscall -1630 wrap-halt stays; leftover dest GetProc dest leftover hop forbidden; do not leftover dest)" + : " (dump leftover dest GetProc leftover dest lw $v0,0($s6) $s6=0x01FFFCA4 GetProc cache; leftover dest dest-wrapper success wrap-cont; leftover dest leftover-syscall wrap-halt stays; leftover dest GetProc dest leftover hop forbidden; do not leftover dest)")); + } + + private static void TryNoteLeftoverWait99Why(MipsBus bus, uint plant, + uint ra, uint destWord, uint raWord) + { + if (_leftoverWait99WhyLogged) + return; + _leftoverWait99WhyLogged = true; + uint w0 = 0; + uint w1 = 0; + uint w2 = 0; + uint w3 = 0; + TryPeekWord(bus, LeftoverWait99Wrap, out w0); + TryPeekWord(bus, LeftoverWait99Wrap + 4, out w1); + TryPeekWord(bus, LeftoverWait99Wrap + 8, out w2); + TryPeekWord(bus, LeftoverWait99Wrap + 12, out w3); + uint gpWord = 0; + TryPeekWord(bus, LeftoverWait99GetProc, out gpWord); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-why plant=0x" + + plant.ToString("X8") + + " getproc=0x" + LeftoverWait99GetProcDest.ToString("X8") + + " wrap=0x" + LeftoverWait99Wrap.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " ra-word=0x" + raWord.ToString("X8") + + " dest-word=0x" + destWord.ToString("X8") + + " hash=0x" + LeftoverWait99HashWord.ToString("X8") + + " gp-word=0x" + gpWord.ToString("X8") + + " w0=0x" + w0.ToString("X8") + + " w1=0x" + w1.ToString("X8") + + " w2=0x" + w2.ToString("X8") + + " w3=0x" + w3.ToString("X8") + + " (dump leftover dest GetProc leftover dest lw $v0,0($s6) at wrap $s6=0x01FFFCA4 GetProc cache; dump dest leftover-syscall wrapper success lw $v0,608($v0) / jalr; leftover dest leftover-syscall wrap-halt stays; leftover dest GetProc dest leftover hop forbidden; do not leftover dest)"); + } + + // Live 05a9778 leftover-ret frame+4 + // leftover dest already. Dump who wrote + // it: 0x800391CC sw leftover $ra during + // leftover-syscall ObjectCall. api is + // 0($fp) leftover-syscall index. One + // Hive line. leftover-ret / leftover- + // skip / leftover-halt stay. Do not + // leftover hop. Do not invent dest. + public static void TryNoteLeftoverCstkObserve(MipsBus bus, uint[] regs, + uint pc) + { + if (_leftoverCstkLogged) + return; + if (pc != LeftoverCstkSw) + return; + uint t3 = PeekGpr(regs, 11); + if (!IsLeftoverDestVa(t3)) + return; + _leftoverCstkLogged = true; + uint frame = PeekGpr(regs, 23); + uint fp = PeekGpr(regs, 30); + uint api = 0; + uint plus18 = 0; + uint thr = 0; + if (fp != 0 && fp != 0xFFFFFFFFu) + TryPeekWord(bus, fp, out api); + _leftoverCstkApi = api; + if (TryPeekWord(bus, ThreadPtr, out thr) && thr != 0 + && thr != 0xFFFFFFFFu) + TryPeekWord(bus, thr + ThreadSyscallFrame, out plus18); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-cstk sw=0x" + + LeftoverCstkSw.ToString("X8") + + " frame=0x" + frame.ToString("X8") + + " +4=0x" + t3.ToString("X8") + + " api=0x" + api.ToString("X8") + + " +18=0x" + plus18.ToString("X8") + + " (dump ObjectCall stores leftover $ra)"); + } + + // Live 541bebf leftover-cstk $t3 leftover + // dest mid-hash. Dump leftover-syscall + // -1630 jalr+8 is 0x8009573C, not that + // $ra. Rewrite $t3 before the sw so + // frame+4 is the dest wrapper return. + // Live 8741ab2: first-win leftover-cstk- + // fix then a second ObjectCall frame + // 0x86FA7800 still leftover dest +4 + // (one-shot missed it). Apply every + // leftover dest store with a dump jalr+8. + // Live 84e6a7f leftover dest +4 0x03F70830 + // is leftover-syscall -938 dest wrapper + // (jalr+8 0x80088828), not mid-hash. + // Live f99af0d leftover-cstk api=0xFFFFFFB2 + // (-78) +4 leftover dest 0x03F70830. The + // 938 RA range planted LeftoverApi938Ret + // 0x80088828 then leftover-halt dest stub. + // api -78 is leftover-syscall -1334 / + // methods[78], not -938. Do not leftover + // hop to 0x80088828. leftover dest GetProc + // dest leftover hop forbidden. leftover- + // api-78-need refuses leftover-syscall + // jalr+8; leftover-api-78-cont replays + // dump-true thread+0xEC even when leftover + // dest destPlant and leftover-dispatch +DC + // jal is not +EC. Dump-fill methods[78] so + // ObjectCall can jalr. Live 6ac0299 leftover- + // api-78-cont then leftover-cstk-fix planted + // leftover-syscall -1238 jalr+8 0x80095EBC + // for api 0xFFFFFFCA (-54 / methods[54]). + // leftover-api-54-need refuses that hop; + // leftover-api-54-cont ObjectCall jalr + // dest-live methods[54] already present. + // Do not replay dump memset mid +EC= + // 0x8005950C. Do not leftover hop. Do not + // invent dest. + public static void TryFixLeftoverCstkRa(MipsBus bus, uint[] regs, + uint pc) + { + if (pc != LeftoverCstkSw) + return; + if (regs == null || regs.Length <= 30) + return; + uint t3 = PeekGpr(regs, 11); + if (!IsLeftoverDestVa(t3)) + return; + uint fp = PeekGpr(regs, 30); + uint api = 0; + if (fp != 0 && fp != 0xFFFFFFFFu) + TryPeekWord(bus, fp, out api); + _leftoverCstkApi = api; + uint dest; + if (!TryResolveLeftoverCstkDest(bus, api, t3, out dest)) + { + if (api == LeftoverApi78) + TryNoteLeftoverApi78Need(bus, t3, 0); + else if (api == LeftoverApi54) + TryNoteLeftoverApi54Need(bus, t3, 0); + return; + } + if (IsLeftoverSyscallStubRet(bus, dest)) + { + if (api == LeftoverApi78) + { + TryNoteLeftoverApi78Need(bus, t3, dest); + return; + } + if (api == LeftoverApi54) + { + TryNoteLeftoverApi54Need(bus, t3, dest); + return; + } + } + regs[11] = dest; + if (_leftoverCstkFixLogged) + return; + _leftoverCstkFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-cstk-fix was=0x" + + t3.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " api=0x" + api.ToString("X8") + + " (dump jalr+8 of leftover-syscall; do not leftover dest)"); + } + + // Live f919479 leftover-cstk-fix then silent + // freeze; leftover-ret / leftover-skip / + // leftover-halt did not fire. Name the + // stuck PC after leftover-cstk-fix if + // leftover-halt has not. Do not leftover + // hop. Do not invent dest. + public static void TryNoteLeftoverCstkSpin(MipsBus bus, uint[] regs, + uint pc) + { + if (!_leftoverCstkFixLogged || _leftoverCstkSpinLogged + || _leftoverHaltLogged) + return; + if (pc == 0 || pc == LeftoverCstkSw) + return; + _leftoverCstkSpinN++; + if (_leftoverCstkSpinN < 4096) + return; + _leftoverCstkSpinLogged = true; + uint v0 = PeekGpr(regs, 2); + uint a0 = PeekGpr(regs, 4); + uint ra = PeekGpr(regs, 31); + uint fp = PeekGpr(regs, 30); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-cstk-spin pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " fp=0x" + fp.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (after leftover-cstk-fix; do not leftover dest)"); + } + + // Live a6102f2 leftover-wait99-fix dest-live + // continue leftover dest leftover-syscall $ra + // then leftover-wait99-spin pc=0x80015368 + // v0=0 a0=1 ra=0x80015360 dest=0. Dump + // 0x80015368 is xori IE (jalr+8 0x80015360); + // 0x80015380 beq $v0,$0, restore/ERET. + // dest-live continue leftover dest leftover- + // syscall $ra is leftover-wait99-halt. Live + // 2239756 leftover-wait99-halt then leftover- + // cstk leftover-halt dest stub; leftover- + // wait99-halt now stays at wait99 plant + // root so leftover-cstk / leftover-halt dest + // stub should not fire. Live a2375d3 leftover- + // wait99-halt then leftover-wait99-spin + // pc=0x800558A0 v0=0 a0=0x80338F68 ra= + // 0x80055808 dest=0. Dump 0x800557F4 tick vs + // 0x80338F70. 0x800558A0 is mid OEM tick, not + // leftover dest / not a LoadO32 continue. + // leftover-wait99-tick-halt that PC. Name + // leftover dest leftover-syscall $ra / dest + // mid-hash if leftover-halt has not. Do not + // leftover hop. Do not invent dest. + public static bool TryNoteLeftoverWait99Spin(MipsBus bus, uint[] regs, + uint pc) + { + if (!_wait99PlantFixLogged || _leftoverHaltLogged) + return false; + if (pc == 0 || pc == LeftoverWait99RaSw) + return false; + if (IsLeftoverWait99OemTick(pc)) + { + uint v0Tick = PeekGpr(regs, 2); + uint a0Tick = PeekGpr(regs, 4); + uint raTick = PeekGpr(regs, 31); + if (!_leftoverWait99SpinLogged) + { + _leftoverWait99SpinLogged = true; + uint word = 0; + TryPeekWord(bus, pc, out word); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-tick-halt pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0Tick.ToString("X8") + + " a0=0x" + a0Tick.ToString("X8") + + " ra=0x" + raTick.ToString("X8") + + " word=0x" + word.ToString("X8") + + " (dump 0x" + OemTickDelta.ToString("X8") + + " tick vs 0x" + LeftoverWait99TickWord.ToString("X8") + + "; leftover dest leftover-syscall $ra dest mid-hash not LoadO32; leftover-wait99-halt stays; do not leftover dest)"); + } + return true; + } + if (_leftoverWait99SpinLogged) + return false; + _leftoverWait99SpinN++; + if (_leftoverWait99SpinN < 4096) + return false; + _leftoverWait99SpinLogged = true; + uint v0 = PeekGpr(regs, 2); + uint a0 = PeekGpr(regs, 4); + uint ra = PeekGpr(regs, 31); + uint dest = LeftoverWait99DestOf(pc); + if (dest == 0 && IsLeftoverDestVa(ra) && (ra & 3) == 0) + dest = LeftoverDestKseg + (ra - LeftoverDestLo); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-wait99-spin pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " (after leftover-wait99-fix; do not leftover dest)"); + if (!IsLeftoverWait99PoisonResume(bus, pc)) + return false; + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + if (!_leftoverHaltLogged) + { + _leftoverHaltLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-halt was=0x" + + pc.ToString("X8") + + " +EC=0x" + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " (refuse leftover dest leftover-syscall $ra mid-hash after leftover-wait99-fix; do not leftover dest)"); + } + return true; + } + + // Live a2375d3 leftover-wait99-spin pc=0x800558A0 + // ra=0x80055808. Live 98463a8 leftover-wait99- + // spin pc=0x80055814 after leftover-wait99-halt + // dest=0x80088B94 dest-word=0x01495825. Dump + // 0x800557F4 tick vs 0x80338F70. OEM tick mid, + // not leftover dest / not a LoadO32 continue. + private static bool IsLeftoverWait99OemTick(uint pc) + { + if (pc == LeftoverWait99Tick || pc == LeftoverWait99TickMid + || pc == LeftoverWait99TickRa) + return true; + return pc >= OemTickDelta && pc <= LeftoverWait99Tick; + } + + private static uint LeftoverWait99DestOf(uint pc) + { + if (IsLeftoverDestVa(pc) && (pc & 3) == 0) + return LeftoverDestKseg + (pc - LeftoverDestLo); + if ((pc & 3) == 0 + && pc >= LeftoverDestKseg + && pc < LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo)) + return pc; + return 0; + } + + // leftover dest leftover-syscall $ra dest-live + // continue (live 0x03F71740) / dest mid-hash + // (live 0x80089740 addu) is not a LoadO32 + // resume. dest leftover-syscall jalr+8 / dest + // wrapper stay leftover-halt dest stub, not + // this mid-hash. Do not leftover hop. Do not + // invent dest. + private static bool IsLeftoverWait99PoisonResume(MipsBus bus, uint pc) + { + if ((pc & 3) != 0) + return false; + if (IsLeftoverDestVa(pc)) + return true; + uint dest = LeftoverWait99DestOf(pc); + if (dest == 0 || dest != pc) + return false; + if (IsLeftoverSyscallStubRet(bus, dest)) + return false; + uint leftoverRa = LeftoverDestLo + (dest - LeftoverDestKseg); + uint wrapperDest; + if (TryResolveLeftoverCstkFromDestWrapper(bus, leftoverRa, out wrapperDest)) + return false; + return true; + } + + private static bool IsLeftoverApi938Ra(uint ra) + { + return ra >= LeftoverApi938RaLo && ra < LeftoverApi938RaHi; + } + + private static bool TryResolveLeftoverCstkDest(MipsBus bus, uint api, + uint leftoverRa, out uint dest) + { + dest = 0; + // leftover dest $ra wrapper/thunk first. + // Mid-hash leftover dest (live 0x03F71618 + // dest 0x80089618) has no jalr+8 at + // that PC. Invert leftover-syscall api: + // imm = (int16)((api<<2)-0x3FE), dest ROM + // addiu $0,imm; jalr → jalr+8. Live + // f99af0d leftover dest 0x03F70830 is + // also leftover-syscall -938 jalr delay; + // api -78 must not plant 0x80088828. + // Named api / dest-ROM scan first. 938 + // RA range only when api is 0 or 938. + // Do not leftover hop. Do not invent dest. + if (api == LeftoverApi1630) + dest = LeftoverApi1630Ret; + else if (api == LeftoverApi938) + dest = LeftoverApi938Ret; + else if (TryResolveLeftoverCstkFromApi(bus, api, out dest)) + return true; + else if (TryResolveLeftoverCstkFromDestWrapper(bus, leftoverRa, + out dest)) + return true; + else if ((api == 0 || api == LeftoverApi938) + && IsLeftoverApi938Ra(leftoverRa)) + dest = LeftoverApi938Ret; + else + return false; + return IsSanePlantResumePc(dest); + } + + private static bool IsAddiuZeroNeg(uint word, out uint rt) + { + rt = (word >> 16) & 31; + int simm = (short)(word & 0xFFFFu); + return ((word >> 26) & 63) == 9 + && ((word >> 21) & 31) == 0 + && simm < 0; + } + + // Dump leftover-syscall index api = + // (EPC+0x3FE)>>2. EPC low 16 is the dest + // stub addiu imm. Scan dest window once. + // api 0 / -1 is not a stub. Do not leftover + // hop. Do not invent dest. + private static bool TryResolveLeftoverCstkFromApi(MipsBus bus, uint api, + out uint dest) + { + dest = 0; + if (bus == null || api == 0 || api == 0xFFFFFFFFu) + return false; + int imm = (short)(((api << 2) - 0x3FEu) & 0xFFFFu); + if (imm >= 0) + return false; + EnsureLeftoverStubJalr8(bus); + if (_leftoverStubJalr8 == null + || !_leftoverStubJalr8.TryGetValue(imm, out dest) + || dest == 0) + return false; + return IsSanePlantResumePc(dest); + } + + private static void EnsureLeftoverStubJalr8(MipsBus bus) + { + if (_leftoverStubJalr8 != null) + return; + var map = new Dictionary(); + uint lo = LeftoverDestKseg; + uint hi = LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo); + if (hi > NkImageEnd) + hi = NkImageEnd; + for (uint va = lo; va + 36 < hi; va += 4) + { + uint w = 0; + uint rt; + if (!TryPeekWord(bus, va, out w) || !IsAddiuZeroNeg(w, out rt)) + continue; + int imm = (short)(w & 0xFFFFu); + if (map.ContainsKey(imm)) + continue; + for (uint k = 1; k <= 8; k++) + { + uint w2 = 0; + uint rs; + if (!TryPeekWord(bus, va + k * 4, out w2)) + break; + if (!IsJalrInsn(w2, out rs) || rs != rt) + continue; + uint jalr8 = va + k * 4 + 8; + if (IsSanePlantResumePc(jalr8)) + map[imm] = jalr8; + break; + } + } + if (map.Count == 0) + return; + _leftoverStubJalr8 = map; + } + + private static bool IsJalrInsn(uint word, out uint rs) + { + rs = (word >> 21) & 31; + return ((word >> 26) & 63) == 0 && (word & 63) == 9; + } + + private static bool IsLwRaSp(uint word) + { + return ((word >> 26) & 63) == 35 + && ((word >> 16) & 31) == 31 + && ((word >> 21) & 31) == 29; + } + + // Dump dest wrapper / KData thunk: jalr; + // delay; lw $ra,N($sp); jr $ra. Live + // 1f83cb1 leftover dest 0x03F71EBC is + // dest 0x80089EBC jalr delay nop, not + // leftover-syscall -N. jalr+8 is + // 0x80089EC0. leftover dest $ra at jalr + // delay / jalr+8 / jr / jr-delay. Store + // dest jalr+8. Mid-hash 0x80089740 and + // GetProc 0x8008C844 do not match. Do + // not leftover hop. Do not invent dest. + private static bool TryResolveLeftoverCstkFromDestWrapper(MipsBus bus, + uint leftoverRa, out uint dest) + { + dest = 0; + if (bus == null || !IsLeftoverDestVa(leftoverRa)) + return false; + uint destPc = leftoverRa - LeftoverDestLo + LeftoverDestKseg; + if ((destPc & 3) != 0 || destPc < LeftoverDestKseg + || destPc >= LeftoverDestKseg + (LeftoverDestHi - LeftoverDestLo) + || destPc < 0x80010000u || destPc >= NkImageEnd) + return false; + uint jalrPc = 0; + uint w0 = 0; + uint wm4 = 0; + uint wm8 = 0; + uint wm12 = 0; + uint wm16 = 0; + uint wp4 = 0; + uint wp8 = 0; + if (!TryPeekWord(bus, destPc, out w0)) + return false; + if (TryPeekWord(bus, destPc - 4, out wm4) && IsFirmwareJrRa(wm4) + && TryPeekWord(bus, destPc - 8, out wm8) && IsLwRaSp(wm8) + && TryPeekWord(bus, destPc - 16, out wm16) + && IsJalrInsn(wm16, out _)) + jalrPc = destPc - 16; + else if (IsFirmwareJrRa(w0) + && TryPeekWord(bus, destPc - 4, out wm4) && IsLwRaSp(wm4) + && TryPeekWord(bus, destPc - 12, out wm12) + && IsJalrInsn(wm12, out _)) + jalrPc = destPc - 12; + else if (IsLwRaSp(w0) + && TryPeekWord(bus, destPc + 4, out wp4) && IsFirmwareJrRa(wp4) + && TryPeekWord(bus, destPc - 8, out wm8) + && IsJalrInsn(wm8, out _)) + jalrPc = destPc - 8; + else if (TryPeekWord(bus, destPc - 4, out wm4) + && IsJalrInsn(wm4, out _) + && TryPeekWord(bus, destPc + 4, out wp4) && IsLwRaSp(wp4) + && TryPeekWord(bus, destPc + 8, out wp8) + && IsFirmwareJrRa(wp8)) + jalrPc = destPc - 4; + else + return false; + dest = jalrPc + 8; + return IsSanePlantResumePc(dest); + } + + // Live b757425 leftover-skip $v0 leftover + // dest. Dump 0x800397F8 lw $s3,4(frame) + // before 0x80039860 unlinks thread+0x18. + // leftover dest in $v0 is that frame+4 + // leftover-syscall PC, not FD50 GetProc. + // One Hive line. Do not leftover hop. + // Do not invent dest. + public static void TryNoteLeftoverRetObserve(MipsBus bus, uint[] regs, + uint pc) + { + if (_leftoverRetLogged) + return; + if (pc != LeftoverLoadS3) + return; + if (regs == null || regs.Length <= 4) + return; + uint frame = PeekGpr(regs, 4); + uint frame4 = 0; + uint fd50 = 0; + uint plus18 = 0; + uint thr = 0; + if (frame != 0 && frame != 0xFFFFFFFFu) + TryPeekWord(bus, frame + 4, out frame4); + bool destStub = IsLeftoverSyscallStubRet(bus, frame4); + if (!IsLeftoverDestVa(frame4) && !destStub) + return; + _leftoverRetLogged = true; + TryPeekWord(bus, ExnContinueWord, out fd50); + if (TryPeekWord(bus, ThreadPtr, out thr) && thr != 0 + && thr != 0xFFFFFFFFu) + TryPeekWord(bus, thr + ThreadSyscallFrame, out plus18); + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-ret a0=0x" + + frame.ToString("X8") + + " +4=0x" + frame4.ToString("X8") + + " FD50=0x" + fd50.ToString("X8") + + " +18=0x" + plus18.ToString("X8") + + (destStub + ? " (dump frame+4 dest leftover-syscall jalr+8)" + : " (dump frame+4 leftover dest)")); + } + + // Live 1f83cb1 leftover-ret leftover dest + // +4=0x03F71EBC (dest thunk jalr delay, + // jalr+8 0x80089EC0). Write dest jalr+8 + // before 0x800397F8 lw $s3. Live f99af0d + // leftover-ret +4 leftover dest 0x03F70830 + // after leftover-cstk api -78. Do not + // leftover hop to 0x80088828. Pass the + // leftover-cstk api; refuse leftover- + // syscall jalr+8 for api -78 / api -54 + // (0x80095EBC leftover-syscall -1238). + // leftover-skip / leftover-halt stay. Do + // not leftover hop. Do not invent dest. + public static void TryFixLeftoverRetRa(MipsBus bus, uint[] regs, + uint pc) + { + if (pc != LeftoverLoadS3) + return; + if (regs == null || regs.Length <= 4 || bus == null) + return; + uint frame = PeekGpr(regs, 4); + uint frame4 = 0; + if (frame == 0 || frame == 0xFFFFFFFFu) + return; + if (!TryPeekWord(bus, frame + 4, out frame4)) + return; + if (!IsLeftoverDestVa(frame4)) + return; + uint dest; + uint api = _leftoverCstkApi; + if (!TryResolveLeftoverCstkDest(bus, api, frame4, out dest)) + return; + if (IsLeftoverSyscallStubRet(bus, dest)) + { + if (api == LeftoverApi78) + { + TryNoteLeftoverApi78Need(bus, frame4, dest); + return; + } + if (api == LeftoverApi54) + { + TryNoteLeftoverApi54Need(bus, frame4, dest); + return; + } + } + try + { + bus.Write32(frame + 4, dest); + } + catch + { + return; + } + if (_leftoverRetFixLogged) + return; + _leftoverRetFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop leftover-ret-fix was=0x" + + frame4.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " a0=0x" + frame.ToString("X8") + + " (dump jalr+8 of leftover-syscall; do not leftover dest)"); + } + + // Live 3275fe9: kernel 0x80031D38 TLBS + // 0xC201FE84. Peek insn / rs / rt / base. + // a1 is nk ROM evidence, not a hop. One + // Hive line. Do not invent dest. Do not + // map 0xC2xxxxxx. + private static void TryNoteC2TlbsObserve(MipsBus bus, uint[] regs, + uint epc, uint vaddr) + { + if (_c2TlbsLogged) + return; + _c2TlbsLogged = true; + uint insn = 0; + string via = "peek-miss"; + if (TryPeekWord(bus, epc, out insn)) + via = "kseg"; + string dis = via != "peek-miss" ? FormatMipsOp(epc, insn) : "peek-miss"; + uint rs = (insn >> 21) & 31; + uint rt = (insn >> 16) & 31; + int simm = (short)(insn & 0xFFFFu); + uint bas = PeekGpr(regs, (int)rs); + uint formed = bas + (uint)simm; + string extra = via == "kseg" ? "" : " via=" + via; + BootLog.Write("[Hive] ExtraROM ddi_nop c2-tlbs epc=0x" + + epc.ToString("X8") + + " va=0x" + vaddr.ToString("X8") + + " insn=" + (via != "peek-miss" ? "0x" + insn.ToString("X8") : "peek-miss") + + (via != "peek-miss" ? " " + dis : "") + + " rs=" + rs + + " rt=" + rt + + " base=0x" + bas.ToString("X8") + + " formed=0x" + formed.ToString("X8") + + extra + + " a1=" + GprHex(regs, 5) + + " (TLBS; do not invent dest)"); + } + + private static void TryNoteBindImpExnSave(MipsBus bus, uint[] regs, uint pc) + { + if (!_ddiNopAwaitCallDll || !_ddiNopIatStoreLogged) + return; + if (pc < BindImpExnLo || pc > BindImpExnHi) + return; + if (_bindImpExnSaveLogged) + return; + if (IsGwesDataB9Page(_bindImpExnVaddr)) + return; + if (IsFilesysSlot2ExtraPage(_bindImpExnVaddr)) + return; + if (IsDdiNopCoredllImageVa(_bindImpExnVaddr)) + return; + if (IsNearNullVa(_bindImpExnVaddr)) + return; + if (IsAdelSkip(_bindImpExnCode, _bindImpExnEpc, _bindImpExnVaddr)) + return; + if (IsC2TlbsVa(_bindImpExnCode, _bindImpExnVaddr)) + return; + _bindImpExnSaveLogged = true; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + BootLog.Write("[Hive] ExtraROM BindImp-exn save pc=0x" + + pc.ToString("X8") + + " cause=" + _bindImpExnCode + + " epc=0x" + _bindImpExnEpc.ToString("X8") + + " badvaddr=0x" + _bindImpExnVaddr.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " stores=" + _ddiNopIatStoreN); + } + + // Live edf15b0: after stores=24, coredll + // 0x03F6C908 lw $v0,0($s5) TLBL on 0x01FFFCA4. + // Observe $s5 / mappedness, then demand-map the + // process-info page via firmware PTE, KData keep, + // or a zero valloc host page. Do not invent heap. + private static void TryNoteDdiNopProcessInfo(MipsBus bus, uint[] regs) + { + if (_ddiNopInfoObserved || !_ddiNopAwaitCallDll) + return; + if (_ddiNopIatStoreN < BindImpObserveMax && !_ddiNopSawCallDllPc) + return; + _ddiNopInfoObserved = true; + uint s5 = regs != null && regs.Length > 21 ? regs[21] : 0; + uint word = 0; + bool mapped = false; + _ddiNopInfoPeekRaw = true; + try + { + mapped = TryPeekWord(bus, ProcessInfoFaultVa, out word); + } + finally + { + _ddiNopInfoPeekRaw = false; + } + BootLog.Write("[Hive] ExtraROM ddi_nop proc-info s5=0x" + + s5.ToString("X8") + + " va=0x" + ProcessInfoFaultVa.ToString("X8") + + (mapped ? " mapped" : " unmapped") + + " word=0x" + word.ToString("X8") + + " stores=" + _ddiNopIatStoreN); + TryResolveDdiNopProcessInfo(bus); + } + + private static bool IsDdiNopProcessInfoArmed() + { + if (_leftoverWait99O32NkCoredllSawEntry) + return true; + if (!_ddiNopAwaitCallDll) + return false; + if (_ddiNopInfoDemand || _ddiNopSawCallDllPc) + return true; + return _ddiNopIatStoreN >= BindImpObserveMax; + } + + public static uint MapDdiNopProcessInfoVa(MipsBus bus, uint va) + { + if (_ddiNopInfoPeekRaw || _ddiNopInfoBusy) + return va; + if (!IsDdiNopProcessInfoArmed()) + return va; + if (va < ProcessInfoPage || va >= 0x02000000u) + return va; + if (_ddiNopInfoKseg != 0) + return _ddiNopInfoKseg | (va & 0xFFFu); + TryResolveDdiNopProcessInfo(bus); + if (_ddiNopInfoKseg != 0) + return _ddiNopInfoKseg | (va & 0xFFFu); + return va; + } + + private static void TryResolveDdiNopProcessInfo(MipsBus bus) + { + if (_ddiNopInfoKseg != 0 || _ddiNopInfoBusy || bus == null) + return; + try + { + _ddiNopInfoBusy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, ProcessInfoFaultVa, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopInfoKseg = kseg & ~0xFFFu; + if (!_ddiNopInfoMapLogged) + { + _ddiNopInfoMapLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop proc-info map va=0x" + + ProcessInfoPage.ToString("X8") + + " -> 0x" + _ddiNopInfoKseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " (firmware PTE; same page as *0x01FFFFA0; do not invent heap bytes)"); + } + return; + } + uint kdata = (KDataBase & ~0xFFFu) | (ProcessInfoFaultVa & 0xFFFu); + uint word = 0; + if (TryPeekWord(bus, kdata, out word)) + { + _ddiNopInfoKseg = KDataBase & ~0xFFFu; + if (!_ddiNopInfoMapLogged) + { + _ddiNopInfoMapLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop proc-info map va=0x" + + ProcessInfoPage.ToString("X8") + + " -> 0x" + _ddiNopInfoKseg.ToString("X8") + + " (KData keep; same page as UserKPage alias; do not invent heap bytes)"); + } + return; + } + if (TryHostBackProcessInfoPage() && !_ddiNopInfoMapLogged) + { + _ddiNopInfoMapLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop proc-info map va=0x" + + ProcessInfoPage.ToString("X8") + + " -> 0x" + _ddiNopInfoKseg.ToString("X8") + + " (zero page; existing valloc host; do not invent heap bytes)"); + } + } + finally + { + _ddiNopInfoBusy = false; + } + } + + // Live 6b8a9eb: I-fetch TLBL at 0x0005D2E0 after + // DllMain. Same page as GwesVaDispAlloc 0x0005D250. + // Demand-map via firmware PTE only. Do not invent + // dest / 0x03FAD2E0 / zero code bytes. + public static uint MapDdiNopGwesDispFetchVa(MipsBus bus, uint va) + { + if (_ddiNopGwesFetchBusy) + return va; + if (!IsDdiNopGwesDispFetchArmed()) + return va; + if ((va & ~0xFFFu) != GwesDispFetchPage) + return va; + if (_ddiNopGwesFetchKseg != 0) + return _ddiNopGwesFetchKseg | (va & 0xFFFu); + TryResolveDdiNopGwesDispFetch(bus); + if (_ddiNopGwesFetchKseg != 0) + return _ddiNopGwesFetchKseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesDispFetchArmed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiNopGwesFetchDemand; + } + + private static void TryNoteDdiNopGwesDispFetchTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiNopGwesFetchDemand = true; + if (!_ddiNopGwesFetchTlblLogged) + { + _ddiNopGwesFetchTlblLogged = true; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop fetch-TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dllmain-ra=0x" + _ddiNopDllMainRa.ToString("X8") + + " (I-fetch; gwes Display page 0x0005D000; not COREDLL 0x03FAD2E0)"); + } + TryResolveDdiNopGwesDispFetch(bus); + } + + private static void TryResolveDdiNopGwesDispFetch(MipsBus bus) + { + if (_ddiNopGwesFetchKseg != 0 || _ddiNopGwesFetchBusy || bus == null) + return; + try + { + _ddiNopGwesFetchBusy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, GwesDispFetchFault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopGwesFetchKseg = kseg & ~0xFFFu; + if (!_ddiNopGwesFetchLogged) + { + _ddiNopGwesFetchLogged = true; + uint word = 0; + TryPeekWord(bus, kseg | (GwesDispFetchFault & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp map va=0x" + + GwesDispFetchPage.ToString("X8") + + " -> 0x" + _ddiNopGwesFetchKseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; GwesVaDispAlloc page; do not invent dest)"); + } + return; + } + if (!_ddiNopGwesFetchLogged) + { + _ddiNopGwesFetchLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp map va=0x" + + GwesDispFetchPage.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (I-fetch 0x0005D2E0; do not invent dest or 0x03FAD2E0)"); + } + } + finally + { + _ddiNopGwesFetchBusy = false; + } + } + + // Live 4f43fe4: data TLBL epc=0x0005D310 + // badvaddr=0x000B6008 (GwesIatGetProc). Demand-map + // that IAT page via firmware PTE only. Do not + // invent dest-word or zero-fill. + public static uint MapDdiNopGwesDispDataVa(MipsBus bus, uint va) + { + if (_ddiNopGwesDataBusy) + return va; + if (!IsDdiNopGwesDispDataArmed()) + return va; + if ((va & ~0xFFFu) != GwesDispDataPage) + return va; + if (_ddiNopGwesDataKseg != 0) + return _ddiNopGwesDataKseg | (va & 0xFFFu); + TryResolveDdiNopGwesDispData(bus); + if (_ddiNopGwesDataKseg != 0) + return _ddiNopGwesDataKseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesDispDataArmed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiNopGwesDataDemand; + } + + private static void TryNoteDdiNopGwesDispDataTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiNopGwesDataDemand = true; + if (!_ddiNopGwesDataTlblLogged) + { + _ddiNopGwesDataTlblLogged = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop data-TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (GwesIatGetProc; gwes Display IAT page; do not invent dest)"); + } + TryResolveDdiNopGwesDispData(bus); + } + + private static void TryResolveDdiNopGwesDispData(MipsBus bus) + { + if (_ddiNopGwesDataKseg != 0 || _ddiNopGwesDataBusy || bus == null) + return; + try + { + _ddiNopGwesDataBusy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, GwesDispDataFault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopGwesDataKseg = kseg & ~0xFFFu; + if (!_ddiNopGwesDataLogged) + { + _ddiNopGwesDataLogged = true; + uint word = 0; + TryPeekWord(bus, kseg | (GwesDispDataFault & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data map va=0x" + + GwesDispDataPage.ToString("X8") + + " -> 0x" + _ddiNopGwesDataKseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; GwesIatGetProc; do not invent dest)"); + } + return; + } + if (!_ddiNopGwesDataLogged) + { + _ddiNopGwesDataLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data map va=0x" + + GwesDispDataPage.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (data TLBL 0x000B6008; do not invent dest)"); + } + } + finally + { + _ddiNopGwesDataBusy = false; + } + } + + // Live 8623be5: NK 0x80020174 data-TLBL on + // 0x00011C10. First gwes .text page (VA + // 0x00011000 / FILESYS API 0x000111A8). + // Firmware PTE only. Do not invent dest or + // steal sipcfg 0x00011000. + public static uint MapDdiNopGwesTextBaseVa(MipsBus bus, uint va) + { + if (_ddiNopGwesTextBusy) + return va; + if (!IsDdiNopGwesTextBaseArmed()) + return va; + if ((va & ~0xFFFu) != GwesTextBasePage) + return va; + if (_ddiNopGwesTextKseg != 0) + return _ddiNopGwesTextKseg | (va & 0xFFFu); + TryResolveDdiNopGwesTextBase(bus); + if (_ddiNopGwesTextKseg != 0) + return _ddiNopGwesTextKseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesTextBaseArmed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiNopGwesTextDemand; + } + + private static void TryNoteDdiNopGwesTextBaseTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiNopGwesTextDemand = true; + if (!_ddiNopGwesTextTlblLogged) + { + _ddiNopGwesTextTlblLogged = true; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop text-TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " (nk near ThreadContextSetup; gwes .text 0x00011000; do not invent dest)"); + } + TryResolveDdiNopGwesTextBase(bus); + } + + private static void TryResolveDdiNopGwesTextBase(MipsBus bus) + { + if (_ddiNopGwesTextKseg != 0 || _ddiNopGwesTextBusy || bus == null) + return; + try + { + _ddiNopGwesTextBusy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, GwesTextBaseFault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopGwesTextKseg = kseg & ~0xFFFu; + if (!_ddiNopGwesTextLogged) + { + _ddiNopGwesTextLogged = true; + uint word = 0; + TryPeekWord(bus, kseg | (GwesTextBaseFault & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-text map va=0x" + + GwesTextBasePage.ToString("X8") + + " -> 0x" + _ddiNopGwesTextKseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; gwes VA 0x00011000 / FILESYS API page; do not invent dest)"); + } + return; + } + if (!_ddiNopGwesTextLogged) + { + _ddiNopGwesTextLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-text map va=0x" + + GwesTextBasePage.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (data TLBL 0x00011C10; do not invent dest or sipcfg dest)"); + } + } + finally + { + _ddiNopGwesTextBusy = false; + } + } + + // Live 04b8c34: Display 0x0005D380 data-TLBL + // 0x000B7CA8. Page 0x000B7000 holds GwesInitFlag + // 0x000B7A1D. Firmware PTE only. Do not invent dest. + public static uint MapDdiNopGwesDispData2Va(MipsBus bus, uint va) + { + if (_ddiNopGwesData2Busy) + return va; + if (!IsDdiNopGwesDispData2Armed()) + return va; + if ((va & ~0xFFFu) != GwesDispData2Page) + return va; + if (_ddiNopGwesData2Kseg != 0) + return _ddiNopGwesData2Kseg | (va & 0xFFFu); + TryResolveDdiNopGwesDispData2(bus); + if (_ddiNopGwesData2Kseg != 0) + return _ddiNopGwesData2Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesDispData2Armed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiNopGwesData2Demand; + } + + private static void TryNoteDdiNopGwesDispData2Tlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiNopGwesData2Demand = true; + if (!_ddiNopGwesData2TlblLogged) + { + _ddiNopGwesData2TlblLogged = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop data2-TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (GwesInitFlag page; gwes Display data 0x000B7000; do not invent dest)"); + } + TryResolveDdiNopGwesDispData2(bus); + } + + private static void TryResolveDdiNopGwesDispData2(MipsBus bus) + { + if (_ddiNopGwesData2Kseg != 0 || _ddiNopGwesData2Busy || bus == null) + return; + try + { + _ddiNopGwesData2Busy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, GwesDispData2Fault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopGwesData2Kseg = kseg & ~0xFFFu; + if (!_ddiNopGwesData2Logged) + { + _ddiNopGwesData2Logged = true; + uint word = 0; + TryPeekWord(bus, kseg | (GwesDispData2Fault & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data2 map va=0x" + + GwesDispData2Page.ToString("X8") + + " -> 0x" + _ddiNopGwesData2Kseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; GwesInitFlag page; do not invent dest)"); + } + return; + } + if (!_ddiNopGwesData2Logged) + { + _ddiNopGwesData2Logged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data2 map va=0x" + + GwesDispData2Page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (data TLBL 0x000B7CA8; do not invent dest)"); + } + } + finally + { + _ddiNopGwesData2Busy = false; + } + } + + // Live 5db4c8e: Display 0x0005D38C data-TLBL + // 0x000BA954 (GwesDispObj). Firmware PTE only. + // Do not invent dest. + public static uint MapDdiNopGwesDispData3Va(MipsBus bus, uint va) + { + if (_ddiNopGwesData3Busy) + return va; + if (!IsDdiNopGwesDispData3Armed()) + return va; + if ((va & ~0xFFFu) != GwesDispData3Page) + return va; + if (_ddiNopGwesData3Kseg != 0) + return _ddiNopGwesData3Kseg | (va & 0xFFFu); + TryResolveDdiNopGwesDispData3(bus); + if (_ddiNopGwesData3Kseg != 0) + return _ddiNopGwesData3Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesDispData3Armed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiNopGwesData3Demand; + } + + private static void TryNoteDdiNopGwesDispData3Tlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiNopGwesData3Demand = true; + if (!_ddiNopGwesData3TlblLogged) + { + _ddiNopGwesData3TlblLogged = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop data3-TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (GwesDispObj page; gwes Display data 0x000BA000; do not invent dest)"); + } + TryResolveDdiNopGwesDispData3(bus); + } + + private static void TryResolveDdiNopGwesDispData3(MipsBus bus) + { + if (_ddiNopGwesData3Kseg != 0 || _ddiNopGwesData3Busy || bus == null) + return; + try + { + _ddiNopGwesData3Busy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, GwesDispData3Fault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopGwesData3Kseg = kseg & ~0xFFFu; + if (!_ddiNopGwesData3Logged) + { + _ddiNopGwesData3Logged = true; + uint word = 0; + TryPeekWord(bus, kseg | (GwesDispData3Fault & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data3 map va=0x" + + GwesDispData3Page.ToString("X8") + + " -> 0x" + _ddiNopGwesData3Kseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; GwesDispObj; do not invent dest)"); + } + return; + } + if (!_ddiNopGwesData3Logged) + { + _ddiNopGwesData3Logged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data3 map va=0x" + + GwesDispData3Page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (data TLBL 0x000BA954; do not invent dest)"); + } + } + finally + { + _ddiNopGwesData3Busy = false; + } + } + + // Live c36c2a4: I-fetch TLBL 0x00014B3C after + // data3 map. gwes .text page 0x00014000 (ROM + // 0x80149B3C). Firmware PTE only. Do not invent + // dest or steal tv2 PE 0x00014000. + public static uint MapDdiNopGwesText2Va(MipsBus bus, uint va) + { + if (_ddiNopGwesText2Busy) + return va; + if (!IsDdiNopGwesText2Armed()) + return va; + if ((va & ~0xFFFu) != GwesText2Page) + return va; + if (_ddiNopGwesText2Kseg != 0) + return _ddiNopGwesText2Kseg | (va & 0xFFFu); + TryResolveDdiNopGwesText2(bus); + if (_ddiNopGwesText2Kseg != 0) + return _ddiNopGwesText2Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesText2Armed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiNopGwesText2Demand; + } + + private static void TryNoteDdiNopGwesText2Tlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiNopGwesText2Demand = true; + if (!_ddiNopGwesText2TlblLogged) + { + _ddiNopGwesText2TlblLogged = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop text2-TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (gwes .text 0x00014000 / ROM 0x80149B3C; do not invent dest)"); + } + TryResolveDdiNopGwesText2(bus); + } + + private static void TryResolveDdiNopGwesText2(MipsBus bus) + { + if (_ddiNopGwesText2Kseg != 0 || _ddiNopGwesText2Busy || bus == null) + return; + try + { + _ddiNopGwesText2Busy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (sec != 0 + && WalkFirmwarePte(bus, sec, GwesText2Fault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _ddiNopGwesText2Kseg = kseg & ~0xFFFu; + if (!_ddiNopGwesText2Logged) + { + _ddiNopGwesText2Logged = true; + uint word = 0; + TryPeekWord(bus, kseg | (GwesText2Fault & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-text2 map va=0x" + + GwesText2Page.ToString("X8") + + " -> 0x" + _ddiNopGwesText2Kseg.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; gwes .text 0x00014000; do not invent dest)"); + } + return; + } + if (!_ddiNopGwesText2Logged) + { + _ddiNopGwesText2Logged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-text2 map va=0x" + + GwesText2Page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (fetch TLBL 0x00014B3C; do not invent dest)"); + } + } + finally + { + _ddiNopGwesText2Busy = false; + } + } + + // Live 187f5be: fetch-TLBL 0x000B4B80 after text2. + // Same firmware-PTE demand-map as 0x00011000 / + // 0x00014000 / 0x0005D000 / 0x000B6000 / 0x000B7000 + // / 0x000BA000. Live d01f68a: 0x00059000 PTE + // dest 0x86FA1000 dest-word=0 hid ROM 0x8018E000. + // Dest-word=0 .text uses o32 dataptr. Live + // 831a196: ImageBase 0x00010000 / +4 is headers; + // TOC gwes o32/load, not slot-0 filesys PTE. + // Live 7214ee6: 0x000B9000 is compressed .data; + // dest-word=0 firmware PTE is dump zeros, not + // a missing section. Named pages keep tags. + public static uint MapDdiNopGwesImageVa(MipsBus bus, uint va) + { + if (_gwesImageBusy) + return va; + if (!IsDdiNopGwesImageArmed()) + return va; + if (!IsDdiNopGwesImageVa(va) || IsNamedDdiNopGwesPage(va)) + return va; + uint kseg = LookupGwesImageKseg(va); + if (kseg != 0) + { + TryReplaceGwesDest0WithRom(bus, va, kseg); + kseg = LookupGwesImageKseg(va); + if (kseg != 0) + return kseg | (va & 0xFFFu); + } + TryResolveDdiNopGwesImage(bus, va); + kseg = LookupGwesImageKseg(va); + if (kseg != 0) + return kseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopGwesImageArmed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _gwesImageDemand; + } + + private static bool IsDdiNopGwesImageVa(uint va) + { + if ((va >> 25) != 0) + return false; + uint page = va & ~0xFFFu; + if (page == GwesImageBasePage) + return true; + return page >= GwesImageLo && page < GwesImageHi; + } + + private static bool IsGwesImageBasePage(uint va) + { + return (va >> 25) == 0 && (va & ~0xFFFu) == GwesImageBasePage; + } + + private static bool IsGwesDataB9Page(uint va) + { + return (va >> 25) == 0 && (va & ~0xFFFu) == GwesDataB9Page; + } + + private static bool IsNamedDdiNopGwesPage(uint va) + { + uint page = va & ~0xFFFu; + return page == GwesDispFetchPage + || page == GwesDispDataPage + || page == GwesTextBasePage + || page == GwesDispData2Page + || page == GwesDispData3Page + || page == GwesText2Page; + } + + private static void EnsureGwesImageMaps() + { + if (_gwesImagePage != null) + return; + _gwesImagePage = new uint[GwesImagePageCap]; + _gwesImageKseg = new uint[GwesImagePageCap]; + _gwesImageDone = new bool[GwesImagePageCap]; + _gwesImageTlbl = new bool[GwesImagePageCap]; + } + + private static int FindGwesImageSlot(uint page) + { + EnsureGwesImageMaps(); + for (int i = 0; i < _gwesImageN; i++) + { + if (_gwesImagePage[i] == page) + return i; + } + return -1; + } + + private static int ClaimGwesImageSlot(uint page) + { + int i = FindGwesImageSlot(page); + if (i >= 0) + return i; + if (_gwesImageN >= GwesImagePageCap) + return -1; + i = _gwesImageN; + _gwesImageN++; + _gwesImagePage[i] = page; + return i; + } + + private static uint LookupGwesImageKseg(uint va) + { + int i = FindGwesImageSlot(va & ~0xFFFu); + if (i < 0) + return 0; + return _gwesImageKseg[i]; + } + + private static void RememberGwesImageKseg(uint va, uint dest) + { + if (!IsDdiNopGwesImageVa(va) || IsNamedDdiNopGwesPage(va)) + return; + int i = ClaimGwesImageSlot(va & ~0xFFFu); + if (i < 0) + return; + uint kseg = dest & ~0xFFFu; + if (kseg != 0) + { + _gwesImageKseg[i] = kseg; + _gwesImageDone[i] = true; + } + } + + // TOC[7] o32[0] dataptr + (page - 0x00011000). + // Only .text through GwesRomTextEnd. Not data. + // Not ImageBase 0x00010000 (headers). + private static uint GwesRomTextPage(uint va) + { + uint page = va & ~0xFFFu; + if (page < GwesImageLo) + return 0; + uint rom = GwesRomText + (page - GwesImageLo); + if (rom < GwesRomText || rom >= GwesRomTextEnd) + return 0; + return rom; + } + + // Live d01f68a: dest-word=0 at 0x86FA1000. + // Prefer o32 ROM when that dest peeks. + private static bool TryGwesRomTextDest(MipsBus bus, uint va, + uint destWord, out uint rom, out uint romWord) + { + rom = 0; + romWord = 0; + if (destWord != 0) + return false; + rom = GwesRomTextPage(va); + if (rom == 0 || bus == null) + return false; + uint off = va & 0xFFFu; + if (TryPeekWord(bus, rom | off, out romWord) + || TryPeekWord(bus, rom, out romWord)) + return true; + rom = 0; + return false; + } + + // Live 7214ee6: o32[1] .data is compressed and + // page-off 0x3000 >= psize 0xCF5. Do not emit + // 0x80288000. B9 uses firmware PTE dest0. + private static bool TryGwesO32SectionDest(MipsBus bus, uint va, + uint destWord, out uint rom, out uint romWord, out uint o32Index) + { + rom = 0; + romWord = 0; + o32Index = 0; + if (destWord != 0 || bus == null || !IsGwesDataB9Page(va)) + return false; + uint tocEntry = 0; + if (!TryFindGwesTocEntry(bus, out tocEntry)) + return false; + try + { + uint e32 = bus.Read32(tocEntry + 0x14); + uint o32 = bus.Read32(tocEntry + 0x18); + if (e32 == 0 || o32 == 0) + return false; + if (bus.Read32(e32 + 8) != ExeVbase) + return false; + uint objcnt = bus.Read32(e32) & 0xFFFF; + if (objcnt == 0 || objcnt > 16) + return false; + uint page = va & ~0xFFFu; + for (uint s = 0; s < objcnt; s++) + { + uint src = o32 + s * O32RomSize; + uint vsize = bus.Read32(src); + uint rva = bus.Read32(src + 4); + uint psize = bus.Read32(src + 8); + uint dataptr = bus.Read32(src + 0xC); + uint real = bus.Read32(src + 0x10); + uint flags = bus.Read32(src + 0x14); + if (vsize == 0 || psize == 0) + continue; + if ((flags & O32Compressed) != 0) + continue; + if (dataptr < 0x80000000u || dataptr >= 0xA0000000u) + continue; + uint start = real != 0 ? real : (ExeVbase + rva); + if (va < start || va >= start + vsize) + continue; + uint startPage = start & ~0xFFFu; + if (page < startPage) + continue; + uint rel = page - startPage; + if (rel >= psize) + continue; + uint dest = (dataptr + rel) & ~0xFFFu; + if (dest == 0 || dest == GwesRomText) + continue; + if (dest >= GwesRomText && dest < GwesRomTextEnd) + continue; + uint off = va & 0xFFFu; + if (!TryPeekWord(bus, dest | off, out romWord) + && !TryPeekWord(bus, dest, out romWord)) + continue; + rom = dest; + o32Index = s; + return true; + } + } + catch + { + } + return false; + } + + // Live 831a196: 0x00010004 is TOC[7] ImageBase + // headers, not .text. Slot 0 PTE is filesys. + // Dest from gwes o32 rva0 / TOCentry load / + // peeked MZ immediately before o32[0] dataptr. + // Do not invent PE bytes. + private static bool TryGwesHeaderDest(MipsBus bus, uint va, + out uint rom, out uint romWord, out string via) + { + rom = 0; + romWord = 0; + via = null; + if (bus == null || !IsGwesImageBasePage(va)) + return false; + uint dest = 0; + string how = null; + if (!TryFindGwesHeaderRom(bus, out dest, out how) || dest == 0) + return false; + uint off = va & 0xFFFu; + if (!TryPeekWord(bus, dest | off, out romWord) + && !TryPeekWord(bus, dest, out romWord)) + return false; + rom = dest; + via = how; + return true; + } + + private static bool TryFindGwesTocEntry(MipsBus bus, out uint tocEntry) + { + tocEntry = 0; + uint attr = 0; + if (bus == null) + return false; + try + { + if (TryFindTocModule(bus, 0, 80, "gwes.exe", out tocEntry, out attr) + && tocEntry != 0) + return true; + uint extra = ExtraRomToc(bus); + if (extra != 0 + && TryFindTocModule(bus, extra, 128, "gwes.exe", out tocEntry, out attr) + && tocEntry != 0) + return true; + if (TryFindGwesTocByTextO32(bus, 0, 80, out tocEntry)) + return true; + if (extra != 0 + && TryFindGwesTocByTextO32(bus, extra, 128, out tocEntry)) + return true; + } + catch + { + } + tocEntry = 0; + return false; + } + + // nk TOC[7] identity: e32 vbase 0x00010000 and + // o32[0] dataptr 0x80146000. filesys/device share + // the EXE vbase. + private static bool TryFindGwesTocByTextO32(MipsBus bus, uint tocOrZero, + uint maxMods, out uint tocEntry) + { + tocEntry = 0; + if (bus == null) + return false; + try + { + uint toc = tocOrZero; + if (toc == 0) + toc = bus.Read32(EcecTocPtr); + if (toc == 0) + return false; + uint nmods = bus.Read32(toc + RomHdrNumMods); + if (nmods == 0 || nmods > maxMods) + return false; + uint found = 0; + for (uint i = 0; i < nmods; i++) + { + uint entry = toc + TocFirst + i * TocEntrySize; + uint e32 = bus.Read32(entry + 0x14); + uint o32 = bus.Read32(entry + 0x18); + if (e32 == 0 || o32 == 0) + continue; + if (bus.Read32(e32 + 8) != ExeVbase) + continue; + uint dataptr = bus.Read32(o32 + 0xC); + uint real = bus.Read32(o32 + 0x10); + if (dataptr != GwesRomText) + continue; + if (real != 0 && (real & ~0xFFFu) != GwesImageLo) + continue; + if (found != 0) + return false; + found = entry; + } + if (found == 0) + return false; + tocEntry = found; + return true; + } + catch + { + return false; + } + } + + private static bool TryFindGwesHeaderRom(MipsBus bus, out uint dest, + out string via) + { + dest = 0; + via = null; + uint tocEntry = 0; + if (!TryFindGwesTocEntry(bus, out tocEntry)) + return false; + try + { + uint e32 = bus.Read32(tocEntry + 0x14); + uint o32 = bus.Read32(tocEntry + 0x18); + uint load = bus.Read32(tocEntry + 0x1C); + if (e32 == 0 || o32 == 0) + return false; + if (bus.Read32(e32 + 8) != ExeVbase) + return false; + uint objcnt = bus.Read32(e32) & 0xFFFF; + if (objcnt == 0 || objcnt > 16) + return false; + for (uint s = 0; s < objcnt; s++) + { + uint src = o32 + s * O32RomSize; + uint vsize = bus.Read32(src); + uint rva = bus.Read32(src + 4); + uint dataptr = bus.Read32(src + 0xC); + uint real = bus.Read32(src + 0x10); + if (vsize == 0) + continue; + if (dataptr < 0x80000000u || dataptr >= 0xA0000000u) + continue; + uint page = dataptr & ~0xFFFu; + if (page == 0 || page == GwesRomText) + continue; + bool covers = false; + if (real != 0 + && real <= GwesImageBasePage + && GwesImageBasePage < real + vsize) + covers = true; + if ((ExeVbase + rva) <= GwesImageBasePage + && GwesImageBasePage < (ExeVbase + rva + vsize)) + covers = true; + if (rva == 0) + covers = true; + if (!covers) + continue; + dest = page; + via = "o32-hdr"; + return true; + } + uint loadPage = load & ~0xFFFu; + if (load >= 0x80000000u && load < 0xA0000000u + && loadPage != 0 && loadPage != GwesRomText) + { + dest = loadPage; + via = "toc-load"; + return true; + } + uint o0ptr = bus.Read32(o32 + 0xC); + uint o0real = bus.Read32(o32 + 0x10); + if (o0ptr == GwesRomText + && (o0real == 0 || (o0real & ~0xFFFu) == GwesImageLo)) + { + uint hdr = GwesRomText - (GwesImageLo - GwesImageBasePage); + uint word = 0; + if (hdr < GwesRomText && hdr >= 0x80000000u + && (TryPeekWord(bus, hdr | (GwesImageBaseFault & 0xFFFu), out word) + || TryPeekWord(bus, hdr, out word)) + && (word & 0xFFFFu) == 0x5A4Du) + { + dest = hdr; + via = "o32-pre"; + return true; + } + } + } + catch + { + } + return false; + } + + private static void TryReplaceGwesDest0WithRom(MipsBus bus, uint va, + uint kseg) + { + uint rom = 0; + uint romWord = 0; + string via = null; + if (IsGwesImageBasePage(va)) + { + if (!TryGwesHeaderDest(bus, va, out rom, out romWord, out via)) + return; + } + else if (IsGwesDataB9Page(va)) + { + // dest-word=0 is decompressed .data zeros. + // Do not replace firmware PTE with XIP. + return; + } + else + { + uint word = 0; + TryPeekWord(bus, (kseg & ~0xFFFu) | (va & 0xFFFu), out word); + if (!TryGwesRomTextDest(bus, va, word, out rom, out romWord)) + return; + via = "o32-rom"; + } + if ((kseg & ~0xFFFu) == rom) + return; + int i = FindGwesImageSlot(va & ~0xFFFu); + if (i < 0) + return; + _gwesImageKseg[i] = rom; + _gwesImageDone[i] = true; + string why = IsGwesImageBasePage(va) + ? " (ImageBase headers; TOC[7] gwes; do not invent dest)" + : " (dest-word=0 .text; TOC[7] o32; do not invent dest)"; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + (va & ~0xFFFu).ToString("X8") + + " -> 0x" + rom.ToString("X8") + + " dest-word=0x" + romWord.ToString("X8") + + " via=" + via + + " was=0x" + (kseg & ~0xFFFu).ToString("X8") + + why); + } + + private static void TryNoteDdiNopGwesImageTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _gwesImageDemand = true; + uint page = vaddr & ~0xFFFu; + int slot = ClaimGwesImageSlot(page); + if (slot >= 0 && !_gwesImageTlbl[slot]) + { + _gwesImageTlbl[slot] = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (gwes image page 0x" + page.ToString("X8") + + "; do not invent dest)"); + } + TryResolveDdiNopGwesImage(bus, vaddr); + } + + private static void TryResolveDdiNopGwesImage(MipsBus bus, uint va) + { + if (bus == null || _gwesImageBusy) + return; + if (!IsDdiNopGwesImageVa(va) || IsNamedDdiNopGwesPage(va)) + return; + uint page = va & ~0xFFFu; + int slot = FindGwesImageSlot(page); + if (slot >= 0 && (_gwesImageKseg[slot] != 0 || _gwesImageDone[slot])) + return; + try + { + _gwesImageBusy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + slot = ClaimGwesImageSlot(page); + if (slot < 0) + return; + uint word = 0; + uint rom = 0; + uint romWord = 0; + string via = null; + if (TryGwesHeaderDest(bus, va, out rom, out romWord, out via)) + { + _gwesImageKseg[slot] = rom; + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " -> 0x" + rom.ToString("X8") + + " dest-word=0x" + romWord.ToString("X8") + + " via=" + via + + " (ImageBase headers; TOC[7] gwes; do not invent dest)"); + } + return; + } + if (IsGwesImageBasePage(va)) + { + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (ImageBase headers; TOC gwes miss; do not invent dest)"); + } + return; + } + if (IsGwesDataB9Page(va)) + { + if (sec != 0 + && WalkFirmwarePte(bus, sec, va, out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + TryPeekWord(bus, (kseg & ~0xFFFu) | (va & 0xFFFu), out word); + _gwesImageKseg[slot] = kseg & ~0xFFFu; + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " -> 0x" + _gwesImageKseg[slot].ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; compressed .data dest0; do not invent dest)"); + } + return; + } + // 7214ee6: o32-sec miss then hard-done + // hid the later 0x80040278 PTE. Retry. + // Do not invent 0x80288000. + if (!_gwesImageTlbl[slot]) + { + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (compressed .data; wait firmware PTE; do not invent dest)"); + } + return; + } + if (sec != 0 + && WalkFirmwarePte(bus, sec, va, out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + TryPeekWord(bus, (kseg & ~0xFFFu) | (va & 0xFFFu), out word); + if (TryGwesRomTextDest(bus, va, word, out rom, out romWord)) + { + _gwesImageKseg[slot] = rom; + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " -> 0x" + rom.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + romWord.ToString("X8") + + " via=o32-rom was=0x" + (kseg & ~0xFFFu).ToString("X8") + + " (dest-word=0 .text; TOC[7] o32; do not invent dest)"); + } + return; + } + _gwesImageKseg[slot] = kseg & ~0xFFFu; + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " -> 0x" + _gwesImageKseg[slot].ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; gwes image; do not invent dest)"); + } + return; + } + if (TryGwesRomTextDest(bus, va, 0, out rom, out romWord)) + { + _gwesImageKseg[slot] = rom; + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " -> 0x" + rom.ToString("X8") + + " dest-word=0x" + romWord.ToString("X8") + + " via=o32-rom (pte-miss .text; TOC[7] o32; do not invent dest)"); + } + return; + } + if (!_gwesImageDone[slot]) + { + _gwesImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page map va=0x" + + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (gwes image TLBL; do not invent dest)"); + } + } + finally + { + _gwesImageBusy = false; + } + } + + // Live 147e54f: I-fetch TLBL 0x03FB492C after gwes + // image generalize. IAT slot6 word. COREDLL + // ImageBase 0x03F50000. MapCoredllSharedVa still + // caps at 0x03FA0000 until tv2 (OEMIdle). Demand- + // map remaining COREDLL pages after DllMain via + // slot-1 firmware PTE only. Live 1bba9df: slot-4 + // view 0x09F574F8 ≡ 0x03F574F8. Canon to slot-1 + // IB VA; alias dest. Do not invent dest. + public static uint MapDdiNopCoredllImageVa(MipsBus bus, uint va) + { + if (_coredllImageBusy) + return va; + if (!IsDdiNopCoredllImageArmed()) + return va; + if (!IsDdiNopCoredllImageVa(va)) + return va; + uint use = CoredllImageCanonVa(va); + uint kseg = LookupCoredllImageKseg(use); + if (kseg != 0) + { + TryLogCoredllSlotView(bus, va, use, kseg, 0); + return kseg | (va & 0xFFFu); + } + TryResolveDdiNopCoredllImage(bus, va); + kseg = LookupCoredllImageKseg(use); + if (kseg != 0) + { + TryLogCoredllSlotView(bus, va, use, kseg, 0); + return kseg | (va & 0xFFFu); + } + return va; + } + + private static bool IsDdiNopCoredllImageArmed() + { + if (_leftoverWait99O32NkCoredllSawEntry) + return true; + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _coredllImageDemand; + } + + // Slot-relative COREDLL ImageBase pages. + // Rel in [0x01F50000, 0x01FF0000). Slot 1 is + // 0x03F5xxxx (keep ImageBase). Slot 4 is + // 0x09F5xxxx (live 1bba9df). Slot 0 is IAT + // real 0x01F57000 — exclude. Not a blanket + // bit25 walk. Not MapCoredllSharedVa. + private static bool IsDdiNopCoredllImageVa(uint va) + { + uint rel = va & 0x01FFFFFFu; + if (rel < CoredllImageRelLo || rel >= CoredllImageRelHi) + return false; + uint slot = (va & ~0xFFFu) >> 25; + return slot >= 1 && slot <= 31; + } + + // Slot-1 ImageBase view. Keep 0x03F50000. + private static uint CoredllImageCanonVa(uint va) + { + return (CoredllSharedLo & ~0x01FFFFFFu) | (va & 0x01FFFFFFu); + } + + private static void EnsureCoredllImageMaps() + { + if (_coredllImagePage != null) + return; + _coredllImagePage = new uint[CoredllImagePageCap]; + _coredllImageKseg = new uint[CoredllImagePageCap]; + _coredllImageDone = new bool[CoredllImagePageCap]; + _coredllImageTlbl = new bool[CoredllImagePageCap]; + } + + private static int FindCoredllImageSlot(uint page) + { + EnsureCoredllImageMaps(); + for (int i = 0; i < _coredllImageN; i++) + { + if (_coredllImagePage[i] == page) + return i; + } + return -1; + } + + private static int ClaimCoredllImageSlot(uint page) + { + int i = FindCoredllImageSlot(page); + if (i >= 0) + return i; + if (_coredllImageN >= CoredllImagePageCap) + return -1; + i = _coredllImageN; + _coredllImageN++; + _coredllImagePage[i] = page; + return i; + } + + private static uint LookupCoredllImageKseg(uint va) + { + int i = FindCoredllImageSlot(CoredllImageCanonVa(va) & ~0xFFFu); + if (i < 0) + return 0; + return _coredllImageKseg[i]; + } + + private static void TryNoteDdiNopCoredllImageTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _coredllImageDemand = true; + uint page = vaddr & ~0xFFFu; + uint use = CoredllImageCanonVa(vaddr); + uint canon = use & ~0xFFFu; + bool view = page != canon; + int slot = ClaimCoredllImageSlot(canon); + bool first = view + ? !_coredllSlotViewTlbl + : (slot >= 0 && !_coredllImageTlbl[slot]); + if (first) + { + if (view) + _coredllSlotViewTlbl = true; + else if (slot >= 0) + _coredllImageTlbl[slot] = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop coredll-page TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (COREDLL ImageBase 0x03F50000 page 0x" + + page.ToString("X8") + + " canon=0x" + canon.ToString("X8") + + "; IAT slot6 class; do not invent dest)"); + } + TryResolveDdiNopCoredllImage(bus, vaddr); + } + + private static void TryResolveDdiNopCoredllImage(MipsBus bus, uint va) + { + if (bus == null || _coredllImageBusy) + return; + if (!IsDdiNopCoredllImageVa(va)) + return; + uint use = CoredllImageCanonVa(va); + uint page = use & ~0xFFFu; + int slot = FindCoredllImageSlot(page); + if (slot >= 0 && (_coredllImageKseg[slot] != 0 || _coredllImageDone[slot])) + return; + try + { + _coredllImageBusy = true; + uint sec = _coredllLiveSec != 0 ? _coredllLiveSec : PeekSection(bus, 1); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + slot = ClaimCoredllImageSlot(page); + if (slot < 0) + return; + if (sec != 0 + && WalkFirmwarePte(bus, sec, use, out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _coredllImageKseg[slot] = kseg & ~0xFFFu; + if (!_coredllImageDone[slot]) + { + _coredllImageDone[slot] = true; + uint word = 0; + TryPeekWord(bus, _coredllImageKseg[slot] | (va & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop coredll-page map va=0x" + + page.ToString("X8") + + " -> 0x" + _coredllImageKseg[slot].ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware PTE; COREDLL ImageBase; do not invent dest)"); + } + return; + } + if (!_coredllImageDone[slot]) + { + _coredllImageDone[slot] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop coredll-page map va=0x" + + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (COREDLL image TLBL; do not invent dest)"); + } + } + finally + { + _coredllImageBusy = false; + } + } + + // Live 1bba9df: first process-slot view of an + // already-mapped IB page. Same dest. Do not + // invent dest. Do not rewrite ImageBase. + private static void TryLogCoredllSlotView(MipsBus bus, uint va, + uint canon, uint kseg, uint l2) + { + uint page = va & ~0xFFFu; + uint ib = canon & ~0xFFFu; + if (page == ib) + return; + if (_coredllSlotViewLogged) + return; + _coredllSlotViewLogged = true; + uint word = 0; + TryPeekWord(bus, (kseg & ~0xFFFu) | (va & 0xFFFu), out word); + BootLog.Write("[Hive] ExtraROM ddi_nop coredll-page map va=0x" + + page.ToString("X8") + + " -> 0x" + (kseg & ~0xFFFu).ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " via=slot-1-alias canon=0x" + ib.ToString("X8") + + " (COREDLL ImageBase slot view; do not invent dest)"); + } + + // Live a633b83: NK 0x8003D254 data-TLBL + // 0x040110FC. One filesys slot-2 page after + // DllMain. Slot-2 section first; slot-0 + // 0x00011000 is the same filesys page + // (HostHardDisk). Live 5b54d07: same + // relative page in slot 4 (0x08011000 / + // 0x08011BE8). Alias to the already-mapped + // FILESYS ROM dest when slot-4 PTE misses. + // Do not walk all slot-2 / slot-4. Do not + // invent dest or steal gwes ROM. + public static uint MapDdiNopFilesysSlot2Va(MipsBus bus, uint va) + { + if (_filesysSlot2Busy || _filesysSlot2ExtraBusy) + return va; + if (!IsDdiNopFilesysSlot2Armed()) + return va; + if (IsFilesysSlot2ExtraPage(va)) + return MapFilesysSlot2ExtraVa(bus, va); + if (!IsDdiNopFilesysSlotVa(va)) + return va; + if (_filesysSlot2Kseg != 0) + { + TryLogFilesysSlotMap(bus, va, _filesysSlot2Kseg, 0, "slot-2-alias"); + return _filesysSlot2Kseg | (va & 0xFFFu); + } + TryResolveDdiNopFilesysSlot2(bus, va); + if (_filesysSlot2Kseg != 0) + return _filesysSlot2Kseg | (va & 0xFFFu); + return va; + } + + private static bool IsDdiNopFilesysSlot2Armed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _filesysSlot2Demand; + } + + // FILESYS API page at slot+0x11000. + // Slot 2 proven 017b67e; slot 4 live + // 5b54d07. Slot 0 is gwes-text / filesys + // ROM — other handlers. Not a blanket + // bit25 slot walk. + private static bool IsDdiNopFilesysSlotVa(uint va) + { + if (IsFilesysSlot2ExtraPage(va)) + return true; + uint page = va & ~0xFFFu; + if ((page & FilesysSlotMask) != FilesysSlotRelPage) + return false; + uint slot = page >> 25; + return slot == 2 || slot == 4; + } + + // Slot 2 extra pages only. Not FILESYS API + // +0x11000 (0x04011000). Not slot-0 gwes + // (rel 0x00021000 is gwes .text). Not a + // blanket slot-2 walk. + private static bool IsFilesysSlot2ExtraPage(uint va) + { + if ((va >> 25) != 2) + return false; + uint page = va & ~0xFFFu; + if (page < FilesysSlot2ExtraLo || page >= FilesysSlot2ExtraHi) + return false; + return (page & FilesysSlotMask) != FilesysSlotRelPage; + } + + private static string FilesysSlotHiveTag(uint va) + { + uint slot = (va & ~0xFFFu) >> 25; + if (slot == 4) + return "filesys-slot4"; + return "filesys-slot2"; + } + + private static void TryNoteDdiNopFilesysSlot2Tlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _filesysSlot2Demand = true; + if (IsFilesysSlot2ExtraPage(vaddr)) + { + TryNoteFilesysSlot2ExtraTlbl(bus, regs, epc, vaddr, vector); + return; + } + uint page = vaddr & ~0xFFFu; + bool first = page == FilesysSlot4Page + ? !_filesysSlot4TlblLogged + : !_filesysSlot2TlblLogged; + if (first) + { + if (page == FilesysSlot4Page) + _filesysSlot4TlblLogged = true; + else + _filesysSlot2TlblLogged = true; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint insn = 0; + TryPeekWord(bus, epc, out insn); + string dis = insn != 0 ? FormatMipsOp(epc, insn) : "peek-miss"; + BootLog.Write("[Hive] ExtraROM ddi_nop " + + FilesysSlotHiveTag(vaddr) + + " TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " insn=0x" + insn.ToString("X8") + + " " + dis + + " a1=0x" + a1.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " (FILESYS API page slot+" + + FilesysSlotRelPage.ToString("X") + + "; do not invent dest)"); + } + TryResolveDdiNopFilesysSlot2(bus, vaddr); + } + + private static void TryResolveDdiNopFilesysSlot2(MipsBus bus, uint va) + { + if (_filesysSlot2Kseg != 0 || _filesysSlot2Busy || bus == null) + return; + try + { + _filesysSlot2Busy = true; + uint page = va & ~0xFFFu; + uint slot = page >> 25; + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + uint sec = PeekSection(bus, slot); + if (sec != 0 + && WalkFirmwarePte(bus, sec, page | (va & 0xFFFu), + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + RememberFilesysSlot2Kseg(bus, kseg, l2, + "slot-" + slot, page, va); + return; + } + // Same FILESYS API page at slot 2 + // (proven 017b67e → 0x80105000). + uint sec2 = slot == 2 ? sec : PeekSection(bus, 2); + if (slot != 2 && sec2 != 0 + && WalkFirmwarePte(bus, sec2, FilesysSlot2Fault, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + RememberFilesysSlot2Kseg(bus, kseg, l2, "slot-2", page, va); + return; + } + // Same filesys page at slot 0 (HostHardDisk: + // slot 0 is filesys). Firmware PTE only. + uint sec0 = PeekSection(bus, 0); + if (sec0 != 0 + && WalkFirmwarePte(bus, sec0, GwesTextBasePage, + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + RememberFilesysSlot2Kseg(bus, kseg, l2, "slot-0", page, va); + return; + } + TryLogFilesysSlotMiss(page, sec, sec2, sec0); + } + finally + { + _filesysSlot2Busy = false; + } + } + + private static void RememberFilesysSlot2Kseg(MipsBus bus, uint kseg, + uint l2, string via, uint page, uint va) + { + _filesysSlot2Kseg = kseg & ~0xFFFu; + TryLogFilesysSlotMap(bus, page | (va & 0xFFFu), + _filesysSlot2Kseg, l2, via); + } + + private static void TryLogFilesysSlotMap(MipsBus bus, uint va, + uint kseg, uint l2, string via) + { + uint page = va & ~0xFFFu; + if (page == FilesysSlot4Page) + { + if (_filesysSlot4Logged) + return; + _filesysSlot4Logged = true; + } + else + { + if (_filesysSlot2Logged) + return; + _filesysSlot2Logged = true; + } + uint word = 0; + TryPeekWord(bus, (kseg & ~0xFFFu) | (va & 0xFFFu), out word); + if (via == null) + via = "firmware PTE"; + BootLog.Write("[Hive] ExtraROM ddi_nop " + + FilesysSlotHiveTag(va) + + " map va=0x" + page.ToString("X8") + + " -> 0x" + (kseg & ~0xFFFu).ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " via=" + via + + " (firmware PTE; FILESYS API page slot+" + + FilesysSlotRelPage.ToString("X") + + "; do not invent dest)"); + } + + private static void TryLogFilesysSlotMiss(uint page, uint sec, + uint sec2, uint sec0) + { + if (page == FilesysSlot4Page) + { + if (_filesysSlot4Logged) + return; + _filesysSlot4Logged = true; + } + else + { + if (_filesysSlot2Logged) + return; + _filesysSlot2Logged = true; + } + BootLog.Write("[Hive] ExtraROM ddi_nop " + + FilesysSlotHiveTag(page) + + " map va=0x" + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " sec2=0x" + sec2.ToString("X8") + + " sec0=0x" + sec0.ToString("X8") + + " (FILESYS API page; do not invent dest or walk slot-2/4)"); + } + + // Live 725f2f4: extra maps won through + // 0x0405D000. Next miss 0x04021ABC. + // Per-page firmware PTE after DllMain. + // Do not alias FILESYS API dest 0x80105000. + // Do not walk all slot-2. Do not invent dest. + private static void EnsureFilesysSlot2ExtraMaps() + { + if (_filesysSlot2ExtraPage != null) + return; + _filesysSlot2ExtraPage = new uint[FilesysSlot2ExtraCap]; + _filesysSlot2ExtraKseg = new uint[FilesysSlot2ExtraCap]; + _filesysSlot2ExtraLogged = new bool[FilesysSlot2ExtraCap]; + _filesysSlot2ExtraTlbl = new bool[FilesysSlot2ExtraCap]; + _filesysSlot2ExtraMiss = new bool[FilesysSlot2ExtraCap]; + } + + private static int FindFilesysSlot2ExtraSlot(uint page) + { + EnsureFilesysSlot2ExtraMaps(); + for (int i = 0; i < _filesysSlot2ExtraN; i++) + { + if (_filesysSlot2ExtraPage[i] == page) + return i; + } + return -1; + } + + private static int ClaimFilesysSlot2ExtraSlot(uint page) + { + int i = FindFilesysSlot2ExtraSlot(page); + if (i >= 0) + return i; + if (_filesysSlot2ExtraN >= FilesysSlot2ExtraCap) + return -1; + i = _filesysSlot2ExtraN; + _filesysSlot2ExtraN++; + _filesysSlot2ExtraPage[i] = page; + return i; + } + + private static uint LookupFilesysSlot2ExtraKseg(uint va) + { + int i = FindFilesysSlot2ExtraSlot(va & ~0xFFFu); + if (i < 0) + return 0; + return _filesysSlot2ExtraKseg[i]; + } + + private static uint MapFilesysSlot2ExtraVa(MipsBus bus, uint va) + { + uint kseg = LookupFilesysSlot2ExtraKseg(va); + if (kseg != 0) + return kseg | (va & 0xFFFu); + TryResolveFilesysSlot2Extra(bus, va); + kseg = LookupFilesysSlot2ExtraKseg(va); + if (kseg != 0) + return kseg | (va & 0xFFFu); + return va; + } + + private static void TryNoteFilesysSlot2ExtraTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + uint page = vaddr & ~0xFFFu; + int i = ClaimFilesysSlot2ExtraSlot(page); + if (i >= 0 && !_filesysSlot2ExtraTlbl[i]) + { + _filesysSlot2ExtraTlbl[i] = true; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint insn = 0; + TryPeekWord(bus, epc, out insn); + string dis = insn != 0 ? FormatMipsOp(epc, insn) : "peek-miss"; + BootLog.Write("[Hive] ExtraROM ddi_nop filesys-slot2 TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " insn=0x" + insn.ToString("X8") + + " " + dis + + " a1=0x" + a1.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " (filesys 0x" + (page & FilesysSlotMask).ToString("X") + + "; do not invent dest)"); + } + TryResolveFilesysSlot2Extra(bus, vaddr); + } + + private static void TryResolveFilesysSlot2Extra(MipsBus bus, uint va) + { + if (_filesysSlot2ExtraBusy || bus == null) + return; + if (!IsFilesysSlot2ExtraPage(va)) + return; + uint page = va & ~0xFFFu; + int i = ClaimFilesysSlot2ExtraSlot(page); + if (i < 0) + return; + if (_filesysSlot2ExtraKseg[i] != 0) + return; + try + { + _filesysSlot2ExtraBusy = true; + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + uint sec = PeekSection(bus, 2); + if (sec != 0 + && WalkFirmwarePte(bus, sec, page | (va & 0xFFFu), + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + _filesysSlot2ExtraKseg[i] = kseg & ~0xFFFu; + if (!_filesysSlot2ExtraLogged[i]) + { + _filesysSlot2ExtraLogged[i] = true; + uint word = 0; + TryPeekWord(bus, _filesysSlot2ExtraKseg[i] | (va & 0xFFFu), + out word); + BootLog.Write("[Hive] ExtraROM ddi_nop filesys-slot2 map va=0x" + + page.ToString("X8") + + " -> 0x" + _filesysSlot2ExtraKseg[i].ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " via=slot-2 (firmware PTE; filesys 0x" + + (page & FilesysSlotMask).ToString("X") + + "; do not invent dest)"); + } + return; + } + if (!_filesysSlot2ExtraMiss[i]) + { + _filesysSlot2ExtraMiss[i] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop filesys-slot2 map va=0x" + + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " (filesys 0x" + (page & FilesysSlotMask).ToString("X") + + "; do not invent dest or walk slot-2)"); + } + } + finally + { + _filesysSlot2ExtraBusy = false; + } + } + + // Live 82240a0: page0 mapped. Next miss is filesys + // 0x00031A10 data-TLBL 0x48D01000 v1=0x48D05000. + // Per-page Hive. Do not invent dest. + private static void TryNoteDdiNopFilesys48dTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _filesys48dLogged = true; + EnsureFilesys48dMaps(); + int i = Filesys48dIndex(vaddr); + if (i >= 0 && !_filesys48dTlbl[i]) + { + _filesys48dTlbl[i] = true; + uint insn = 0; + TryPeekWord(bus, epc, out insn); + string dis = insn != 0 ? FormatMipsOp(epc, insn) : "peek-miss"; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint v1 = regs != null && regs.Length > 3 ? regs[3] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop filesys-48d TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " insn=0x" + insn.ToString("X8") + + " " + dis + + " v0=0x" + v0.ToString("X8") + + " v1=0x" + v1.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " strip=0x" + (vaddr & ~Filesys48dBit30).ToString("X8") + + " (tagged gwes-slot page; do not invent dest or walk slot-2)"); + } + TryResolveDdiNopFilesys48d(bus, vaddr); + } + + // Live 82240a0: page0 0x48D00000→0x08D00000→0x87B63000. + // Live next: 0x48D01000 (gwes dest-word 0x00082000). + // Bit30 clear; range [0x08D00000, 0x08D06000) from + // v1=0x48D05000. Per-page neighbor/VALLOC-adj if + // dest peeks, else zero-valloc 4K. + public static uint MapDdiNopFilesys48dVa(MipsBus bus, uint va) + { + if (_filesys48dBusy) + return va; + if (!IsDdiNopFilesys48dArmed()) + return va; + if (!IsDdiNopFilesys48dVa(va)) + return va; + uint use = va & ~Filesys48dBit30; + int i = Filesys48dIndex(use); + if (i < 0) + return va; + EnsureFilesys48dMaps(); + if (_filesys48dKsegs[i] != 0) + return _filesys48dKsegs[i] | (va & 0xFFFu); + TryResolveDdiNopFilesys48d(bus, use); + if (_filesys48dKsegs[i] != 0) + return _filesys48dKsegs[i] | (va & 0xFFFu); + return use; + } + + private static bool IsDdiNopFilesys48dArmed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _filesys48dLogged; + } + + // Tagged 0x48Dxxxxx or cleared 0x08Dxxxxx in + // [0x08D00000, 0x08D06000). Not a blanket bit30 strip. + private static bool IsDdiNopFilesys48dVa(uint va) + { + uint page = va & ~0xFFFu; + uint use = page & ~Filesys48dBit30; + if (use < Filesys48dClearLo || use >= Filesys48dClearHi) + return false; + return page == use || page == (use | Filesys48dBit30); + } + + private static int Filesys48dIndex(uint va) + { + uint use = (va & ~Filesys48dBit30) & ~0xFFFu; + if (use < Filesys48dClearLo || use >= Filesys48dClearHi) + return -1; + return (int)((use - Filesys48dClearLo) >> 12); + } + + private static void EnsureFilesys48dMaps() + { + if (_filesys48dKsegs != null) + return; + _filesys48dKsegs = new uint[Filesys48dPageCap]; + _filesys48dDone = new bool[Filesys48dPageCap]; + _filesys48dTlbl = new bool[Filesys48dPageCap]; + } + + private static void TryResolveDdiNopFilesys48d(MipsBus bus, uint va) + { + if (bus == null || _filesys48dBusy) + return; + uint use = va & ~Filesys48dBit30; + int i = Filesys48dIndex(use); + if (i < 0) + return; + EnsureFilesys48dMaps(); + if (_filesys48dKsegs[i] != 0 || _filesys48dDone[i]) + return; + try + { + _filesys48dBusy = true; + uint page = use & ~0xFFFu; + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + uint sec = PeekSection(bus, Filesys48dGwesSlot); + if (sec != 0 + && WalkFirmwarePte(bus, sec, page | (va & 0xFFFu), + out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + RememberFilesys48dKseg(bus, i, page, kseg, l2, va, + "tagged gwes-slot; bit30 clear; slot-4 firmware PTE"); + return; + } + uint alias = 0; + uint aliasL2 = 0; + string why; + if (TryAliasFilesys48dNeighbor(bus, sec, page, va, + out alias, out aliasL2, out why)) + { + RememberFilesys48dKseg(bus, i, page, alias, aliasL2, va, why); + return; + } + if (TryHostBackFilesys48dPage(i, page)) + { + RememberFilesys48dKseg(bus, i, page, _filesys48dKsegs[i], 0, va, + "zero-valloc; uncommitted gwes-slot page"); + return; + } + if (!_filesys48dDone[i]) + { + _filesys48dDone[i] = true; + BootLog.Write("[Hive] ExtraROM ddi_nop filesys-48d map va=0x" + + (page | Filesys48dBit30).ToString("X8") + + " -> 0x" + page.ToString("X8") + + " pte-miss sec4=0x" + sec.ToString("X8") + + " (tagged gwes-slot; do not invent dest or walk slot-2)"); + } + } + finally + { + _filesys48dBusy = false; + } + } + + private static void RememberFilesys48dKseg(MipsBus bus, int i, uint page, + uint kseg, uint l2, uint va, string why) + { + EnsureFilesys48dMaps(); + _filesys48dKsegs[i] = kseg & ~0xFFFu; + if (_filesys48dDone[i]) + return; + _filesys48dDone[i] = true; + uint word = 0; + TryPeekWord(bus, _filesys48dKsegs[i] | (va & 0xFFFu), out word); + if (why == null) + why = "tagged gwes-slot"; + BootLog.Write("[Hive] ExtraROM ddi_nop filesys-48d map va=0x" + + (page | Filesys48dBit30).ToString("X8") + + " -> 0x" + page.ToString("X8") + + " -> 0x" + _filesys48dKsegs[i].ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (" + why + "; do not invent dest)"); + } + + // Live 82240a0: page0 dest 0x87B63000. Next page + // tries dest+0x1000 / VALLOC dest+delta when that + // dest already peeks. Do not invent dest bytes. + private static bool TryAliasFilesys48dNeighbor(MipsBus bus, uint sec, + uint page, uint va, out uint dest, out uint l2, out string why) + { + dest = 0; + l2 = 0; + why = null; + if (bus == null) + return false; + EnsureFilesys48dMaps(); + int i = Filesys48dIndex(page); + uint off = va & 0xFFFu; + if (i > 0 && _filesys48dKsegs[i - 1] != 0) + { + uint cand = _filesys48dKsegs[i - 1] + 0x1000u; + uint word = 0; + if (TryPeekWord(bus, cand | off, out word) || TryPeekWord(bus, cand, out word)) + { + dest = cand; + why = "neighbor-dest; peek-ok"; + return true; + } + } + if (i >= 0 && i + 1 < Filesys48dPageCap && _filesys48dKsegs[i + 1] != 0) + { + uint cand = _filesys48dKsegs[i + 1] - 0x1000u; + uint word = 0; + if (TryPeekWord(bus, cand | off, out word) || TryPeekWord(bus, cand, out word)) + { + dest = cand; + why = "neighbor-dest; peek-ok"; + return true; + } + } + uint[] nbr = { page - 0x1000u, page + 0x1000u, 0x080D0000u, 0x080DF000u }; + uint walkSec = sec != 0 ? sec : PeekSection(bus, Filesys48dGwesSlot); + for (int n = 0; n < nbr.Length; n++) + { + uint l1 = 0; + uint pfn = 0; + uint kseg = 0; + if (walkSec == 0 + || !WalkFirmwarePte(bus, walkSec, nbr[n], + out l1, out l2, out pfn, out kseg) + || (kseg & 0x1FFFFFFFu) < 0x00010000u) + continue; + uint cand = kseg & ~0xFFFu; + if (nbr[n] < page) + cand += page - nbr[n]; + else + cand -= nbr[n] - page; + uint word = 0; + if (!TryPeekWord(bus, cand | off, out word) + && !TryPeekWord(bus, cand, out word)) + continue; + dest = cand; + if (nbr[n] == 0x080D0000u || nbr[n] == 0x080DF000u) + why = "valloc-dest-adj; peek-ok"; + else + why = "neighbor-dest; peek-ok"; + return true; + } + return false; + } + + // Uncommitted gwes-slot page. One zero 4K from the + // valloc host pool (same as process-info). Do not + // invent firmware payload. + private static bool TryHostBackFilesys48dPage(int i, uint page) + { + EnsureFilesys48dMaps(); + uint lo = page; + uint hi = page + 0x1000u; + if (_filesys48dKsegs[i] != 0) + return true; + if (VallocHostCovers(lo, hi)) + { + for (int n = 0; n < _vallocHostN; n++) + { + if (_vallocHostLo[n] <= lo && _vallocHostHi[n] >= hi) + { + _filesys48dKsegs[i] = _vallocHostKseg[n]; + return _filesys48dKsegs[i] != 0; + } + } + return false; + } + if (_vallocHostN >= _vallocHostLo.Length) + return false; + uint span = 0x1000u; + uint kseg = _vallocHostPool; + if (kseg < VallocHostKseg || kseg + span > VallocHostKsegLim) + return false; + _vallocHostLo[_vallocHostN] = lo; + _vallocHostHi[_vallocHostN] = hi; + _vallocHostKseg[_vallocHostN] = kseg; + _vallocHostN++; + _vallocHostPool += span; + _filesys48dKsegs[i] = kseg; + return true; + } + + // Live 68b9567: data-TLBL epc=0x039833A4 + // badvaddr=0x0199B050. IAT page 0x01999000 was + // mapped; .data vsz continues. 0x0398* is linked + // preferred (MapDdiNopDestVa aliases fetch). Do + // not rewrite PC. Firmware PTE only. + public static uint MapDdiNopVallocDataVa(MipsBus bus, uint va) + { + if (_ddiDataBusy) + return va; + if (!IsDdiNopVallocDataArmed()) + return va; + uint use = DdiNopVallocAlias(va); + if (!IsDdiNopVallocDataVa(use)) + return va; + uint kseg = LookupDdiDataKseg(use); + if (kseg != 0) + return kseg | (use & 0xFFFu); + TryResolveDdiNopVallocData(bus, use); + kseg = LookupDdiDataKseg(use); + if (kseg != 0) + return kseg | (use & 0xFFFu); + return va; + } + + private static bool IsDdiNopVallocDataArmed() + { + if (!_ddiNopAwaitCallDll) + return false; + return _ddiNopDllMainLogged || _ddiDataDemand; + } + + private static uint DdiNopVallocAlias(uint va) + { + if (va >= DdiNopVbase && va < 0x039B0000u) + return DdiNopVbasePage + (va - DdiNopVbase); + return va; + } + + private static uint DdiNopVallocDataHi() + { + uint hi = DdiNopVallocHi; + if (_ddiNopIatSpan == 0) + return hi; + uint end = DdiNopVbasePage + DdiNopIatRva + _ddiNopIatSpan; + uint pageHi = (end + 0xFFFu) & ~0xFFFu; + if (pageHi > hi) + return pageHi; + return hi; + } + + private static bool IsDdiNopVallocDataVa(uint va) + { + uint use = DdiNopVallocAlias(va); + return use >= DdiNopVallocLo && use < DdiNopVallocDataHi(); + } + + private static void EnsureDdiDataMaps() + { + if (_ddiDataPage != null) + return; + _ddiDataPage = new uint[DdiNopDataPageCap]; + _ddiDataKseg = new uint[DdiNopDataPageCap]; + _ddiDataDone = new bool[DdiNopDataPageCap]; + _ddiDataTlbl = new bool[DdiNopDataPageCap]; + } + + private static int FindDdiDataSlot(uint page) + { + EnsureDdiDataMaps(); + for (int i = 0; i < _ddiDataN; i++) + { + if (_ddiDataPage[i] == page) + return i; + } + return -1; + } + + private static int ClaimDdiDataSlot(uint page) + { + int i = FindDdiDataSlot(page); + if (i >= 0) + return i; + if (_ddiDataN >= DdiNopDataPageCap) + return -1; + i = _ddiDataN; + _ddiDataN++; + _ddiDataPage[i] = page; + return i; + } + + private static uint LookupDdiDataKseg(uint va) + { + int i = FindDdiDataSlot(va & ~0xFFFu); + if (i < 0) + return 0; + return _ddiDataKseg[i]; + } + + private static void TryNoteDdiNopPrefPc(uint epc, uint[] regs) + { + if (_ddiPrefPcLogged) + return; + if (epc < DdiNopVbase || epc >= 0x039B0000u) + return; + _ddiPrefPcLogged = true; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop ddi-pref-pc epc=0x" + + epc.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " valloc=0x" + DdiNopVbasePage.ToString("X8") + + " alias=0x" + DdiNopVallocAlias(epc).ToString("X8") + + " (linked preferred; dest alias; do not rewrite PC)"); + } + + private static void TryNoteDdiNopVallocDataTlbl(MipsBus bus, uint[] regs, + uint epc, uint vaddr, uint vector) + { + _ddiDataDemand = true; + TryNoteDdiNopPrefPc(epc, regs); + uint use = DdiNopVallocAlias(vaddr); + uint page = use & ~0xFFFu; + int slot = ClaimDdiDataSlot(page); + if (slot >= 0 && !_ddiDataTlbl[slot]) + { + _ddiDataTlbl[slot] = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop ddi-data TLBL epc=0x" + + epc.ToString("X8") + + " badvaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " (VALLOC .data page 0x" + page.ToString("X8") + + "; do not invent dest)"); + } + TryResolveDdiNopVallocData(bus, use); + } + + private static void TryResolveDdiNopVallocData(MipsBus bus, uint va) + { + if (bus == null || _ddiDataBusy) + return; + uint use = DdiNopVallocAlias(va); + if (!IsDdiNopVallocDataVa(use)) + return; + uint page = use & ~0xFFFu; + int slot = FindDdiDataSlot(page); + if (slot >= 0 && (_ddiDataKseg[slot] != 0 || _ddiDataDone[slot])) + return; + try + { + _ddiDataBusy = true; + uint sec = PeekSection(bus, 0); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + slot = ClaimDdiDataSlot(page); + if (slot < 0) + return; + if (sec != 0 + && WalkFirmwarePte(bus, sec, use, out l1, out l2, out pfn, out kseg) + && (kseg & 0x1FFFFFFFu) >= 0x00010000u) + { + RememberDdiDataMap(bus, slot, page, kseg, l2, use, + "firmware PTE; VALLOC .data"); + return; + } + uint dest6 = 0; + uint dest10 = 0; + if (WalkDdiNopPteDests(bus, use, out l2, out dest6, out dest10) + && dest6 != 0 + && !IsDdiNopDest10Page(dest6) + && (dest6 & 0x1FFFFFFFu) >= 0x00010000u) + { + uint word = 0; + if (TryPeekWord(bus, dest6, out word)) + { + RememberDdiDataMap(bus, slot, page, dest6, l2, use, + "firmware dest6; VALLOC .data"); + return; + } + } + // Live 778120c: 0x0199B000 pte-miss dest6=0 + // while neighbors mapped. VALLOC commit ended + // before this page. Offset 0x2050 < psize + // 0x297A: file-backed. Alias to dest6-adj / + // o32.real if those dests already peek. Do + // not invent dest bytes. + uint alias = 0; + uint aliasL2 = 0; + string why; + if (TryAliasDdiDataFilePage(bus, page, use, out alias, + out aliasL2, out why)) + { + RememberDdiDataMap(bus, slot, page, alias, aliasL2, use, why); + return; + } + if (!_ddiDataDone[slot]) + { + _ddiDataDone[slot] = true; + uint off = 0; + uint dataDest = _ddiNopIatValloc != 0 + ? _ddiNopIatValloc : (DdiNopVbasePage + DdiNopIatRva); + if (page >= dataDest) + off = page - dataDest; + BootLog.Write("[Hive] ExtraROM ddi_nop ddi-data map va=0x" + + page.ToString("X8") + + " pte-miss sec=0x" + sec.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " off=0x" + off.ToString("X") + + " psize=0x" + _ddiNopIatPsize.ToString("X") + + " real=0x" + _ddiNopIatReal.ToString("X8") + + " (VALLOC .data TLBL; do not invent dest)"); + } + } + finally + { + _ddiDataBusy = false; + } + } + + private static void RememberDdiDataMap(MipsBus bus, int slot, uint page, + uint dest, uint l2, uint va, string why) + { + _ddiDataKseg[slot] = dest & ~0xFFFu; + if (_ddiDataDone[slot]) + return; + _ddiDataDone[slot] = true; + uint word = 0; + TryPeekWord(bus, (dest & ~0xFFFu) | (va & 0xFFFu), out word); + if (why == null) + why = "firmware PTE; VALLOC .data"; + BootLog.Write("[Hive] ExtraROM ddi_nop ddi-data map va=0x" + + page.ToString("X8") + + " -> 0x" + _ddiDataKseg[slot].ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (" + why + "; do not invent dest)"); + } + + // Live 778120c: 0x0199B000 has no slot-0 PTE (VALLOC + // ended at 0x0199B000). File-backed: dest+psize = + // 0x0199B97A. Map from dest6-adjacent or o32.real + // only when that dest already peeks. + private static bool TryAliasDdiDataFilePage(MipsBus bus, uint page, + uint use, out uint dest, out uint l2, out string why) + { + dest = 0; + l2 = 0; + why = null; + int sec; + uint vsize; + uint rva; + uint psize; + uint dataptr; + uint real; + uint flags; + uint[] blob; + TryFindDdiNopDataO32(out sec, out vsize, out rva, out psize, + out dataptr, out real, out flags, out blob); + if (psize == 0) + psize = _ddiNopIatPsize; + if (vsize == 0) + vsize = _ddiNopIatSpan; + if (real == 0) + real = _ddiNopIatReal; + uint dataDest = _ddiNopIatValloc != 0 + ? _ddiNopIatValloc : (DdiNopVbasePage + DdiNopIatRva); + if (page < dataDest) + return false; + uint off = page - dataDest; + bool fileBacked = psize == 0 || off < psize; + uint dest6 = _ddiNopIatDest6; + uint dest10 = 0; + if (dest6 == 0) + WalkDdiNopPteDests(bus, dataDest, out l2, out dest6, out dest10); + if (dest6 != 0 && !IsDdiNopDest10Page(dest6) + && (dest6 & 0x1FFFFFFFu) >= 0x00010000u) + { + uint cand = (dest6 & ~0xFFFu) + off; + uint word = 0; + if (TryPeekWord(bus, cand | (use & 0xFFFu), out word)) + { + dest = cand; + why = "dest6-adj; file-backed o32[.data]"; + return true; + } + } + if (page >= 0x1000u) + { + uint prevK = LookupDdiDataKseg(page - 0x1000u); + if (prevK != 0) + { + uint cand = prevK + 0x1000u; + uint word = 0; + if (TryPeekWord(bus, cand | (use & 0xFFFu), out word)) + { + dest = cand; + why = "neighbor-dest; file-backed o32[.data]"; + return true; + } + } + } + if (fileBacked && real != 0) + { + uint realVa = (real & ~0xFFFu) + off; + uint mapped = realVa; + if (realVa >= 0x01F57000u && realVa < 0x01F67000u) + mapped = ExtraRomDestKseg1 + (realVa - 0x01F57000u); + uint word = 0; + if (TryPeekWord(bus, mapped | (use & 0xFFFu), out word)) + { + dest = mapped; + why = "o32.real; file-backed o32[.data]"; + return true; + } + } + return false; + } + + // During BindImp, dump-real IAT (o32.real) is the + // same bytes as VALLOC dest. MapDdiNopDestVa + // otherwise sends 0x01F57000 to ExtraRomDestKseg1. + // Do not invent dest. + public static uint MapBindImpIatRealVa(uint va) + { + if (!_ddiNopAwaitCallDll || !_ddiNopIatWatch) + return va; + if (_ddiNopIatReal == 0 || _ddiNopIatValloc == 0) + return va; + if (IsDdiNopDest10Page(_ddiNopIatValloc)) + return va; + if (va < _ddiNopIatReal) + return va; + uint span = _ddiNopIatSpan != 0 ? _ddiNopIatSpan : 0x1000u; + if (va >= _ddiNopIatReal + span) + return va; + return _ddiNopIatValloc + (va - _ddiNopIatReal); + } + + private static bool IsDdiNopDest10Page(uint dest) + { + if (dest == 0) + return false; + return (dest & ~0xFFFu) == (DdiNopDest10Live & ~0xFFFu); + } + + // Live b4b6454: BindImp IAT stores at vbase+0x19000. + // One observe. Do not invent PTE. + private static void TryLogDdiNopIatPage(MipsBus bus) + { + if (_ddiNopIatLogged) + return; + _ddiNopIatLogged = true; + uint va = DdiNopVbasePage + DdiNopIatRva; + uint l2 = 0; + uint dest6 = 0; + uint dest10 = 0; + WalkDdiNopPteDests(bus, va, out l2, out dest6, out dest10); + if (dest6 != 0 && !IsDdiNopDest10Page(dest6)) + _ddiNopIatDest6 = dest6; + bool threw; + uint word = 0; + bool mapped = false; + if (dest6 != 0 && !IsDdiNopDest10Page(dest6)) + { + word = PeekDestWordRaw(bus, dest6, out threw); + mapped = !threw; + } + if (!mapped) + { + word = PeekDestWordRaw(bus, va, out threw); + mapped = !threw; + } + bool writable = false; + if (mapped) + { + uint poke = dest6 != 0 && !IsDdiNopDest10Page(dest6) ? dest6 : va; + try + { + bool raw = dest6 != 0 && !IsDdiNopDest10Page(dest6); + if (raw) + _ddiNopDestPeekRaw = true; + try + { + bus.Write32(poke, word); + writable = true; + } + finally + { + if (raw) + _ddiNopDestPeekRaw = false; + } + } + catch + { + } + } + BootLog.Write("[Hive] ExtraROM ddi_nop IAT va=0x" + + va.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " word=0x" + word.ToString("X8") + + (mapped ? " mapped" : " unmapped") + + (writable ? " writable" : " not-writable")); + } + + // First guest store into VALLOC IAT 0x01999000 / + // dest6. Host IAT poke sets destPeekRaw. Do not + // invent the written word. + public static void TryNoteDdiNopIatStore(uint origVa, uint mappedVa, uint value) + { + if (!_ddiNopIatWatch || _ddiNopDestPeekRaw) + return; + uint iat = DdiNopVbasePage + DdiNopIatRva; + uint dest6 = _ddiNopIatDest6; + uint page = origVa & ~0xFFFu; + uint mappedPage = mappedVa & ~0xFFFu; + bool hit = page == iat + || mappedPage == iat + || (dest6 != 0 && !IsDdiNopDest10Page(dest6) + && (page == (dest6 & ~0xFFFu) + || mappedPage == (dest6 & ~0xFFFu))); + if (!hit) + return; + uint baseVa = page == iat ? iat + : mappedPage == iat ? iat + : (dest6 & ~0xFFFu); + uint slotVa = page == iat ? origVa + : mappedPage == iat ? mappedVa + : (mappedPage == (dest6 & ~0xFFFu) ? mappedVa : origVa); + uint slot = (slotVa - baseVa) / 4; + _ddiNopIatStoreLogged = true; + if (_ddiNopIatStoreN >= BindImpObserveMax) + return; + _ddiNopIatStoreN++; + BootLog.Write("[Hive] ExtraROM ddi_nop IAT-store va=0x" + + origVa.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " word=0x" + value.ToString("X8") + + " slot=" + slot); + } + + private static bool TryFindDdiNopDataO32(out int sec, out uint vsize, + out uint rva, out uint psize, out uint dataptr, out uint real, + out uint flags, out uint[] blob) + { + sec = -1; + vsize = 0; + rva = 0; + psize = 0; + dataptr = 0; + real = 0; + flags = 0; + blob = null; + uint[] words = _ddiNopO32Words; + uint[][] data = _ddiNopData; + if (words == null || words.Length < 6) + { + ExtraRomTocMod slot = FindCachedExtraRomToc("ddi_nop.dll"); + if (slot != null) + { + words = slot.O32Words; + data = slot.Data; + } + } + if (words == null || words.Length < 6) + return false; + int nsec = words.Length / 6; + uint iatVa = DdiNopVbasePage + DdiNopIatRva; + uint iatDump = DdiNopVbase + DdiNopIatRva; + for (int s = 0; s < nsec; s++) + { + uint vs = words[s * 6]; + uint rv = words[s * 6 + 1]; + uint rl = words.Length > s * 6 + 4 ? words[s * 6 + 4] : 0; + uint span = vs == 0 ? 0 : vs; + bool covers = span != 0 + && rv <= DdiNopIatRva + && DdiNopIatRva < rv + span; + if (!covers && rl != 0) + { + uint slotReal = rl & SlotMask; + covers = (rl & ~0xFFFu) == (iatDump & ~0xFFFu) + || (slotReal & ~0xFFFu) == (iatVa & ~0xFFFu); + } + if (!covers) + continue; + sec = s; + vsize = vs; + rva = rv != 0 ? rv : DdiNopIatRva; + psize = words[s * 6 + 2]; + dataptr = words[s * 6 + 3]; + real = rl; + flags = words.Length > s * 6 + 5 ? words[s * 6 + 5] : 0; + if (data != null && s < data.Length) + blob = data[s]; + return true; + } + return false; + } + + private static bool DdiNopO32LooksCompressed(uint vsize, uint psize, + uint flags, uint[] blob) + { + if (psize == 0) + return false; + if ((flags & O32Compressed) != 0) + return true; + if (psize < vsize) + return true; + if (blob == null || blob.Length == 0) + return false; + uint first = blob[0]; + uint declared = first & 0x00FFFFFFu; + uint sig = first >> 24; + return declared == vsize + || sig == 0xB5 || sig == 0xB4 + || sig == 0x11 || sig == 0x0C; + } + + private static bool TryWriteDdiNopVallocWord(MipsBus bus, uint va, uint word) + { + if (bus == null || va == 0 || IsDdiNopDest10Page(va)) + return false; + uint l2; + uint dest6; + uint dest10; + WalkDdiNopPteDests(bus, va, out l2, out dest6, out dest10); + if (IsDdiNopDest10Page(dest6)) + return false; + try + { + if (dest6 != 0) + { + _ddiNopDestPeekRaw = true; + try + { + bus.Write32(dest6, word); + } + finally + { + _ddiNopDestPeekRaw = false; + } + return true; + } + bus.Write32(va, word); + return true; + } + catch + { + return false; + } + } + + // Live b4b6454: .text CEDecompress only. IAT lives in + // .data RVA 0x19000. Serve that o32's VALLOC dest the + // same way (.text CopyO32 / dest6). Do not invent + // dest10 or a new image. Honest skip-no-o32. + private static void TryServeDdiNopDataO32(MipsBus bus) + { + if (_ddiNopDataO32Logged) + return; + _ddiNopDataO32Logged = true; + int sec; + uint vsize; + uint rva; + uint psize; + uint dataptr; + uint real; + uint flags; + uint[] blob; + if (!TryFindDdiNopDataO32(out sec, out vsize, out rva, out psize, + out dataptr, out real, out flags, out blob)) + { + BootLog.Write("[Hive] ExtraROM o32[.data] skip-no-o32" + + " rva=0x" + DdiNopIatRva.ToString("X") + + " (TOC has no .data o32; do not invent)"); + return; + } + uint dest = DdiNopVbasePage + rva; + if (IsDdiNopDest10Page(dest)) + { + BootLog.Write("[Hive] ExtraROM o32[.data] s=" + sec + + " rva=0x" + rva.ToString("X") + + " dest=0x" + dest.ToString("X8") + + " skip-dest10"); + return; + } + uint l2; + uint dest6; + uint dest10; + WalkDdiNopPteDests(bus, dest, out l2, out dest6, out dest10); + if (IsDdiNopDest10Page(dest6)) + dest6 = 0; + bool compressed = DdiNopO32LooksCompressed(vsize, psize, flags, blob); + string why; + uint filled = 0; + if (dest6 == 0) + TryHostBackValloc(dest, dest, 0x1000u, 0x1000u, false); + if (psize > 0 && !compressed) + { + uint n = psize; + if (n > 0x20000u) + n = 0x20000u; + uint[] src = blob; + for (uint i = 0; i < n; i += 4) + { + uint word = 0; + uint w = i / 4; + if (src != null && w < (uint)src.Length) + word = src[w]; + if (TryWriteDdiNopVallocWord(bus, dest + i, word)) + filled += 4; + } + why = dest6 != 0 ? "set-copyo32" : "set-copyo32-host"; + if (filled == 0) + why = dest6 == 0 ? "skip-unmapped" : "skip-write"; + } + else if (psize == 0) + { + // BSS CopyO32: zero the IAT page only. + for (uint i = 0; i < 0x1000u; i += 4) + { + if (TryWriteDdiNopVallocWord(bus, dest + i, 0)) + filled += 4; + } + why = dest6 != 0 ? "set-bss-zero" : "set-bss-host"; + if (filled == 0) + why = dest6 == 0 ? "skip-unmapped" : "skip-write"; + } + else if (dest6 != 0) + { + // Compressed TOC blob. Do not host-CEDecompress + // ExtraROM (no host LZX; do not invent dest + // bytes). dest6 is the firmware dest; BindImp + // can store IAT. Dest10 never. + why = "set-dest6"; + } + else if (TryWriteDdiNopVallocWord(bus, dest, 0)) + { + filled = 4; + why = "set-valloc-commit"; + } + else + why = "skip-unmapped"; + if (real != 0 && dest != 0 && !IsDdiNopDest10Page(dest)) + { + _ddiNopIatReal = real; + _ddiNopIatValloc = dest; + _ddiNopIatSpan = vsize; + _ddiNopIatPsize = psize; + } + BootLog.Write("[Hive] ExtraROM o32[.data] s=" + sec + + " rva=0x" + rva.ToString("X") + + " vsz=0x" + vsize.ToString("X") + + " psize=0x" + psize.ToString("X") + + " dest=0x" + dest.ToString("X8") + + " dest6=0x" + dest6.ToString("X8") + + " " + why + + " n=0x" + filled.ToString("X") + + (dataptr != 0 ? " dp=0x" + dataptr.ToString("X8") : "") + + (real != 0 ? " real=0x" + real.ToString("X8") : "")); + } + + private const uint ModuleLpSelf = 0; + private const uint ModulePmodNext = 4; + private const uint ModuleLpszName = 8; + private const int DdiNopWalkCap = 32; + private const int DdiNopWalkSeedMax = 12; + + private static void ResetDdiNopModuleHunt() + { + _ddiNopBindLibV0 = 0; + _ddiNopBindLibName = null; + _coredllModule = 0; + _coredllBasePtrLogged = false; + _ddiNopFileObj = 0; + _ddiNopStartipAttempted = false; + _ddiNopAwaitCallDll = false; + _ddiNopSawCallDllPc = false; + _ddiNopCallDllMissLogged = false; + _ddiNopCallDllMissPoll = 0; + _ddiNopStallLogged = false; + _ddiNopIatLogged = false; + _ddiNopDataO32Logged = false; + _ddiNopIatWatch = false; + _ddiNopIatStoreLogged = false; + _ddiNopIatStoreN = 0; + _ddiNopIatDest6 = 0; + _ddiNopIatReal = 0; + _ddiNopIatValloc = 0; + _ddiNopIatSpan = 0; + _ddiNopIatPsize = 0; + _bindImpIatSlotLog = 0; + _ddiNopOrdLog = 0; + _ddiNopOrdLastA1 = 0; + _ddiNopOrdRetLog = 0; + _ddiNopOrdRetLastA1 = 0; + _ddiNopOrdExpLogged = false; + _ddiNopOrdGoodV0 = 0; + _ddiNopOrdAfterDone = false; + _ddiNopOrdAfterN = 0; + _ddiNopOrdAfterLast = 0; + _userKPageAlias = false; + _userKPageAliasNoted = false; + _ffffFce1Logged = false; + _ffffF000Kseg = 0; + _ffffF000Logged = false; + _ffffF000Busy = false; + _ffffF000Demand = false; + _ffffF000Done = false; + _ffffE000Kseg = 0; + _ffffE000Logged = false; + _ffffE000Busy = false; + _ffffE000Demand = false; + _ffffE000Done = false; + _ffffE000SkipLogged = false; + _ffffE428SkipLogged = false; + _ffffEa88SkipLogged = false; + _jalr7eb8Kseg = 0; + _jalr7eb8Logged = false; + _jalr7eb8Busy = false; + _jalr7eb8Done = false; + _jalr1db0Kseg = 0; + _jalr1db0Logged = false; + _jalr1db0Busy = false; + _jalr1db0Done = false; + _jalrRiLogged = false; + _jalrTableFixLogged = false; + _jalrT9MsecLogged = false; + _jalrE478JrLogged = false; + _stk2470Kseg = 0; + _stk2470Logged = false; + _stk2470Busy = false; + _stk2470Done = false; + _stk2470SwLogged = false; + _stk2470ExnLogged = false; + _stk1670Logged = false; + _stk1670SbLogged = false; + _absStoreMemLogN = 0; + if (_dumpMemLoggedPc != null) + { + for (int i = 0; i < _dumpMemLoggedPc.Length; i++) + _dumpMemLoggedPc[i] = 0; + } + _dumpMemFallN = 0; + if (_dumpMemFallPc != null) + { + for (int i = 0; i < _dumpMemFallPc.Length; i++) + _dumpMemFallPc[i] = 0; + } + _abs1828ExnLogged = false; + _abs6670DumpSkipLogged = false; + _abs6670FallthroughLogged = false; + _abs6670JalTakenLogged = false; + _abs6670JalRa = 0; + _abs6670JalA0 = 0; + _abs6670DestFetchLogged = false; + _abs6670DestExnLogged = false; + _badAKseg = 0; + _badABusy = false; + _badADone = false; + _badAMapLogged = false; + _badAExnLogged = false; + _badASrcLogged = false; + _badARestoreLogged = false; + _badASkipLogged = false; + _badAJalContinueLogged = false; + _badACalleeContinueLogged = false; + _badABeforeE000YankLogged = false; + _badAListSaved = false; + _badAWrapperRa = 0; + _badAListA0 = 0; + _badAListA1 = 0; + _badAListV0 = 0; + _badAListS6 = 0; + _abs6670ExnLogged = false; + _c000Kseg = 0; + _c000Logged = false; + _c000Busy = false; + _c000Done = false; + _c000ExnLogged = false; + _c000SkipLogged = false; + _c000SkipN = 0; + _c000SkipLast = 0; + _c000LowUsegSkipN = 0; + _c000LowUsegSkipLast = 0; + _listInsertDestClassLogged = 0; + _exn15C28Logged = false; + _exn15C28TakenLogged = false; + _exn15C28Wrote = false; + _exn15C28NextLogged = false; + _exn15C28Left = false; + _exn15C28StkPage = 0; + _exn15C28StkSkipLogged = false; + _exn15C28AfterLogged = false; + _exn15C28AfterExnLogged = false; + _exn15C28LeaveHoldLogged = false; + _exn15C28JalLogged = false; + _exn15C28JalDestLogged = false; + _exn15C28JalThrLogged = false; + _exn15C28JalRetLogged = false; + _exn15C28JalRetSkipLogged = false; + _exn15C28AfterMemsetLogged = false; + _c000E000SkipLogged = false; + _c000F000SkipLogged = false; + _c000Page0SkipLogged = false; + _c000LowUsegSkipLogged = false; + _exn15C28JalS1Logged = false; + _exn15C28JalS1SkipLogged = false; + _exn15C28AfterS1Logged = false; + _exn15C28AfterS1NextLogged = false; + _exn15C28AfterS1AluLogged = false; + _exn15C28AfterS1AluNextLogged = false; + _exn15C28StkSwSkipLogged = false; + _exn15C28StkSwLogN = 0; + _exn15C28StkSwLast = 0; + _exn15C28AfterStkSwLogged = false; + _exn15C28AfterStkSwBneLogged = false; + _exn15C28AfterStkSwBneLogN = 0; + _exn15C28AfterStkSwBneLast = 0; + _exn15C28AfterStkSwNextLogged = false; + _exn15C28FpLwSkipLogged = false; + _exn15C28FpLwLogN = 0; + _exn15C28FpLwLast = 0; + _exn15C28AfterFpLwLogged = false; + _exn15C28SpT9SkipLogged = false; + _exn15C28SpT9LogN = 0; + _exn15C28SpT9Last = 0; + _exn15C28AfterSpT9Logged = false; + _exn15C28JalRaEpiSkipLogged = false; + _exn15C28JalRaEpiLogN = 0; + _exn15C28JalRaEpiLast = 0; + _exn15C28AfterJalRaEpiLogged = false; + _exn15C28OuterJalTakenLogged = false; + _exn15C28AfterOuterJalLogged = false; + _exn15C28AfterOuterJalAluLogged = false; + _exn15C28AfterOuterJalNextLogged = false; + _exn15C28AfterOuterJalLwLogged = false; + _exn15C28AfterOuterJalIncLogged = false; + _exn15C28AfterOuterJalJrLogged = false; + _exn15C28AfterOuterJalJrNextLogged = false; + _exn15C28AfterOuterJalLhuLogged = false; + _exn15C28AfterOuterJalLhuNextLogged = false; + _exn15C28AfterOuterJalS3Logged = false; + _exn15C28AfterOuterJalS3NextLogged = false; + _exn15C28AfterOuterJalBneLogged = false; + _exn15C28AfterOuterJalBneNextLogged = false; + _exn15C28AfterOuterJalLandLogged = false; + _exn15C28AfterOuterJalLandNextLogged = false; + _exn15C28AfterOuterJalSltuLogged = false; + _exn15C28AfterOuterJalSltuNextLogged = false; + _exn15C28AfterOuterJalBeqLogged = false; + _exn15C28AfterOuterJalBeqNextLogged = false; + _exn15C28AfterOuterJalAddiuLogged = false; + _exn15C28AfterOuterJalAddiuNextLogged = false; + _exn15C28AfterOuterJalLwT4Logged = false; + _exn15C28AfterOuterJalLwT4NextLogged = false; + _exn15C28AfterOuterJalLwS7Logged = false; + _exn15C28AfterOuterJalLwS7NextLogged = false; + _exn15C28AfterOuterJalAdduLogged = false; + _exn15C28AfterOuterJalAdduNextLogged = false; + _exn15C28AfterOuterJalLwFpLogged = false; + _exn15C28AfterOuterJalLwFpNextLogged = false; + _exn15C28AfterOuterJalLwS6Logged = false; + _exn15C28AfterOuterJalLwS6NextLogged = false; + _exn15C28AfterOuterJalLwS5Logged = false; + _exn15C28AfterOuterJalLwS5NextLogged = false; + _exn15C28AfterOuterJalLwS4Logged = false; + _exn15C28AfterOuterJalLwS4NextLogged = false; + _exn15C28AfterOuterJalLwS3Logged = false; + _exn15C28AfterOuterJalLwS3NextLogged = false; + _exn15C28AfterOuterJalLwS2Logged = false; + _exn15C28AfterOuterJalLwS2NextLogged = false; + _exn15C28AfterOuterJalLwS1Logged = false; + _exn15C28AfterOuterJalLwS1NextLogged = false; + _exn15C28AfterOuterJalLwS0Logged = false; + _exn15C28AfterOuterJalLwS0NextLogged = false; + _exn15C28AfterOuterJalLwRaLogged = false; + _exn15C28AfterOuterJalLwRaNextLogged = false; + _exn15C28AfterOuterJalEpiAddiuLogged = false; + _exn15C28AfterOuterJalEpiAddiuNextLogged = false; + _exn15C28AfterOuterJalEpiJrLogged = false; + _exn15C28AfterOuterJalEpiJrNextLogged = false; + _exn15C28AfterOuterJalEpiLuiLogged = false; + _exn15C28AfterOuterJalEpiLuiNextLogged = false; + _exn15C28AfterOuterJalEpiV0AddiuLogged = false; + _exn15C28AfterOuterJalEpiV0AddiuNextLogged = false; + _exn15C28AfterOuterJalEpiV1AddiuLogged = false; + _exn15C28AfterOuterJalEpiV1AddiuNextLogged = false; + _exn15C28AfterOuterJalEpiSwLogged = false; + _exn15C28AfterOuterJalEpiSwNextLogged = false; + _exn15C28AfterOuterJalEpiA3LuiLogged = false; + _exn15C28AfterOuterJalEpiA3LuiNextLogged = false; + _exn15C28AfterOuterJalEpiLhuLogged = false; + _exn15C28AfterOuterJalEpiLhuNextLogged = false; + _exn15C28AfterOuterJalEpiA2AddiuLogged = false; + _exn15C28AfterOuterJalEpiA2AddiuNextLogged = false; + _exn15C28AfterOuterJalEpiA2SwLogged = false; + _exn15C28AfterOuterJalEpiA2SwNextLogged = false; + _exn15C28AfterOuterJalEpiA1AddiuLogged = false; + _exn15C28AfterOuterJalEpiA1AddiuNextLogged = false; + _exn15C28AfterOuterJalEpiA3LhuLogged = false; + _exn15C28AfterOuterJalEpiA3LhuNextLogged = false; + _exn15C28AfterOuterJalEpiSltuLogged = false; + _exn15C28AfterOuterJalEpiSltuNextLogged = false; + _exn15C28AfterOuterJalEpiBeqLogged = false; + _exn15C28AfterOuterJalEpiBeqNextLogged = false; + _exn15C28AfterOuterJalEpiBeqAddiuLogged = false; + _exn15C28AfterOuterJalEpiBeqAddiuNextLogged = false; + _exn15C28AfterOuterJalEpiBeqSltLogged = false; + _exn15C28AfterOuterJalEpiBeqSltNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallLogged = false; + _exn15C28AfterOuterJalEpiBeqBneNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallSwLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallJrLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged = false; + _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged = false; + _exn15C28AfterOuterJalEpiPrologueSwLogged = false; + _exn15C28AfterOuterJalEpiPrologueSwNextLogged = false; + _exn15C28AfterOuterJalEpiPrologueJalLogged = false; + _exn15C28AfterOuterJalEpiPrologueJalNextLogged = false; + _exn15C28AfterOuterJalEpiTrampolineLogged = false; + _exn15C28AfterOuterJalEpiTrampolineNextLogged = false; + _exn15C28AfterOuterJalEpiRetLogged = false; + _exn15C28AfterOuterJalEpiRetNextLogged = false; + _exn15C28AfterOuterJalEpiRetLeave = 0; + _exn15C28AfterOuterJalEpiRetBneLogged = false; + _exn15C28AfterOuterJalEpiRetBneNextLogged = false; + _exn15C28AfterOuterJalEpiRetBneLeave = 0; + _exn15C28AfterOuterJalEpiRetFallLogged = false; + _exn15C28AfterOuterJalEpiRetFallNextLogged = false; + _exn15C28AfterOuterJalEpiRetFallLeave = 0; + _exn15C28AfterOuterJalEpiRetCallerLogged = false; + _exn15C28AfterOuterJalEpiRetCallerNextLogged = false; + _exn15C28AfterOuterJalEpiRetCallerLeave = 0; + _exn15C28AfterOuterJalEpiRetCallerNextFnLogged = false; + _exn15C28AfterOuterJalEpiRetCallerNextFnNextLogged = false; + _exn15C28AfterOuterJalEpiRetCallerNextFnLeave = 0; + _exn15C28AfterOuterJalEpiRetCallerRaLogged = false; + _exn15C28AfterOuterJalEpiRetCallerRaNextLogged = false; + _exn15C28AfterOuterJalEpiRetCallerRaLhuLogged = false; + _exn15C28AfterOuterJalEpiRetCallerRaS3Logged = false; + _exn15C28AfterOuterJalEpiRetCallerRaT1Logged = false; + _exn15C28AfterOuterJalEpiRetCallerRaBneLogged = false; + _exn15C28AfterOuterJalEpiRetCallerRaRefuseLogged = false; + _exn15C28AfterOuterJalEpiRetCallerRaLeave = 0; + _exn15C28AfterOuterJalEpiFn854OuterRa = 0; + _exn15C28Na02IFetchLogN = 0; + _exn15C28Na02IFetchLast = 0; + _abs59488Logged = false; + _abs59488ExecLogged = false; + _ffffFe54SkipLogged = false; + _bindImpIatSwExpect = false; + _bindImpIatSwLogged = false; + _bindImpIatSwLog = 0; + _bindImpIatWinLog = 0; + _bindImpIatWinLast = 0; + _bindImpIatNextLog = 0; + _bindImpIatNextLast = 0; + _bindImpExnLogged = false; + _bindImpExnSaveLogged = false; + _bindImpExnCode = 0; + _bindImpExnEpc = 0; + _bindImpExnVaddr = 0; + _gwesB9SpinLogged = false; + _gwesB9SpinPage = 0; + _gwesB9SpinN = 0; + _gwesNullStoreLogged = false; + _nearNullTlblLogged = false; + _ffffFb2aAdelLogged = false; + _adelC6FaLogged = false; + _adelPcEpc = 0; + _adelPcSp = 0; + _adelPlantClrLogged = false; + _idleHaltLogged = false; + _exnContinueWord = 0; + _thrSpLogged = false; + _spFixLogged = false; + _plantFixLogged = false; + _plantHaltLogged = false; + _leftoverHaltLogged = false; + _leftoverSkipLogged = false; + _leftoverRetLogged = false; + _leftoverCstkLogged = false; + _leftoverCstkFixLogged = false; + _leftoverCstkApi = 0; + _leftoverApi78NeedLogged = false; + _leftoverApi78PlantLogged = false; + _leftoverApi54NeedLogged = false; + _leftoverApi54PlantLogged = false; + _leftoverApi54ContLogged = false; + _leftoverApi54HaltLogged = false; + _wait99PlantFixLogged = false; + _leftoverWait99WrapLogged = false; + _leftoverWait99WrapContLogged = false; + _leftoverWait99WrapGetProcLogged = false; + _leftoverWait99WrapPlantLogged = false; + _leftoverWait99WrapRaContLogged = false; + _leftoverWait99WrapPlantMeth = 0; + _leftoverWait99WrapPlantGp = 0; + _leftoverWait99O32ContLogged = false; + _leftoverWait99O32HaltLogged = false; + _leftoverWait99O32SwLogged = false; + _leftoverWait99O32RaSrcLogged = false; + _leftoverWait99O32NkCallLogged = false; + _leftoverWait99O32NkRetLogged = false; + _leftoverWait99O32NkWrapLogged = false; + _leftoverWait99O32NkWrapAfterLogged = false; + _leftoverWait99O32NkWrapVallocLogged = false; + _leftoverWait99O32NkWrapS5Logged = false; + _leftoverWait99O32NkWrapCopyLogged = false; + _leftoverWait99O32NkWrapCopyRetLogged = false; + _leftoverWait99O32NkPostCopyLogged = false; + _leftoverWait99O32NkE32Logged = false; + _leftoverWait99O32NkNextLogged = false; + _leftoverWait99O32NkImpLogged = false; + _leftoverWait99O32NkWrapSp = 0; + _leftoverWait99O32NkWrapFp = 0; + _leftoverWait99O32NkWrapDestFp50 = 0; + _leftoverWait99O32NkHdr = 0; + _leftoverWait99O32NkHdrOff = 0; + _leftoverWait99O32NkBindLogged = false; + _leftoverWait99O32NkBindName = ""; + _leftoverWait99O32NkBindMod = 0; + _leftoverWait99O32NkIatStubLog = 0; + _leftoverWait99O32NkIatStubLast = 0; + _leftoverWait99O32NkIatStubVia = ""; + _leftoverWait99O32NkBindLastPc = 0; + _leftoverWait99O32NkEntryRva = 0; + _leftoverWait99O32NkEntryTarget = 0; + _leftoverWait99O32NkCallDllLogged = false; + _leftoverWait99O32NkJalrLog = 0; + _leftoverWait99O32NkJalrSawCall = false; + _leftoverWait99O32NkJalrSawTarget = false; + _leftoverWait99O32NkAfterLog = 0; + _leftoverWait99O32NkChainLog = 0; + _leftoverWait99O32NkChainLast = 0; + _leftoverWait99O32NkChainVia = ""; + _leftoverWait99O32NkChainName = ""; + _leftoverWait99O32NkChainCallVa = 0; + _leftoverWait99O32NkCoredllStartip = 0; + _leftoverWait99O32NkCoredllSawStartip = false; + _leftoverWait99O32NkCoredllSawCall = false; + _leftoverWait99O32NkCoredllSawEntry = false; + _leftoverWait99O32NkCoredllMissLog = false; + _leftoverWait99O32NkCoredllRetLog = false; + _leftoverWait99O32NkCoredllAfterLog = 0; + _leftoverWait99O32NkCoredllBodyPc = 0; + _leftoverWait99O32NkCoredllSpin = 0; + _leftoverWait99O32NkCoredllExnLog = false; + _leftoverWait99O32NkCoredllJalLog = false; + _leftoverWait99O32NkCoredllJalRa = 0; + _leftoverWait99O32NkCoredllPc0Log = false; + _leftoverWait99O32NkChainSawEntry = false; + _leftoverWait99O32NkRa = 0; + _leftoverWait99O32NkA0 = 0; + _leftoverWait99O32NkA2 = 0; + _leftoverWait99O32NkA3 = 0; + _leftoverWait99O32NkDestWord = 0; + _leftoverWait99O32NkLive0 = 0; + _leftoverWait99O32NkBit200 = false; + _leftoverWait99O32NkSkip200 = false; + _leftoverWait99WrapNeedLogged = false; + _leftoverWait99DumpRecsTried = false; + _leftoverWait99DumpRecs = null; + _leftoverWait99ScanVia = ""; + _leftoverWait99Cf = 0; + _leftoverWait99Sk = 0; + _leftoverWait99WhyLogged = false; + _leftoverRetFixLogged = false; + _leftoverCstkSpinLogged = false; + _leftoverCstkSpinN = 0; + _leftoverWait99SpinLogged = false; + _leftoverWait99SpinN = 0; + _leftoverFrameLogged = false; + _epcHaltLogged = false; + _c2TlbsLogged = false; + _c2SpLogged = false; + _c2EretHaltLogged = false; + _ddiNopInfoObserved = false; + _ddiNopInfoDemand = false; + _ddiNopInfoBusy = false; + _ddiNopInfoPeekRaw = false; + _ddiNopInfoMapLogged = false; + _ddiNopInfoKseg = 0; + _ddiNopCallDllHiveLogged = false; + _ddiNopDllMainLogged = false; + _ddiNopDllMainRa = 0; + _ddiNopCallDllSite = 0; + _ddiNopAfterDllMainLogged = false; + _ddiNopGwesFetchKseg = 0; + _ddiNopGwesFetchLogged = false; + _ddiNopGwesFetchBusy = false; + _ddiNopGwesFetchDemand = false; + _ddiNopGwesFetchTlblLogged = false; + _ddiNopGwesDataKseg = 0; + _ddiNopGwesDataLogged = false; + _ddiNopGwesDataBusy = false; + _ddiNopGwesDataDemand = false; + _ddiNopGwesDataTlblLogged = false; + _ddiNopGwesTextKseg = 0; + _ddiNopGwesTextLogged = false; + _ddiNopGwesTextBusy = false; + _ddiNopGwesTextDemand = false; + _ddiNopGwesTextTlblLogged = false; + _ddiNopGwesData2Kseg = 0; + _ddiNopGwesData2Logged = false; + _ddiNopGwesData2Busy = false; + _ddiNopGwesData2Demand = false; + _ddiNopGwesData2TlblLogged = false; + _ddiNopGwesData3Kseg = 0; + _ddiNopGwesData3Logged = false; + _ddiNopGwesData3Busy = false; + _ddiNopGwesData3Demand = false; + _ddiNopGwesData3TlblLogged = false; + _ddiNopGwesText2Kseg = 0; + _ddiNopGwesText2Logged = false; + _ddiNopGwesText2Busy = false; + _ddiNopGwesText2Demand = false; + _ddiNopGwesText2TlblLogged = false; + _gwesImageDemand = false; + _gwesImageBusy = false; + _gwesImageN = 0; + if (_gwesImagePage != null) + { + for (int i = 0; i < _gwesImagePage.Length; i++) + { + _gwesImagePage[i] = 0; + _gwesImageKseg[i] = 0; + _gwesImageDone[i] = false; + _gwesImageTlbl[i] = false; + } + } + _coredllImageDemand = false; + _coredllImageBusy = false; + _coredllImageN = 0; + _coredllSlotViewLogged = false; + _coredllSlotViewTlbl = false; + if (_coredllImagePage != null) + { + for (int i = 0; i < _coredllImagePage.Length; i++) + { + _coredllImagePage[i] = 0; + _coredllImageKseg[i] = 0; + _coredllImageDone[i] = false; + _coredllImageTlbl[i] = false; + } + } + _filesysSlot2Kseg = 0; + _filesysSlot2Logged = false; + _filesysSlot2Busy = false; + _filesysSlot2Demand = false; + _filesysSlot2TlblLogged = false; + _filesysSlot4Logged = false; + _filesysSlot4TlblLogged = false; + _filesysSlot2ExtraBusy = false; + _filesysSlot2ExtraN = 0; + if (_filesysSlot2ExtraPage != null) + { + for (int i = 0; i < _filesysSlot2ExtraPage.Length; i++) + { + _filesysSlot2ExtraPage[i] = 0; + _filesysSlot2ExtraKseg[i] = 0; + _filesysSlot2ExtraLogged[i] = false; + _filesysSlot2ExtraTlbl[i] = false; + _filesysSlot2ExtraMiss[i] = false; + } + } + _filesys48dLogged = false; + _filesys48dBusy = false; + if (_filesys48dKsegs != null) + { + for (int i = 0; i < _filesys48dKsegs.Length; i++) + { + _filesys48dKsegs[i] = 0; + _filesys48dDone[i] = false; + _filesys48dTlbl[i] = false; + } + } + _ddiDataDemand = false; + _ddiDataBusy = false; + _ddiDataN = 0; + _ddiPrefPcLogged = false; + if (_ddiDataPage != null) + { + for (int i = 0; i < _ddiDataPage.Length; i++) + { + _ddiDataPage[i] = 0; + _ddiDataKseg[i] = 0; + _ddiDataDone[i] = false; + _ddiDataTlbl[i] = false; + } + } + _ddiNopWalkSeedN = 0; + _ddiNopNoModDiag = false; + _ddiNopWalkDiag = false; + if (_ddiNopWalkSeeds != null) + { + for (int i = 0; i < _ddiNopWalkSeeds.Length; i++) + _ddiNopWalkSeeds[i] = 0; + } + } + + // Sticky ddi_nop file object. ClearLoadE32OkWatch + // must not drop this; first startip is after the + // 200k cap. Reset only on Boot / hunt reset. + private static void LatchDdiNopFileObj(uint obj) + { + if (obj == 0 || obj == 0xDEADBEEFu) + return; + if (_ddiNopFileObj == 0) + _ddiNopFileObj = obj; + } + + // Live e29762a: $fp is often the heap file object. + // Accept only a trusted MODULE whose +96 is the + // sticky TOC object. Do not invent obj-96. + private static void TryHuntDdiNopModuleFromRegs(MipsBus bus, uint[] regs) + { + if (bus == null || regs == null) + return; + if (_ddiNopModule != 0 && IsDdiNopModule(bus, _ddiNopModule)) + return; + if (_ddiNopFileObj == 0 + && !NamesMatchRom(_loadE32OkName, "ddi_nop.dll") + && !NamesMatchRom(_loadE32WatchName, "ddi_nop.dll")) + return; + NoteDdiNopWalkSeeds(regs); + if (_ddiNopWalkSeeds == null) + return; + for (int i = 0; i < _ddiNopWalkSeedN; i++) + { + if (AcceptDdiNopModule(bus, _ddiNopWalkSeeds[i]) != 0) + return; + } + } + + private static void NoteDdiNopWalkSeed(uint va) + { + if (va == 0 || va == 0xDEADBEEFu) + return; + if (_ddiNopWalkSeeds == null) + _ddiNopWalkSeeds = new uint[DdiNopWalkSeedMax]; + for (int i = 0; i < _ddiNopWalkSeedN; i++) + { + if (_ddiNopWalkSeeds[i] == va) + return; + } + if (_ddiNopWalkSeedN >= _ddiNopWalkSeeds.Length) + return; + _ddiNopWalkSeeds[_ddiNopWalkSeedN++] = va; + } + + private static void NoteDdiNopWalkSeeds(uint[] regs) + { + if (regs == null) + return; + for (int r = 16; r <= 23 && r < regs.Length; r++) + NoteDdiNopWalkSeed(regs[r]); + if (regs.Length > 30) + NoteDdiNopWalkSeed(regs[30]); + if (regs.Length > 2) + NoteDdiNopWalkSeed(regs[2]); + } + + // Pointer oe: module+96 is either the embedded + // openexe or a pointer to the heap TOC-attach + // object. Do not invent obj-96. + private static bool IsDdiNopModule(MipsBus bus, uint module) + { + if (bus == null || module == 0) + return false; + if (IsDdiNopTocObject(bus, module + ModuleFileObj)) + return true; + uint p; + if (!TryPeekWord(bus, module + ModuleFileObj, out p) || p == 0) + return false; + if (_ddiNopFileObj != 0 && p == _ddiNopFileObj) + return true; + if (IsDdiNopTocObject(bus, p)) + return true; + if (p != _loadE32Obj && p != _loadE32OkObj && p != _loadE32WatchA0) + return false; + return IsDdiNopTocObject(bus, p); + } + + private static bool IsTrustedModule(MipsBus bus, uint module) + { + if (module == 0 || module == 0xDEADBEEFu) + return false; + uint self; + if (!TryPeekWord(bus, module + ModuleLpSelf, out self)) + return false; + return self == module; + } + + private static bool MatchesDdiNopRamOrDumpStartip(MipsBus bus, uint module) + { + uint ip; + if (!TryPeekWord(bus, module + ModuleStartip, out ip) || ip == 0) + return false; + if (ip == DdiNopVbasePage + DdiNopEntryRvaExtract) + return true; + return ip == DdiNopVbase + DdiNopEntryRvaExtract; + } + + private static uint AcceptDdiNopModule(MipsBus bus, uint module) + { + if (module == 0) + return 0; + if (IsDdiNopModule(bus, module)) + { + _ddiNopModule = module; + return module; + } + if (IsTrustedModule(bus, module) && MatchesDdiNopRamOrDumpStartip(bus, module)) + { + _ddiNopModule = module; + return module; + } + return 0; + } + + private static uint WalkDdiNopModuleList(MipsBus bus, uint seed) + { + uint m = seed; + for (int i = 0; i < DdiNopWalkCap && m != 0 && m != 0xDEADBEEFu; i++) + { + if (!IsTrustedModule(bus, m)) + return 0; + uint hit = AcceptDdiNopModule(bus, m); + if (hit != 0) + return hit; + uint next; + if (!TryPeekWord(bus, m + ModulePmodNext, out next)) + return 0; + if (next == 0 || next == m) + return 0; + m = next; + } + return 0; + } + + // Live 9183b83: skip-no-mod. Heap TOC-attach + // openexe is not an embedded MODULE+96. Walk + // pmodNext from CurProc+0x50, BindImp LoadLibrary + // ret v0, and $fp / callee-saved. No invent. + private static uint FindInFlightDdiNopModule(MipsBus bus, uint hintModule) + { + uint hit = AcceptDdiNopModule(bus, hintModule); + if (hit != 0) + return hit; + hit = AcceptDdiNopModule(bus, _ddiNopModule); + if (hit != 0) + return hit; + uint fromObj = ModuleFromEmbeddedDdiNopFileObj(bus, _ddiNopFileObj); + if (fromObj == 0) + fromObj = ModuleFromEmbeddedDdiNopFileObj(bus, _loadE32OkObj); + if (fromObj == 0) + fromObj = ModuleFromEmbeddedDdiNopFileObj(bus, _loadE32Obj); + if (fromObj == 0) + fromObj = ModuleFromEmbeddedDdiNopFileObj(bus, _loadE32WatchA0); + if (fromObj != 0) + { + _ddiNopModule = fromObj; + return fromObj; + } + uint proc = 0; + uint p50 = 0; + if (TryPeekWord(bus, CurProc, out proc) && proc != 0) + TryPeekWord(bus, proc + ProcModule, out p50); + hit = WalkDdiNopModuleList(bus, p50); + if (hit != 0) + return hit; + hit = WalkDdiNopModuleList(bus, hintModule); + if (hit != 0) + return hit; + hit = WalkDdiNopModuleList(bus, _ddiNopBindLibV0); + if (hit != 0) + return hit; + if (_ddiNopWalkSeeds != null) + { + for (int i = 0; i < _ddiNopWalkSeedN; i++) + { + uint seed = _ddiNopWalkSeeds[i]; + hit = AcceptDdiNopModule(bus, seed); + if (hit != 0) + return hit; + hit = WalkDdiNopModuleList(bus, seed); + if (hit != 0) + return hit; + } + } + return 0; + } + + // obj-96 is the MODULE only when obj is the + // embedded openexe. A standalone heap file + // object minus 96 is a corrupt write. + private static uint ModuleFromEmbeddedDdiNopFileObj(MipsBus bus, uint obj) + { + if (obj < ModuleFileObj || !IsDdiNopTocObject(bus, obj)) + return 0; + uint module = obj - ModuleFileObj; + if (module < 0x80000000u || module >= 0xC0000000u) + return 0; + if (!IsDdiNopTocObject(bus, module + ModuleFileObj)) + return 0; + if (!IsTrustedModule(bus, module)) + return 0; + uint unused; + if (!TryPeekWord(bus, module + ModuleStartip, out unused)) + return 0; + if (!TryPeekWord(bus, module + ProcModule, out unused)) + return 0; + return module; + } + + private static void LogDdiNopNoModOnce(MipsBus bus) + { + if (_ddiNopNoModDiag) + return; + _ddiNopNoModDiag = true; + uint proc = 0; + uint p50 = 0; + TryPeekWord(bus, CurProc, out proc); + if (proc != 0) + TryPeekWord(bus, proc + ProcModule, out p50); + bool emb = ModuleFromEmbeddedDdiNopFileObj(bus, _ddiNopFileObj) != 0 + || ModuleFromEmbeddedDdiNopFileObj(bus, _loadE32OkObj) != 0 + || ModuleFromEmbeddedDdiNopFileObj(bus, _loadE32Obj) != 0 + || ModuleFromEmbeddedDdiNopFileObj(bus, _loadE32WatchA0) != 0; + bool p50Self = IsTrustedModule(bus, p50); + BootLog.Write("[Hive] ExtraROM ddi_nop skip-no-mod obj=0x" + + _loadE32Obj.ToString("X8") + + " okObj=0x" + _loadE32OkObj.ToString("X8") + + " sticky=0x" + _ddiNopFileObj.ToString("X8") + + " emb=" + (emb ? "1" : "0") + + " CurProc=0x" + proc.ToString("X8") + + " +50=0x" + p50.ToString("X8") + + " lpSelf=" + (p50Self ? "1" : "0")); + LogDdiNopBindWalkOnce(bus); + } + + // Always walk 3 nodes from the live BindImp + // LoadLibrary ret MODULE, even when CurProc+50 + // failed lpSelf. Do not invent the list head. + private static void LogDdiNopBindWalkOnce(MipsBus bus) + { + if (_ddiNopWalkDiag || _ddiNopBindLibV0 == 0) + return; + _ddiNopWalkDiag = true; + string walk = FormatDdiNopWalk(bus, _ddiNopBindLibV0, 3); + if (walk.Length == 0) + walk = "v0=0x" + _ddiNopBindLibV0.ToString("X8") + + (IsTrustedModule(bus, _ddiNopBindLibV0) ? "" : " not-lpSelf"); + BootLog.Write("[Hive] ExtraROM ddi_nop walk " + walk); + } + + private static string FormatDdiNopWalk(MipsBus bus, uint seed, int cap) + { + if (!IsTrustedModule(bus, seed)) + return ""; + string walk = ""; + uint m = seed; + int n = 0; + while (n < cap && m != 0 && m != 0xDEADBEEFu) + { + if (!IsTrustedModule(bus, m)) + break; + uint oe = 0; + uint ip = 0; + TryPeekWord(bus, m + ModuleFileObj, out oe); + TryPeekWord(bus, m + ModuleStartip, out ip); + if (walk.Length > 0) + walk += " "; + walk += "m=0x" + m.ToString("X8") + + " +96=0x" + oe.ToString("X8") + + " ip=0x" + ip.ToString("X8"); + uint next; + if (!TryPeekWord(bus, m + ModulePmodNext, out next) || next == 0 || next == m) + break; + m = next; + n++; + } + return walk; + } + + // PTE dest6 at RAM entry 0x01998014. Peek 0 is + // honest; do not invent 0x27BDFFD8. + private static uint PeekDdiNopRamEntryWord(MipsBus bus) + { + uint va = DdiNopVbasePage + DdiNopEntryRvaExtract; + uint l2; + uint dest6; + uint dest10; + if (WalkDdiNopPteDests(bus, va, out l2, out dest6, out dest10) + && dest6 != 0) + return PeekDestWordRaw(bus, dest6, out _); + return PeekDestWordRaw(bus, va, out _); + } + + private static bool IsCallDllSkipUseg(uint p50) + { + if (p50 < 0x80000000u) + return true; + return (p50 & 0xFF000000u) == 0xC2000000u; + } + + private static uint DumpTocVbase(ExtraRomTocMod slot) + { + if (slot == null) + return 0; + if (slot.Vbase != 0) + return slot.Vbase; + if (slot.E32Words != null && slot.E32Words.Length > 2 && slot.E32Words[2] != 0) + return slot.E32Words[2]; + if (slot.O32Words != null && slot.O32Words.Length >= 5 + && slot.O32Words[1] == 0x1000 && slot.Dest >= 0x1000) + return slot.Dest - 0x1000; + return 0; + } + + public static bool TryServeExtraRomLoadLibrary(MipsBus bus, string name, uint[] regs) + { + if (regs == null || regs.Length <= 2 || regs[2] != 0) + return false; + string baseName = FileBaseName(name); + ExtraRomTocMod slot = FindCachedExtraRomToc(baseName); + if (slot == null && !string.IsNullOrEmpty(baseName)) + slot = FindCachedExtraRomToc(name); + if (slot == null) + return false; + uint destDump = slot.Dest; + uint dest0 = destDump & SlotMask; + uint hdr = 0; + if (slot.Data != null && slot.Data.Length > 0 + && slot.Data[0] != null && slot.Data[0].Length > 0) + hdr = slot.Data[0][0]; + if (NamesMatchRom(slot.Name, "ddi_nop.dll") && dest0 == 0x01981000u + && bus != null) + TryMeasureDdiNopDestAfterDecomp(bus, hdr, _ddiNopDecompVsize); + uint wordDump = PeekDestWordRaw(bus, destDump, out _); + uint word0 = PeekDestWordRaw(bus, dest0, out _); + // Live 021a2eb: dest6+0x1000 sig 0x8C481B78 is + // dump .text RVA 0x2000. Serve dest6; vbase is + // VALLOC 0x01980000. Do not require MZ at vbase. + // Do not serve dest10. Do not invent dest. + uint fwDest = 0; + uint fwWord = 0; + if (!DdiNopDestStoresAllowServe()) + { + fwDest = 0; + fwWord = 0; + } + else if (_ddiNopLandedBySig && _ddiNopLandedDest != 0 + && (_ddiNopLandedDest & ~0xFFFu) != DdiNopDest10Live) + { + fwDest = _ddiNopLandedDest; + fwWord = _ddiNopLandedWord; + } + else if (_ddiNopLandedDest != 0 && IsMzWord(_ddiNopLandedWord) + && (_ddiNopLandedDest & ~0xFFFu) != DdiNopDest10Live) + { + fwDest = _ddiNopLandedDest; + fwWord = _ddiNopLandedWord; + } + uint vbase; + if (_ddiNopLandedBySig && fwDest != 0) + vbase = DdiNopVbasePage; + else if (fwDest != 0) + vbase = fwDest; + else + vbase = DumpTocVbase(slot); + string why; + if (fwDest == 0) + { + if (!DdiNopDestStoresAllowServe()) + why = "dest0 dest6 vbase6 store-count=0; do not serve"; + else + why = "dest6 .text sig miss; do not serve dest10"; + } + else if (_ddiNopLandedBySig) + why = "dest6 .text sig; serve dest6"; + else + why = "vbase MZ; serve vbase dest"; + BootLog.Write("[Hive] TOC[" + slot.Index + "] " + slot.Name + + " LoadLibrary v0=0 destDump=0x" + destDump.ToString("X8") + + " dump-word=0x" + wordDump.ToString("X") + + " dest0=0x" + dest0.ToString("X8") + + " dest0-word=0x" + word0.ToString("X") + + " landed=0x" + fwDest.ToString("X8") + + " landed-word=0x" + fwWord.ToString("X") + + " " + why); + if (fwDest == 0 || vbase == 0) + { + BootLog.Rom("miss", "ExtraROM", "TOC", slot.Index, slot.Name, 7, destDump, wordDump, vbase, why); + return false; + } + slot.DecompDest = fwDest; + slot.Vbase = vbase; + regs[2] = fwDest; + BootLog.Rom("ok", "ExtraROM", "TOC", slot.Index, slot.Name, 7, fwDest, fwWord, regs[2], why); + return true; + } + + // Dump-cached e32 size. o32 follows that copy at + // LiveE32+e32Bytes (TOC+0x18). Do not pack o32 at + // +0x5C: that was leftover CurMSec a1, not a pointer. + private static uint ExtraRomHostE32Bytes(ExtraRomTocMod slot) + { + if (slot == null || slot.E32Words == null || slot.E32Words.Length == 0) + return 0; + return (uint)slot.E32Words.Length * 4; + } + + private static bool WriteHostExtraRomE32O32(MipsBus bus, ExtraRomTocMod slot, string name) + { + try + { + for (int i = 0; i < slot.TocWords.Length && i < 8; i++) + bus.Write32(slot.LiveEntry + (uint)(i * 4), slot.TocWords[i]); + bus.Write32(slot.LiveEntry + 0x14, slot.LiveE32); + bus.Write32(slot.LiveEntry + 0x18, slot.LiveO32); + if (slot.LiveName != 0) + bus.Write32(slot.LiveEntry + 0x10, slot.LiveName); + uint e32Bytes = ExtraRomHostE32Bytes(slot); + int e32n = (int)(e32Bytes / 4); + if (e32n > slot.E32Words.Length) + e32n = slot.E32Words.Length; + for (int i = 0; i < e32n; i++) + bus.Write32(slot.LiveE32 + (uint)(i * 4), slot.E32Words[i]); + if (slot.O32Words != null && slot.LiveO32 != 0) + { + for (int i = 0; i < slot.O32Words.Length; i++) + bus.Write32(slot.LiveO32 + (uint)(i * 4), slot.O32Words[i]); + } + if (slot.LiveName != 0 && !string.IsNullOrEmpty(name)) + { + for (int i = 0; i < name.Length; i++) + bus.Write8(slot.LiveName + (uint)i, (byte)name[i]); + bus.Write8(slot.LiveName + (uint)name.Length, 0); + } + return true; + } + catch (System.Exception ex) + { + System.Console.WriteLine("[Hive] ExtraROM TOC[" + slot.Index + "] " + + slot.Name + " e32-host-fail " + ex.Message); + return false; + } + } + + private static bool TryFindTocModule(MipsBus bus, uint tocOrZero, uint maxMods, + string baseName, out uint tocEntry, out uint attr) + { + tocEntry = 0; + attr = 0; + if (bus == null || string.IsNullOrEmpty(baseName)) + return false; + try + { + uint toc = tocOrZero; + if (toc == 0) + toc = bus.Read32(EcecTocPtr); + if (toc == 0) + return false; + uint nmods = bus.Read32(toc + RomHdrNumMods); + if (nmods == 0 || nmods > maxMods) + return false; + for (uint i = 0; i < nmods; i++) + { + uint entry = toc + TocFirst + i * TocEntrySize; + uint name = bus.Read32(entry + 0x10); + if (!NamesMatchRom(baseName, ReadAscii(bus, name))) + continue; + uint tocAttr = bus.Read32(entry); + attr = (tocAttr & 0xFFFFEFFFu) | 0x2040u; + tocEntry = entry; + return true; + } + } + catch + { + } + return false; + } + + // ExtraROM FILESentry follows TOC modules + // (romhdr+0x54+nmods*32, 28 bytes). wait53 CreateFile + // miss: NK/BINFS never walks this table. + private static bool TryFindExtraRomFile(MipsBus bus, string baseName, + out uint filesEntry, out uint attr, out uint real, out uint comp, out uint load) + { + filesEntry = 0; + attr = 0; + real = 0; + comp = 0; + load = 0; + if (bus == null || string.IsNullOrEmpty(baseName)) + return false; + try + { + uint toc = ExtraRomToc(bus); + if (toc == 0) + return false; + uint nmods = bus.Read32(toc + RomHdrNumMods); + uint nfiles = bus.Read32(toc + RomHdrNumFiles); + if (nmods > 128 || nfiles == 0 || nfiles > 128) + return false; + uint first = toc + TocFirst + nmods * TocEntrySize; + for (uint i = 0; i < nfiles; i++) + { + uint entry = first + i * FilesEntrySize; + uint name = bus.Read32(entry + FilesNameOff); + if (!NamesMatchRom(baseName, ReadAscii(bus, name))) + continue; + uint fileAttr = bus.Read32(entry); + real = bus.Read32(entry + FilesRealSize); + comp = bus.Read32(entry + FilesCompSize); + load = bus.Read32(entry + FilesLoadOff); + // Keep the dump FILE attr (0x807). Do not set + // ROMMODULE 0x2000: LoadE32 then reads +0x14 as e32. + attr = fileAttr; + filesEntry = entry; + return true; + } + } + catch + { + } + return false; + } + + private static bool TryFindNkFile(MipsBus bus, string baseName, + out uint filesEntry, out uint attr, out uint real, out uint comp, out uint load) + { + filesEntry = 0; + attr = 0; + real = 0; + comp = 0; + load = 0; + if (bus == null || string.IsNullOrEmpty(baseName)) + return false; + try + { + uint toc = bus.Read32(EcecTocPtr); + if (toc == 0) + return false; + uint nmods = bus.Read32(toc + RomHdrNumMods); + uint nfiles = bus.Read32(toc + RomHdrNumFiles); + if (nmods > 80 || nfiles == 0 || nfiles > 80) + return false; + uint first = toc + TocFirst + nmods * TocEntrySize; + for (uint i = 0; i < nfiles; i++) + { + uint entry = first + i * FilesEntrySize; + uint name = bus.Read32(entry + FilesNameOff); + if (!NamesMatchRom(baseName, ReadAscii(bus, name))) + continue; + attr = bus.Read32(entry); + real = bus.Read32(entry + FilesRealSize); + comp = bus.Read32(entry + FilesCompSize); + load = bus.Read32(entry + FilesLoadOff); + filesEntry = entry; + return true; + } + } + catch + { + } + return false; + } + + private static uint ExtraRomToc(MipsBus bus) + { + if (_extraRomHdr != 0) + return _extraRomHdr; + if (bus == null || _extraRomStart == 0) + return 0; + try + { + uint sig = bus.Read32(_extraRomStart + 0x40); + uint romhdr = bus.Read32(_extraRomStart + 0x44); + if (sig != ExtraRomCece || romhdr == 0) + return _extraRomStart; + _extraRomHdr = romhdr; + return romhdr; + } + catch + { + return 0; + } + } + + public static bool TryMissMscoreeWin32(MipsBus bus, uint path, uint[] regs, ref uint programCounter) + { + if (regs == null || regs.Length <= 31) + return false; + string baseName = ""; + try + { + if (bus != null && path != 0) + baseName = Basename(bus, path); + } + catch + { + } + if (string.IsNullOrEmpty(baseName)) + baseName = _pendingRomFile; + if (!IsMscoreeDll(baseName) && !IsOle32Dll(baseName)) + return false; + regs[2] = 0xFFFFFFFFu; + programCounter = regs[31]; + System.Console.WriteLine("[Hive] Win32 CreateFile " + baseName + + " INVALID_HANDLE (no dump FILE; ExtraROM TOC type-7 attach at 0x8001D400)"); + return true; + } + + public static void TryRejectMscoreeFileHandle(MipsBus bus, uint[] regs) + { + if (bus == null || regs == null || regs.Length <= 23) + return; + uint v0 = regs[2]; + if (v0 == 0xFFFFFFFFu) + return; + string baseName = _pendingRomFile; + if (!IsMscoreeDll(baseName) && !IsOle32Dll(baseName)) + { + try + { + baseName = Basename(bus, regs[23]); + if (!IsMscoreeDll(baseName) && !IsOle32Dll(baseName) && regs[4] != 0) + baseName = Basename(bus, regs[4]); + } + catch + { + return; + } + } + if (!IsMscoreeDll(baseName) && !IsOle32Dll(baseName)) + return; + regs[2] = 0xFFFFFFFFu; + System.Console.WriteLine("[Hive] Win32 CreateFile " + baseName + + " v0=0x" + v0.ToString("X8") + + " (filesys handle; FILE table has no " + baseName + + "; INVALID_HANDLE so ExtraROM TOC type-7 attach)"); + } + + public static bool TryMissMissingDevice(MipsBus bus, uint path, uint[] regs, ref uint programCounter) + { + if (bus == null || regs == null || regs.Length <= 31 || path == 0) + return false; + try + { + string name = Basename(bus, path); + if (string.IsNullOrEmpty(name)) + return false; + int n = name.Length; + if (n > 0 && name[n - 1] == ':') + n--; + if (n != 4) + return false; + if ((name[0] != 'B' && name[0] != 'b') + || (name[1] != 'T' && name[1] != 't') + || (name[2] != 'V' && name[2] != 'v') + || name[3] != '1') + return false; + regs[2] = 0xFFFFFFFFu; + programCounter = regs[31]; + return true; + } + catch + { + return false; + } + } + + public static void TryEnableFilterProcessAttach(MipsBus bus, uint[] regs) + { + if (bus == null || regs == null || regs.Length <= 30) + return; + try + { + if ((regs[20] & CallDllFlag) != 0) + return; + uint module = regs[30]; + if (module == 0) + return; + if (bus.Read32(module + ModuleStartip) != FilterStartip) + return; + regs[20] |= CallDllFlag; + } + catch + { + } + } + + public static void TryFillTocStartip(MipsBus bus, uint module) + { + TryFillTocStartip(bus, module, false); + } + + public static void TryFillTocStartip(MipsBus bus, uint module, bool replaceWrong) + { + if (bus == null || module == 0) + return; + try + { + // RAM .text sig landed: do not fill dump XIP + // 0x03998014. Set VALLOC startip on this module. + if (_ddiNopLandedBySig && IsDdiNopModule(bus, module)) + { + TrySetDdiNopRamStartip(bus, module); + return; + } + uint obj = module + ModuleFileObj; + if (bus.Read8(obj + 4) != TocAttachType) + return; + uint tocEntry = bus.Read32(obj); + if (tocEntry == 0) + return; + uint e32 = bus.Read32(tocEntry + 0x14); + if (e32 == 0) + return; + uint entryrva = bus.Read32(e32 + 4); + uint vbase = bus.Read32(e32 + 8); + if (entryrva == 0) + return; + uint cur = bus.Read32(module + ModuleStartip); + if (vbase >= DdiNopVbase && vbase < 0x04000000u) + { + if (cur == 0) + bus.Write32(module + ModuleStartip, vbase + entryrva); + return; + } + if (vbase != ExeVbase) + return; + uint va = vbase + entryrva; + if (cur == va) + return; + if (!replaceWrong && cur != 0) + return; + bus.Write32(module + ModuleStartip, va); + } + catch + { + } + } + + public static void NoteDdiNopCallDllPc(MipsBus bus, uint[] regs, uint pc) + { + // Live c231655: any module's CallDLL PC set saw + // before await armed, so the poll never logged. + // Only this load, only ddi_nop. + if (!_ddiNopAwaitCallDll || bus == null || regs == null + || regs.Length <= 30) + return; + if (pc != XipCallDllUsegChk && pc != XipExeCallDllSkip + && pc != CallDllStartip && pc != XipDllCallDllJal + && pc != CallDllAfterJalr) + return; + bool hit = IsDdiNopModule(bus, regs[30]); + if (!hit && (pc == CallDllStartip || pc == CallDllAfterJalr)) + { + if (regs.Length > 23 && IsDdiNopModule(bus, regs[23])) + hit = true; + else if (regs.Length > 4 && IsDdiNopModule(bus, regs[4])) + hit = true; + } + bool startipHit = false; + if (!hit && (pc == CallDllStartip || pc == CallDllAfterJalr + || pc == XipDllCallDllJal)) + startipHit = IsDdiNopStartipModule(bus, regs); + if (hit || startipHit) + { + _ddiNopSawCallDllPc = true; + if (_ddiNopCallDllSite == 0) + _ddiNopCallDllSite = pc; + if (!_ddiNopCallDllHiveLogged) + { + _ddiNopCallDllHiveLogged = true; + uint a1 = regs.Length > 5 ? regs[5] : 0; + uint ip = 0; + if (_ddiNopModule != 0) + TryPeekWord(bus, _ddiNopModule + ModuleStartip, out ip); + BootLog.Write("[Hive] ExtraROM ddi_nop CallDLL pc=0x" + + pc.ToString("X8") + + " module=0x" + regs[30].ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " startip=0x" + ip.ToString("X8") + + (startipHit && !hit ? " (startip-site)" : "")); + } + TryNoteDdiNopProcessInfo(bus, regs); + } + } + + private static bool IsDdiNopStartipModule(MipsBus bus, uint[] regs) + { + if (bus == null || regs == null) + return false; + uint ip = 0; + if (_ddiNopModule != 0 + && TryPeekWord(bus, _ddiNopModule + ModuleStartip, out ip) + && IsDdiNopRamStartip(ip)) + return true; + for (int i = 0; i < 3; i++) + { + uint mod = 0; + if (i == 0 && regs.Length > 30) + mod = regs[30]; + else if (i == 1 && regs.Length > 23) + mod = regs[23]; + else if (i == 2 && regs.Length > 4) + mod = regs[4]; + if (mod == 0) + continue; + if (!TryPeekWord(bus, mod + ModuleStartip, out ip)) + continue; + if (IsDdiNopRamStartip(ip)) + return true; + } + return false; + } + + private static bool IsDdiNopRamStartip(uint ip) + { + return ip == DdiNopVbasePage + DdiNopEntryRvaExtract + || ip == DdiNopVbase + DdiNopEntryRvaExtract; + } + + // Live edf15b0: DllMain / CallDLL already had + // a1=1 and MODULE in v0, but died in coredll + // lw $v0,0($s5) before any Hive. Log startip + // when it actually runs. Do not invent CallDLL. + private static void TryNoteDdiNopDllMain(MipsBus bus, uint[] regs, uint pc) + { + if (_ddiNopDllMainLogged || !_ddiNopAwaitCallDll) + return; + if (_ddiNopModule == 0 || bus == null) + return; + uint ip = 0; + if (!TryPeekWord(bus, _ddiNopModule + ModuleStartip, out ip) || ip == 0) + return; + if (pc != ip) + return; + _ddiNopDllMainLogged = true; + _ddiNopSawCallDllPc = true; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + _ddiNopDllMainRa = ra; + BootLog.Write("[Hive] ExtraROM ddi_nop DllMain startip=0x" + + ip.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " module=0x" + _ddiNopModule.ToString("X8") + + " calldll-site=" + + (_ddiNopCallDllSite != 0 + ? "0x" + _ddiNopCallDllSite.ToString("X8") + : "none")); + TryNoteDdiNopProcessInfo(bus, regs); + TryResolveDdiNopGwesDispFetch(bus); + TryResolveDdiNopGwesDispData(bus); + TryResolveDdiNopGwesTextBase(bus); + TryResolveDdiNopGwesDispData2(bus); + TryResolveDdiNopGwesDispData3(bus); + TryResolveDdiNopGwesText2(bus); + } + + // Live 6b8a9eb: after DllMain the next I-fetch + // was 0x0005D2E0 (gwes Display page). Name that + // PC/$ra once. Do not invent a jump. + private static void TryNoteDdiNopAfterDllMain(MipsBus bus, uint[] regs, uint pc) + { + if (!_ddiNopDllMainLogged || _ddiNopAfterDllMainLogged) + return; + if (pc >= DdiNopVbasePage && pc < 0x019B0000u) + return; + if (pc >= BindImpExnLo && pc <= BindImpExnHi) + return; + if (pc == 0 || pc == 0x80000000u || pc == 0x80000180u) + return; + _ddiNopAfterDllMainLogged = true; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + bool fetchPage = (pc & ~0xFFFu) == GwesDispFetchPage; + BootLog.Write("[Hive] ExtraROM ddi_nop after-DllMain pc=0x" + + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " dllmain-ra=0x" + _ddiNopDllMainRa.ToString("X8") + + (fetchPage ? " (gwes Display fetch page)" : "") + + " calldll-site=" + + (_ddiNopCallDllSite != 0 + ? "0x" + _ddiNopCallDllSite.ToString("X8") + : "none")); + if (fetchPage) + TryResolveDdiNopGwesDispFetch(bus); + TryResolveDdiNopGwesDispData(bus); + TryResolveDdiNopGwesTextBase(bus); + TryResolveDdiNopGwesDispData2(bus); + TryResolveDdiNopGwesDispData3(bus); + TryResolveDdiNopGwesText2(bus); + if (IsDdiNopGwesImageVa(pc) && !IsNamedDdiNopGwesPage(pc)) + TryResolveDdiNopGwesImage(bus, pc); + if (IsDdiNopCoredllImageVa(pc)) + TryResolveDdiNopCoredllImage(bus, pc); + if (IsDdiNopVallocDataVa(pc)) + TryResolveDdiNopVallocData(bus, pc); + } + + // Observe only. After BindImp, startip is set but + // firmware may never reach 0x8001DD6C. Do not + // invent a CallDLL site. + public static void TryPollDdiNopCallDllMiss(MipsBus bus, uint pc) + { + TryPollDdiNopCallDllMiss(bus, null, pc); + } + + private static bool IsBindImpIatWalkPc(uint pc) + { + if (pc >= BindImpHdr && pc <= BindImpIatNextAfter) + return true; + if (pc == BindImpOrdLookup || pc == BindImpOrdBaseLw) + return true; + if (pc == BindImpLoadLib || pc == BindImpLoadLibRet) + return true; + if (_ddiNopIatStoreLogged + && pc >= BindImpExnLo && pc <= BindImpExnHi) + return true; + return false; + } + + public static void TryPollDdiNopCallDllMiss(MipsBus bus, uint[] regs, uint pc) + { + TryNoteC2SpObserve(regs, pc); + TryNoteDdiNopOrdGetProc(bus, regs, pc); + NoteDdiNopCallDllPc(bus, regs, pc); + TryNoteGwesB9SpinObserve(bus, regs, pc); + if (!_ddiNopAwaitCallDll || _ddiNopCallDllMissLogged || _ddiNopSawCallDllPc) + return; + // Live edf15b0: CallDLL-miss still fired + // mid-bind after slot0..23. Wait until the + // IAT walk is done (24 stores). + if (_ddiNopIatStoreN < BindImpObserveMax) + return; + // Live 1c3b70a: slot0 IAT-store won, then + // CallDLL-miss fired while BindImp was still + // at GetProc-ord for the next ordinal. + if (IsBindImpIatWalkPc(pc)) + return; + _ddiNopCallDllMissPoll++; + if (_ddiNopCallDllMissPoll < 4096) + return; + TryLogDdiNopCallDllMiss(bus, regs, pc); + } + + // Live c0347e8: after B9 dest0 map, Hive froze + // (~84KB) while the host burned CPU. Observe + // the stuck PC. Do not invent dest. Do not hop. + // Live 98db5d5: same-page reset never reached + // 256K/16K. Count total steps after B9 map. + private static void TryNoteGwesB9SpinObserve(MipsBus bus, uint[] regs, + uint pc) + { + if (_gwesB9SpinLogged || pc == 0) + return; + if (LookupGwesImageKseg(GwesDataB9Page) == 0) + return; + _gwesB9SpinPage = pc & ~0xFFFu; + _gwesB9SpinN++; + bool vec = (pc >= 0x80000000u && pc < 0x80000200u) + || (pc >= BindImpExnLo && pc <= BindImpExnHi); + int need = vec ? GwesDataB9SpinVec : GwesDataB9SpinSame; + if (_gwesB9SpinN < need) + return; + _gwesB9SpinLogged = true; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + BootLog.Write("[Hive] ExtraROM ddi_nop spin-observe epc=0x" + + pc.ToString("X8") + + " badvaddr=0x" + _bindImpExnVaddr.ToString("X8") + + " cause=" + _bindImpExnCode + + " v0=0x" + v0.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " (after B9 dest0; do not invent dest)"); + } + + public static void TryLogDdiNopCallDllMiss(MipsBus bus) + { + TryLogDdiNopCallDllMiss(bus, null, 0); + } + + public static void TryLogDdiNopCallDllMiss(MipsBus bus, uint pc) + { + TryLogDdiNopCallDllMiss(bus, null, pc); + } + + public static void TryLogDdiNopCallDllMiss(MipsBus bus, uint[] regs, uint pc) + { + if (_ddiNopCallDllMissLogged || !_ddiNopAwaitCallDll || _ddiNopSawCallDllPc) + return; + if (_ddiNopIatStoreN < BindImpObserveMax) + return; + if (_ddiNopModule == 0) + return; + _ddiNopCallDllMissLogged = true; + uint p50 = 0; + uint ip = 0; + TryPeekWord(bus, _ddiNopModule + ProcModule, out p50); + TryPeekWord(bus, _ddiNopModule + ModuleStartip, out ip); + BootLog.Write("[Hive] ExtraROM ddi_nop CallDLL-miss module=0x" + + _ddiNopModule.ToString("X8") + + " mod+0x50=0x" + p50.ToString("X8") + + " startip=0x" + ip.ToString("X8") + + " no-0x8001DD6C"); + TryLogDdiNopBindImpStall(bus, regs, pc); + } + + // Observe only. Do not invent a CallDLL site. If + // stall is BinaryDecompress/MapO32 for o32[1], + // say so; do not host-CEDecompress .data. + private static void TryLogDdiNopBindImpStall(MipsBus bus, uint[] regs, uint pc) + { + if (_ddiNopStallLogged) + return; + _ddiNopStallLogged = true; + string why = ""; + if (pc == BinaryDecompressRom || pc == MapO32Decompress) + why = " BinaryDecompress"; + else if (pc == MapO32Rom || pc == MapO32InnerJal + || pc == MapO32FlagsBnez || pc == MapO32VallocJal) + why = " MapO32"; + else if (pc == BindImpOrdBaseLw) + why = " GetProc-ord"; + else if (pc >= BindImpExnLo && pc <= BindImpExnHi) + why = " exception-save"; + uint dest = 0; + if (regs != null && regs.Length > 4) + dest = regs[4]; + uint iat = DdiNopVbasePage + DdiNopIatRva; + uint l2 = 0; + uint dest6 = 0; + uint dest10 = 0; + WalkDdiNopPteDests(bus, iat, out l2, out dest6, out dest10); + if (dest != 0 && (dest == iat + || (dest6 != 0 && (dest & ~0xFFFu) == (dest6 & ~0xFFFu)))) + why += " o32[1]"; + BootLog.Write("[Hive] ExtraROM BindImp-stall pc=0x" + + pc.ToString("X8") + why); + if (_ddiNopOrdGoodV0 == 0 || _ddiNopIatStoreLogged + || _ddiNopOrdAfterDone) + return; + uint iatWord = 0; + uint iatDest6 = 0; + PeekDdiNopIatWord(bus, out iatWord, out iatDest6); + if (iatWord != 0) + return; + _ddiNopOrdAfterDone = true; + BootLog.Write("[Hive] ExtraROM BindImp-ord drop-v0=0x" + + _ddiNopOrdGoodV0.ToString("X8") + + " no-IAT last=0x" + pc.ToString("X8") + + " (stall)"); + TryNoteBindImpIatSwSkipped(); + } + + public static bool TryForceDdiNopCallDll(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (bus == null || regs == null || regs.Length <= 30 || !_ddiNopLandedBySig) + return false; + // $fp is the CallDLL module. Do not steal + // filesys/gwes by substituting a cached ddi_nop. + uint module = regs[30]; + if (!IsDdiNopModule(bus, module)) + return false; + try + { + TrySetDdiNopRamStartip(bus, module); + uint p50 = 0; + uint ip = 0; + TryPeekWord(bus, module + ProcModule, out p50); + TryPeekWord(bus, module + ModuleStartip, out ip); + if (programCounter == XipCallDllUsegChk && !IsCallDllSkipUseg(p50)) + return false; + if (ip == 0) + { + BootLog.Write("[Hive] ExtraROM ddi_nop CallDLL-skip module=0x" + + module.ToString("X8") + + " mod+0x50=0x" + p50.ToString("X8") + + " startip=0x00000000 skip-startip-0"); + return false; + } + regs[4] = module; + regs[5] = 1; + programCounter = XipDllCallDllJal; + _ddiNopSawCallDllPc = true; + BootLog.Write("[Hive] force CallDLL ExtraROM ddi_nop module=0x" + + module.ToString("X8") + + " mod+0x50=0x" + p50.ToString("X8") + + " startip=0x" + ip.ToString("X8") + + " a1=1 (jal 0x80018B34; useg +0x50)"); + System.Console.WriteLine("[Hive] force CallDLL ExtraROM ddi_nop module=0x" + + module.ToString("X8") + " startip=0x" + ip.ToString("X8") + + " a1=1 (jal 0x80018B34; do not land on addiu a1,0,0)"); + return true; + } + catch + { + return false; + } + } + + public static bool TryForceXipExeCallDll(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (bus == null || regs == null || regs.Length <= 30) + return false; + uint module = regs[30]; + if (module == 0) + return false; + try + { + RefreshExeXipAlias(bus); + if (!_aliasOn) + return false; + TryFillTocStartip(bus, module, true); + uint cur = bus.Read32(module + ModuleStartip); + if (cur == 0) + return false; + regs[4] = module; + regs[5] = 0; + programCounter = XipExeCallDllJal; + System.Console.WriteLine("[Hive] force CallDLL module=0x" + module.ToString("X8") + + " startip=0x" + cur.ToString("X8")); + return true; + } + catch + { + return false; + } + } + + public static bool IsAllowedTv2Startip(uint va) + { + if (va >= 0x00012000u && va < 0x00013000u) return true; + if (va >= 0x00014000u && va < 0x00015000u) return true; + if (va >= 0x00016000u && va < 0x00017000u) return true; + if (va >= 0x014B1000u && va < 0x014D0000u) return true; + return false; + } + + public static void TryNoteTv2LoadExeE32(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2FileDestOn || pc != LoadExeE32Ret || bus == null || regs == null) + return; + if (regs.Length <= 29) + return; + try + { + uint proc = bus.Read32(CurProc); + if (proc >= 0x80000000u && (_tv2Proc == 0 || IsNkOrFilesysProc(_tv2Proc))) + _tv2Proc = proc; + uint sp = regs[29]; + uint s5 = regs.Length > 21 ? regs[21] : 0; + uint entryRva = sp != 0 ? bus.Read32(sp + 28) : 0; + uint e32plus4 = 0; + uint e32plus8 = 0; + uint e32plus16 = 0; + if (s5 >= 0x80000000u) + { + e32plus4 = bus.Read32(s5 + 4); + e32plus8 = bus.Read32(s5 + 8); + e32plus16 = bus.Read32(s5 + 16); + } + System.Console.WriteLine("[Hive] FILE[25] load-exe e32: 28(sp)=0x" + + entryRva.ToString("X8") + + " e32+4=0x" + e32plus4.ToString("X8") + + " e32+8=0x" + e32plus8.ToString("X8") + + " e32+16=0x" + e32plus16.ToString("X8") + + " dump-entryrva=0x" + _tv2PeEntryRva.ToString("X8") + + " dump-imagebase=0x" + _tv2PeImageBase.ToString("X8") + + " dump-comrva=0x" + _tv2PeComRva.ToString("X8") + + " (COM path if e32+16!=0; do not invent 0x00017F54)"); + } + catch + { + } + } + + public static void TryKeepTv2FileStartip(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2FileDestOn || pc != LoadExeStartipRet || bus == null || regs == null) + return; + if (regs.Length <= 19) + return; + uint s3 = regs[19]; + System.Console.WriteLine("[Hive] FILE[25] load-exe startip-ret: s3=0x" + + s3.ToString("X8") + + " dump-entryrva=0x" + _tv2PeEntryRva.ToString("X8") + + " dump-comrva=0x" + _tv2PeComRva.ToString("X8") + + " (firmware RVA->VA or _CorExeMain; not invented 0x00017F54)"); + if (!IsAllowedTv2Startip(s3)) + return; + _tv2Startip = s3; + try + { + uint proc = bus.Read32(CurProc); + if (proc >= 0x80000000u && (_tv2Proc == 0 || IsNkOrFilesysProc(_tv2Proc))) + _tv2Proc = proc; + if (_tv2Proc != 0) + TryFillFileExeStartip(bus, _tv2Proc); + } + catch + { + } + } + + // wait70: dest-on gated this past the primary ThreadContextSetup + // (thr+5C still 0). First noted thread after FILE dest-on was + // the NK helper. Bind the CreateProcess thread even before + // dest-on; displace only when incoming +5C is firmware startip + // and the current bind is not. + public static void NoteTv2Thread(uint thr) + { + NoteTv2Thread(null, thr); + } + + public static void NoteTv2Thread(MipsBus bus, uint thr) + { + if (thr < 0x80000000u) + return; + uint incomingIp = 0; + if (bus != null) + { + try + { + incomingIp = bus.Read32(thr + ThreadStartip); + } + catch + { + } + } + bool incomingPrimary = incomingIp != 0 && IsAllowedTv2Startip(incomingIp); + if (_tv2Thread != 0 && _tv2Thread != thr) + { + if (!incomingPrimary) + return; + uint curIp = 0; + if (bus != null) + { + try + { + curIp = bus.Read32(_tv2Thread + ThreadStartip); + } + catch + { + } + } + if (curIp != 0 && IsAllowedTv2Startip(curIp)) + return; + System.Console.WriteLine("[Hive] FILE[25] thread bind: was=0x" + + _tv2Thread.ToString("X8") + + " now=0x" + thr.ToString("X8") + + " +5C=0x" + incomingIp.ToString("X8") + + " (firmware startip; not NK helper)"); + } + else if (_tv2Thread == 0) + { + System.Console.WriteLine("[Hive] FILE[25] thread bind: now=0x" + + thr.ToString("X8") + + " +5C=0x" + incomingIp.ToString("X8") + + " (tv2 CreateProcess thread; dest-on not required)"); + } + _tv2Thread = thr; + } + + private static bool IsNkOrFilesysProc(uint proc) + { + return proc == ProcTable || proc == ProcTable + ProcSize; + } + + // wait71: keep/force while +5C was trampoline 0x8001FF38 + // aborted CreateProcess (v0=0 last-error=193). Wait until + // firmware has stored startip on the primary (CreateProcess-ret). + private static bool IsTv2PrimaryStartipReady(MipsBus bus) + { + if (bus == null || _tv2Thread == 0) + return false; + try + { + uint ip = bus.Read32(_tv2Thread + ThreadStartip); + return IsAllowedTv2Startip(ip); + } + catch + { + return false; + } + } + + public static void TryKeepTv2ThreadOwner(MipsBus bus, string tag) + { + if (!_tv2FileDestOn || bus == null || _tv2Thread == 0 || _tv2Proc == 0) + return; + if (!IsTv2PrimaryStartipReady(bus)) + return; + if (IsNkOrFilesysProc(_tv2Proc)) + return; + uint owner; + try + { + owner = bus.Read32(_tv2Thread + ThreadPrc); + } + catch + { + return; + } + if (owner == _tv2Proc) + return; + if (owner != 0 && !IsNkOrFilesysProc(owner)) + return; + try + { + bus.Write32(_tv2Thread + ThreadPrc, _tv2Proc); + System.Console.WriteLine("[Hive] FILE[25] thread +0C: " + tag + + " thr=0x" + _tv2Thread.ToString("X8") + + " was=0x" + owner.ToString("X8") + + " now=0x" + _tv2Proc.ToString("X8") + + " (firmware tv2 proc; switcher CurProc; not a slot map)"); + } + catch + { + } + } + + public static bool TryForceTv2ProcSwitch(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (!_tv2FileDestOn || _tv2Thread == 0 || _tv2Proc == 0 || regs == null || regs.Length <= 2) + return false; + if (programCounter != ThreadSwitchProcChk) + return false; + if (regs[2] != _tv2Thread) + return false; + if (!IsTv2PrimaryStartipReady(bus)) + return false; + if (IsNkOrFilesysProc(_tv2Proc)) + return false; + uint cur = 0; + if (bus != null) + { + try + { + cur = bus.Read32(CurProc); + } + catch + { + return false; + } + if (cur == _tv2Proc) + return false; + } + programCounter = ThreadSwitchProcSlow; + if (!_tv2SwitchForced) + { + _tv2SwitchForced = true; + System.Console.WriteLine("[Hive] FILE[25] switcher force-slow v0=0x" + + regs[2].ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " owner=0x" + _tv2Proc.ToString("X8") + + " (firmware 0x8001554C; not an invented slot map)"); + } + return true; + } + + // wait73: 0x800154FC can skip 0x8001554C and land on + // 0x800155A8; fast ERET 0x8001566C then restores startip + // with CurProc still filesys. Send that ERET through + // 0x80015550 (v0=s0) so firmware 0x80015570 re-reads +0C. + // Do not poke CurProc. + public static bool TryForceTv2EretSlowPath(MipsBus bus, uint[] regs, ref uint programCounter) + { + if (!_tv2FileDestOn || _tv2Thread == 0 || _tv2Proc == 0 || regs == null || regs.Length <= 16) + return false; + if (programCounter != ThreadCtxRestore2) + return false; + if (regs[16] != _tv2Thread) + return false; + if (!IsTv2PrimaryStartipReady(bus)) + return false; + if (IsNkOrFilesysProc(_tv2Proc)) + return false; + uint cur = 0; + if (bus != null) + { + try + { + cur = bus.Read32(CurProc); + } + catch + { + return false; + } + if (cur == _tv2Proc) + return false; + } + regs[2] = regs[16]; + programCounter = ThreadSwitchProcSlow; + _tv2SwitchStoreLogged = false; + System.Console.WriteLine("[Hive] FILE[25] ERET2 force-slow s0=0x" + + regs[16].ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " owner=0x" + _tv2Proc.ToString("X8") + + " (firmware 0x80015550; not an invented slot map)"); + return true; + } + + public static void TryNoteTv2ProcSwitchStore(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2FileDestOn || pc != ThreadSwitchProcStore || bus == null || regs == null) + return; + if (regs.Length <= 8) + return; + uint t0 = regs[8]; + if (t0 != _tv2Proc) + return; + uint cur = 0; + try + { + cur = bus.Read32(CurProc); + } + catch + { + return; + } + if (cur == _tv2Proc) + return; + if (_tv2SwitchStoreLogged) + return; + _tv2SwitchStoreLogged = true; + try + { + uint slot = 0; + if (_tv2Proc != 0) + slot = bus.Read32(_tv2Proc + ProcSlot); + System.Console.WriteLine("[Hive] FILE[25] switcher CurProc t0=0x" + + t0.ToString("X8") + + " before=0x" + cur.ToString("X8") + + " proc+0C=0x" + slot.ToString("X8") + + " (firmware 0x80015570; not an invented slot map)"); + } + catch + { + } + } + + public static void TryKeepTv2ThreadStartip(MipsBus bus, uint threadStartip) + { + if (!_tv2FileDestOn || bus == null) + return; + if (IsAllowedTv2Startip(threadStartip) && _tv2Startip == 0) + _tv2Startip = threadStartip; + uint proc = _tv2Proc; + if (proc == 0) + return; + TryFillFileExeStartip(bus, proc); + try + { + uint p50 = bus.Read32(proc + ProcModule); + uint p5c = bus.Read32(proc + ModuleStartip); + uint m5c = 0; + if (p50 != 0 && p50 != 0xDEADBEEFu && p50 != proc) + m5c = bus.Read32(p50 + ModuleStartip); + uint ctxPc = 0; + uint ctxSr = 0; + if (_tv2Thread != 0) + { + ctxPc = bus.Read32(_tv2Thread + ThreadCtxPc); + ctxSr = bus.Read32(_tv2Thread + ThreadCtxSr); + } + uint owner = 0; + uint slot = 0; + uint p0 = 0; + uint p8 = 0; + if (_tv2Thread != 0) + owner = bus.Read32(_tv2Thread + ThreadPrc); + if (proc >= 0x80000000u) + { + p0 = bus.Read32(proc); + p8 = bus.Read32(proc + 8); + slot = bus.Read32(proc + ProcSlot); + } + System.Console.WriteLine("[Hive] FILE[25] CreateProcess-ret proc=0x" + + proc.ToString("X8") + + " +0=0x" + p0.ToString("X8") + + " +8=0x" + p8.ToString("X8") + + " +0C=0x" + slot.ToString("X8") + + " +50=0x" + p50.ToString("X8") + + " +5C=0x" + p5c.ToString("X8") + + " module+5C=0x" + m5c.ToString("X8") + + " thread=0x" + _tv2Thread.ToString("X8") + + " thread+0C=0x" + owner.ToString("X8") + + " thread+5C=0x" + threadStartip.ToString("X8") + + " ctxPC=0x" + ctxPc.ToString("X8") + + " +F0=0x" + ctxSr.ToString("X8") + + " kept=0x" + _tv2Startip.ToString("X8") + + " (tv2 proc, not CurProc/filesys)"); + TryKeepTv2ThreadOwner(bus, "CreateProcess-ret"); + TryKeepTv2UserStatus(bus); + TryKeepTv2ThreadCtx(bus, "CreateProcess-ret"); + } + catch + { + } + } + + public static bool IsDecompressLeftoverPc(uint pc) + { + return pc >= BinaryDecompressInner && pc < 0x80053000u; + } + + public static bool IsExnDispatchLeftover(uint pc) + { + // wait82: 0x80015404 ctxPC=0x8001588C only. + // 0x80015B9C is the live ERET2 frame; rewriting + // it loops the switcher. Do not touch that. + return pc == ExnAfterFetch; + } + + // wait91-94: leftover 0x8001588C is still mid + // 0x8001586C. 0x800159B4 or $ra,$v0 then + // 0x80015A24 ERET mtc0 $t4,EPC ($t4=$ra=$v0). + // That is not thread+0xEC. 0x800153E8 already + // lw $ra,220($s0) before the 0x80015404 hook. + // I-fetch of leftover after startip/store + // continue returns to 0x03F6CAC0 (real insn). + // Do not skip that to 28($sp). Do not yank + // startip. Do not invent dest bytes. + public static void TryResumeTv2LeftoverFetch(MipsBus bus, uint[] regs, ref uint pc) + { + if (IsDdiNopDestLive()) + return; + if (!_tv2FetchLogged || !_tv2StoreContLogged) + return; + if (pc != ExnAfterFetch) + return; + // wait98: leftover already continued past CAE8 on + // tv2. A later I-fetch 0x8001588C is firmware + // leftover still mid 0x8001586C (filesys TEE). + // Re-applying 0x03F6CAC0 rewinds leftover and + // yanks the current thread. Do not rewind. + if (_tv2LeftoverLiveLogged) + { + if (_tv2LeftoverSkipLogged) + return; + _tv2LeftoverSkipLogged = true; + uint curThr = 0; + uint cur = 0; + try + { + if (bus != null) + curThr = bus.Read32(ThreadPtr); + if (bus != null) + cur = bus.Read32(CurProc); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover skip-resume pc=0x8001588C CurThread=0x" + + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " bound=0x" + _tv2Thread.ToString("X8") + + " (firmware leftover still mid 0x8001586C after leftover-CAE8; do not rewind 0x03F6CAC0; do not skip to 28($sp); not TV UI)"); + return; + } + uint resume = _tv2ImplResume != 0 + ? _tv2ImplResume + : 0x03F6CAC0u; + if (resume != 0x03F6CAC0u) + return; + uint destWord = 0; + TryPeekWord(bus, resume, out destWord); + uint liveRa = regs != null && regs.Length > 31 ? regs[31] : 0; + uint liveV0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint liveT9 = regs != null && regs.Length > 25 ? regs[25] : 0; + pc = resume; + if (_tv2Thread != 0 && bus != null) + { + try + { + bus.Write32(_tv2Thread + ThreadCtxPc, resume); + } + catch + { + } + } + _tv2LeftoverStoreFrame = true; + TryKeepTv2StoreFrame(bus, regs); + if (_tv2LeftoverLiveLogged) + return; + _tv2LeftoverLiveLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover live-pc was=0x8001588C now=0x" + + resume.ToString("X8") + + " dest-word=0x" + destWord.ToString("X8") + + " ra=0x" + liveRa.ToString("X8") + + " v0=0x" + liveV0.ToString("X8") + + " t9=0x" + liveT9.ToString("X8") + + " (firmware leftover still mid 0x8001586C; 0x80015A24 ERET uses $v0 not ctxPC; do not skip 0x03F6CAC0 to 28($sp); do not yank startip; not dest 0xE4DA9AA4; not a mapped page 0)"); + } + + // wait99: leftover still mid 0x8001586C after + // leftover-CAE8. jal 0x800397B0 returned -1. + // 0x800159B4 or $ra,$v0,$0 then mtc0 $t4,EPC + // set EPC/ra to 0xFFFFFFFF. That or can run + // before the skip-resume I-fetch log. After + // leftover-CAE8, set $v0/$t4 to leftover + // continue 0x03F6CAF0 after dest peek. + // Leftover ERET 0x80015A24 then returns to + // that insn. Do not rewrite 0x80015B9C. Do + // not rewind 0x03F6CAC0. Do not skip to + // 28($sp). Do not invent dest. + public static void TryRestoreTv2LeftoverEret(MipsBus bus, uint[] regs, uint pc) + { + if (IsDdiNopDestLive()) + return; + if (_tv2LeftoverEretLogged) + return; + if (!_tv2LeftoverCae8Logged) + return; + if (pc != LeftoverOrRa && pc != LeftoverMtc0Epc && pc != LeftoverJrRa) + return; + if (regs == null || regs.Length <= 31) + return; + uint was = pc == LeftoverOrRa ? regs[2] : (pc == LeftoverMtc0Epc ? regs[12] : regs[31]); + if (IsFirmwareUserOrCoredllVa(was) && was != 0) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryResolveLeftoverContinue(bus, out dest, out word, out live)) + return; + if (pc == LeftoverOrRa) + regs[2] = dest; + else + { + regs[12] = dest; + regs[31] = dest; + } + _tv2LeftoverEretLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover eret-restore was=0x" + + was.ToString("X8") + + " at=0x" + pc.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cae8") + + " (jal 0x800397B0 returned -1; leftover ERET dest; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static bool TryFixTv2LeftoverJump(MipsBus bus, uint[] regs, ref uint target) + { + if (IsDdiNopDestLive()) + { + if (target != 0xFFFFFFFFu) + return false; + uint thr; + uint ec; + uint dc; + uint plant; + TryPeekThreadCtxPc(bus, out thr, out ec, out dc, out plant); + if (!IsSanePlantResumePc(ec) || IsJalCalleeMid(bus, ec, dc)) + return false; + target = ec; + if (regs != null && regs.Length > 31) + { + regs[12] = ec; + regs[31] = ec; + regs[2] = ec; + } + if (!_plantFixLogged) + { + _plantFixLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop plant-fix was=0xFFFFFFFF +EC=0x" + + ec.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + " plant=0x" + plant.ToString("X8") + + " (replay thread+0xEC; do not leftover dest)"); + } + return true; + } + if (_tv2LeftoverEretLogged || !_tv2LeftoverCae8Logged) + return false; + if (target != 0xFFFFFFFFu) + return false; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryResolveLeftoverContinue(bus, out dest, out word, out live)) + return false; + target = dest; + if (regs != null && regs.Length > 31) + { + regs[12] = dest; + regs[31] = dest; + } + _tv2LeftoverEretLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover eret-restore was=0xFFFFFFFF at=jr dest=0x" + + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cae8") + + " (jal 0x800397B0 returned -1; leftover jr $ra; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + return true; + } + + private static bool TryResolveLeftoverContinue(MipsBus bus, out uint dest, out uint word, out bool live) + { + dest = LeftoverContinue; + word = 0; + live = TryPeekWord(bus, dest, out word); + if (!live) + { + if (!_tv2LeftoverCaf0Peeked) + return false; + word = _tv2LeftoverCaf0Word; + } + return (dest & 0x1FFFFFFFu) >= 0x00010000u; + } + + // wait100: leftover jr to CAF0 executed the nop + // delay and fell through, skipping beq at CAEC. + // I-fetch 0. Not leftover mid 0x8001586C. Not + // jr $ra ra=0 (ra was 0x03F6CB08). After CAF0, + // continue at CAFC if leftover-CAE8 $v0==0 else + // CAF4. Dest peek only. Do not map page 0. + public static void TryResumeTv2LeftoverAfterCaf0(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCaf0Logged) + return; + if (!_tv2LeftoverCae8Logged) + return; + if (pc != LeftoverContinue) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryResolveLeftoverAfterCaf0(bus, out dest, out word, out live)) + return; + pc = dest; + _tv2LeftoverAfterCaf0Logged = true; + uint v0 = _tv2LeftoverCae8V0Set ? _tv2LeftoverCae8V0 : 0xFFFFFFFFu; + System.Console.WriteLine("[Hive] FILE[25] leftover after-caf0 was=0x03F6CAF0 now=0x" + + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cae8") + + " cae8-v0=0x" + v0.ToString("X8") + + " (dest nop then fallthrough skipped beq $v0,$0,+12; do not map page 0; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait101: leftover CAFC then lw $a1,-20($s6) + // at CB0C vaddr=0xFFFFFFEC. $s6==0 (null-20). + // leftover-CAE8 already lw $v0,0($s6) from a + // real process-info VA. leftover firmware + // mid 0x8001586C clobbered $s6. Keep that + // leftover-CAE8 $s6 after dest peek of $s6 + // and $s6-20. Do not map page 0. Do not map + // 0xFFFFFFEC. Do not invent dest. If leftover + // -CAE8 $s6 is 0 this is an honest null deref. + public static void TryKeepTv2LeftoverS6(MipsBus bus, uint[] regs, uint pc) + { + if (pc != LeftoverCb0c) + return; + if (!_tv2LeftoverCae8Logged) + return; + if (regs == null || regs.Length <= 22) + return; + uint live = regs[22]; + if (live != 0) + return; + if (!_tv2LeftoverCae8S6Set || _tv2LeftoverCae8S6 == 0) + { + if (_tv2LeftoverS6Logged) + return; + _tv2LeftoverS6Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover s6-keep skip live=0x00000000 cae8-s6=0x" + + _tv2LeftoverCae8S6.ToString("X8") + + " (leftover-CAE8 $s6 unset/0; honest null-20; do not map page 0; do not map 0xFFFFFFEC; not TV UI)"); + return; + } + uint keep = _tv2LeftoverCae8S6; + if (!IsFirmwareUserOrCoredllVa(keep)) + return; + if ((keep & 0x1FFFFFFFu) < 0x00010000u) + return; + uint minus20 = keep - 20u; + if ((minus20 & 0x1FFFFFFFu) < 0x00010000u) + return; + uint wordS6 = 0; + uint wordM20 = 0; + if (!TryPeekWord(bus, keep, out wordS6)) + return; + if (!TryPeekWord(bus, minus20, out wordM20)) + return; + regs[22] = keep; + if (_tv2LeftoverS6Logged) + return; + _tv2LeftoverS6Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover s6-keep was=0x00000000 now=0x" + + keep.ToString("X8") + + " s6-word=0x" + wordS6.ToString("X8") + + " m20=0x" + minus20.ToString("X8") + + " m20-word=0x" + wordM20.ToString("X8") + + " (leftover-CAE8 $s6 after dest peek; lw $a1,-20($s6); do not map page 0; do not map 0xFFFFFFEC; not TV UI)"); + } + + // wait102: leftover past CB10 then tv2 ctxPC + // is ERET2 0x80015B9C. Not the next coredll + // insn. Not leftover mid 0x8001586C (skip- + // resume already ran after leftover-CAE8). + // Not OEMIdle (that is the later 600M DONE). + // After leftover-CB10, I-fetch of ERET2 or + // leftover 0x8001588C resumes at CB14 after + // dest peek. Do not rewrite 0x80015B9C. + // Do not rewind 0x03F6CAC0. Do not invent dest. + public static void TryResumeTv2LeftoverAfterCb10(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb10Logged) + return; + if (!_tv2LeftoverPastCb0cLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb14, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb10Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb10 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb10") + + " (ERET2/leftover mid after leftover CB10; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait103: leftover past CB14 then leftover + // mid 0x8001588C and ERET2 0x80015B9C. +DC + // later 0x03F6CB34 (beq taken). After leftover + // -CB14, I-fetch of ERET2 or leftover 0x8001588C + // resumes at CB34 after dest peek. Do not + // rewrite 0x80015B9C. Do not rewind 0x03F6CAC0 + // or CB14. Do not invent dest. + public static void TryResumeTv2LeftoverAfterCb14(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb14Logged) + return; + if (!_tv2LeftoverPastCb14Logged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb34, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb14Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb14 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb14") + + " (ERET2/leftover mid after leftover CB14; beq taken 0x03F6CB34; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait104: leftover past CB34 then ERET2 + // 0x80015B9C. after-cb14 already one-shot. + // Not leftover still mid 0x8001586C as the + // immediate next. Not OEMIdle (later 600M + // DONE). After leftover-CB34, I-fetch of + // ERET2 or leftover 0x8001588C resumes at + // CB38 after dest peek. Do not rewrite + // 0x80015B9C. Do not rewind 0x03F6CAC0, + // CB14, or CB34. Do not invent dest. + public static void TryResumeTv2LeftoverAfterCb34(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb34Logged) + return; + if (!_tv2LeftoverPastCb34Logged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb38, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb34Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb34 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb34") + + " (ERET2/leftover mid after leftover CB34; next dest-live 0x03F6CB38; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait105: leftover past CB38 then ERET2 + // 0x80015B9C. after-cb34 already one-shot. + // Not leftover still mid 0x8001586C as the + // immediate next. Not OEMIdle (later 600M + // DONE). After leftover-CB38, I-fetch of + // ERET2 or leftover 0x8001588C resumes at + // CB3C after dest peek. Do not invent dest + // at CB3C. Do not rewrite 0x80015B9C. Do + // not rewind 0x03F6CAC0, CB34, or CB38. + public static void TryResumeTv2LeftoverAfterCb38(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb38Logged) + return; + if (!_tv2LeftoverPastCb38Logged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb3c, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb38Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb38 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb38") + + " (ERET2/leftover mid after leftover CB38; next dest-live 0x03F6CB3C; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait106: leftover past CB3C then ERET2 + // 0x80015B9C. after-cb38 already one-shot. + // Not leftover still mid 0x8001586C as the + // immediate next. Not OEMIdle (later 600M + // DONE). After leftover-CB3C, I-fetch of + // ERET2 or leftover 0x8001588C resumes at + // CB40 after dest peek. Do not invent dest + // at CB40. Do not rewrite 0x80015B9C. Do + // not rewind 0x03F6CAC0, CB38, or CB3C. + public static void TryResumeTv2LeftoverAfterCb3c(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb3cLogged) + return; + if (!_tv2LeftoverPastCb3cLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb40, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb3cLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb3c was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb3c") + + " (ERET2/leftover mid after leftover CB3C; next dest-live 0x03F6CB40; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait107: leftover past CB40 then ERET2 + // 0x80015B9C. after-cb3c already one-shot. + // Not leftover still mid 0x8001586C as the + // immediate next. Not OEMIdle (later 600M + // DONE). After leftover-CB40, I-fetch of + // ERET2 or leftover 0x8001588C resumes at + // CB44 after dest peek. Do not invent dest + // at CB44. Do not rewrite 0x80015B9C. Do + // not rewind 0x03F6CAC0, CB3C, or CB40. + public static void TryResumeTv2LeftoverAfterCb40(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb40Logged) + return; + if (!_tv2LeftoverPastCb40Logged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb44, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb40Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb40 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb40") + + " (ERET2/leftover mid after leftover CB40; next dest-live 0x03F6CB44; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait108: leftover past CB44 then ERET2 + // 0x80015B9C. after-cb40 already one-shot. + // Not leftover still mid 0x8001586C as the + // immediate next. Not OEMIdle (later 600M + // DONE). After leftover-CB44, I-fetch of + // ERET2 or leftover 0x8001588C resumes at + // CB48 after dest peek. Do not invent dest + // at CB48. Do not rewrite 0x80015B9C. Do + // not rewind 0x03F6CAC0, CB40, or CB44. + // Do not skip leftover 0x03F6CAC0 to 28($sp). + public static void TryResumeTv2LeftoverAfterCb44(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb44Logged) + return; + if (!_tv2LeftoverPastCb44Logged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb48, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb44Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb44 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb44") + + " (ERET2/leftover mid after leftover CB44; next dest-live 0x03F6CB48; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait109: leftover past CB48 (jr $ra) then + // leftover left. after-cb44 already one-shot. + // I-fetch of ERET2 or leftover 0x8001588C + // resumes at dest-live delay slot CB4C after + // dest peek. Do not invent dest at CB4C. + // Do not rewrite 0x80015B9C. Do not rewind + // leftover. Do not skip leftover 0x03F6CAC0 + // to 28($sp). + public static void TryResumeTv2LeftoverAfterCb48(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb48Logged) + return; + if (!_tv2LeftoverPastCb48Logged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverCb4c, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb48Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb48 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-cb48") + + " (ERET2/leftover mid after leftover CB48; dest-live delay slot 0x03F6CB4C; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + // wait110: leftover past CB4C then leftover + // left. after-cb48 already one-shot. I-fetch + // of ERET2 or leftover 0x8001588C follows + // dest-live user $ra from peeked 28($sp) + // (CB44 lw $ra,28($sp)). Do not invent dest + // at 0x03F731E4. Do not follow leftover- + // dispatch $ra. Do not rewrite 0x80015B9C. + // Do not rewind leftover to 0x03F6C8F4. + public static void TryResumeTv2LeftoverAfterCb4c(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterCb4cLogged) + return; + if (!_tv2LeftoverPastCb4cLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + TryCaptureLeftoverUserRa(bus, regs); + if (!_tv2LeftoverUserRaSet) + return; + uint ra = _tv2LeftoverUserRa; + if (ra == 0 || ra == 0xFFFFFFFFu || ra == 0xFFFFFFECu) + return; + if ((ra & 0x1FFFFFFFu) < 0x00010000u) + return; + if (ra >= 0x03F6C8F4u && ra <= LeftoverCb4c) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, ra, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterCb4cLogged = true; + _tv2LeftoverJrRaDest = dest; + System.Console.WriteLine("[Hive] FILE[25] leftover after-cb4c was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + (live ? " dest-live" : " dest-ra") + + " (ERET2/leftover mid after leftover CB4C; follow dest-live user $ra from 28($sp); do not invent 0x03F731E4; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait111: leftover past leftover-jr-ra dest + // 0x03F731E4 then leftover left. after-cb4c + // already one-shot. I-fetch of ERET2 or + // leftover 0x8001588C follows dest-live + // next insn after beq $v0,$0,+10. Peek + // fallthrough 0x03F731E8 and taken + // 0x03F73210 first. Follow leftover $v0 + // captured at leftover-past 0x03F731E4. + // Do not invent dest. Do not rewrite + // 0x80015B9C. Do not rewind leftover. + // Do not invent dest at 0x03F731E4. + public static void TryResumeTv2LeftoverAfterJrRa(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterJrRaLogged) + return; + if (!_tv2LeftoverPastJrRaLogged) + return; + if (_tv2LeftoverPastBeqRaFtLogged || _tv2LeftoverPastBeqRaTkLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + if (!_tv2LeftoverBeqRaV0Set) + return; + uint v0 = _tv2LeftoverBeqRaV0; + if (v0 >= 0x80010000u && v0 < 0x80020000u) + return; + uint dest = 0; + uint word = 0; + bool live = false; + uint prefer = v0 == 0 ? LeftoverBeqRaTk : LeftoverBeqRaFt; + if (!TryAcceptLeftoverAfterDest(bus, prefer, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterJrRaLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-jr-ra was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-jr-ra") + + " beq-ra-v0=0x" + v0.ToString("X8") + + " (ERET2/leftover mid after leftover jr $ra dest; follow dest-live $v0 after beq $v0,$0,+10; peek 0x03F731E8/0x03F73210; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait112: leftover past 0x03F73210 (b +2) + // then leftover left. after-jr-ra already + // one-shot. I-fetch of ERET2 or leftover + // 0x8001588C follows dest-live next insn + // after that branch. Peek delay 0x03F73214 + // and taken 0x03F7321C first. b +2 is + // unconditional. Do not invent dest. Do + // not rewrite 0x80015B9C. Do not rewind + // leftover. Do not invent dest at + // 0x03F731E4. + public static void TryResumeTv2LeftoverAfterBPlus2(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterBPlus2Logged) + return; + if (!_tv2LeftoverPastBeqRaTkLogged) + return; + if (_tv2LeftoverPastBPlus2DelayLogged || _tv2LeftoverPastBPlus2TakenLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverBPlus2Delay, out dest, out word, out live) + && !TryAcceptLeftoverAfterDest(bus, LeftoverBPlus2Taken, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterBPlus2Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-b+2 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-b+2") + + " (ERET2/leftover mid after leftover b +2; dest-live next insn after 0x03F73210; peek 0x03F73214/0x03F7321C; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait113: leftover past 0x03F7321C then + // leftover left. after-b+2 already one-shot. + // I-fetch of ERET2 or leftover 0x8001588C + // follows dest-live next insn 0x03F73220 + // after dest peek. Do not invent dest. Do + // not rewrite 0x80015B9C. Do not rewind + // leftover. Do not invent dest at + // 0x03F731E4. + public static void TryResumeTv2LeftoverAfterBPlus2Taken(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterBPlus2TakenLogged) + return; + if (!_tv2LeftoverPastBPlus2TakenLogged) + return; + if (_tv2LeftoverPastBPlus2NextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverBPlus2Next, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterBPlus2TakenLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-taken was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-taken") + + " (ERET2/leftover mid after leftover 0x03F7321C; dest-live next 0x03F73220; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait114: leftover past 0x03F73220 then + // leftover left. after-taken already + // one-shot. I-fetch of ERET2 or leftover + // 0x8001588C follows dest-live next insn + // 0x03F73224 after dest peek. Do not + // invent dest. Do not rewrite 0x80015B9C. + // Do not rewind leftover. Do not invent + // dest at 0x03F731E4. + public static void TryResumeTv2LeftoverAfterFp(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterFpLogged) + return; + if (!_tv2LeftoverPastBPlus2NextLogged) + return; + if (_tv2LeftoverPastFpNextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverFpNext, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterFpLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-fp was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-fp") + + " (ERET2/leftover mid after leftover 0x03F73220; dest-live next 0x03F73224; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait115: leftover past 0x03F73224 then + // leftover left. after-fp already one-shot. + // I-fetch of ERET2 or leftover 0x8001588C + // follows dest-live next insn 0x03F73228 + // after dest peek. Do not invent dest. Do + // not rewrite 0x80015B9C. Do not rewind + // leftover. Do not invent dest at + // 0x03F731E4. + public static void TryResumeTv2LeftoverAfterS7(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterS7Logged) + return; + if (!_tv2LeftoverPastFpNextLogged) + return; + if (_tv2LeftoverPastS7NextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverS7Next, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterS7Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-s7 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-s7") + + " (ERET2/leftover mid after leftover 0x03F73224; dest-live next 0x03F73228; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait117: leftover past 0x03F73228 then + // leftover left. after-s7 already one-shot. + // I-fetch of ERET2 or leftover 0x8001588C + // follows dest-live next insn 0x03F7322C + // after dest peek. Do not invent dest. Do + // not rewrite 0x80015B9C. Do not rewind + // leftover. + public static void TryResumeTv2LeftoverAfterS6(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterS6Logged) + return; + if (!_tv2LeftoverPastS7NextLogged) + return; + if (_tv2LeftoverPastS6NextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverS6Next, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterS6Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-s6 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-s6") + + " (ERET2/leftover mid after leftover 0x03F73228; dest-live next 0x03F7322C; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait118: leftover past 0x03F7322C then + // leftover left. after-s6 already one-shot. + // I-fetch of ERET2 or leftover 0x8001588C + // follows dest-live next insn 0x03F73230 + // after dest peek. Do not invent dest. Do + // not rewrite 0x80015B9C. Do not rewind + // leftover. + public static void TryResumeTv2LeftoverAfterS5(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterS5Logged) + return; + if (!_tv2LeftoverPastS6NextLogged) + return; + if (_tv2LeftoverPastS5NextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverS5Next, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterS5Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-s5 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-s5") + + " (ERET2/leftover mid after leftover 0x03F7322C; dest-live next 0x03F73230; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait119: leftover past 0x03F73230 then + // leftover left. after-s5 already one-shot. + // I-fetch of ERET2 or leftover 0x8001588C + // follows dest-live next insn 0x03F73234 + // after dest peek. Do not invent dest. Do + // not rewrite 0x80015B9C. Do not rewind + // leftover. + public static void TryResumeTv2LeftoverAfterS4(MipsBus bus, uint[] regs, ref uint pc) + { + if (_tv2LeftoverAfterS4Logged) + return; + if (!_tv2LeftoverPastS5NextLogged) + return; + if (_tv2LeftoverPastS4NextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint dest = 0; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, LeftoverS4Next, out dest, out word, out live)) + return; + uint was = pc; + pc = dest; + _tv2LeftoverAfterS4Logged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover after-s4 was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-s4") + + " (ERET2/leftover mid after leftover 0x03F73230; dest-live next 0x03F73234; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + // wait120: leftover dest-live continue. leftover + // already past 0x03F73234. leftover-after-s4 + // stays off. leftover mid / ERET2 I-fetch + // resumes dest-live next after dest peek. + // leftover dest-live next starts at peeked + // 0x03F73238 (jr $ra / delay). Write leftover + // ctxPC to dest-live next so leftover does not + // leave after every lw. Do not rewrite + // 0x80015B9C. Do not invent dest. + // wait121: dest-live continue stays live after + // leftover-past dest-live delay. after-* only + // rewrites one I-fetch. leftover-left / + // leftover ctxPC / EPC yank leftover to ERET2 + // unless dest-live next keeps PC+4 after dest + // peek. leftover DISPATCH after leftover dest-live + // I-fetch must not yank leftover ctxPC to ERET2. + // leftover restore re-apply is too early (restore + // I-fetch, not dispatch). dest-live I-fetch stays + // dest-live next, not ERET2. Do not follow + // dest-live $ra before dest-live delay (already + // walked; rewind). wait124: dest-live $ra is + // still already walked after dest-live delay. + // After dest-live delay, dest-live next is + // leftover dest-live delay's live leftover next + // (leftover $ra at dest-live jr $ra if live + // leftover dest), not dest-live $ra, not PC+4. + // prior peek named 0x03F731E4 as evidence only; + // do not invent dest. Do not follow dest-live $ra + // blindly. Do not add a one-shot hop at + // 0x03F73238. + public static void TryResumeTv2LeftoverDestLiveContinue(MipsBus bus, uint[] regs, ref uint pc) + { + if (IsDdiNopDestLive()) + return; + if (!_tv2LeftoverPastS4NextLogged) + return; + // wait127: leftover dest-live I-fetch of dest-live + // next / PC+4 after dest-live delay+4 walk takes + // leftover interrupt. leftover exception handler + // I-fetches leftover mid / ERET2. leftover dest-live + // continue hops leftover exception / leftover mid / + // ERET2 to dest-live next / PC+4 after dest-live + // delay+4 walk. leftover after dest-live delay+4 + // walk stays dest-live next / PC+4, not leftover + // mid / ERET2. + // wait128: leftover dest-live keep hops leftover + // I-fetch / leftover FetchInstruction leftover mid / + // ERET2 0x80015B9C after dest-live delay+4 to + // dest-live next / leftover dest-live next / + // leftover ctxPC / leftover PC+4 before leftover + // FetchInstruction. leftover dest-live continue + // after leftover interrupt is too late. leftover + // after dest-live delay+4, including leftover + // interrupt, stays dest-live next / PC+4, not + // leftover mid / ERET2. + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch + && !(_tv2LeftoverPastEpilogueDelayLogged && pc == 0x80000180u)) + return; + uint dest = _tv2LeftoverDestLiveNext; + if (dest == 0) + dest = LeftoverEpilogueNext; + if (_tv2LeftoverPastEpilogueLogged && dest == LeftoverEpilogueNext) + dest = LeftoverEpilogueNext + 4; + if (_tv2LeftoverPastEpilogueDelayLogged) + { + // dest-live $ra is already walked (leftover + // past dest-live $ra). dest-live next after + // dest-live delay is leftover dest-live + // delay's live leftover next, not dest-live + // $ra, not PC+4. wait126: after leftover + // dest-live continue hops leftover mid to + // dest-live delay+4 / dest-live next / + // PC+4, leftover dest-live next stays + // dest-live next / PC+4. leftover dest-live + // continue hops leftover mid / ERET2 to + // dest-live next / PC+4, not dest-live + // delay+4. + if (dest == LeftoverEpilogueNext + 8 + || dest == LeftoverEpilogueNext + 12 + || dest > LeftoverEpilogueNext + 8) + { + // dest-live delay+4 already walked. + } + else if (_tv2LeftoverPastJrRaLogged + && dest == _tv2LeftoverUserRa) + dest = LeftoverEpilogueNext + 8; + else if (dest == LeftoverEpilogueNext + 4 || dest == 0) + dest = LeftoverEpilogueNext + 8; + } + if (dest == LeftoverS4Next) + return; + if (dest == 0x03F731E4u) + return; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, dest, out dest, out word, out live)) + return; + if (dest == pc) + return; + uint was = pc; + pc = dest; + _tv2LeftoverDestLiveNext = dest + 4; + TryKeepLeftoverDestLiveCtx(bus, dest); + System.Console.WriteLine("[Hive] FILE[25] leftover dest-live continue was=0x" + + was.ToString("X8") + + " now=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-epilogue") + + " (leftover mid/ERET2 after leftover 0x03F73234; dest-live next peeked; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + private static void TryKeepLeftoverDestLiveCtx(MipsBus bus, uint dest) + { + if (bus == null || _tv2Thread == 0 || dest == 0) + return; + if ((dest & 0x1FFFFFFFu) < 0x00010000u) + return; + if (dest == LeftoverS4Next) + return; + if (dest == 0x03F731E4u) + return; + if (dest == ExnAfterFetch || dest == ExnAfterFetch2) + return; + if (!IsTv2CoredllShared(dest)) + return; + try + { + uint ctx = bus.Read32(_tv2Thread + ThreadCtxPc); + if (ctx == dest) + return; + bool yanked = ctx == ExnAfterFetch || ctx == ExnAfterFetch2; + bool destLive = IsTv2CoredllShared(ctx); + if (!yanked && !destLive) + return; + bus.Write32(_tv2Thread + ThreadCtxPc, dest); + } + catch + { + } + } + + private static bool TryResolveLeftoverDestLiveNext(out uint dest) + { + dest = _tv2LeftoverDestLiveNext; + if (dest == 0) + dest = LeftoverEpilogueNext; + if (_tv2LeftoverPastEpilogueLogged && dest == LeftoverEpilogueNext) + dest = LeftoverEpilogueNext + 4; + if (_tv2LeftoverPastEpilogueDelayLogged) + { + // wait126: after leftover dest-live continue + // hops leftover mid to dest-live delay+4 / + // dest-live next / PC+4, leftover dest-live + // next stays dest-live next / PC+4. leftover + // DISPATCH dest is dest-live next / PC+4, + // not dest-live delay+4. + if (dest == LeftoverEpilogueNext + 8 + || dest == LeftoverEpilogueNext + 12 + || dest > LeftoverEpilogueNext + 8) + { + // dest-live delay+4 already walked. + } + else if (_tv2LeftoverPastJrRaLogged + && dest == _tv2LeftoverUserRa) + dest = LeftoverEpilogueNext + 8; + else if (dest == LeftoverEpilogueNext + 4 || dest == 0) + dest = LeftoverEpilogueNext + 8; + } + if (dest == LeftoverS4Next) + return false; + if (dest == 0x03F731E4u) + return false; + return dest != 0 && (dest & 0x1FFFFFFFu) >= 0x00010000u; + } + + // leftover DISPATCH after leftover dest-live I-fetch + // must not yank leftover ctxPC to ERET2. dest-live + // I-fetch stays dest-live next / PC+4, not ERET2. + // leftover restore re-apply is too early (restore + // I-fetch, not dispatch). wait126: leftover dest-live + // continue hops leftover mid to dest-live delay+4 / + // PC+4. leftover DISPATCH after leftover dest-live + // I-fetch of dest-live delay+4 / PC+4 yanks leftover + // ctxPC. leftover later I-fetches ERET2. leftover + // DISPATCH after leftover dest-live I-fetch of + // dest-live delay+4 / PC+4 writes leftover ctxPC + // to dest-live next / PC+4, not ERET2. leftover + // dest-live continue after leftover dest-live + // I-fetch hops leftover mid / ERET2 to dest-live + // next / PC+4. leftover dest-live next after + // dest-live delay+4 walk stays dest-live next / + // PC+4, not ERET2. Do not follow dest-live $ra. + // Do not rewrite 0x80015B9C. Do not add a one-shot + // hop at 0x03F73238. + public static void TryKeepLeftoverDestLiveDispatch(MipsBus bus, uint pc) + { + if (IsDdiNopDestLive()) + return; + if (!_tv2LeftoverPastS4NextLogged) + return; + uint dest; + if (!TryResolveLeftoverDestLiveNext(out dest)) + return; + if (pc != ExnAfterFetch && pc != ExnAfterFetch2 + && IsTv2CoredllShared(pc) + && pc != LeftoverS4Next + && pc != 0x03F731E4u) + { + // wait126: leftover dest-live continue hops + // leftover mid to dest-live delay+4 / + // dest-live next / PC+4. leftover DISPATCH + // after leftover dest-live I-fetch of + // dest-live delay+4 / dest-live next / + // PC+4 must not yank leftover dest-live + // next / leftover ctxPC back to dest-live + // delay+4 / leftover dest-live delay's + // live leftover next. leftover dest-live + // next stays dest-live next / PC+4. + if (_tv2LeftoverPastEpilogueDelayLogged + && dest != 0 && dest != pc && dest != pc + 4 + && dest < pc + && dest != LeftoverS4Next + && dest != 0x03F731E4u) + dest = pc; + if (dest == pc) + dest = pc + 4; + if (dest != LeftoverS4Next + && dest != 0x03F731E4u + && dest != ExnAfterFetch && dest != ExnAfterFetch2 + && (dest & 0x1FFFFFFFu) >= 0x00010000u) + _tv2LeftoverDestLiveNext = dest; + } + if (dest == LeftoverS4Next) + return; + if (dest == 0x03F731E4u) + return; + if (dest == ExnAfterFetch || dest == ExnAfterFetch2) + return; + TryKeepLeftoverDestLiveCtx(bus, dest); + if (_tv2LeftoverDispatchLogged) + return; + _tv2LeftoverDispatchLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover dest-live dispatch keep dest=0x" + + dest.ToString("X8") + + " after=0x" + pc.ToString("X8") + + " (leftover DISPATCH after leftover dest-live I-fetch; dest-live I-fetch stays dest-live next / PC+4, not ERET2; leftover restore re-apply is too early; do not invent dest; do not rewrite 0x80015B9C; do not rewind leftover $ra 0x03F731E4; not TV UI)"); + } + + // leftover-drop: leftover dest-live resume hijacks + // leftover mid / ERET2 I-fetch. leftover ctxPC stays + // leftover mid / ERET2. leftover ERET 0x80015A24 + // uses $v0 not leftover ctxPC. leftover $v0 restore + // is one-shot leftover-CAE8 dest. After leftover + // dest-live lw leftover $v0 stays leftover mid. + // leftover ERET returns leftover mid / ERET2. + // leftover dest-live continue leftover ERET $v0 + // restore dest-live next. Stay-off after leftover + // dest-live delay. Do not rewind leftover $ra + // 0x03F731E4. Do not rewrite 0x80015B9C. + public static void TryNoteTv2LeftoverDrop(MipsBus bus, uint[] regs, uint pc) + { + if (_tv2LeftoverDropLogged) + return; + if (!_tv2LeftoverPastS4NextLogged) + return; + if (pc != ExnAfterFetch2 && pc != ExnAfterFetch) + return; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint t4 = regs != null && regs.Length > 12 ? regs[12] : 0; + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + uint ctx = 0; + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null && _tv2Thread != 0) + ctx = bus.Read32(_tv2Thread + ThreadCtxPc); + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + _tv2LeftoverDropLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover-drop pc=0x" + + pc.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " t4=0x" + t4.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " ctxPC=0x" + ctx.ToString("X8") + + " dest-live-next=0x" + _tv2LeftoverDestLiveNext.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " (leftover mid/ERET2 after leftover dest-live; leftover ERET 0x80015A24 uses $v0 not leftover ctxPC; leftover $v0 restore is one-shot leftover-CAE8 dest; leftover dest-live continue leftover ERET $v0 restore dest-live next; do not invent dest; do not rewrite 0x80015B9C; do not rewind leftover $ra 0x03F731E4; not TV UI)"); + } + + // leftover dest-live continue leftover ERET $v0 + // restore dest-live next. leftover ERET 0x80015A24 + // mtc0 $t4,EPC ($t4=$ra=$v0). leftover dest-live + // resume hijacks leftover mid / ERET2 I-fetch. + // leftover dest-live continue leftover ERET $v0 + // restore dest-live next so leftover ERET returns + // dest-live next. wait124: dest-live $ra is already + // walked after dest-live delay. After dest-live + // delay, dest-live next is leftover dest-live + // delay's live leftover next, not dest-live $ra, + // not PC+4. leftover dest-live ERET $v0 restore + // after dest-live delay writes leftover $v0 to + // leftover dest-live delay's live leftover next. + // leftover mid / ERET2 after dest-live delay is + // leftover ERET $v0 restore, not leftover ERET + // path. prior peek named 0x03F731E4 as evidence + // only; do not invent dest. Do not follow dest-live + // $ra blindly. Do not hop 0x03F73238. Do not + // rewrite 0x80015B9C. + public static void TryRestoreTv2LeftoverDestLiveEret(MipsBus bus, uint[] regs, uint pc) + { + if (IsDdiNopDestLive()) + return; + if (!_tv2LeftoverPastS4NextLogged) + return; + bool leftoverEret = pc == LeftoverOrRa || pc == LeftoverMtc0Epc + || pc == LeftoverJrRa || pc == LeftoverEret; + bool leftoverMidAfterDelay = _tv2LeftoverPastEpilogueDelayLogged + && (pc == ExnAfterFetch2 || pc == ExnAfterFetch + || pc == LeftoverEpilogueNext + 4); + if (!leftoverEret && !leftoverMidAfterDelay) + return; + if (regs == null || regs.Length <= 31) + return; + uint dest; + if (!TryResolveLeftoverDestLiveNext(out dest)) + return; + uint word = 0; + bool live = false; + if (!TryAcceptLeftoverAfterDest(bus, dest, out dest, out word, out live)) + return; + if (dest == LeftoverS4Next) + return; + if (dest == 0x03F731E4u) + return; + uint was = leftoverMidAfterDelay + ? regs[2] + : (pc == LeftoverOrRa ? regs[2] : (pc == LeftoverMtc0Epc ? regs[12] : regs[31])); + if (was == dest) + return; + if (leftoverMidAfterDelay) + { + regs[2] = dest; + regs[12] = dest; + regs[31] = dest; + } + else if (pc == LeftoverOrRa) + regs[2] = dest; + else + { + regs[12] = dest; + regs[31] = dest; + if (pc == LeftoverEret) + regs[2] = dest; + } + TryKeepLeftoverDestLiveCtx(bus, dest); + if (_tv2LeftoverDestLiveEretLogged) + return; + _tv2LeftoverDestLiveEretLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover dest-live eret-restore was=0x" + + was.ToString("X8") + + " at=0x" + pc.ToString("X8") + + " dest=0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + (live ? " dest-live" : " dest-epilogue") + + " (leftover ERET 0x80015A24 uses $v0 not leftover ctxPC; leftover dest-live continue leftover ERET $v0 restore dest-live next; do not invent dest; do not rewrite 0x80015B9C; do not rewind leftover $ra 0x03F731E4; not TV UI)"); + } + + private static bool TryResolveLeftoverAfterCaf0(MipsBus bus, out uint dest, out uint word, out bool live) + { + dest = 0; + word = 0; + live = false; + uint prefer = LeftoverAfterCaf0; + uint other = LeftoverBeqTaken; + if (_tv2LeftoverCae8V0Set && _tv2LeftoverCae8V0 == 0) + { + prefer = LeftoverBeqTaken; + other = LeftoverAfterCaf0; + } + if (TryAcceptLeftoverAfterDest(bus, prefer, out dest, out word, out live)) + return true; + return TryAcceptLeftoverAfterDest(bus, other, out dest, out word, out live); + } + + private static bool TryAcceptLeftoverAfterDest(MipsBus bus, uint va, out uint dest, out uint word, out bool live) + { + dest = va; + word = 0; + live = TryPeekWord(bus, va, out word); + if (!live) + { + if (va == LeftoverAfterCaf0 && _tv2LeftoverCaf4Peeked) + word = _tv2LeftoverCaf4Word; + else if (va == LeftoverBeqTaken && _tv2LeftoverCafcPeeked) + word = _tv2LeftoverCafcWord; + else if (va == LeftoverCb14 && _tv2LeftoverCb14Peeked) + word = _tv2LeftoverCb14Word; + else if (va == LeftoverCb34 && _tv2LeftoverCb34Peeked) + word = _tv2LeftoverCb34Word; + else if (va == LeftoverCb38 && _tv2LeftoverCb38Peeked) + word = _tv2LeftoverCb38Word; + else if (va == LeftoverCb3c && _tv2LeftoverCb3cPeeked) + word = _tv2LeftoverCb3cWord; + else if (va == LeftoverCb40 && _tv2LeftoverCb40Peeked) + word = _tv2LeftoverCb40Word; + else if (va == LeftoverCb44 && _tv2LeftoverCb44Peeked) + word = _tv2LeftoverCb44Word; + else if (va == LeftoverCb48 && _tv2LeftoverCb48Peeked) + word = _tv2LeftoverCb48Word; + else if (va == LeftoverCb4c && _tv2LeftoverCb4cPeeked) + word = _tv2LeftoverCb4cWord; + else if (va == LeftoverBeqRaFt && _tv2LeftoverBeqRaFtPeeked) + word = _tv2LeftoverBeqRaFtWord; + else if (va == LeftoverBeqRaTk && _tv2LeftoverBeqRaTkPeeked) + word = _tv2LeftoverBeqRaTkWord; + else if (va == LeftoverBPlus2Delay && _tv2LeftoverBPlus2DelayPeeked) + word = _tv2LeftoverBPlus2DelayWord; + else if (va == LeftoverBPlus2Taken && _tv2LeftoverBPlus2TakenPeeked) + word = _tv2LeftoverBPlus2TakenWord; + else if (va == LeftoverBPlus2Next && _tv2LeftoverBPlus2NextPeeked) + word = _tv2LeftoverBPlus2NextWord; + else if (va == LeftoverFpNext && _tv2LeftoverFpNextPeeked) + word = _tv2LeftoverFpNextWord; + else if (va == LeftoverS7Next && _tv2LeftoverS7NextPeeked) + word = _tv2LeftoverS7NextWord; + else if (va == LeftoverS6Next && _tv2LeftoverS6NextPeeked) + word = _tv2LeftoverS6NextWord; + else if (va == LeftoverS5Next && _tv2LeftoverS5NextPeeked) + word = _tv2LeftoverS5NextWord; + else if (va == LeftoverS4Next && _tv2LeftoverS4NextPeeked) + word = _tv2LeftoverS4NextWord; + else if (va == LeftoverEpilogueNext && _tv2LeftoverEpiloguePeeked) + word = _tv2LeftoverEpilogueWord; + else + return false; + } + if ((va & 0x1FFFFFFFu) < 0x00010000u) + return false; + if (word == 0 || IsFirmwareJumpToZero(word)) + return false; + return true; + } + + private static bool IsFirmwareJumpToZero(uint word) + { + uint op = word >> 26; + uint rs = (word >> 21) & 31; + uint funct = word & 63; + if (op == 0 && rs == 0 && (funct == 8 || funct == 9)) + return true; + if (op == 2 && (word & 0x3FFFFFFu) == 0) + return true; + return false; + } + + public static void TryKeepTv2ThreadCtx(MipsBus bus, string tag) + { + if (!_tv2FileDestOn || bus == null || _tv2Thread == 0) + return; + if (!IsTv2PrimaryStartipReady(bus)) + return; + uint startip = _tv2Startip; + if (startip == 0) + { + try + { + startip = bus.Read32(_tv2Thread + ThreadStartip); + } + catch + { + return; + } + } + if (!IsAllowedTv2Startip(startip)) + return; + _tv2Startip = startip; + uint ctxPc; + try + { + ctxPc = bus.Read32(_tv2Thread + ThreadCtxPc); + } + catch + { + return; + } + if (ctxPc == startip) + return; + // wait82: after 0x03F6C8F8, 0x80015404 ERET + // ctxPC=0x8001588C (mid 0x8001586C). +0xDC + // is still 0 from 0x80020C30, so 0x80015A28 + // jr $ra fetches 0. 0x80020D80 a1=8 is Cause + // code 2; ctxPC=0 is that EPC. Not a missing + // page. wait83: dest 0x800908B0 / VA + // 0x03F6C8B0 is addiu $s7, $0, 0x5800 then + // jalr; 0x03F6C8F4 is lw $a2, 0($s7). + // Rewriting leftover to that RA after + // continue rewinds the lw with s7=0. + // wait84: keeping leftover ERET to + // 0x8001588C. 0x800159B4 or $ra, $v0 + // after 0x800397B0, then 0x80015A28 + // jr $ra. +DC was 0x03F70830 (live); + // that or left ra=0. I-fetch 0. Do not + // keep leftover. wait85: resume user + // RA 0x03F6C8F4. wait86: first pass + // already continued 0x03F6CAC0 with + // slot-6 $sp; leftover rewrite to + // 0x03F6C8F4 rewound and live $sp + // became 0xE4DA9A88. Firmware would + // not ERET that leftover after user + // continued. Resume last continued + // user PC. wait87 held 0x03F6CAC0. + // wait88: leftover hook ra=0x800159A0 + // (mid 0x8001586C). 28($sp) was + // 0x03F731E4. +D4 $sp 0x0C03F518 is + // not that frame, so jr $ra ra=0. + // Not a real CE jump. Do not map page 0. + if (_tv2LeftoverPastS4NextLogged && _tv2LeftoverDestLiveNext != 0 + && (ctxPc == ExnAfterFetch || ctxPc == ExnAfterFetch2 + || IsExnDispatchLeftover(ctxPc) + || IsTv2CoredllShared(ctxPc))) + { + // leftover DISPATCH after leftover dest-live + // I-fetch must not yank leftover ctxPC to + // ERET2. dest-live I-fetch stays dest-live + // next / PC+4. leftover restore re-apply is + // too early (restore I-fetch, not dispatch). + TryKeepLeftoverDestLiveDispatch(bus, ctxPc); + if (ctxPc == ExnAfterFetch || ctxPc == ExnAfterFetch2 + || IsExnDispatchLeftover(ctxPc)) + return; + } + if (IsExnDispatchLeftover(ctxPc) && _tv2FetchLogged) + { + // wait98: leftover already continued past CAE8. + // Rewriting ctxPC back to 0x03F6CAC0 rewinds. + if (_tv2LeftoverCae8Logged) + return; + uint resume = _tv2ImplResume != 0 + ? _tv2ImplResume + : (_tv2ImplRa != 0 ? _tv2ImplRa : startip); + if (resume == 0 || resume == ctxPc) + return; + try + { + uint dc = bus.Read32(_tv2Thread + ThreadCtxRa); + bus.Write32(_tv2Thread + ThreadCtxPc, resume); + TryKeepTv2UserStatus(bus); + TryKeepTv2UserS7(bus, null); + TryKeepTv2UserSp(bus, null); + TryKeepTv2UserRa(bus, null); + if (_tv2StoreContLogged && resume == 0x03F6CAC0u) + { + _tv2LeftoverStoreFrame = true; + TryKeepTv2StoreFrame(bus, null); + } + if (!_tv2DispatchCtxLogged) + { + _tv2DispatchCtxLogged = true; + System.Console.WriteLine("[Hive] FILE[25] thread ctxPC: " + tag + + " thr=0x" + _tv2Thread.ToString("X8") + + " was=0x" + ctxPc.ToString("X8") + + " now=0x" + resume.ToString("X8") + + " +DC=0x" + dc.ToString("X8") + + (_tv2StoreContLogged + ? " (firmware leftover 0x8001588C; after 0x03F6CAC0; +DC unsaved; do not rewind 0x03F6C8F4; not dest 0xE4DA9AA4; not a mapped page 0)" + : (_tv2ImplContLogged + ? " (firmware leftover 0x8001588C; after implicit-api continue; do not keep jr $ra; s7=0x5800; not a mapped page 0)" + : " (firmware leftover 0x8001588C; live user RA; not a mapped page 0)"))); + } + } + catch + { + } + return; + } + if (!IsDecompressLeftoverPc(ctxPc) && ctxPc != 0) + return; + try + { + bus.Write32(_tv2Thread + ThreadCtxPc, startip); + TryKeepTv2UserStatus(bus); + System.Console.WriteLine("[Hive] FILE[25] thread ctxPC: " + tag + + " thr=0x" + _tv2Thread.ToString("X8") + + " was=0x" + ctxPc.ToString("X8") + + " now=0x" + startip.ToString("X8") + + " (firmware +5C; CEDecompressROM leftover; not invented 0x00017F54)"); + } + catch + { + } + } + + // 0x80015370 mtc0 thread+0xF0. 3 is kernel + // (bit 4 clear). 0x13 is firmware user so + // 0x8001589C takes the frame/ERET path. + // Do not map page 0. Do not poke CurProc. + public static void TryKeepTv2UserStatus(MipsBus bus) + { + if (!_tv2FileDestOn || bus == null || _tv2Thread == 0) + return; + if (!IsTv2PrimaryStartipReady(bus)) + return; + uint sr; + try + { + sr = bus.Read32(_tv2Thread + ThreadCtxSr); + } + catch + { + return; + } + if (sr != 0 && sr != ThreadCtxSrKernel) + return; + try + { + bus.Write32(_tv2Thread + ThreadCtxSr, ThreadCtxSrUser); + if (_tv2UserSrLogged) + return; + _tv2UserSrLogged = true; + System.Console.WriteLine("[Hive] FILE[25] thread +F0: user 0x" + + ThreadCtxSrUser.ToString("X8") + + " was=0x" + sr.ToString("X8") + + " thr=0x" + _tv2Thread.ToString("X8") + + " (firmware 0x8003980C; bit 4; not kernel 3; not a mapped page 0)"); + } + catch + { + } + } + + // wait83 leftover rewrite to 0x03F6C8F4 had s7=0 + // because 0x8001586C skipped 0x800154DC and + // 0x800155C4 loaded +0xBC. 0x80015404 does not + // restore s7. Firmware 0x03F6C8B0 is addiu $s7, + // $0, 0x5800. wait85 leftover then s7=0xE4DA9AB8 + // (slot 114). Same unsaved +0xBC, not MMIO. + // Do not map page 0. Do not poke CurProc. + public static void TryKeepTv2UserS7(MipsBus bus, uint[] regs) + { + if (!_tv2FileDestOn || !_tv2FetchLogged || !_tv2ImplContLogged) + return; + if (bus == null || _tv2Thread == 0) + return; + if (regs != null && regs.Length > 23 && !IsFirmwareUserKdataOrSlot(regs[23])) + regs[23] = UserKData; + try + { + uint saved = bus.Read32(_tv2Thread + ThreadCtxS7); + if (!IsFirmwareUserKdataOrSlot(saved)) + bus.Write32(_tv2Thread + ThreadCtxS7, UserKData); + } + catch + { + } + } + + // wait85: leftover ERET lw $sp, 212(s0). +0xD4 + // was never saved on implicit-API. Store + // 0x03F6CABC vaddr=0xE4DA9AA4 is that $sp, not + // BCM MMIO. Restore live/$+D4 from firmware + // thread+0x24 when that is a process-slot VA. + // Do not map page 0. Do not invent dest at + // 0xE4DA9AA4. Do not poke CurProc. + public static void TryKeepTv2UserSp(MipsBus bus, uint[] regs) + { + if (!_tv2FileDestOn || !_tv2FetchLogged || !_tv2ImplContLogged) + return; + if (bus == null || _tv2Thread == 0) + return; + uint stack = 0; + uint saved = 0; + try + { + stack = bus.Read32(_tv2Thread + ThreadStack); + saved = bus.Read32(_tv2Thread + ThreadCtxSp); + } + catch + { + return; + } + uint src = IsFirmwareUserSlotVa(saved) ? saved : stack; + if (!IsFirmwareUserSlotVa(src)) + return; + uint live = regs != null && regs.Length > 29 ? regs[29] : 0; + bool fixLive = regs != null && regs.Length > 29 && !IsFirmwareUserSlotVa(live); + bool fixSaved = !IsFirmwareUserSlotVa(saved); + if (!fixLive && !fixSaved) + return; + if (fixLive) + regs[29] = src; + if (fixSaved) + { + try + { + bus.Write32(_tv2Thread + ThreadCtxSp, src); + } + catch + { + } + } + if (_tv2UserSpLogged || regs == null) + return; + _tv2UserSpLogged = true; + System.Console.WriteLine("[Hive] FILE[25] thread +D4: user sp=0x" + + src.ToString("X8") + + " live=0x" + live.ToString("X8") + + " saved=0x" + saved.ToString("X8") + + " thr=0x" + _tv2Thread.ToString("X8") + + " (firmware 0x80014488 lw $sp,212(s0); leftover +0xD4; not 0xE4DA9AA4; not a mapped page 0)"); + } + + // wait87: leftover 0x8001588C -> 0x03F6CAC0 + // then jr $ra ra=0. +DC=0. Implicit-API + // 0x8001586C never hits 0x800152CC. + // 0x80020C30 zeros +DC. Firmware + // 0x80014434 lw $ra, 220(s0). First pass + // already sw $ra, 28($sp) at 0x03F6CABC + // (AFBF001C). Landing at 0x03F6CAC0 skips + // that sw. Restore from 28($sp) or live + // +DC. Do not write 0. Do not map page 0. + // Do not rewind leftover to 0x03F6C8F4. + public static void TryKeepTv2UserRa(MipsBus bus, uint[] regs) + { + if (!_tv2FileDestOn || !_tv2FetchLogged || !_tv2ImplContLogged) + return; + if (bus == null || _tv2Thread == 0) + return; + uint live = regs != null && regs.Length > 31 ? regs[31] : 0; + if (IsFirmwareUserOrCoredllVa(live)) + return; + uint saved = 0; + uint savedSp = 0; + try + { + saved = bus.Read32(_tv2Thread + ThreadCtxRa); + savedSp = bus.Read32(_tv2Thread + ThreadCtxSp); + } + catch + { + return; + } + uint keep = 0; + uint sp = 0; + if (IsFirmwareUserSlotVa(_tv2StoreSp)) + sp = _tv2StoreSp; + else if (regs != null && regs.Length > 29 && IsFirmwareUserSlotVa(regs[29])) + sp = regs[29]; + else if (IsFirmwareUserSlotVa(savedSp)) + sp = savedSp; + uint stacked = 0; + if (sp != 0 && TryPeekWord(bus, sp + 28, out stacked) + && IsFirmwareUserOrCoredllVa(stacked)) + keep = stacked; + if (keep == 0 && IsFirmwareUserOrCoredllVa(saved)) + keep = saved; + if (keep == 0 || keep == live) + return; + if (regs != null && regs.Length > 31) + regs[31] = keep; + if (saved == 0 || !IsFirmwareUserOrCoredllVa(saved)) + { + try + { + bus.Write32(_tv2Thread + ThreadCtxRa, keep); + } + catch + { + } + } + if (_tv2UserRaLogged || regs == null) + return; + _tv2UserRaLogged = true; + System.Console.WriteLine("[Hive] FILE[25] thread +DC: user ra=0x" + + keep.ToString("X8") + + " live=0x" + live.ToString("X8") + + " saved=0x" + saved.ToString("X8") + + " 28($sp)=0x" + stacked.ToString("X8") + + " thr=0x" + _tv2Thread.ToString("X8") + + " (firmware 0x80014434 lw $ra,220(s0); leftover +0xDC; first-pass 28($sp); not a mapped page 0)"); + } + + // wait88: leftover 0x8001588C -> 0x03F6CAC0 + // skips sw $ra, 28($sp). +DC keep wrote + // 0x03F731E4; live ra was 0x800159A0 + // (mid 0x8001586C). ERET used +D4 + // 0x0C03F518, not first-pass 0x0C03F550, + // so lw 28($sp) then jr $ra fetched 0. + // Land with that frame and complete the + // skipped sw. Do not write 0. Do not map + // page 0. Do not rewind 0x03F6C8F4. + public static void TryKeepTv2StoreFrame(MipsBus bus, uint[] regs) + { + if (!_tv2LeftoverStoreFrame || !_tv2StoreContLogged) + return; + if (bus == null || _tv2Thread == 0) + return; + if (_tv2ImplResume != 0x03F6CAC0u) + return; + if (!IsFirmwareUserSlotVa(_tv2StoreSp)) + return; + uint stacked = 0; + if (!TryPeekWord(bus, _tv2StoreSp + 28, out stacked)) + return; + uint keep = 0; + if (IsFirmwareUserOrCoredllVa(stacked)) + keep = stacked; + if (IsLeftoverUserRa(stacked)) + { + _tv2LeftoverUserRa = stacked; + _tv2LeftoverUserRaSet = true; + } + if (keep == 0) + { + uint saved = 0; + try + { + saved = bus.Read32(_tv2Thread + ThreadCtxRa); + } + catch + { + return; + } + if (IsFirmwareUserOrCoredllVa(saved)) + keep = saved; + } + if (keep == 0) + return; + if (!IsFirmwareUserOrCoredllVa(stacked)) + { + try + { + bus.Write32(_tv2StoreSp + 28, keep); + stacked = keep; + } + catch + { + return; + } + } + try + { + bus.Write32(_tv2Thread + ThreadCtxSp, _tv2StoreSp); + } + catch + { + } + if (regs != null && regs.Length > 29) + regs[29] = _tv2StoreSp; + if (regs != null && regs.Length > 31 + && !IsFirmwareUserOrCoredllVa(regs[31])) + regs[31] = keep; + try + { + uint dc = bus.Read32(_tv2Thread + ThreadCtxRa); + if (dc == 0 || !IsFirmwareUserOrCoredllVa(dc)) + bus.Write32(_tv2Thread + ThreadCtxRa, keep); + } + catch + { + } + if (_tv2StoreFrameLogged || regs == null) + return; + _tv2StoreFrameLogged = true; + System.Console.WriteLine("[Hive] FILE[25] leftover store-frame sp=0x" + + _tv2StoreSp.ToString("X8") + + " ra=0x" + keep.ToString("X8") + + " 28($sp)=0x" + stacked.ToString("X8") + + " thr=0x" + _tv2Thread.ToString("X8") + + " (first-pass 0x03F6CABC sw $ra,28($sp); leftover 0x03F6CAC0; not rewind 0x03F6C8F4; not a mapped page 0)"); + } + + private static bool IsFirmwareUserSlotVa(uint va) + { + uint slot = va >> 25; + return va != 0 && va < 0x80000000u && slot >= 1 && slot <= 16; + } + + private static bool IsFirmwareUserOrCoredllVa(uint va) + { + if (va == 0) + return false; + if (va >= CoredllSharedLo && va < CoredllSharedHi) + return true; + if (IsFirmwareUserSlotVa(va)) + return true; + uint slot = va >> 25; + return slot == 0 && va >= 0x00010000u && va < 0x02000000u; + } + + private static bool IsFirmwareUserKdataOrSlot(uint va) + { + return va == UserKData || IsFirmwareUserSlotVa(va); + } + + public static void TryNoteTv2ThreadRestore(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2FileDestOn || _tv2Thread == 0 || bus == null || regs == null) + return; + if (pc != ThreadCtxRestore && pc != ThreadCtxRestore2) + return; + if (regs.Length <= 16) + return; + uint s0 = regs[16]; + if (s0 != _tv2Thread) + return; + TryKeepTv2UserStatus(bus); + TryKeepTv2ThreadOwner(bus, pc == ThreadCtxRestore ? "ERET" : "ERET2"); + TryKeepTv2ThreadCtx(bus, pc == ThreadCtxRestore ? "ERET" : "ERET2"); + // wait121: leftover-left / leftover restore + // overwrites leftover ctxPC to ERET2 after + // leftover-past dest-live. leftover restore + // re-apply is too early (restore I-fetch, not + // dispatch). leftover DISPATCH after leftover + // dest-live I-fetch must not yank leftover + // ctxPC to ERET2. dest-live I-fetch stays + // dest-live next / PC+4, not ERET2. Do not + // follow dest-live $ra 0x03F731E4. Do not + // rewrite ERET2. Do not add a one-shot hop + // at 0x03F73238. + if (_tv2LeftoverPastS4NextLogged && _tv2LeftoverDestLiveNext != 0) + TryKeepLeftoverDestLiveDispatch(bus, pc); + TryKeepTv2UserS7(bus, regs); + TryKeepTv2UserSp(bus, regs); + TryKeepTv2UserRa(bus, regs); + TryKeepTv2StoreFrame(bus, regs); + try + { + uint ctxPc = bus.Read32(_tv2Thread + ThreadCtxPc); + uint startip = bus.Read32(_tv2Thread + ThreadStartip); + uint cur = bus.Read32(CurProc); + uint owner = bus.Read32(_tv2Thread + ThreadPrc); + uint savedRa = bus.Read32(_tv2Thread + ThreadCtxRa); + bool notable = ctxPc == _tv2Startip + || ctxPc == ExnAfterFetch + || ctxPc == ExnAfterFetch2 + || ctxPc == _tv2ImplRa + || !_tv2RestoreLogged; + if (notable) + { + _tv2RestoreLogged = true; + System.Console.WriteLine("[Hive] FILE[25] thread restore pc=0x" + + pc.ToString("X8") + + " thr=0x" + s0.ToString("X8") + + " ctxPC=0x" + ctxPc.ToString("X8") + + " +5C=0x" + startip.ToString("X8") + + " +0C=0x" + owner.ToString("X8") + + " +DC=0x" + savedRa.ToString("X8") + + " CurProc=0x" + cur.ToString("X8")); + } + } + catch + { + } + TryNoteTv2ProcSwitch(bus); + } + + public static void TryNoteTv2CurThread(MipsBus bus) + { + if (_tv2CurThreadLogged || _tv2Thread == 0 || bus == null) + return; + try + { + uint curThr = bus.Read32(ThreadPtr); + if (curThr != _tv2Thread) + return; + _tv2CurThreadLogged = true; + uint cur = bus.Read32(CurProc); + uint ctxPc = bus.Read32(_tv2Thread + ThreadCtxPc); + System.Console.WriteLine("[Hive] FILE[25] CurThread=0x" + + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " ctxPC=0x" + ctxPc.ToString("X8") + + " startip=0x" + _tv2Startip.ToString("X8") + + " (scheduler switched onto tv2 thread)"); + TryNoteTv2ProcSwitch(bus); + } + catch + { + } + } + + public static bool IsTv2StartipFault(uint va) + { + if (_tv2Startip != 0 && va == _tv2Startip) + return true; + if (_tv2Startip != 0 + && (va & ~0xFFFu) == (_tv2Startip & ~0xFFFu)) + return true; + if (va >= 0x014B1000u && va < 0x014D0000u) + return true; + uint slot0 = va & SlotMask; + return _mscoreeDestOn + && slot0 >= 0x014B1000u && slot0 < 0x014D0000u; + } + + public static bool IsTv2CoredllShared(uint va) + { + return va >= CoredllSharedLo && va < CoredllSharedHi; + } + + private static uint PeekSection(MipsBus bus, uint slot) + { + if (bus == null || slot > 16) + return 0; + try + { + return bus.Read32(KDataSection + (slot * 4)); + } + catch + { + return 0; + } + } + + private static bool TryPeekWord(MipsBus bus, uint va, out uint word) + { + word = 0; + if (bus == null || va == 0) + return false; + try + { + word = bus.Read32(va); + return true; + } + catch + { + return false; + } + } + + // 0x80040278 user walk: l1 = section[((va>>16)&0x1FF)*4], + // l2 = l1[(((va>>12)&0xF)+3)*4]. bit1 is valid. PFN is + // bits 10+. Do not invent a static 0x03F73000 map. + private static bool WalkFirmwarePte(MipsBus bus, uint section, uint va, + out uint l1, out uint l2, out uint pfn, out uint kseg) + { + l1 = 0; + l2 = 0; + pfn = 0; + kseg = 0; + if (bus == null || section == 0 || section == 1) + return false; + uint l1Ptr = section + (((va >> 16) & 0x1FFu) * 4); + if (!TryPeekWord(bus, l1Ptr, out l1) || l1 == 0 || l1 == 1) + return false; + uint l2Ptr = l1 + ((((va >> 12) & 0xFu) + 3) * 4); + if (!TryPeekWord(bus, l2Ptr, out l2) || l2 == 0) + return false; + if ((l2 & 2) == 0) + return false; + // pfn6 is the live dest. wait77: 0x40002A1A + // pfn10 is 0x0000A000 (empty low RAM); + // pfn6 is 0x000A8000 dest-word 0x27BDFFD8. + // wait81: 0x400023DA pfn6 is 0x0008F000, + // linear with 0x03F73000->0x00097000. + // dest-word at 0x8008FE10 is 0 (delay-slot + // nop in the ROM page), not a miss. Accept + // pfn6 when the dest is readable. Do not + // let pfn10 zeros win. + uint phys6 = (l2 >> 6) << 12; + uint dest6 = 0x80000000u | (phys6 & 0x1FFFFFFFu); + uint word6 = 0; + if (TryPeekWord(bus, dest6 | (va & 0xFFFu), out word6)) + { + pfn = phys6; + kseg = dest6; + return true; + } + uint phys10 = (l2 >> 10) << 12; + uint dest10 = 0x80000000u | (phys10 & 0x1FFFFFFFu); + uint word10 = 0; + if (TryPeekWord(bus, dest10 | (va & 0xFFFu), out word10) && word10 != 0) + { + pfn = phys10; + kseg = dest10; + return true; + } + return false; + } + + public static void TryCacheLiveCoredllSec(MipsBus bus, uint pc) + { + if (_coredllLiveSec != 0 || _tv2FetchLogged || bus == null) + return; + if (!IsTv2CoredllShared(pc)) + return; + uint word = 0; + if (!TryPeekWord(bus, pc, out word) || word == 0) + return; + uint sec1 = PeekSection(bus, 1); + if (sec1 == 0) + return; + _coredllLiveSec = sec1; + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + bool pte = WalkFirmwarePte(bus, sec1, pc, out l1, out l2, out pfn, out kseg); + if (_coredllLiveLogged) + return; + _coredllLiveLogged = true; + System.Console.WriteLine("[Hive] FILE[25] coredll live-sec=0x" + + sec1.ToString("X8") + + " pc=0x" + pc.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " kseg=0x" + kseg.ToString("X8") + + (pte + ? " (firmware 0x80040278 walk; not a static slot map)" + : " (dest-mapped; PTE walk miss; do not invent a slot map)")); + } + + public static uint MapCoredllSharedVa(MipsBus bus, uint va) + { + if (_coredllMapBusy || bus == null || !IsTv2CoredllShared(va)) + return va; + // wait77 code 0x03F5xxxx-0x03FA0000 is safe from + // first I-fetch. 0x03FDxxxx during NK CallDLL hung + // OEMIdle before filesys. Walk those pages only + // after tv2 startip. Not a static 0x03FD0000 map. + if (va >= 0x03FA0000u && !_tv2FetchLogged) + return va; + uint sec = _coredllLiveSec != 0 ? _coredllLiveSec : PeekSection(bus, 1); + if (sec == 0) + return va; + try + { + _coredllMapBusy = true; + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (!WalkFirmwarePte(bus, sec, va, out l1, out l2, out pfn, out kseg)) + return va; + uint dest = kseg | (va & 0xFFFu); + if (dest == va) + return va; + if (!_coredllMapLogged) + { + _coredllMapLogged = true; + System.Console.WriteLine("[Hive] FILE[25] coredll PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " (firmware section; not a static slot map)"); + } + if (va >= 0x03FA0000u && !_coredllHighLogged) + { + uint word = 0; + TryPeekWord(bus, dest, out word); + _coredllHighLogged = true; + System.Console.WriteLine("[Hive] FILE[25] coredll high PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (slot-1 past 0x03FA0000; firmware PTE; not invented 0x03FD0000)"); + } + if (!_coredllZeroLogged) + { + uint word = 0; + TryPeekWord(bus, dest, out word); + if (word == 0) + { + _coredllZeroLogged = true; + System.Console.WriteLine("[Hive] FILE[25] coredll dest-word 0 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " (delay-slot nop; pfn6 live; not a miss; not a static slot map)"); + } + } + return dest; + } + finally + { + _coredllMapBusy = false; + } + } + + // After the 0xFFFFF3DA jalr, a1=0xC at 0x80020D80 is + // Cause for TLB store (code 3). nest was 2 so the + // general path built a frame at sp-248 (0x0C03E930) + // and jal 0x80040278. Walk that VA's live section. + // Slot 1 is coredll. Slot 6 is tv2 proc+0C. + // Slot 2 (filesys) after leftover live-pc only: wait95 + // dest-unmapped 0x0407F6DC while dest 0x86FAA6DC already + // holds 0x86FA5000 (pte-live). wait77 walked slot-2 after + // store-continue and hung in OEMIdle. + // Slot 0 process-info page after leftover-past only: + // wait96 dest-unmapped 0x01FFFCA4 (same page as + // 0x01FFFFA0). leftover 0x03F6CAE8 lw $v0,0($s6) + // dest-word 0x8EC20000. Not leftover mid 0x8001586C. + // Slot 0 I-fetch after leftover-CAE8 only: wait97 + // dest-unmapped 0x00044154 while dest 0x80179154 is + // pte-live (kseg 0x80179000). Not page 0. + // Do not invent dest. Do not invent a slot map. + public static uint MapFirmwareSlotVa(MipsBus bus, uint va) + { + if (_ddiNopDestPeekRaw || _ddiNopInfoPeekRaw) + return va; + bool dest0 = _ddiNopDestOn + && va >= DdiNopVallocLo && va < DdiNopVallocDataHi(); + bool ddiInfo = va >= ProcessInfoPage && va < 0x02000000u + && IsDdiNopProcessInfoArmed(); + bool ddiFetch = (va & ~0xFFFu) == GwesDispFetchPage + && IsDdiNopGwesDispFetchArmed(); + bool ddiData = (va & ~0xFFFu) == GwesDispDataPage + && IsDdiNopGwesDispDataArmed(); + bool ddiText = (va & ~0xFFFu) == GwesTextBasePage + && IsDdiNopGwesTextBaseArmed(); + bool ddiData2 = (va & ~0xFFFu) == GwesDispData2Page + && IsDdiNopGwesDispData2Armed(); + bool ddiData3 = (va & ~0xFFFu) == GwesDispData3Page + && IsDdiNopGwesDispData3Armed(); + bool ddiText2 = (va & ~0xFFFu) == GwesText2Page + && IsDdiNopGwesText2Armed(); + bool ddiGwes = IsDdiNopGwesImageArmed() + && IsDdiNopGwesImageVa(va) + && !IsNamedDdiNopGwesPage(va); + if (_pteMapBusy || bus == null || (_tv2ImplRa == 0 && !dest0 && !ddiInfo && !ddiFetch && !ddiData && !ddiText && !ddiData2 && !ddiData3 && !ddiText2 && !ddiGwes)) + return va; + if (va >= 0x80000000u) + return va; + if (IsTv2CoredllShared(va)) + return va; + uint slot = va >> 25; + bool walkSlot2 = slot == 2 && _tv2LeftoverLiveLogged; + bool walkSlot0Info = slot == 0 + && (_tv2LeftoverPastLogged || ddiInfo) + && va >= ProcessInfoPage + && va < 0x02000000u; + bool walkSlot0Fetch = slot == 0 + && va >= 0x00010000u + && va < 0x01FFF000u + && (_tv2LeftoverCae8Logged || ddiFetch || ddiData || ddiText || ddiData2 || ddiData3 || ddiText2 || ddiGwes); + if (slot != 1 && slot != 6 && !walkSlot2 && !walkSlot0Info + && !walkSlot0Fetch && !dest0) + return va; + uint sec = PeekSection(bus, slot); + if (sec == 0) + return va; + try + { + _pteMapBusy = true; + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + if (!WalkFirmwarePte(bus, sec, va, out l1, out l2, out pfn, out kseg)) + return va; + uint dest = kseg | (va & 0xFFFu); + if (dest == va) + return va; + // KSEG0 0x80000000 is physical page 0. Do not map it. + if ((dest & 0x1FFFFFFFu) < 0x00010000u) + return va; + if (dest0) + { + if ((va & 0xFFFFF000u) == 0x01981000u) + _ddiNopDest0Pte = dest & ~0xFFFu; + if (!_ddiNopDest0PteLogged) + { + _ddiNopDest0PteLogged = true; + BootLog.Write("[Hive] ExtraROM ddi_nop dest0 PTE va=0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " (firmware 0x80040278; useg dest)"); + } + } + else if (walkSlot0Info && !_slot0InfoMapLogged) + { + uint word = 0; + TryPeekWord(bus, dest, out word); + _slot0InfoMapLogged = true; + _pteMapLogged = true; + if (ddiInfo && !_tv2LeftoverPastLogged) + { + if (_ddiNopInfoKseg == 0) + _ddiNopInfoKseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop proc-info PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; same page as *0x01FFFFA0; do not invent heap bytes)"); + } + else + { + System.Console.WriteLine("[Hive] FILE[25] slot-0 info PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " slot=" + slot + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (process-info leftover-past; firmware 0x80040278; dest already expanded; do not map page 0; do not invent dest bytes)"); + } + } + else if (walkSlot0Fetch && !_slot0FetchMapLogged) + { + uint word = 0; + TryPeekWord(bus, dest, out word); + _slot0FetchMapLogged = true; + _pteMapLogged = true; + if (ddiGwes && !_tv2LeftoverCae8Logged) + { + uint rom = 0; + uint romWord = 0; + string via = null; + if (IsGwesImageBasePage(va)) + { + if (TryGwesHeaderDest(bus, va, out rom, out romWord, out via)) + { + RememberGwesImageKseg(va, rom); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page PTE 0x" + + va.ToString("X8") + " -> 0x" + rom.ToString("X8") + + " dest-word=0x" + romWord.ToString("X8") + + " via=" + via + + " was=0x" + dest.ToString("X8") + + " (ImageBase headers; TOC[7] gwes; do not invent dest)"); + } + } + else if (IsGwesDataB9Page(va)) + { + RememberGwesImageKseg(va, dest); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; compressed .data dest0; do not invent dest)"); + } + else if (TryGwesRomTextDest(bus, va, word, out rom, out romWord)) + { + RememberGwesImageKseg(va, rom); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page PTE 0x" + + va.ToString("X8") + " -> 0x" + rom.ToString("X8") + + " dest-word=0x" + romWord.ToString("X8") + + " via=o32-rom was=0x" + dest.ToString("X8") + + " (dest-word=0 .text; TOC[7] o32; do not invent dest)"); + } + else + { + RememberGwesImageKseg(va, dest); + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-page PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; gwes image; do not invent dest)"); + } + } + else if (ddiText2 && !_tv2LeftoverCae8Logged) + { + if (_ddiNopGwesText2Kseg == 0) + _ddiNopGwesText2Kseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-text2 PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; gwes .text 0x00014000; do not invent dest)"); + } + else if (ddiData3 && !_tv2LeftoverCae8Logged) + { + if (_ddiNopGwesData3Kseg == 0) + _ddiNopGwesData3Kseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data3 PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; GwesDispObj; do not invent dest)"); + } + else if (ddiData2 && !_tv2LeftoverCae8Logged) + { + if (_ddiNopGwesData2Kseg == 0) + _ddiNopGwesData2Kseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data2 PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; GwesInitFlag page; do not invent dest)"); + } + else if (ddiText && !_tv2LeftoverCae8Logged) + { + if (_ddiNopGwesTextKseg == 0) + _ddiNopGwesTextKseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-text PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; gwes VA 0x00011000; do not invent dest)"); + } + else if (ddiData && !_tv2LeftoverCae8Logged) + { + if (_ddiNopGwesDataKseg == 0) + _ddiNopGwesDataKseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp data PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; GwesIatGetProc page; do not invent dest)"); + } + else if (ddiFetch && !_tv2LeftoverCae8Logged) + { + if (_ddiNopGwesFetchKseg == 0) + _ddiNopGwesFetchKseg = dest & ~0xFFFu; + BootLog.Write("[Hive] ExtraROM ddi_nop gwes-disp PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278; GwesVaDispAlloc page; do not invent dest)"); + } + else + { + System.Console.WriteLine("[Hive] FILE[25] slot-0 fetch PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " slot=" + slot + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (gwes leftover-CAE8; firmware 0x80040278; dest already expanded; do not map page 0; do not invent dest bytes)"); + } + } + else if (walkSlot2 && !_slot2MapLogged) + { + uint word = 0; + TryPeekWord(bus, dest, out word); + _slot2MapLogged = true; + _pteMapLogged = true; + System.Console.WriteLine("[Hive] FILE[25] slot-2 PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " slot=" + slot + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (filesys leftover-live; firmware 0x80040278; dest already expanded; do not invent dest bytes)"); + } + else if (!_pteMapLogged) + { + uint word = 0; + TryPeekWord(bus, dest, out word); + _pteMapLogged = true; + System.Console.WriteLine("[Hive] FILE[25] slot PTE 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " slot=" + slot + + " sec=0x" + sec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " dest-word=0x" + word.ToString("X8") + + " (firmware 0x80040278 walk after jalr; not a static slot map)"); + } + return dest; + } + finally + { + _pteMapBusy = false; + } + } + + public static void TryNoteTv2StartipFetch(MipsBus bus, uint pc) + { + if (_tv2Startip == 0 || pc != _tv2Startip || _tv2FetchLogged) + return; + _tv2FetchLogged = true; + uint cur = 0; + uint owner = 0; + uint slot = 0; + uint curThr = 0; + uint word = 0; + bool mapped = false; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + if (bus != null && _tv2Thread != 0) + owner = bus.Read32(_tv2Thread + ThreadPrc); + if (bus != null && _tv2Proc != 0) + slot = bus.Read32(_tv2Proc + ProcSlot); + if (bus != null) + { + mapped = DestReadable(bus, pc); + if (mapped) + word = bus.Read32(pc); + } + } + catch + { + mapped = false; + } + System.Console.WriteLine("[Hive] FILE[25] I-fetch startip=0x" + + pc.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " bound=0x" + _tv2Thread.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " thread+0C=0x" + owner.ToString("X8") + + " proc+0C=0x" + slot.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (peek only; do not invent dest bytes)"); + TryNoteTv2ProcSwitch(bus); + } + + public static void TryNoteTv2StartipContinue(MipsBus bus, uint pc) + { + if (!_tv2FetchLogged || _tv2ContinueLogged || _tv2Startip == 0) + return; + if (pc == _tv2Startip) + return; + if (pc != _tv2Startip + 4 + && (pc < 0x014B1000u || pc >= 0x014D0000u)) + return; + _tv2ContinueLogged = true; + uint cur = 0; + uint curThr = 0; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] startip continue pc=0x" + + pc.ToString("X8") + + " from=0x" + _tv2Startip.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past first instruction; peek only; not TV UI)"); + } + + public static void TryNoteTv2ExnHelper(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2FetchLogged || _tv2ExnHelperLogged) + return; + if (pc != SwitcherExnCall + && (pc < ExnVmCheck || pc >= ExnVmCheckEnd)) + return; + _tv2ExnHelperLogged = true; + uint a0 = regs != null && regs.Length > 4 ? regs[4] : 0; + uint a1 = regs != null && regs.Length > 5 ? regs[5] : 0; + uint cur = 0; + uint curThr = 0; + uint ctxPc = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + if (bus != null && _tv2Thread != 0) + ctxPc = bus.Read32(_tv2Thread + ThreadCtxPc); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] switcher VM-check pc=0x" + + pc.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " ctxPC=0x" + ctxPc.ToString("X8") + + " (0x80040278; not a vector; do not invent dest bytes)"); + } + + // 0x8001521C: (EPC | 0xFFFC) + 2 == 0. Any + // 0xFFFF???? with bits 1:0 == 2 is a jalr trap + // (0x80095A98 addiu/jalr; 0xFFFFDFEE SetFilePointer). + public static bool IsFirmwareImplicitApi(uint epc) + { + return ((epc | 0xFFFCu) + 2u) == 0; + } + + // 0x8001567C clears k1 before ERET. Copied + // 0x80000180 is 0x80015210: bne k1, 0 skips the + // syscall ori/addiu/beq and 0x80015484 overwrites + // EPC with t0. Stale k1 makes 0xFFFFF3DA a fatal + // AdEL. Do not poke CurProc. + public static bool TryClearImplicitApiK1(uint[] regs, uint vaddr) + { + if (!_tv2FetchLogged || regs == null || regs.Length <= 27) + return false; + if (!IsFirmwareImplicitApi(vaddr)) + return false; + _tv2ImplK1Before = regs[27]; + regs[27] = 0; + return true; + } + + public static void TryNoteTv2PostFetchException(uint code, uint epc, uint vaddr, + uint vector, MipsBus bus) + { + TryNoteTv2PostFetchException(code, epc, vaddr, vector, bus, null); + } + + public static void TryNoteTv2PostFetchException(uint code, uint epc, uint vaddr, + uint vector, MipsBus bus, uint[] regs) + { + if (!_tv2FetchLogged || code == 0) + return; + bool implicitApi = IsFirmwareImplicitApi(epc) || IsFirmwareImplicitApi(vaddr); + uint ra = regs != null && regs.Length > 31 ? regs[31] : 0; + if (implicitApi && ra != 0 && _tv2ImplRa == 0) + { + _tv2ImplRa = ra; + _tv2ImplEpc = epc != 0 ? epc : vaddr; + } + if (implicitApi) + { + if (_tv2ImplAdelLogged) + return; + _tv2ImplAdelLogged = true; + } + else + { + if (_tv2PostFetchExnLogged) + return; + _tv2PostFetchExnLogged = true; + } + uint cur = 0; + uint curThr = 0; + uint nest = 0; + uint k1 = _tv2ImplK1Before != 0 + ? _tv2ImplK1Before + : (regs != null && regs.Length > 27 ? regs[27] : 0); + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + if (bus != null) + nest = bus.Read8(KDataNest); + } + catch + { + } + bool startip = IsTv2StartipFault(epc) || IsTv2StartipFault(vaddr); + bool coredll = IsTv2CoredllShared(epc) || IsTv2CoredllShared(vaddr); + uint va = (vaddr != 0 && vaddr != epc) ? vaddr : epc; + uint slot = va >> 25; + uint sec0 = PeekSection(bus, 0); + uint sec1 = PeekSection(bus, 1); + uint sec6 = PeekSection(bus, 6); + uint destWord = 0; + bool mapped = TryPeekWord(bus, va, out destWord); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + uint walkSlot; + if (va >= 0x00010000u && va < 0x02000000u) + walkSlot = 0; + else if (va < 0x80000000u && slot >= 1 && slot <= 16) + walkSlot = slot; + else + walkSlot = 1u; + uint walkSec = PeekSection(bus, walkSlot); + if (walkSec == 0) + walkSec = _coredllLiveSec != 0 ? _coredllLiveSec : sec1; + bool pte = WalkFirmwarePte(bus, walkSec, va, out l1, out l2, out pfn, out kseg); + string where; + if (implicitApi) + where = " (coredll jalr 0xFFFFFxxx; firmware 0x8001521C; not KData; not a slot map)"; + else if (startip) + where = " (startip/mscoree dest; do not invent dest bytes)"; + else if (epc == LeftoverCb0c && vaddr == 0xFFFFFFECu) + where = " (lw $a1,-20($s6); $s6==0 null-20; not a ROM page; do not map page 0)"; + else if (va >= 0x01FFF000u && va < 0x02000000u) + where = " (process-info page; firmware PTE; not page 0; not a slot map)"; + else if (coredll) + where = " (coredll shared slot-1; not mscoree; do not invent a slot map)"; + else if (epc == 0 && vaddr == 0) + where = ra == 0 + ? " (jr $ra ra=0; not a null user RA; do not map page 0)" + : " (I-fetch 0; do not map page 0)"; + else + where = " (after jalr return; firmware PTE walk; not a static slot map)"; + uint v0 = regs != null && regs.Length > 2 ? regs[2] : 0; + uint t9 = regs != null && regs.Length > 25 ? regs[25] : 0; + uint s6 = regs != null && regs.Length > 22 ? regs[22] : 0; + uint s7 = regs != null && regs.Length > 23 ? regs[23] : 0; + uint sp = regs != null && regs.Length > 29 ? regs[29] : 0; + uint frame = 0; + uint retpc = 0; + uint ctxSr = 0; + uint savedSp = 0; + uint savedRa = 0; + uint thrStack = 0; + uint epcWord = 0; + bool epcMapped = false; + try + { + if (bus != null && curThr != 0) + frame = bus.Read32(curThr + ThreadSyscallFrame); + if (frame != 0) + TryPeekWord(bus, frame + 4, out retpc); + if (bus != null && _tv2Thread != 0) + ctxSr = bus.Read32(_tv2Thread + ThreadCtxSr); + if (bus != null && _tv2Thread != 0) + savedSp = bus.Read32(_tv2Thread + ThreadCtxSp); + if (bus != null && _tv2Thread != 0) + savedRa = bus.Read32(_tv2Thread + ThreadCtxRa); + if (bus != null && _tv2Thread != 0) + thrStack = bus.Read32(_tv2Thread + ThreadStack); + if (epc != 0) + epcMapped = TryPeekWord(bus, epc, out epcWord); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] post-fetch exception code=" + + code + + " epc=0x" + epc.ToString("X8") + + " vaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " slot=" + slot + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + destWord.ToString("X8") + + " nest=0x" + nest.ToString("X2") + + " k1=0x" + k1.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " t9=0x" + t9.ToString("X8") + + " s6=0x" + s6.ToString("X8") + + " s7=0x" + s7.ToString("X8") + + " sp=0x" + sp.ToString("X8") + + " +D4=0x" + savedSp.ToString("X8") + + " +DC=0x" + savedRa.ToString("X8") + + " +24=0x" + thrStack.ToString("X8") + + " epc-" + (epcMapped ? "mapped" : "unmapped") + + " epc-word=0x" + epcWord.ToString("X8") + + " frame=0x" + frame.ToString("X8") + + " frame+4=0x" + retpc.ToString("X8") + + " +F0=0x" + ctxSr.ToString("X8") + + " implicit=" + implicitApi + + " walk-slot=" + walkSlot + + " walk-sec=0x" + walkSec.ToString("X8") + + " sec0=0x" + sec0.ToString("X8") + + " sec1=0x" + sec1.ToString("X8") + + " sec6=0x" + sec6.ToString("X8") + + " live-sec=0x" + _coredllLiveSec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " kseg=0x" + kseg.ToString("X8") + + (pte ? " pte-live" : " pte-miss") + + where); + } + + public static void TryNoteTv2CoredllFetch(MipsBus bus, uint pc) + { + if (!_tv2FetchLogged || _tv2CoredllLogged || !IsTv2CoredllShared(pc)) + return; + _tv2CoredllLogged = true; + uint cur = 0; + uint curThr = 0; + uint procSlot = 0; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint slot = pc >> 25; + uint sec0 = PeekSection(bus, 0); + uint sec1 = PeekSection(bus, 1); + uint sec6 = PeekSection(bus, 6); + uint l1 = 0; + uint l2 = 0; + uint pfn = 0; + uint kseg = 0; + uint walkSec = _coredllLiveSec != 0 ? _coredllLiveSec : sec1; + bool pte = WalkFirmwarePte(bus, walkSec, pc, out l1, out l2, out pfn, out kseg); + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + if (bus != null && _tv2Proc != 0) + procSlot = bus.Read32(_tv2Proc + ProcSlot); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] I-fetch coredll=0x" + + pc.ToString("X8") + + " page=0x" + (pc & ~0xFFFu).ToString("X8") + + " slot=" + slot + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " proc+0C=0x" + procSlot.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " sec0=0x" + sec0.ToString("X8") + + " sec1=0x" + sec1.ToString("X8") + + " sec6=0x" + sec6.ToString("X8") + + " live-sec=0x" + _coredllLiveSec.ToString("X8") + + " l1=0x" + l1.ToString("X8") + + " l2=0x" + l2.ToString("X8") + + " pfn=0x" + pfn.ToString("X8") + + " kseg=0x" + kseg.ToString("X8") + + (pte ? " pte-live" : " pte-miss") + + " (coredll shared 0x03F5xxxx; not mscoree; firmware PTE; do not invent a slot map)"); + } + + public static void TryNoteTv2CoredllContinue(MipsBus bus, uint pc) + { + if (!_tv2CoredllLogged || _tv2CoredllContLogged) + return; + if (pc == 0x03F73380u) + return; + if (pc != 0x03F73384u + && (pc < 0x014B1000u || pc >= 0x014D0000u)) + return; + _tv2CoredllContLogged = true; + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] coredll continue pc=0x" + + pc.ToString("X8") + + " from=0x03F73380 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " (past coredll I-fetch; not TV UI)"); + } + + public static void TryNoteTv2HighContinue(MipsBus bus, uint pc) + { + if (!_tv2FetchLogged || !_coredllHighLogged || _tv2HighContLogged) + return; + if (pc != BindImpNameWalk + 4) + return; + _tv2HighContLogged = true; + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] coredll-high continue pc=0x" + + pc.ToString("X8") + + " from=0x03FD1FD8 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " (past name-walk load; not TV UI)"); + } + + public static void TryNoteTv2ImplicitContinue(MipsBus bus, uint pc) + { + TryNoteTv2ImplicitContinue(bus, pc, null); + } + + public static void TryNoteTv2ImplicitContinue(MipsBus bus, uint pc, uint[] regs) + { + if (!_tv2FetchLogged || _tv2ImplContLogged || _tv2ImplRa == 0) + return; + if (pc != _tv2ImplRa) + return; + _tv2ImplContLogged = true; + if (_tv2ImplRa != 0) + _tv2ImplResume = _tv2ImplRa; + TryKeepTv2UserS7(bus, regs); + TryKeepTv2UserSp(bus, regs); + uint cur = 0; + uint curThr = 0; + uint s7 = regs != null && regs.Length > 23 ? regs[23] : 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] implicit-api continue pc=0x" + + pc.ToString("X8") + + " from=0x" + (_tv2ImplEpc != 0 ? _tv2ImplEpc.ToString("X8") : "FFFFF9B2") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " s7=0x" + s7.ToString("X8") + + " (past jalr implicit-API; not TV UI)"); + } + + public static void TryNoteTv2ImplicitPast(MipsBus bus, uint pc) + { + TryNoteTv2ImplicitPast(bus, pc, null); + } + + public static void TryNoteTv2ImplicitPast(MipsBus bus, uint pc, uint[] regs) + { + if (!_tv2FetchLogged || !_tv2ImplContLogged || _tv2ImplPastLogged) + return; + if (_tv2ImplRa == 0 || pc != _tv2ImplRa + 4) + return; + _tv2ImplPastLogged = true; + if (_tv2ImplRa != 0) + _tv2ImplResume = _tv2ImplRa + 4; + TryKeepTv2UserS7(bus, regs); + TryKeepTv2UserSp(bus, regs); + uint cur = 0; + uint curThr = 0; + uint s7 = regs != null && regs.Length > 23 ? regs[23] : 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] implicit-api past pc=0x" + + pc.ToString("X8") + + " from=0x" + _tv2ImplRa.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " s7=0x" + s7.ToString("X8") + + " (past lw 0($s7); firmware 0x03F6C8B0 s7=0x5800; not a mapped page 0; not TV UI)"); + } + + public static void TryNoteTv2StoreContinue(MipsBus bus, uint pc) + { + TryNoteTv2StoreContinue(bus, pc, null); + } + + public static void TryNoteTv2StoreContinue(MipsBus bus, uint pc, uint[] regs) + { + if (!_tv2FetchLogged || !_tv2ImplContLogged || _tv2StoreContLogged) + return; + if (pc != 0x03F6CAC0u) + return; + _tv2StoreContLogged = true; + _tv2ImplResume = pc; + if (regs != null && regs.Length > 29 && IsFirmwareUserSlotVa(regs[29])) + _tv2StoreSp = regs[29]; + uint cur = 0; + uint curThr = 0; + uint sp = regs != null && regs.Length > 29 ? regs[29] : 0; + uint s7 = regs != null && regs.Length > 23 ? regs[23] : 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] store continue pc=0x" + + pc.ToString("X8") + + " from=0x03F6CABC CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " sp=0x" + sp.ToString("X8") + + " s7=0x" + s7.ToString("X8") + + " (past leftover $sp store; firmware thread+0x24; not dest 0xE4DA9AA4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPast(MipsBus bus, uint pc) + { + if (!_tv2LeftoverLiveLogged || _tv2LeftoverPastLogged) + return; + if (pc != 0x03F6CAC4u) + return; + _tv2LeftoverPastLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CAC0 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past leftover sw $fp,16($sp); do not skip to 28($sp); not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCae8(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2LeftoverPastLogged || _tv2LeftoverCae8Logged) + return; + if (pc != 0x03F6CAECu) + return; + _tv2LeftoverCae8Logged = true; + if (regs != null && regs.Length > 2) + { + _tv2LeftoverCae8V0Set = true; + _tv2LeftoverCae8V0 = regs[2]; + } + uint s6 = regs != null && regs.Length > 22 ? regs[22] : 0u; + if (s6 != 0 && IsFirmwareUserOrCoredllVa(s6) && (s6 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCae8S6 = s6; + _tv2LeftoverCae8S6Set = true; + } + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint nextWord = 0; + if (TryPeekWord(bus, LeftoverContinue, out nextWord) + && (LeftoverContinue & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCaf0Peeked = true; + _tv2LeftoverCaf0Word = nextWord; + } + uint caf4 = 0; + if (TryPeekWord(bus, LeftoverAfterCaf0, out caf4) + && (LeftoverAfterCaf0 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCaf4Peeked = true; + _tv2LeftoverCaf4Word = caf4; + } + uint cafc = 0; + if (TryPeekWord(bus, LeftoverBeqTaken, out cafc) + && (LeftoverBeqTaken & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCafcPeeked = true; + _tv2LeftoverCafcWord = cafc; + } + uint cb14 = 0; + if (TryPeekWord(bus, LeftoverCb14, out cb14) + && (LeftoverCb14 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb14Peeked = true; + _tv2LeftoverCb14Word = cb14; + } + uint cb34 = 0; + if (TryPeekWord(bus, LeftoverCb34, out cb34) + && (LeftoverCb34 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb34Peeked = true; + _tv2LeftoverCb34Word = cb34; + } + uint cb38 = 0; + if (TryPeekWord(bus, LeftoverCb38, out cb38) + && (LeftoverCb38 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb38Peeked = true; + _tv2LeftoverCb38Word = cb38; + } + uint cb3c = 0; + if (TryPeekWord(bus, LeftoverCb3c, out cb3c) + && (LeftoverCb3c & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb3cPeeked = true; + _tv2LeftoverCb3cWord = cb3c; + } + uint cb40 = 0; + if (TryPeekWord(bus, LeftoverCb40, out cb40) + && (LeftoverCb40 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb40Peeked = true; + _tv2LeftoverCb40Word = cb40; + } + uint cb44 = 0; + if (TryPeekWord(bus, LeftoverCb44, out cb44) + && (LeftoverCb44 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb44Peeked = true; + _tv2LeftoverCb44Word = cb44; + } + uint cb48 = 0; + if (TryPeekWord(bus, LeftoverCb48, out cb48) + && (LeftoverCb48 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb48Peeked = true; + _tv2LeftoverCb48Word = cb48; + } + uint cb4c = 0; + if (TryPeekWord(bus, LeftoverCb4c, out cb4c) + && (LeftoverCb4c & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb4cPeeked = true; + _tv2LeftoverCb4cWord = cb4c; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CAE8 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next=0x03F6CAF0 next-word=0x" + nextWord.ToString("X8") + + " caf4-word=0x" + caf4.ToString("X8") + + " cafc-word=0x" + cafc.ToString("X8") + + " cb14-word=0x" + cb14.ToString("X8") + + " cb34-word=0x" + cb34.ToString("X8") + + " cb38-word=0x" + cb38.ToString("X8") + + " cb3c-word=0x" + cb3c.ToString("X8") + + " cb40-word=0x" + cb40.ToString("X8") + + " cb44-word=0x" + cb44.ToString("X8") + + " cb48-word=0x" + cb48.ToString("X8") + + " cb4c-word=0x" + cb4c.ToString("X8") + + " v0=0x" + (_tv2LeftoverCae8V0Set ? _tv2LeftoverCae8V0.ToString("X8") : "unset") + + " s6=0x" + s6.ToString("X8") + + " (past leftover lw $v0,0($s6); do not skip to 28($sp); not page 0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCaf0(MipsBus bus, uint pc) + { + if (!_tv2LeftoverCae8Logged || _tv2LeftoverCaf0Logged) + return; + if (pc != 0x03F6CAF0u) + return; + _tv2LeftoverCaf0Logged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CAEC CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past leftover beq $v0,$0,+12; do not rewind 0x03F6CAC0; do not skip to 28($sp); not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastAfterCaf0(MipsBus bus, uint pc) + { + if (!_tv2LeftoverAfterCaf0Logged || _tv2LeftoverPastAfterLogged) + return; + if (pc != LeftoverAfterCaf0 && pc != LeftoverBeqTaken) + return; + _tv2LeftoverPastAfterLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CAF0 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past leftover CAF0 nop; do not map page 0; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb0c(MipsBus bus, uint pc) + { + if (!_tv2LeftoverAfterCaf0Logged || _tv2LeftoverPastCb0cLogged) + return; + if (pc != LeftoverCb0cNext) + return; + _tv2LeftoverPastCb0cLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb14 = 0; + if (TryPeekWord(bus, LeftoverCb14, out cb14) + && (LeftoverCb14 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb14Peeked = true; + _tv2LeftoverCb14Word = cb14; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB0C CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb14-word=0x" + cb14.ToString("X8") + + " (past leftover lw $a1,-20($s6); do not map page 0; do not map 0xFFFFFFEC; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb14(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastCb0cLogged || _tv2LeftoverPastCb14Logged) + return; + if (pc != LeftoverCb14) + return; + _tv2LeftoverPastCb14Logged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb34 = 0; + if (TryPeekWord(bus, LeftoverCb34, out cb34) + && (LeftoverCb34 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb34Peeked = true; + _tv2LeftoverCb34Word = cb34; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB10 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb34-word=0x" + cb34.ToString("X8") + + " (past leftover andi $a0,$a1,1; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb34(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastCb14Logged || _tv2LeftoverPastCb34Logged) + return; + if (pc != LeftoverCb34) + return; + _tv2LeftoverPastCb34Logged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb38 = 0; + if (TryPeekWord(bus, LeftoverCb38, out cb38) + && (LeftoverCb38 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb38Peeked = true; + _tv2LeftoverCb38Word = cb38; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB14 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb38-word=0x" + cb38.ToString("X8") + + " (past leftover beq $a0,$0,+7; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb38(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastCb34Logged || _tv2LeftoverPastCb38Logged) + return; + if (pc != LeftoverCb38) + return; + _tv2LeftoverPastCb38Logged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb3c = 0; + if (TryPeekWord(bus, LeftoverCb3c, out cb3c) + && (LeftoverCb3c & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb3cPeeked = true; + _tv2LeftoverCb3cWord = cb3c; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB34 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb3c-word=0x" + cb3c.ToString("X8") + + " (past leftover or $v0,$s7,$0; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb3c(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastCb38Logged || _tv2LeftoverPastCb3cLogged) + return; + if (pc != LeftoverCb3c) + return; + _tv2LeftoverPastCb3cLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb40 = 0; + if (TryPeekWord(bus, LeftoverCb40, out cb40) + && (LeftoverCb40 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb40Peeked = true; + _tv2LeftoverCb40Word = cb40; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB38 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb40-word=0x" + cb40.ToString("X8") + + " (past leftover lw $fp,16($sp); do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb40(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastCb3cLogged || _tv2LeftoverPastCb40Logged) + return; + if (pc != LeftoverCb40) + return; + _tv2LeftoverPastCb40Logged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb44 = 0; + if (TryPeekWord(bus, LeftoverCb44, out cb44) + && (LeftoverCb44 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb44Peeked = true; + _tv2LeftoverCb44Word = cb44; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB3C CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb44-word=0x" + cb44.ToString("X8") + + " (past leftover lw $s7,20($sp); do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb44(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastCb40Logged || _tv2LeftoverPastCb44Logged) + return; + if (pc != LeftoverCb44) + return; + _tv2LeftoverPastCb44Logged = true; + TryCaptureLeftoverUserRa(bus, null); + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb48 = 0; + if (TryPeekWord(bus, LeftoverCb48, out cb48) + && (LeftoverCb48 & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb48Peeked = true; + _tv2LeftoverCb48Word = cb48; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB40 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb48-word=0x" + cb48.ToString("X8") + + " (past leftover lw $s6,24($sp); do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + private static bool IsLeftoverUserRa(uint ra) + { + if (ra == 0 || ra == 0xFFFFFFFFu || ra == 0xFFFFFFECu) + return false; + if ((ra & 0x1FFFFFFFu) < 0x00010000u) + return false; + if (ra >= 0x03F6C8F4u && ra <= LeftoverCb4c) + return false; + if ((ra & 0xFF000000u) == 0x0C000000u) + return false; + return IsFirmwareUserOrCoredllVa(ra); + } + + private static void TryCaptureLeftoverUserRa(MipsBus bus, uint[] regs) + { + if (_tv2LeftoverUserRaSet) + return; + if (!IsFirmwareUserSlotVa(_tv2StoreSp)) + return; + uint stacked = 0; + if (TryPeekWord(bus, _tv2StoreSp + 28, out stacked) + && IsLeftoverUserRa(stacked)) + { + _tv2LeftoverUserRa = stacked; + _tv2LeftoverUserRaSet = true; + } + } + + public static void TryNoteTv2LeftoverPastCb48(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2LeftoverPastCb44Logged || _tv2LeftoverPastCb48Logged) + return; + if (pc != LeftoverCb48) + return; + _tv2LeftoverPastCb48Logged = true; + TryCaptureLeftoverUserRa(bus, regs); + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cb4c = 0; + if (TryPeekWord(bus, LeftoverCb4c, out cb4c) + && (LeftoverCb4c & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverCb4cPeeked = true; + _tv2LeftoverCb4cWord = cb4c; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB44 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " cb4c-word=0x" + cb4c.ToString("X8") + + " ra=0x" + (_tv2LeftoverUserRaSet ? _tv2LeftoverUserRa.ToString("X8") : "unset") + + " (past leftover lw $ra,28($sp); do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastCb4c(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2LeftoverPastCb48Logged || _tv2LeftoverPastCb4cLogged) + return; + if (pc != LeftoverCb4c) + return; + _tv2LeftoverPastCb4cLogged = true; + TryCaptureLeftoverUserRa(bus, regs); + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB48 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " ra=0x" + (_tv2LeftoverUserRaSet ? _tv2LeftoverUserRa.ToString("X8") : "unset") + + " (past leftover jr $ra delay slot; peeked 28($sp); do not invent 0x03F731E4; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastJrRa(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2LeftoverAfterCb4cLogged || _tv2LeftoverPastJrRaLogged) + return; + if (_tv2LeftoverJrRaDest == 0 || pc != _tv2LeftoverJrRaDest) + return; + _tv2LeftoverPastJrRaLogged = true; + if (regs != null && regs.Length > 2) + { + uint v0 = regs[2]; + if (v0 < 0x80010000u || v0 >= 0x80020000u) + { + _tv2LeftoverBeqRaV0Set = true; + _tv2LeftoverBeqRaV0 = v0; + } + } + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint ft = 0; + if (TryPeekWord(bus, LeftoverBeqRaFt, out ft) + && (LeftoverBeqRaFt & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBeqRaFtPeeked = true; + _tv2LeftoverBeqRaFtWord = ft; + } + uint tk = 0; + if (TryPeekWord(bus, LeftoverBeqRaTk, out tk) + && (LeftoverBeqRaTk & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBeqRaTkPeeked = true; + _tv2LeftoverBeqRaTkWord = tk; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F6CB48 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " ft-word=0x" + ft.ToString("X8") + + " tk-word=0x" + tk.ToString("X8") + + " v0=0x" + (_tv2LeftoverBeqRaV0Set ? _tv2LeftoverBeqRaV0.ToString("X8") : "unset") + + " (past leftover jr $ra; live $ra; peek 0x03F731E8/0x03F73210; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6CAC0; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastBeqRaFt(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastJrRaLogged || _tv2LeftoverPastBeqRaFtLogged) + return; + if (pc != LeftoverBeqRaFt) + return; + _tv2LeftoverPastBeqRaFtLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBeqRaFtPeeked = true; + _tv2LeftoverBeqRaFtWord = word; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F731E4 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past leftover beq $v0,$0,+10 fallthrough; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastBeqRaTk(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastJrRaLogged || _tv2LeftoverPastBeqRaTkLogged) + return; + if (pc != LeftoverBeqRaTk) + return; + _tv2LeftoverPastBeqRaTkLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBeqRaTkPeeked = true; + _tv2LeftoverBeqRaTkWord = word; + } + uint delay = 0; + if (TryPeekWord(bus, LeftoverBPlus2Delay, out delay) + && (LeftoverBPlus2Delay & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBPlus2DelayPeeked = true; + _tv2LeftoverBPlus2DelayWord = delay; + } + uint taken = 0; + if (TryPeekWord(bus, LeftoverBPlus2Taken, out taken) + && (LeftoverBPlus2Taken & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBPlus2TakenPeeked = true; + _tv2LeftoverBPlus2TakenWord = taken; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F731E4 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " delay-word=0x" + delay.ToString("X8") + + " taken-word=0x" + taken.ToString("X8") + + " (past leftover beq $v0,$0,+10 taken; peek 0x03F73214/0x03F7321C; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastBPlus2Delay(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastBeqRaTkLogged || _tv2LeftoverPastBPlus2DelayLogged) + return; + if (pc != LeftoverBPlus2Delay) + return; + _tv2LeftoverPastBPlus2DelayLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBPlus2DelayPeeked = true; + _tv2LeftoverBPlus2DelayWord = word; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73210 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past leftover b +2 delay slot; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastBPlus2Taken(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastBeqRaTkLogged || _tv2LeftoverPastBPlus2TakenLogged) + return; + if (pc != LeftoverBPlus2Taken) + return; + _tv2LeftoverPastBPlus2TakenLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBPlus2TakenPeeked = true; + _tv2LeftoverBPlus2TakenWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverBPlus2Next, out next) + && (LeftoverBPlus2Next & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBPlus2NextPeeked = true; + _tv2LeftoverBPlus2NextWord = next; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73210 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover b +2 taken; peek 0x03F73220; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastBPlus2Next(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastBPlus2TakenLogged || _tv2LeftoverPastBPlus2NextLogged) + return; + if (pc != LeftoverBPlus2Next) + return; + _tv2LeftoverPastBPlus2NextLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverBPlus2NextPeeked = true; + _tv2LeftoverBPlus2NextWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverFpNext, out next) + && (LeftoverFpNext & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverFpNextPeeked = true; + _tv2LeftoverFpNextWord = next; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F7321C CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover or $sp,$s8,$0; peek 0x03F73224; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastFpNext(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastBPlus2NextLogged || _tv2LeftoverPastFpNextLogged) + return; + if (pc != LeftoverFpNext) + return; + _tv2LeftoverPastFpNextLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverFpNextPeeked = true; + _tv2LeftoverFpNextWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverS7Next, out next) + && (LeftoverS7Next & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS7NextPeeked = true; + _tv2LeftoverS7NextWord = next; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73220 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover lw $fp,16($sp); peek 0x03F73228; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastS7Next(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastFpNextLogged || _tv2LeftoverPastS7NextLogged) + return; + if (pc != LeftoverS7Next) + return; + _tv2LeftoverPastS7NextLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS7NextPeeked = true; + _tv2LeftoverS7NextWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverS6Next, out next) + && (LeftoverS6Next & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS6NextPeeked = true; + _tv2LeftoverS6NextWord = next; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73224 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover lw $s7,20($sp); peek 0x03F7322C; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastS6Next(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastS7NextLogged || _tv2LeftoverPastS6NextLogged) + return; + if (pc != LeftoverS6Next) + return; + _tv2LeftoverPastS6NextLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS6NextPeeked = true; + _tv2LeftoverS6NextWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverS5Next, out next) + && (LeftoverS5Next & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS5NextPeeked = true; + _tv2LeftoverS5NextWord = next; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73228 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover lw $s6,24($sp); peek 0x03F73230; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastS5Next(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastS6NextLogged || _tv2LeftoverPastS5NextLogged) + return; + if (pc != LeftoverS5Next) + return; + _tv2LeftoverPastS5NextLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS5NextPeeked = true; + _tv2LeftoverS5NextWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverS4Next, out next) + && (LeftoverS4Next & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS4NextPeeked = true; + _tv2LeftoverS4NextWord = next; + } + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F7322C CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover lw $s5,28($sp); peek 0x03F73234; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastS4Next(MipsBus bus, uint pc) + { + if (!_tv2LeftoverPastS5NextLogged || _tv2LeftoverPastS4NextLogged) + return; + if (pc != LeftoverS4Next) + return; + _tv2LeftoverPastS4NextLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverS4NextPeeked = true; + _tv2LeftoverS4NextWord = word; + } + uint next = 0; + if (TryPeekWord(bus, LeftoverEpilogueNext, out next) + && (LeftoverEpilogueNext & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverEpiloguePeeked = true; + _tv2LeftoverEpilogueWord = next; + if (_tv2LeftoverDestLiveNext == 0) + _tv2LeftoverDestLiveNext = LeftoverEpilogueNext; + } + if (_tv2LeftoverDestLiveNext != 0) + TryKeepLeftoverDestLiveCtx(bus, _tv2LeftoverDestLiveNext); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73230 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " next-word=0x" + next.ToString("X8") + + " (past leftover lw $ra,36($sp); peek 0x03F73238; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastEpilogue(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2LeftoverPastS4NextLogged || _tv2LeftoverPastEpilogueLogged) + return; + if (pc != LeftoverEpilogueNext) + return; + _tv2LeftoverPastEpilogueLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + if (mapped && (pc & 0x1FFFFFFFu) >= 0x00010000u) + { + _tv2LeftoverEpiloguePeeked = true; + _tv2LeftoverEpilogueWord = word; + } + TryCaptureLeftoverEpilogueRa(bus, regs); + if (IsFirmwareJrRa(word)) + _tv2LeftoverDestLiveNext = LeftoverEpilogueNext + 4; + if (_tv2LeftoverDestLiveNext != 0) + TryKeepLeftoverDestLiveCtx(bus, _tv2LeftoverDestLiveNext); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73234 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past leftover dest-live next; peek dest-live $ra; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + public static void TryNoteTv2LeftoverPastEpilogueDelay(MipsBus bus, uint[] regs, uint pc) + { + if (!_tv2LeftoverPastEpilogueLogged || _tv2LeftoverPastEpilogueDelayLogged) + return; + if (pc != LeftoverEpilogueNext + 4) + return; + _tv2LeftoverPastEpilogueDelayLogged = true; + TryCaptureLeftoverEpilogueRa(bus, regs); + // dest-live continue stays live. dest-live + // $ra is already walked (leftover past dest-live + // $ra). dest-live next after dest-live delay is + // leftover dest-live delay's live leftover next + // (leftover $ra at dest-live jr $ra if live + // leftover dest), not dest-live $ra, not PC+4. + // prior peek named 0x03F731E4 as evidence only; + // do not invent dest. Do not follow dest-live + // $ra blindly. Do not hop 0x03F73238. + uint next = 0; + if (regs != null && regs.Length > 31 && IsLeftoverUserRa(regs[31]) + && (!_tv2LeftoverPastJrRaLogged || regs[31] != _tv2LeftoverUserRa)) + next = regs[31]; + if (next == 0) + next = pc + 4; + _tv2LeftoverDestLiveNext = next; + TryKeepLeftoverDestLiveCtx(bus, _tv2LeftoverDestLiveNext); + // leftover ERET 0x80015A24 uses $v0, not leftover + // ctxPC. leftover dest-live ERET $v0 restore after + // dest-live delay writes leftover $v0 to leftover + // dest-live delay's live leftover next so leftover + // ERET / dest-live continue hops leftover mid / + // ERET2 to leftover dest-live delay's live leftover + // next, not dest-live $ra, not ERET2, not PC+4. + // Do not invent dest. Do not hop 0x03F73238. + // Do not rewrite 0x80015B9C. + TryRestoreTv2LeftoverDestLiveEret(bus, regs, pc); + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] leftover past pc=0x" + + pc.ToString("X8") + + " from=0x03F73238 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " ra=0x" + _tv2LeftoverUserRa.ToString("X8") + + " (past leftover dest-live delay; do not invent dest; do not rewrite 0x80015B9C; do not rewind 0x03F6C8F4; not TV UI)"); + } + + private static void TryCaptureLeftoverEpilogueRa(MipsBus bus, uint[] regs) + { + if (_tv2LeftoverUserRaSet && IsLeftoverUserRa(_tv2LeftoverUserRa)) + return; + uint stacked = 0; + uint sp = 0; + if (regs != null && regs.Length > 29 && IsFirmwareUserSlotVa(regs[29])) + sp = regs[29]; + else if (IsFirmwareUserSlotVa(_tv2StoreSp)) + sp = _tv2StoreSp; + if (sp != 0 && TryPeekWord(bus, sp + 36, out stacked) && IsLeftoverUserRa(stacked)) + { + _tv2LeftoverUserRa = stacked; + _tv2LeftoverUserRaSet = true; + return; + } + if (regs != null && regs.Length > 31 && IsLeftoverUserRa(regs[31])) + { + _tv2LeftoverUserRa = regs[31]; + _tv2LeftoverUserRaSet = true; + } + } + + private static bool IsFirmwareJrRa(uint word) + { + return word == 0x03E00008u; + } + + public static void TryNoteTv2GwesFetch(MipsBus bus, uint pc) + { + if (!_tv2LeftoverCae8Logged || _tv2GwesFetchLogged) + return; + if (pc != 0x00044154u) + return; + _tv2GwesFetchLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] I-fetch gwes=0x" + + pc.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (slot-0 leftover-CAE8; firmware PTE dest 0x80179154; do not map page 0; do not invent dest bytes)"); + } + + public static void TryNoteTv2GwesContinue(MipsBus bus, uint pc) + { + if (!_tv2GwesFetchLogged || _tv2GwesContLogged) + return; + if (pc != 0x00044158u) + return; + _tv2GwesContLogged = true; + uint word = 0; + bool mapped = TryPeekWord(bus, pc, out word); + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] gwes continue pc=0x" + + pc.ToString("X8") + + " from=0x00044154 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " dest-" + (mapped ? "mapped" : "unmapped") + + " dest-word=0x" + word.ToString("X8") + + " (past gwes I-fetch; leftover/_CorExeMain not skipped; not page 0; not TV UI)"); + } + + public static void TryNoteTv2ZeroDestContinue(MipsBus bus, uint pc) + { + if (!_tv2FetchLogged || !_coredllZeroLogged || _tv2ZeroContLogged) + return; + if (pc != 0x03F6BE14u) + return; + _tv2ZeroContLogged = true; + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] dest-word-0 continue pc=0x" + + pc.ToString("X8") + + " from=0x03F6BE10 CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " (past delay-slot nop; not TV UI)"); + } + + public static void TryNoteTv2AfterExnContinue(MipsBus bus, uint pc) + { + if (!_tv2PostFetchExnLogged || _tv2AfterExnContLogged) + return; + if (pc < 0x014B1000u || pc >= 0x014D0000u) + return; + _tv2AfterExnContLogged = true; + uint cur = 0; + uint curThr = 0; + try + { + if (bus != null) + cur = bus.Read32(CurProc); + if (bus != null) + curThr = bus.Read32(ThreadPtr); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] after-exn continue pc=0x" + + pc.ToString("X8") + + " CurThread=0x" + curThr.ToString("X8") + + " CurProc=0x" + cur.ToString("X8") + + " (past post-jalr exception; not TV UI)"); + } + + public static void TryNoteTv2ProcSwitch(MipsBus bus) + { + if (_tv2ProcSwitchLogged || _tv2Proc == 0 || bus == null) + return; + try + { + uint cur = bus.Read32(CurProc); + if (cur != _tv2Proc) + return; + _tv2ProcSwitchLogged = true; + uint startip = 0; + try + { + startip = bus.Read32(_tv2Proc + ModuleStartip); + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] CurProc=0x" + + cur.ToString("X8") + + " startip=0x" + startip.ToString("X8") + + " (thread switched onto tv2 proc)"); + } + catch + { + } + } + + private static bool TryFillFileExeStartip(MipsBus bus, uint module) + { + if (!_tv2FileDestOn || bus == null || module == 0 || _tv2Startip == 0) + return false; + if (!IsAllowedTv2Startip(_tv2Startip)) + return false; + try + { + uint cur = bus.Read32(module + ModuleStartip); + if (cur != 0 && IsAllowedTv2Startip(cur)) + return true; + bus.Write32(module + ModuleStartip, _tv2Startip); + System.Console.WriteLine("[Hive] FILE[25] startip: fill 0x" + + module.ToString("X8") + "+0x5C=0x" + + _tv2Startip.ToString("X8") + + " (firmware thread/s3 dest; not invented 0x00017F54)"); + return true; + } + catch + { + return false; + } + } + + public static void TryFillProcExeStartip(MipsBus bus) + { + if (bus == null) + return; + try + { + uint proc = bus.Read32(CurProc); + if (proc == 0 || proc == 0xDEADBEEFu) + return; + if (!TryFillFileExeStartip(bus, proc) + && !TryFillFileExeStartip(bus, proc + ProcModule)) + { + uint p50 = bus.Read32(proc + ProcModule); + if (p50 != 0 && p50 != proc && p50 != proc + ProcModule) + TryFillFileExeStartip(bus, p50); + } + TryFillTocStartip(bus, proc); + TryFillTocStartip(bus, proc + ProcModule); + uint p50Toc = bus.Read32(proc + ProcModule); + if (p50Toc != 0 && p50Toc != proc && p50Toc != proc + ProcModule) + TryFillTocStartip(bus, p50Toc); + RefreshExeXipAlias(bus); + } + catch + { + } + } + + private static bool _aliasBusy; + private static uint _aliasProc; + private static uint _aliasReal; + private static uint _aliasEnd; + private static uint _aliasRom; + private static uint _aliasSlot; + private static bool _aliasOn; + private static uint _aliasLoggedRom; + // After firmware VALLOC of the slot-0 view of o32.real, + // fetch 0x0398xxxx from 0x0198xxxx. Do not host-alias src. + private static bool _ddiNopDestOn; + private static uint _ddiNopSlot0; + private static bool _ddiNopDest0PteLogged; + // Live 6f80c88: dest0 PTE 0x01981000 -> 0x86F1C000. + // PeekDestWord(useg) stayed 0. Firmware dest is the + // PTE result. Do not invent this; walk fills it. + private static uint _ddiNopDest0Pte; + private static bool _ddiNopDestPeekRaw; + private static bool _ddiNopDestPteMeasured; + private static uint _ddiNopLandedDest; + private static uint _ddiNopLandedWord; + private static bool _ddiNopLandedBySig; + private static uint _ddiNopModule; + private static uint _ddiNopBindLibV0; + private static string _ddiNopBindLibName; + private static uint _coredllModule; + private static bool _coredllBasePtrLogged; + private static uint _ddiNopFileObj; + private static bool _ddiNopStartipAttempted; + private static bool _ddiNopAwaitCallDll; + private static bool _ddiNopSawCallDllPc; + private static bool _ddiNopCallDllMissLogged; + private static int _ddiNopCallDllMissPoll; + private static bool _ddiNopStallLogged; + private static bool _ddiNopIatLogged; + private static bool _ddiNopDataO32Logged; + private static bool _ddiNopIatWatch; + private static bool _ddiNopIatStoreLogged; + private static int _ddiNopIatStoreN; + private static uint _ddiNopIatDest6; + private static uint _ddiNopIatReal; + private static uint _ddiNopIatValloc; + private static uint _ddiNopIatSpan; + private static uint _ddiNopIatPsize; + private static int _bindImpIatSlotLog; + private static int _ddiNopOrdLog; + private static uint _ddiNopOrdLastA1; + private static int _ddiNopOrdRetLog; + private static uint _ddiNopOrdRetLastA1; + private static bool _ddiNopOrdExpLogged; + private static uint _ddiNopOrdGoodV0; + private static bool _ddiNopOrdAfterDone; + private static int _ddiNopOrdAfterN; + private static uint _ddiNopOrdAfterLast; + private static bool _userKPageAlias; + private static bool _userKPageAliasNoted; + private static bool _ffffFce1Logged; + private static uint _ffffF000Kseg; + private static bool _ffffF000Logged; + private static bool _ffffF000Busy; + private static bool _ffffF000Demand; + private static bool _ffffF000Done; + private static uint _ffffE000Kseg; + private static bool _ffffE000Logged; + private static bool _ffffE000Busy; + private static bool _ffffE000Demand; + private static bool _ffffE000Done; + private static bool _ffffE000SkipLogged; + private static bool _ffffE428SkipLogged; + private static bool _ffffEa88SkipLogged; + private static uint _jalr7eb8Kseg; + private static bool _jalr7eb8Logged; + private static bool _jalr7eb8Busy; + private static bool _jalr7eb8Done; + private static uint _jalr1db0Kseg; + private static bool _jalr1db0Logged; + private static bool _jalr1db0Busy; + private static bool _jalr1db0Done; + private static bool _jalrRiLogged; + private static bool _jalrTableFixLogged; + private static bool _jalrT9MsecLogged; + private static bool _jalrE478JrLogged; + private static uint _stk2470Kseg; + private static bool _stk2470Logged; + private static bool _stk2470Busy; + private static bool _stk2470Done; + private static bool _stk2470SwLogged; + private static bool _stk2470ExnLogged; + private static bool _stk1670Logged; + private static bool _stk1670SbLogged; + private static int _absStoreMemLogN; + private static readonly uint[] _dumpMemLoggedPc = new uint[8]; + private static int _dumpMemFallN; + private static readonly uint[] _dumpMemFallPc = new uint[8]; + private static bool _abs1828ExnLogged; + private static bool _abs6670DumpSkipLogged; + private static bool _abs6670FallthroughLogged; + private static bool _abs6670JalTakenLogged; + private static uint _abs6670JalRa; + private static uint _abs6670JalA0; + private static bool _abs6670DestFetchLogged; + private static bool _abs6670DestExnLogged; + private static uint _badAKseg; + private static bool _badABusy; + private static bool _badADone; + private static bool _badAMapLogged; + private static bool _badAExnLogged; + private static bool _badASrcLogged; + private static bool _badARestoreLogged; + private static bool _badASkipLogged; + private static bool _badAJalContinueLogged; + private static bool _badACalleeContinueLogged; + private static bool _badABeforeE000YankLogged; + private static bool _badAListSaved; + private static uint _badAWrapperRa; + private static uint _badAListA0; + private static uint _badAListA1; + private static uint _badAListV0; + private static uint _badAListS6; + private static bool _abs6670ExnLogged; + private static uint _c000Kseg; + private static bool _c000Logged; + private static bool _c000Busy; + private static bool _c000Done; + private static bool _c000ExnLogged; + private static bool _c000SkipLogged; + private static int _c000SkipN; + private static uint _c000SkipLast; + private static bool _exn15C28Logged; + private static bool _exn15C28TakenLogged; + private static bool _exn15C28Wrote; + private static bool _exn15C28NextLogged; + private static bool _exn15C28Left; + private static uint _exn15C28StkPage; + private static bool _exn15C28StkSkipLogged; + private static bool _exn15C28AfterLogged; + private static bool _exn15C28AfterExnLogged; + private static bool _exn15C28LeaveHoldLogged; + private static bool _exn15C28JalLogged; + private static bool _exn15C28JalDestLogged; + private static bool _exn15C28JalThrLogged; + private static bool _exn15C28JalRetLogged; + private static bool _exn15C28JalRetSkipLogged; + private static bool _exn15C28JalS1Logged; + private static bool _exn15C28JalS1SkipLogged; + private static bool _exn15C28AfterS1Logged; + private static bool _exn15C28AfterS1NextLogged; + private static bool _exn15C28AfterS1AluLogged; + private static bool _exn15C28AfterS1AluNextLogged; + private static bool _exn15C28StkSwSkipLogged; + private static int _exn15C28StkSwLogN; + private static uint _exn15C28StkSwLast; + private static bool _exn15C28AfterStkSwLogged; + private static bool _exn15C28AfterStkSwBneLogged; + private static int _exn15C28AfterStkSwBneLogN; + private static uint _exn15C28AfterStkSwBneLast; + private static bool _exn15C28AfterStkSwNextLogged; + private static bool _exn15C28FpLwSkipLogged; + private static int _exn15C28FpLwLogN; + private static uint _exn15C28FpLwLast; + private static bool _exn15C28AfterFpLwLogged; + private static bool _exn15C28SpT9SkipLogged; + private static int _exn15C28SpT9LogN; + private static uint _exn15C28SpT9Last; + private static bool _exn15C28AfterSpT9Logged; + private static bool _exn15C28JalRaEpiSkipLogged; + private static int _exn15C28JalRaEpiLogN; + private static uint _exn15C28JalRaEpiLast; + private static bool _exn15C28AfterJalRaEpiLogged; + private static bool _exn15C28OuterJalTakenLogged; + private static bool _exn15C28AfterOuterJalLogged; + private static bool _exn15C28AfterOuterJalAluLogged; + private static bool _exn15C28AfterOuterJalNextLogged; + private static bool _exn15C28AfterOuterJalLwLogged; + private static bool _exn15C28AfterOuterJalIncLogged; + private static bool _exn15C28AfterOuterJalJrLogged; + private static bool _exn15C28AfterOuterJalJrNextLogged; + private static bool _exn15C28AfterOuterJalLhuLogged; + private static bool _exn15C28AfterOuterJalLhuNextLogged; + private static bool _exn15C28AfterOuterJalS3Logged; + private static bool _exn15C28AfterOuterJalS3NextLogged; + private static bool _exn15C28AfterOuterJalBneLogged; + private static bool _exn15C28AfterOuterJalBneNextLogged; + private static bool _exn15C28AfterOuterJalLandLogged; + private static bool _exn15C28AfterOuterJalLandNextLogged; + private static bool _exn15C28AfterOuterJalSltuLogged; + private static bool _exn15C28AfterOuterJalSltuNextLogged; + private static bool _exn15C28AfterOuterJalBeqLogged; + private static bool _exn15C28AfterOuterJalBeqNextLogged; + private static bool _exn15C28AfterOuterJalAddiuLogged; + private static bool _exn15C28AfterOuterJalAddiuNextLogged; + private static bool _exn15C28AfterOuterJalLwT4Logged; + private static bool _exn15C28AfterOuterJalLwT4NextLogged; + private static bool _exn15C28AfterOuterJalLwS7Logged; + private static bool _exn15C28AfterOuterJalLwS7NextLogged; + private static bool _exn15C28AfterOuterJalAdduLogged; + private static bool _exn15C28AfterOuterJalAdduNextLogged; + private static bool _exn15C28AfterOuterJalLwFpLogged; + private static bool _exn15C28AfterOuterJalLwFpNextLogged; + private static bool _exn15C28AfterOuterJalLwS6Logged; + private static bool _exn15C28AfterOuterJalLwS6NextLogged; + private static bool _exn15C28AfterOuterJalLwS5Logged; + private static bool _exn15C28AfterOuterJalLwS5NextLogged; + private static bool _exn15C28AfterOuterJalLwS4Logged; + private static bool _exn15C28AfterOuterJalLwS4NextLogged; + private static bool _exn15C28AfterOuterJalLwS3Logged; + private static bool _exn15C28AfterOuterJalLwS3NextLogged; + private static bool _exn15C28AfterOuterJalLwS2Logged; + private static bool _exn15C28AfterOuterJalLwS2NextLogged; + private static bool _exn15C28AfterOuterJalLwS1Logged; + private static bool _exn15C28AfterOuterJalLwS1NextLogged; + private static bool _exn15C28AfterOuterJalLwS0Logged; + private static bool _exn15C28AfterOuterJalLwS0NextLogged; + private static bool _exn15C28AfterOuterJalLwRaLogged; + private static bool _exn15C28AfterOuterJalLwRaNextLogged; + private static bool _exn15C28AfterOuterJalEpiAddiuLogged; + private static bool _exn15C28AfterOuterJalEpiAddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiJrLogged; + private static bool _exn15C28AfterOuterJalEpiJrNextLogged; + private static bool _exn15C28AfterOuterJalEpiLuiLogged; + private static bool _exn15C28AfterOuterJalEpiLuiNextLogged; + private static bool _exn15C28AfterOuterJalEpiV0AddiuLogged; + private static bool _exn15C28AfterOuterJalEpiV0AddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiV1AddiuLogged; + private static bool _exn15C28AfterOuterJalEpiV1AddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiSwLogged; + private static bool _exn15C28AfterOuterJalEpiSwNextLogged; + private static bool _exn15C28AfterOuterJalEpiA3LuiLogged; + private static bool _exn15C28AfterOuterJalEpiA3LuiNextLogged; + private static bool _exn15C28AfterOuterJalEpiLhuLogged; + private static bool _exn15C28AfterOuterJalEpiLhuNextLogged; + private static bool _exn15C28AfterOuterJalEpiA2AddiuLogged; + private static bool _exn15C28AfterOuterJalEpiA2AddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiA2SwLogged; + private static bool _exn15C28AfterOuterJalEpiA2SwNextLogged; + private static bool _exn15C28AfterOuterJalEpiA1AddiuLogged; + private static bool _exn15C28AfterOuterJalEpiA1AddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiA3LhuLogged; + private static bool _exn15C28AfterOuterJalEpiA3LhuNextLogged; + private static bool _exn15C28AfterOuterJalEpiSltuLogged; + private static bool _exn15C28AfterOuterJalEpiSltuNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqLogged; + private static bool _exn15C28AfterOuterJalEpiBeqNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqAddiuLogged; + private static bool _exn15C28AfterOuterJalEpiBeqAddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqSltLogged; + private static bool _exn15C28AfterOuterJalEpiBeqSltNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallAddiuLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallAddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallSwLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallSwNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallJrLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallJrNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuNextLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwLogged; + private static bool _exn15C28AfterOuterJalEpiBeqBneFallJrAddiuSwNextLogged; + private static bool _exn15C28AfterOuterJalEpiPrologueSwLogged; + private static bool _exn15C28AfterOuterJalEpiPrologueSwNextLogged; + private static bool _exn15C28AfterOuterJalEpiPrologueJalLogged; + private static bool _exn15C28AfterOuterJalEpiPrologueJalNextLogged; + private static bool _exn15C28AfterOuterJalEpiTrampolineLogged; + private static bool _exn15C28AfterOuterJalEpiTrampolineNextLogged; + private static bool _exn15C28AfterOuterJalEpiRetLogged; + private static bool _exn15C28AfterOuterJalEpiRetNextLogged; + private static uint _exn15C28AfterOuterJalEpiRetLeave; + private static bool _exn15C28AfterOuterJalEpiRetBneLogged; + private static bool _exn15C28AfterOuterJalEpiRetBneNextLogged; + private static uint _exn15C28AfterOuterJalEpiRetBneLeave; + private static bool _exn15C28AfterOuterJalEpiRetFallLogged; + private static bool _exn15C28AfterOuterJalEpiRetFallNextLogged; + private static uint _exn15C28AfterOuterJalEpiRetFallLeave; + private static bool _exn15C28AfterOuterJalEpiRetCallerLogged; + private static bool _exn15C28AfterOuterJalEpiRetCallerNextLogged; + private static uint _exn15C28AfterOuterJalEpiRetCallerLeave; + private static bool _exn15C28AfterOuterJalEpiRetCallerNextFnLogged; + private static bool _exn15C28AfterOuterJalEpiRetCallerNextFnNextLogged; + private static uint _exn15C28AfterOuterJalEpiRetCallerNextFnLeave; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaLogged; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaNextLogged; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaLhuLogged; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaS3Logged; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaT1Logged; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaBneLogged; + private static bool _exn15C28AfterOuterJalEpiRetCallerRaRefuseLogged; + private static uint _exn15C28AfterOuterJalEpiRetCallerRaLeave; + private static uint _exn15C28AfterOuterJalEpiFn854OuterRa; + private static int _exn15C28Na02IFetchLogN; + private static uint _exn15C28Na02IFetchLast; + private static bool _exn15C28AfterMemsetLogged; + private static bool _c000E000SkipLogged; + private static bool _c000F000SkipLogged; + private static bool _c000Page0SkipLogged; + private static bool _c000LowUsegSkipLogged; + private static int _c000LowUsegSkipN; + private static uint _c000LowUsegSkipLast; + private static uint _listInsertDestClassLogged; + private static bool _abs59488Logged; + private static bool _abs59488ExecLogged; + private static bool _ffffFe54SkipLogged; + private static bool _bindImpIatSwExpect; + private static bool _bindImpIatSwLogged; + private static int _bindImpIatSwLog; + private static int _bindImpIatWinLog; + private static uint _bindImpIatWinLast; + private static int _bindImpIatNextLog; + private static uint _bindImpIatNextLast; + private static bool _bindImpExnLogged; + private static bool _bindImpExnSaveLogged; + private static uint _bindImpExnCode; + private static uint _bindImpExnEpc; + private static uint _bindImpExnVaddr; + private static bool _gwesB9SpinLogged; + private static uint _gwesB9SpinPage; + private static int _gwesB9SpinN; + private static bool _gwesNullStoreLogged; + private static bool _nearNullTlblLogged; + private static bool _ffffFb2aAdelLogged; + private static bool _adelC6FaLogged; + private static uint _adelPcEpc; + private static uint _adelPcSp; + private static bool _adelPlantClrLogged; + private static bool _idleHaltLogged; + private static uint _exnContinueWord; + private static bool _thrSpLogged; + private static bool _spFixLogged; + private static bool _plantFixLogged; + private static bool _plantHaltLogged; + private static bool _leftoverHaltLogged; + private static bool _leftoverSkipLogged; + private static bool _leftoverRetLogged; + private static bool _leftoverCstkLogged; + private static bool _leftoverCstkFixLogged; + private static uint _leftoverCstkApi; + private static bool _leftoverApi78NeedLogged; + private static bool _leftoverApi78PlantLogged; + private static bool _leftoverApi54NeedLogged; + private static bool _leftoverApi54PlantLogged; + private static bool _leftoverApi54ContLogged; + private static bool _leftoverApi54HaltLogged; + private static bool _wait99PlantFixLogged; + private static bool _leftoverWait99WrapLogged; + private static bool _leftoverWait99WrapContLogged; + private static bool _leftoverWait99WrapGetProcLogged; + private static bool _leftoverWait99WrapPlantLogged; + private static bool _leftoverWait99WrapRaContLogged; + private static uint _leftoverWait99WrapPlantMeth; + private static uint _leftoverWait99WrapPlantGp; + private static bool _leftoverWait99O32ContLogged; + private static bool _leftoverWait99O32HaltLogged; + private static bool _leftoverWait99O32SwLogged; + private static bool _leftoverWait99O32RaSrcLogged; + private static bool _leftoverWait99O32NkCallLogged; + private static bool _leftoverWait99O32NkRetLogged; + private static bool _leftoverWait99O32NkWrapLogged; + private static bool _leftoverWait99O32NkWrapAfterLogged; + private static bool _leftoverWait99O32NkWrapVallocLogged; + private static bool _leftoverWait99O32NkWrapS5Logged; + private static bool _leftoverWait99O32NkWrapCopyLogged; + private static bool _leftoverWait99O32NkWrapCopyRetLogged; + private static bool _leftoverWait99O32NkPostCopyLogged; + private static bool _leftoverWait99O32NkE32Logged; + private static bool _leftoverWait99O32NkNextLogged; + private static bool _leftoverWait99O32NkImpLogged; + private static uint _leftoverWait99O32NkWrapSp; + private static uint _leftoverWait99O32NkWrapFp; + private static uint _leftoverWait99O32NkWrapDestFp50; + private static uint _leftoverWait99O32NkHdr; + private static uint _leftoverWait99O32NkHdrOff; + private static bool _leftoverWait99O32NkBindLogged; + private static string _leftoverWait99O32NkBindName = ""; + private static uint _leftoverWait99O32NkBindMod; + private static int _leftoverWait99O32NkIatStubLog; + private static uint _leftoverWait99O32NkIatStubLast; + private static string _leftoverWait99O32NkIatStubVia = ""; + private static uint _leftoverWait99O32NkBindLastPc; + private static uint _leftoverWait99O32NkEntryRva; + private static uint _leftoverWait99O32NkEntryTarget; + private static bool _leftoverWait99O32NkCallDllLogged; + private static int _leftoverWait99O32NkJalrLog; + private static bool _leftoverWait99O32NkJalrSawCall; + private static bool _leftoverWait99O32NkJalrSawTarget; + private static int _leftoverWait99O32NkAfterLog; + private static int _leftoverWait99O32NkChainLog; + private static uint _leftoverWait99O32NkChainLast; + private static string _leftoverWait99O32NkChainVia = ""; + private static string _leftoverWait99O32NkChainName = ""; + private static uint _leftoverWait99O32NkChainCallVa; + private static uint _leftoverWait99O32NkCoredllStartip; + private static bool _leftoverWait99O32NkCoredllSawStartip; + private static bool _leftoverWait99O32NkCoredllSawCall; + private static bool _leftoverWait99O32NkCoredllSawEntry; + private static bool _leftoverWait99O32NkCoredllExnLog; + private static bool _leftoverWait99O32NkCoredllJalLog; + private static uint _leftoverWait99O32NkCoredllJalRa; + private static bool _leftoverWait99O32NkCoredllPc0Log; + private static bool _leftoverWait99O32NkCoredllMissLog; + private static bool _leftoverWait99O32NkCoredllRetLog; + private static int _leftoverWait99O32NkCoredllAfterLog; + private static uint _leftoverWait99O32NkCoredllBodyPc; + private static int _leftoverWait99O32NkCoredllSpin; + private static bool _leftoverWait99O32NkChainSawEntry; + private static uint _leftoverWait99O32NkRa; + private static uint _leftoverWait99O32NkA0; + private static uint _leftoverWait99O32NkA2; + private static uint _leftoverWait99O32NkA3; + private static uint _leftoverWait99O32NkDestWord; + private static uint _leftoverWait99O32NkLive0; + private static bool _leftoverWait99O32NkBit200; + private static bool _leftoverWait99O32NkSkip200; + private static bool _leftoverWait99WrapNeedLogged; + private static bool _leftoverWait99DumpRecsTried; + private static List _leftoverWait99DumpRecs; + private static string _leftoverWait99ScanVia = ""; + private static int _leftoverWait99Cf; + private static int _leftoverWait99Sk; + private static bool _leftoverWait99WhyLogged; + private static bool _leftoverRetFixLogged; + private static bool _leftoverCstkSpinLogged; + private static int _leftoverCstkSpinN; + private static bool _leftoverWait99SpinLogged; + private static int _leftoverWait99SpinN; + private static Dictionary _leftoverStubJalr8; + private static bool _leftoverFrameLogged; + private static bool _epcHaltLogged; + private static bool _c2TlbsLogged; + private static bool _c2SpLogged; + private static bool _c2EretHaltLogged; + private static bool _ddiNopInfoObserved; + private static bool _ddiNopInfoDemand; + private static bool _ddiNopInfoBusy; + private static bool _ddiNopInfoPeekRaw; + private static bool _ddiNopInfoMapLogged; + private static uint _ddiNopInfoKseg; + private static bool _ddiNopCallDllHiveLogged; + private static bool _ddiNopDllMainLogged; + private static uint _ddiNopDllMainRa; + private static uint _ddiNopCallDllSite; + private static bool _ddiNopAfterDllMainLogged; + private static uint _ddiNopGwesFetchKseg; + private static bool _ddiNopGwesFetchLogged; + private static bool _ddiNopGwesFetchBusy; + private static bool _ddiNopGwesFetchDemand; + private static bool _ddiNopGwesFetchTlblLogged; + private static uint _ddiNopGwesDataKseg; + private static bool _ddiNopGwesDataLogged; + private static bool _ddiNopGwesDataBusy; + private static bool _ddiNopGwesDataDemand; + private static bool _ddiNopGwesDataTlblLogged; + private static uint _ddiNopGwesTextKseg; + private static bool _ddiNopGwesTextLogged; + private static bool _ddiNopGwesTextBusy; + private static bool _ddiNopGwesTextDemand; + private static bool _ddiNopGwesTextTlblLogged; + private static uint _ddiNopGwesData2Kseg; + private static bool _ddiNopGwesData2Logged; + private static bool _ddiNopGwesData2Busy; + private static bool _ddiNopGwesData2Demand; + private static bool _ddiNopGwesData2TlblLogged; + private static uint _ddiNopGwesData3Kseg; + private static bool _ddiNopGwesData3Logged; + private static bool _ddiNopGwesData3Busy; + private static bool _ddiNopGwesData3Demand; + private static bool _ddiNopGwesData3TlblLogged; + private static uint _ddiNopGwesText2Kseg; + private static bool _ddiNopGwesText2Logged; + private static bool _ddiNopGwesText2Busy; + private static bool _ddiNopGwesText2Demand; + private static bool _ddiNopGwesText2TlblLogged; + private static uint[] _gwesImagePage; + private static uint[] _gwesImageKseg; + private static bool[] _gwesImageDone; + private static bool[] _gwesImageTlbl; + private static int _gwesImageN; + private static bool _gwesImageDemand; + private static bool _gwesImageBusy; + private static uint[] _coredllImagePage; + private static uint[] _coredllImageKseg; + private static bool[] _coredllImageDone; + private static bool[] _coredllImageTlbl; + private static int _coredllImageN; + private static bool _coredllImageDemand; + private static bool _coredllImageBusy; + private static bool _coredllSlotViewLogged; + private static bool _coredllSlotViewTlbl; + private static uint _filesysSlot2Kseg; + private static bool _filesysSlot2Logged; + private static bool _filesysSlot2Busy; + private static bool _filesysSlot2Demand; + private static bool _filesysSlot2TlblLogged; + private static bool _filesysSlot4Logged; + private static bool _filesysSlot4TlblLogged; + private static uint[] _filesysSlot2ExtraPage; + private static uint[] _filesysSlot2ExtraKseg; + private static bool[] _filesysSlot2ExtraLogged; + private static bool[] _filesysSlot2ExtraTlbl; + private static bool[] _filesysSlot2ExtraMiss; + private static int _filesysSlot2ExtraN; + private static bool _filesysSlot2ExtraBusy; + private static bool _filesys48dLogged; + private static uint[] _filesys48dKsegs; + private static bool[] _filesys48dDone; + private static bool[] _filesys48dTlbl; + private static bool _filesys48dBusy; + private static uint[] _ddiDataPage; + private static uint[] _ddiDataKseg; + private static bool[] _ddiDataDone; + private static bool[] _ddiDataTlbl; + private static int _ddiDataN; + private static bool _ddiDataDemand; + private static bool _ddiDataBusy; + private static bool _ddiPrefPcLogged; + private static uint[] _ddiNopWalkSeeds; + private static int _ddiNopWalkSeedN; + private static bool _ddiNopNoModDiag; + private static bool _ddiNopWalkDiag; + private static bool _ddiNopDecompWatch; + private static uint _ddiNopWatchDest6; + private static uint _ddiNopWatchDest10; + private static uint _ddiNopWatchVbase6; + private static int _ddiNopStoreN0; + private static int _ddiNopStoreN6; + private static int _ddiNopStoreNV6; + private static int _ddiNopStoreN10; + private static int _ddiNopStoreND; + private static int _ddiNopStoreNK; + private static uint _ddiNopStoreFirstVa; + private static uint _ddiNopStoreFirstVal; + private static uint _ddiNopStoreLastVa; + private static uint _ddiNopStoreLastVal; + private static bool _ddiNopStoreThrew0; + private static bool _ddiNopStoreThrew6; + private static bool _ddiNopStoreThrewV; + private static bool _ddiNopStoreThrew10; + private static bool _ddiNopStoreThrewD; + private static bool _ddiNopStoreThrewK; + private static bool _mscoreeDestOn; + private static uint _mscoreeSlot0; + private static uint _mscoreeVbase; + + public static void ResetExeXipAlias() + { + _aliasBusy = false; + _aliasProc = 0; + _aliasReal = 0; + _aliasEnd = 0; + _aliasRom = 0; + _aliasSlot = 0; + _aliasOn = false; + _aliasLoggedRom = 0; + _ddiNopDestOn = false; + _ddiNopSlot0 = 0; + _ddiNopDest0PteLogged = false; + _ddiNopDest0Pte = 0; + _ddiNopDestPeekRaw = false; + _ddiNopDestPteMeasured = false; + _ddiNopLandedDest = 0; + _ddiNopLandedWord = 0; + _ddiNopLandedBySig = false; + _ddiNopModule = 0; + ResetDdiNopModuleHunt(); + _mscoreeDestOn = false; + _mscoreeSlot0 = 0; + _ole32DestOn = false; + _ole32Slot0 = 0; + _ddiNopDecompRa = 0; + _ddiNopDecompSrc = 0; + _ddiNopDecompCb = 0; + _ddiNopDecompDest = 0; + _ddiNopDecompVsize = 0; + _ddiNopDecompHdr = 0; + ResetDdiNopDecompStores(); + _ddiNopDestWordLogged = false; + _ddiNopObserve = false; + _ddiNopInnerCap = false; + _ddiNopInnerPages = 0; + _ddiNopBindHdr = false; + _ddiNopBindName = false; + _ddiNopBindLib = false; + _ddiNopBindLibRet = false; + ResetDdiNopModuleHunt(); + _vallocHostN = 0; + _vallocHostPool = VallocHostKseg; + _heapSlotBusy = false; + _heapSlotLogged = false; + _heapSlotCached = 0; + _heapOffCached = 0; + _heapSlotCacheLogged = false; + for (int i = 0; i < _vallocHostLo.Length; i++) + { + _vallocHostLo[i] = 0; + _vallocHostHi[i] = 0; + _vallocHostKseg[i] = 0; + } + } + + public static void RefreshExeXipAlias(MipsBus bus) + { + if (bus == null || _aliasBusy) + return; + try + { + _aliasBusy = true; + uint proc = ProcessForXipAlias(bus); + if (proc != _aliasProc) + RebuildExeXipAlias(bus, proc); + } + catch + { + } + finally + { + _aliasBusy = false; + } + } + + public static uint MapDdiNopDestVa(uint va) + { + if (_ddiNopDestPeekRaw) + return va; + if (_ddiNopDestOn && _ddiNopSlot0 != 0) + { + if (va >= DdiNopVbase && va < 0x039B0000u) + va = _ddiNopSlot0 + (va - DdiNopVbase); + // Live 330f08b: ExtraRomDestKseg0 did not + // receive dest=0x01981000 stores. dest0 stays + // useg; MapFirmwareSlotVa walks firmware PTE. + if (va >= 0x01F57000u && va < 0x01F67000u) + return ExtraRomDestKseg1 + (va - 0x01F57000u); + } + // wait89: RI at 0x034B7DA8 dest-word 0x603E984F. + // TOC[46] vbase 0x034B0000. MapO32 steered + // 0x034B1000 -> 0x014B1000. startip 0x014B9D98 + // already fetched that dest (0x27BDFFA8). Linked + // 0x034B7DA8 is the same RVA. Slot-1 firmware + // PTE is miss (coredll sec). Use the steered + // dest. Do not invent dest bytes. Do not map + // page 0. Do not invent a slot map. + if (_mscoreeDestOn) + { + uint slot0 = va & SlotMask; + if (slot0 >= 0x014B0000u && slot0 < 0x014D0000u) + { + uint dest = ExtraRomDestKsegMscoree + (slot0 - 0x014B0000u); + if (!_tv2MscoreeSlotLogged && slot0 != va) + { + _tv2MscoreeSlotLogged = true; + System.Console.WriteLine("[Hive] FILE[25] mscoree dest 0x" + + va.ToString("X8") + " -> 0x" + dest.ToString("X8") + + " slot0=0x" + slot0.ToString("X8") + + " (MapO32 0x034B1000->0x014B1000; firmware CEDecompressROM; not invented dest; not a slot map)"); + } + return dest; + } + if (va >= 0x01F32000u && va < 0x01F33000u) + return ExtraRomDestKsegMscoree1 + (va - 0x01F32000u); + } + if (_ole32DestOn && _ole32Vbase != 0 && _ole32Slot0 != 0) + { + uint vbase = _ole32Vbase; + uint vbaseEnd = vbase + 0x40000u; + if (va >= vbase && va < vbaseEnd) + va = _ole32Slot0 + (va - vbase); + if (va >= 0x01940000u && va < 0x01980000u) + return ExtraRomDestKsegOle32 + (va - 0x01940000u); + } + return va; + } + + // Firmware VirtualAlloc returned a useg base the TLB has + // no PTE for (same class as ExtraROM dest). Host-back that + // returned range only. Not a static 0x000E0000 map. + // NULL+RESERVE uses CE 64K granularity (HeapAlloc of the + // 0x70 HEAP header then hands out +0x1700 in that reserve). + // Skip MEM_IMAGE and the process-info page. + private static readonly uint[] _vallocHostLo = new uint[16]; + private static readonly uint[] _vallocHostHi = new uint[16]; + private static readonly uint[] _vallocHostKseg = new uint[16]; + private static int _vallocHostN; + private static uint _vallocHostPool = VallocHostKseg; + + public static void TryHostBackValloc(uint baseVa, uint reqVa, uint size, uint type, bool alreadyMapped) + { + if (alreadyMapped || baseVa == 0 || baseVa >= 0x80000000u) + return; + if ((type & 0x01000000u) != 0) + return; + if ((type & 0x3000u) == 0) + return; + if (baseVa >= 0x00010000u && baseVa < 0x000CB000u) + return; + if (baseVa >= 0x01FFF000u && baseVa < 0x02000000u) + return; + if (size == 0) + size = 0x1000; + size = (size + 0xFFFu) & ~0xFFFu; + if (reqVa == 0 && (type & 0x2000u) != 0 && size < CeAllocGranularity) + size = CeAllocGranularity; + uint end = baseVa + size; + // CE returns a 64K-aligned base below dest + // (0x01F57000 -> 0x01F50000, 0x019A8000 -> 0x019A0000). + // Host-back [v0, dest+size] so ExtraROM o32.real + // (TOC[33] 0x01F57xxx / slot-0 0x019A8xxx) is covered. + // Not a static 0x000E0000 map. + if (reqVa != 0 && reqVa < 0x80000000u) + { + uint reqEnd = reqVa + size; + if (reqEnd > end) + end = reqEnd; + } + if (end <= baseVa) + return; + uint span = end - baseVa; + if (_vallocHostN >= _vallocHostLo.Length) + return; + uint kseg = _vallocHostPool; + if (kseg < VallocHostKseg || kseg + span > VallocHostKsegLim) + return; + _vallocHostLo[_vallocHostN] = baseVa; + _vallocHostHi[_vallocHostN] = end; + _vallocHostKseg[_vallocHostN] = kseg; + _vallocHostN++; + _vallocHostPool += span; + System.Console.WriteLine("[Hive] VALLOC host-back 0x" + + baseVa.ToString("X8") + "-0x" + end.ToString("X8") + + " -> 0x" + kseg.ToString("X8") + + " (firmware returned this; do not invent 0x000E0000)"); + } + + public static uint MapVallocHostVa(uint va) + { + if (va >= ExtraRomE32Host && va < ExtraRomE32HostLim) + return va; + for (int i = 0; i < _vallocHostN; i++) + { + if (va >= _vallocHostLo[i] && va < _vallocHostHi[i]) + return _vallocHostKseg[i] + (va - _vallocHostLo[i]); + } + return va; + } + + // Live edf15b0: process-info page had no PTE and + // KData peek missed. Host-back one zero 4K via + // the existing valloc pool. Do not invent heap. + private static bool TryHostBackProcessInfoPage() + { + uint lo = ProcessInfoPage; + uint hi = ProcessInfoPage + 0x1000u; + if (_ddiNopInfoKseg != 0) + return true; + if (VallocHostCovers(lo, hi)) + { + for (int i = 0; i < _vallocHostN; i++) + { + if (_vallocHostLo[i] <= lo && _vallocHostHi[i] >= hi) + { + _ddiNopInfoKseg = _vallocHostKseg[i]; + return _ddiNopInfoKseg != 0; + } + } + return false; + } + if (_vallocHostN >= _vallocHostLo.Length) + return false; + uint span = 0x1000u; + uint kseg = _vallocHostPool; + if (kseg < VallocHostKseg || kseg + span > VallocHostKsegLim) + return false; + _vallocHostLo[_vallocHostN] = lo; + _vallocHostHi[_vallocHostN] = hi; + _vallocHostKseg[_vallocHostN] = kseg; + _vallocHostN++; + _vallocHostPool += span; + _ddiNopInfoKseg = kseg; + return true; + } + + // wait42: DllMain dest+0x520 $fp=0x080E1970 is slot-4 of + // the LocalAlloc GDI object (heap 0x080E0000+0x1970). + // VALLOC(0x08000000) returned 0x080D0000, host-back ended + // 0x080E0000. Firmware HEAP is the next 64K (*heap=HeaP). + // Not a dump ExtraROM page. Not a static 0x000E0000 map. + // wait43/44: host-back of that 64K at HeapCreate copied=0 + // (no DestMapped words yet) hid the live firmware HEAP. + // Host-back only DestMapped pages. Retry after LocalAlloc + // (wait45: 0x080E0000-0x080E2000, dest+0x520 gone) and + // again at LoadDriver ret / AV-site for later HEAP pages + // (wait45 miss 0x080E7ECC). Not a dump 0x000E0000 map. + public static bool TryHostBackProcessHeap(MipsBus bus, uint heap) + { + return TryHostBackProcessHeap(bus, heap, 0); + } + + // wait48: AV-site host-back of 0x080E6000-0x080E9000 + // included GDI +0xC8 (0x000E8370 / page 0x080E8000). + // skipVa is that object; leave its 4K on firmware TLB. + // 0x080E7ECC is page 0x080E7000 (ddi_nop load). DestMapped + // only. Not a dump 0x000E0000 page. + public static bool TryHostBackProcessHeap(MipsBus bus, uint heap, uint skipVa) + { + if (bus == null || heap < 0x04000000u || heap >= 0x20000000u) + return false; + uint slot = heap & 0xFE000000u; + uint heapOff = heap & 0x01FFFFFF; + if (slot == 0 || heapOff < 0x000CB000u) + return false; + uint lo = heap & ~0xFFFFu; + uint hi = lo + CeAllocGranularity; + if (hi <= lo) + return false; + if (VallocHostCovers(lo, hi)) return false; - // LoadLibraryExW and CreateProcess already map TOC modules when - // this helper returns 2. DEVMGR CreateFile treats that miss as - // fatal. Filter LoadLibrary of sigcheckfilter.dll is the same - // miss: without this attach the entry ran a1=3 (not - // PROCESS_ATTACH) and FSDMGR never HookVolume. TOC[26] is - // already in this image (not FILESentry). - if (!NamesEqual(baseName, "devmgr.dll") - && !NamesEqual(baseName, "iptvcryptohal.dll") - && !NamesEqual(baseName, "ceddk.dll") - && !NamesEqual(baseName, "sigcheckfilter.dll")) + uint skipPage = 0; + if (skipVa != 0) + { + uint skipOff = skipVa & 0x01FFFFFF; + if ((skipOff & ~0xFFFFu) == (heapOff & ~0xFFFFu)) + skipPage = (slot | skipOff) & ~0xFFFu; + } + uint span = hi - lo; + uint[] words = new uint[span / 4]; + bool[] pageOk = new bool[span / 0x1000]; + uint copied = 0; + for (uint i = 0; i < span; i += 4) + { + try + { + words[i / 4] = bus.Read32(lo + i); + copied++; + pageOk[i / 0x1000] = true; + } + catch + { + words[i / 4] = 0; + } + } + if (copied == 0) + { + System.Console.WriteLine("[Hive] process-heap host-back skip heap=0x" + + heap.ToString("X8") + + " copied=0 (wait43/44 empty 64K hid live HEAP; not a dump 0x000E0000 page)"); return false; + } + bool installed = false; + int p = 0; + while (p < pageOk.Length) + { + uint page = lo + (uint)p * 0x1000u; + if (!pageOk[p] || (skipPage != 0 && page == skipPage)) + { + p++; + continue; + } + uint runLo = page; + int q = p + 1; + while (q < pageOk.Length && pageOk[q]) + { + uint n = lo + (uint)q * 0x1000u; + if (skipPage != 0 && n == skipPage) + break; + q++; + } + uint runHi = lo + (uint)q * 0x1000u; + if (!VallocHostCovers(runLo, runHi)) + { + InstallProcessHeapHost(bus, runLo, runHi, words, lo, heap, copied); + installed = true; + } + p = q; + } + return installed; + } - uint toc; - uint nmods; + private static bool VallocHostCovers(uint lo, uint hi) + { + for (int i = 0; i < _vallocHostN; i++) + { + if (_vallocHostLo[i] <= lo && _vallocHostHi[i] >= hi) + return true; + } + return false; + } + + private static void InstallProcessHeapHost(MipsBus bus, uint runLo, uint runHi, + uint[] words, uint wordBase, uint heap, uint copied) + { + if (_vallocHostN >= _vallocHostLo.Length || runHi <= runLo) + return; + uint span = runHi - runLo; + uint kseg = _vallocHostPool; + if (kseg < VallocHostKseg || kseg + span > VallocHostKsegLim) + return; + _vallocHostLo[_vallocHostN] = runLo; + _vallocHostHi[_vallocHostN] = runHi; + _vallocHostKseg[_vallocHostN] = kseg; + _vallocHostN++; + _vallocHostPool += span; try { - toc = bus.Read32(EcecTocPtr); - if (toc == 0) - return false; - nmods = bus.Read32(toc + RomHdrNumMods); + uint off = runLo - wordBase; + for (uint i = 0; i < span; i += 4) + { + uint va = runLo + i; + // wait49: do not host-back-overwrite GDI +0xC8 + // (0x000E1700+0xC8 / 0x080E17C8). Do not poke it. + if ((va & 0x01FFFFFF) == 0x000E17C8u) + { + System.Console.WriteLine("[Hive] process-heap host-back skip-word va=0x" + + va.ToString("X8") + " word=0x" + words[(off + i) / 4].ToString("X8") + + " (GDI +0xC8; not a dump 0x000E0000 page)"); + continue; + } + bus.Write32(kseg + i, words[(off + i) / 4]); + } } catch { - return false; } + System.Console.WriteLine("[Hive] process-heap host-back 0x" + + runLo.ToString("X8") + "-0x" + runHi.ToString("X8") + + " -> 0x" + kseg.ToString("X8") + + " heap=0x" + heap.ToString("X8") + + " copied=" + copied + + " (firmware HEAP pages; not a dump 0x000E0000 page)"); + } - if (nmods == 0 || nmods > 64) - return false; + // coredll HeapAlloc (0x03F796A4) keeps the heap in the + // process slot (0x080E0000) and returns the slot-0 view + // (0x000E1700). 0x800140A8 is jr $ra, so slot 0 never + // got those PTEs. Rewrite only the 64K that holds + // *0x01FFFFA0, and only past image end. Not a dump + // ExtraROM page. Not a static 0x000E0000 map. + // wait51: compare 0x0005BCA4 Read32(0x000E17C8) returned + // va unchanged (slot-0 zeros) while the write and AV-site + // used 0x080E17C8 -> 0x8F2217C8. No store of 0 after the + // set. Cache the proven slot so a busy/heap-ptr miss still + // hits that page. Do not poke +0xC8. + public const uint HeapSignature = 0x50616548; + private static bool _heapSlotBusy; + private static bool _heapSlotLogged; + private static uint _heapSlotCached; + private static uint _heapOffCached; + private static bool _heapSlotCacheLogged; + public static uint MapProcessHeapSlotVa(MipsBus bus, uint va) + { + if (bus == null || va >= 0x02000000u) + return va; + uint off = va & 0x01FFFFFF; + if (off < 0x000CB000u) + return va; + if (_heapSlotBusy) + return MapCachedHeapSlot(va, off, "busy"); try { - for (uint i = 0; i < nmods; i++) + _heapSlotBusy = true; + uint heap = bus.Read32(ProcessHeapPtr); + if (heap >= 0x000CB000u && heap < 0x02000000u + && _heapSlotCached != 0 + && (heap & ~0xFFFFu) == _heapOffCached) + heap = _heapSlotCached | (heap & 0x01FFFFFF); + if (heap < 0x04000000u || heap >= 0x20000000u) + return MapCachedHeapSlot(va, off, "heap-range"); + uint slot = heap & 0xFE000000u; + uint heapOff = heap & 0x01FFFFFF; + if (slot == 0 || heapOff < 0x000CB000u) + return MapCachedHeapSlot(va, off, "heap-slot"); + _heapSlotCached = slot; + _heapOffCached = heapOff & ~0xFFFFu; + if ((off & ~0xFFFFu) != _heapOffCached) + return va; + uint slotted = slot | off; + if (slotted == va) + return va; + if (!_heapSlotLogged) { - uint entry = toc + TocFirst + i * TocEntrySize; - uint name = bus.Read32(entry + 0x10); - if (!NamesEqual(baseName, ReadAscii(bus, name))) - continue; - uint tocAttr = bus.Read32(entry); - attr = (tocAttr & 0xFFFFEFFFu) | 0x2040u; - tocEntry = entry; - return true; + _heapSlotLogged = true; + System.Console.WriteLine("[Hive] process-heap slot-0 0x" + + va.ToString("X8") + " -> 0x" + slotted.ToString("X8") + + " heap=0x" + heap.ToString("X8") + + " (not a dump 0x000E0000 page)"); } + return slotted; } catch { - return false; + return MapCachedHeapSlot(va, off, "heap-read"); + } + finally + { + _heapSlotBusy = false; } + } - return false; + // wait51: compare saw slot-0 0x000E17C8 / +0xC8=0 with no + // store after 0x000631D4. Reuse the last *0x01FFFFA0 slot + // for that same 64K. Not a static 0x000E0000 map. + private static uint MapCachedHeapSlot(uint va, uint off, string why) + { + if (_heapSlotCached == 0 || _heapOffCached == 0) + return va; + if ((off & ~0xFFFFu) != _heapOffCached) + return va; + uint slotted = _heapSlotCached | off; + if (slotted == va) + return va; + if (!_heapSlotCacheLogged && (off & ~3u) == 0x000E17C8u) + { + _heapSlotCacheLogged = true; + System.Console.WriteLine("[Hive] process-heap slot-0 cache 0x" + + va.ToString("X8") + " -> 0x" + slotted.ToString("X8") + + " why=" + why + + " (wait51 compare missed live +0xC8; not a dump 0x000E0000 page)"); + } + return slotted; } - public static bool TryMissMissingDevice(MipsBus bus, uint path, uint[] regs, ref uint programCounter) + public static uint MapExeXipVa(MipsBus bus, uint va) { - if (bus == null || regs == null || regs.Length <= 31 || path == 0) - return false; + uint off = va & 0x01FFFFFF; + if (off < 0x00010000u || off >= 0x00100000u) + return va; + if (bus == null || _aliasBusy) + return va; try { - string name = Basename(bus, path); - if (string.IsNullOrEmpty(name)) - return false; - int n = name.Length; - if (n > 0 && name[n - 1] == ':') - n--; - if (n != 4) - return false; - if ((name[0] != 'B' && name[0] != 'b') - || (name[1] != 'T' && name[1] != 't') - || (name[2] != 'V' && name[2] != 'v') - || name[3] != '1') - return false; - regs[2] = 0xFFFFFFFFu; - programCounter = regs[31]; - return true; + _aliasBusy = true; + uint proc = ProcessForXipAlias(bus); + if (proc != _aliasProc) + RebuildExeXipAlias(bus, proc); } catch { - return false; + return va; } + finally + { + _aliasBusy = false; + } + if (!_aliasOn || off < _aliasReal || off >= _aliasEnd) + return va; + uint region = va & 0xFE000000u; + if (region != 0 && region != _aliasSlot) + return va; + return _aliasRom + (off - _aliasReal); } - public static void TryEnableFilterProcessAttach(MipsBus bus, uint[] regs) + private static uint ProcessForXipAlias(MipsBus bus) { - if (bus == null || regs == null || regs.Length <= 30) - return; + uint cur = bus.Read32(CurProc); try { - if ((regs[20] & CallDllFlag) != 0) - return; - uint module = regs[30]; - if (module == 0) - return; - if (bus.Read32(module + ModuleStartip) != FilterStartip) - return; - regs[20] |= CallDllFlag; + uint thr = bus.Read32(ThreadPtr); + if (thr != 0 && thr != 0xDEADBEEFu) + { + uint sp = bus.Read32(thr + ThreadStack); + uint slot = sp & 0xFE000000u; + if (slot >= 0x04000000u && slot < 0x20000000u) + { + uint bySlot = FindProcBySlot(bus, slot); + if (bySlot != 0) + return bySlot; + uint tproc = bus.Read32(thr + ProcSlot); + if (tproc != 0 && tproc != 0xDEADBEEFu) + return tproc; + } + } } catch { } + return cur; } - public static void TryFillTocStartip(MipsBus bus, uint module) + private static uint FindProcBySlot(MipsBus bus, uint slot) { - if (bus == null || module == 0) + for (uint i = 0; i < 16; i++) + { + uint p = ProcTable + i * ProcSize; + uint vm = bus.Read32(p + ProcSlot) & 0xFE000000u; + if (vm == slot) + return p; + } + return 0; + } + + private static void RebuildExeXipAlias(MipsBus bus, uint proc) + { + _aliasProc = proc; + _aliasOn = false; + _aliasSlot = 0; + _aliasReal = 0; + _aliasEnd = 0; + _aliasRom = 0; + if (proc == 0 || proc == 0xDEADBEEFu) return; - try + if (!TryBuildExeXipAlias(bus, proc) + && !TryBuildExeXipAlias(bus, proc + ProcModule)) { - if (bus.Read32(module + ModuleStartip) != 0) - return; - uint obj = module + ModuleFileObj; - if (bus.Read8(obj + 4) != TocAttachType) - return; - uint tocEntry = bus.Read32(obj); - if (tocEntry == 0) - return; - uint e32 = bus.Read32(tocEntry + 0x14); - if (e32 == 0) - return; - uint entryrva = bus.Read32(e32 + 4); - uint vbase = bus.Read32(e32 + 8); - if (entryrva == 0 || vbase < 0x03D00000u || vbase >= 0x04000000u) + uint p50 = 0; + try + { + p50 = bus.Read32(proc + ProcModule); + } + catch + { return; - bus.Write32(module + ModuleStartip, vbase + entryrva); + } + if (p50 != 0 && p50 != proc && p50 != proc + ProcModule) + TryBuildExeXipAlias(bus, p50); + } + } + + private static bool TryBuildExeXipAlias(MipsBus bus, uint module) + { + if (module == 0) + return false; + if (bus.Read8(module + ModuleFileObj + 4) != TocAttachType) + return false; + uint tocEntry = bus.Read32(module + ModuleFileObj); + if (tocEntry == 0) + return false; + uint e32 = bus.Read32(tocEntry + 0x14); + if (e32 == 0) + return false; + uint vbase = bus.Read32(e32 + 8); + if (vbase != ExeVbase) + return false; + uint objcnt = bus.Read32(e32) & 0xFFFF; + if (!TryGetTocO32(bus, tocEntry, objcnt, out uint o32Rom)) + return false; + uint vsize = bus.Read32(o32Rom); + uint dataptr = bus.Read32(o32Rom + 0xC); + uint real = bus.Read32(o32Rom + 0x10); + uint flags = bus.Read32(o32Rom + 0x14); + if (vsize == 0 || real == 0) + return false; + if (dataptr < 0x80000000u || dataptr >= 0xA0000000u) + return false; + if ((flags & O32Compressed) != 0) + return false; + uint vaWord = 0; + uint romWord = 0; + try + { + vaWord = bus.Read32(real); + } + catch + { + } + try + { + romWord = bus.Read32(dataptr); + } + catch + { + return false; + } + if (romWord == 0 || vaWord == romWord) + return false; + _aliasReal = real; + _aliasEnd = real + vsize; + _aliasRom = dataptr; + try + { + uint proc = bus.Read32(CurProc); + if (proc != 0 && proc != 0xDEADBEEFu) + _aliasSlot = bus.Read32(proc + ProcSlot) & 0xFE000000u; } catch { } + _aliasOn = true; + if (_aliasLoggedRom != dataptr) + { + _aliasLoggedRom = dataptr; + System.Console.WriteLine("[Hive] XIP alias 0x" + real.ToString("X8") + + "-0x" + (real + vsize).ToString("X8") + + " -> 0x" + dataptr.ToString("X8") + + " slot=0x" + _aliasSlot.ToString("X8")); + } + return true; } // 0x80018F9C walks o32_lite at 180($fp). device.exe PROCESS stores @@ -292,32 +50836,9 @@ private static bool TryGetTocO32(MipsBus bus, uint tocEntry, uint objcnt, out ui o32Rom = 0; if (tocEntry == 0) return false; - try - { - uint toc = bus.Read32(EcecTocPtr); - uint nmods = bus.Read32(toc + RomHdrNumMods); - if (nmods == 0 || nmods > 64) - return false; - for (uint i = 0; i < nmods; i++) - { - uint entry = toc + TocFirst + i * TocEntrySize; - if (entry != tocEntry) - continue; - uint e32 = bus.Read32(entry + 0x14); - uint o32 = bus.Read32(entry + 0x18); - if (e32 == 0 || o32 == 0) - return false; - if ((bus.Read32(e32) & 0xFFFF) != objcnt) - return false; - o32Rom = o32; - return true; - } - } - catch - { - return false; - } - return false; + if (TryGetTocO32In(bus, 0, 64, tocEntry, objcnt, 0, out o32Rom)) + return true; + return TryGetTocO32In(bus, ExtraRomToc(bus), 128, tocEntry, objcnt, 0, out o32Rom); } // ROM DLL vbases in this image are unique (HAL 0x03D90000, @@ -326,26 +50847,48 @@ private static bool TryGetTocO32(MipsBus bus, uint tocEntry, uint objcnt, out ui private static bool TryGetTocO32ByVbase(MipsBus bus, uint vbase, uint objcnt, out uint o32Rom) { o32Rom = 0; - if (vbase < 0x03D00000u || vbase >= 0x04000000u) + if (vbase < DdiNopVbase || vbase >= 0x04000000u) + return false; + if (TryGetTocO32In(bus, 0, 64, 0, objcnt, vbase, out o32Rom)) + return true; + return TryGetTocO32In(bus, ExtraRomToc(bus), 128, 0, objcnt, vbase, out o32Rom); + } + + private static bool TryGetTocO32In(MipsBus bus, uint tocOrZero, uint maxMods, + uint wantEntry, uint objcnt, uint wantVbase, out uint o32Rom) + { + o32Rom = 0; + if (bus == null) return false; try { - uint toc = bus.Read32(EcecTocPtr); + uint toc = tocOrZero; + if (toc == 0) + toc = bus.Read32(EcecTocPtr); + if (toc == 0) + return false; uint nmods = bus.Read32(toc + RomHdrNumMods); - if (nmods == 0 || nmods > 64) + if (nmods == 0 || nmods > maxMods) return false; uint found = 0; for (uint i = 0; i < nmods; i++) { uint entry = toc + TocFirst + i * TocEntrySize; + if (wantEntry != 0 && entry != wantEntry) + continue; uint e32 = bus.Read32(entry + 0x14); uint o32 = bus.Read32(entry + 0x18); if (e32 == 0 || o32 == 0) continue; if ((bus.Read32(e32) & 0xFFFF) != objcnt) continue; - if (bus.Read32(e32 + 8) != vbase) + if (wantVbase != 0 && bus.Read32(e32 + 8) != wantVbase) continue; + if (wantEntry != 0) + { + o32Rom = o32; + return true; + } if (found != 0) return false; found = o32; @@ -363,24 +50906,33 @@ private static bool TryGetTocO32ByVbase(MipsBus bus, uint vbase, uint objcnt, ou private static string Basename(MipsBus bus, uint path) { + if (bus == null || path == 0) + return ""; var sb = new System.Text.StringBuilder(); int start = 0; - for (int i = 0; i < 260; i++) + try { - uint p = path + (uint)(i * 2); - uint word = bus.Read32(p & ~3u); - uint ch = ((p & 2) == 0) ? (word & 0xFFFF) : (word >> 16); - if (ch == 0) - break; - if (ch == '\\' || ch == '/') + for (int i = 0; i < 260; i++) { - sb.Length = 0; - start = i + 1; - continue; + uint p = path + (uint)(i * 2); + uint word = bus.Read32(p & ~3u); + uint ch = ((p & 2) == 0) ? (word & 0xFFFF) : (word >> 16); + if (ch == 0) + break; + if (ch == '\\' || ch == '/') + { + sb.Length = 0; + start = i + 1; + continue; + } + if (ch < 0x20 || ch > 0x7E) + return ""; + sb.Append((char)ch); } - if (ch < 0x20 || ch > 0x7E) - return ""; - sb.Append((char)ch); + } + catch + { + return ""; } return start >= 0 ? sb.ToString() : ""; } @@ -546,6 +51098,194 @@ public static uint KeepProcessHeapIfCreateFailed(MipsBus bus, uint created, uint return created; } + // ExtraROM TOC[46] only. wait61 retry is \mscoree.dll.dll + // (same class as wait53 tv2clientce.exe.exe). Do not match + // mscoree3_5.dll (TOC[79]). + private static bool IsMscoreeDll(string name) + { + return NamesEqual(name, "mscoree.dll") + || NamesEqual(name, "mscoree.dll.dll"); + } + + // ExtraROM TOC[34] only. Do not match oleaut32.dll (TOC[35]). + private static bool IsOle32Dll(string name) + { + return NamesEqual(name, "ole32.dll") + || NamesEqual(name, "ole32.dll.dll"); + } + + // wait53 retry is \Windows\tv2clientce.exe.exe + private static bool IsTv2ClientCe(string name) + { + return NamesEqual(name, "tv2clientce.exe") + || NamesEqual(name, "tv2clientce.exe.exe"); + } + + // ExtraROM FILE type-8 OpenFile after FILE[25]+TOC[46]. + // FILE table names only. Do not match TOC type-7 + // (mscoree / ole32 / tv2engine / mscoree3_5 / zlib / + // uspce / raswrap / crypt32 / toolhelp). Do not invent + // xdrm.dll. FILE[25] stays IsTv2ClientCe. FILE[11]/[26] + // dest/cache stay ExtraRomFileDest 0x8F400000 class. + // Any other ExtraROM FILE[0..47] (RunOnce.exe FILE[32]) + // uses that same dest class when CE CreateFile/OpenFile + // asks. Do not attach ExtraROM TOC names as type-8. + private static readonly string[] ExtraRomOpenFileNames = + { + "mscorlib.dll", + "tv2clientcorece.dll", + "system.dll", + "system.core.dll", + "system.drawing.dll", + "system.web.services.dll", + "system.windows.forms.dll", + "system.xml.dll", + "broadcastservermanagedbridge_dvbs_ce.dll", + "managednetworkclient_dvbs_ce.dll" + }; + + public static bool IsExtraRomOpenFile(string name) + { + if (IsTv2ClientCe(name)) + return false; + if (FindCachedExtraRomToc(name) != null) + return false; + return ExtraRomOpenFileName(name).Length != 0; + } + + private static string ExtraRomOpenFileName(string name) + { + if (string.IsNullOrEmpty(name)) + return ""; + for (int i = 0; i < ExtraRomOpenFileNames.Length; i++) + { + string n = ExtraRomOpenFileNames[i]; + if (NamesEqual(name, n) || NamesMatchRom(name, n)) + return n; + if (NamesEqual(name, n + ".dll") || NamesEqual(name, n + ".exe")) + return n; + } + ExtraRomOpenFile slot = FindExtraRomOpenFile(name); + if (slot != null && !string.IsNullOrEmpty(slot.Label)) + return slot.Label; + return ""; + } + + private sealed class ExtraRomOpenFile + { + public int Index; + public uint Entry; + public uint[] Words; + public uint Name; + public uint[] NameWords; + public uint Real; + public uint Comp; + public uint Load; + public uint[] Data; + public string Label; + } + + private sealed class ExtraRomTocMod + { + public int Index; + public string Name; + public uint Entry; + public uint Attr; + public uint LoadVa; + public uint Dest; + public uint E32; + public uint O32; + public uint[] TocWords; + public uint[] E32Words; + public uint[] O32Words; + public uint LiveEntry; + public uint LiveE32; + public uint LiveO32; + public uint LiveName; + public uint Vbase; + public uint[] DataPtr; + public uint[] DataLen; + public uint[][] Data; + public bool Decompressed; + public uint DecompDest; + public bool LoadE32Ok; + public bool BuiltInSkip; + public bool FwMapO32; + public bool LoggedFwMapO32; + public bool LoggedFwMapInner; + public bool LoggedFwMap28844; + } + + // OpenExe retries \mscoree.dll.dll. Same suffix on any + // ExtraROM TOC name. Do not invent a second module. + private static string RomLookupName(string name) + { + name = FileBaseName(name); + if (string.IsNullOrEmpty(name) || name.Length < 8) + return name; + int n = name.Length; + if (n >= 8 + && ((name[n - 8] == '.' && (name[n - 7] == 'd' || name[n - 7] == 'D') + && (name[n - 6] == 'l' || name[n - 6] == 'L') + && (name[n - 5] == 'l' || name[n - 5] == 'L') + && name[n - 4] == '.' && (name[n - 3] == 'd' || name[n - 3] == 'D') + && (name[n - 2] == 'l' || name[n - 2] == 'L') + && (name[n - 1] == 'l' || name[n - 1] == 'L')) + || (name[n - 8] == '.' && (name[n - 7] == 'e' || name[n - 7] == 'E') + && (name[n - 6] == 'x' || name[n - 6] == 'X') + && (name[n - 5] == 'e' || name[n - 5] == 'E') + && name[n - 4] == '.' && (name[n - 3] == 'e' || name[n - 3] == 'E') + && (name[n - 2] == 'x' || name[n - 2] == 'X') + && (name[n - 1] == 'e' || name[n - 1] == 'E')))) + return name.Substring(0, n - 4); + return name; + } + + private static bool NamesMatchRom(string asked, string have) + { + if (NamesEqual(asked, have)) + return true; + if (string.IsNullOrEmpty(asked) || string.IsNullOrEmpty(have)) + return false; + if (NamesEqual(RomLookupName(asked), have)) + return true; + string askStem = StripRomExt(RomLookupName(asked)); + string haveStem = StripRomExt(have); + return NamesEqual(askStem, haveStem); + } + + // ExtraROM iptvhal_* TOC names. CE may CreateFile/LoadLibrary + // iptvhal.dll or iptvhal_*.dll. Do not invent a second GDI DDI. + private static bool IsIptvHalAsk(string name) + { + string stem = StripRomExt(RomLookupName(name)); + if (string.IsNullOrEmpty(stem) || stem.Length < 7) + return false; + return (stem[0] == 'i' || stem[0] == 'I') + && (stem[1] == 'p' || stem[1] == 'P') + && (stem[2] == 't' || stem[2] == 'T') + && (stem[3] == 'v' || stem[3] == 'V') + && (stem[4] == 'h' || stem[4] == 'H') + && (stem[5] == 'a' || stem[5] == 'A') + && (stem[6] == 'l' || stem[6] == 'L'); + } + + private static string StripRomExt(string name) + { + if (string.IsNullOrEmpty(name) || name.Length < 5) + return name; + int n = name.Length; + if (n >= 4 && name[n - 4] == '.' + && ((name[n - 3] == 'd' || name[n - 3] == 'D') + && (name[n - 2] == 'l' || name[n - 2] == 'L') + && (name[n - 1] == 'l' || name[n - 1] == 'L') + || (name[n - 3] == 'e' || name[n - 3] == 'E') + && (name[n - 2] == 'x' || name[n - 2] == 'X') + && (name[n - 1] == 'e' || name[n - 1] == 'E'))) + return name.Substring(0, n - 4); + return name; + } + private static bool NamesEqual(string a, string b) { if (string.IsNullOrEmpty(a) || string.IsNullOrEmpty(b) || a.Length != b.Length) diff --git a/Core/HostHardDisk.cs b/Core/HostHardDisk.cs index 4c7ed23f..56886d12 100644 --- a/Core/HostHardDisk.cs +++ b/Core/HostHardDisk.cs @@ -13,8 +13,63 @@ namespace ProcessorEmulator.Core // that root and its shallow children by name, case-insensitive. // Take what is present. The path need not contain Uverse. // Read-only: never write, delete, or rename dump files. Not a - // BINBlk/BINFS/ExtraROM object. If etc.bin is found, log it as - // the ExtraROM/XIP file hashes.bin already names; firmware maps it. + // BINBlk/BINFS object. Hunt every etc.bin plus any other B000FF + // sitting next to nk.bin. NkBinLoader maps each file's records + // at THAT file's imageStart so ExtraROM XIP (tv2clientce.exe + // and the rest) is in RAM. A Dumps\etc.bin\ extract folder is + // that same tree unpacked — log it, do not pack it into a fake + // B000FF. Firmware CreateFile of ETC.bin / BOOT.PRF / sec.bin + // is the Hard Disk path, not a second XIP. Firmware has no skip + // for the missing 0x81360000 image. Do not invent that map. + // Host drops leftover inherit pairs at publish/copy (start==0, + // start==end, end=32MB). Keep the NK pair. + // Do not CreateProcess(tv2clientce). + // + // filesys hive-init opens \Windows\boot.hv first. boot.hv + // BootVars Flags=3 (real DWORD). Low nibble != 0 starts + // device.exe and waits; Start DevMgr is not in that hive. + // SystemHive is Documents and Settings\system.hv, which is + // not on this volume. The NK FILESentry default.hv is 266240 + // uncompressed (compressed 65188 at 0x802FA8AC) and holds + // HKLM\init Launch20/30/56. Helper 0x0003EE14 already opens + // boot.hv. Clear the Flags nibble at 0x0002A7F8 so that + // same helper runs for \Windows\default.hv. Do not write + // Launch keys. Do not SetEvent. Do not invent 0x81360000. + // RunApps enums Launch20/30/50/53/56/95 then CreateProcess + // only after Depend WORDs are ready. Depend56 is 20/30/53. + // Launch record +4 is the ready slot. RunApps writes +4=1 + // only on CreateProcess fail or the device.exe / BootPhase2 + // miss. Success leaves +4=0. filesys 0x000177EC (coredll + // SignalStarted ordinal 639 → FILESYS API table 0x000111A8) + // matches a0 to record+0, writes +4=1, then EventModify + // (a1=3 SET) the unnamed event at 0x00059468 so the Depend + // WaitForMultipleObjects INFINITE at 0x000180A4 returns. + // gwes calls SignalStarted(_wtol(cmd)) at slotted 0x0001634C + // then OpenEvent + EventModify SYSTEM/GweApiSetReady (not + // GRAPHICS) at slotted 0x00016354. TOC[7] XIP text is + // 0x80146000 (VA 0x00011000); entry 0x8014B3C8 / WinMain + // 0x8014B014. CreateProcess sets the new thread PC to + // trampoline 0x8001FF38, which jalrs module+0x5C. + // 0x8001E960 skips that store when entryrva is 0. + // EXE jal/j are linked at VA 0x00010000; 0x800140A8 + // (ASID/slot attach) is jr $ra, so slot 0 still + // fetches filesys at 0x000163C8. Alias current-process + // XIP o32[0] to dataptr and keep startip as the VA. + // 0x8001DD6C skips CallDLL when +0x50 is useg/C2. + // After WinMain, the first gwes-thread INFINITE WFSO is + // coredll ThreadExceptionExit (0x03F74B18) waiting on + // its CreateThread handle (start 0x03FBF69C). Who + // signals it: that worker's ExitThread, not SetEvent. + // Log the exception that entered that path. Do not + // SetEvent. DisplayDll is inside 0x00024BE8 (Reg + // DisplayDll / Class). LoadDriver(ddi_nop.dll) is + // proven; TOC-attach ExtraROM TOC[33] on that miss. + // Do not invent 0x81360000. Do not SetEvent. + // Display=ddi_nop.dll (default.hv; ExtraROM + // TOC[33] vbase 0x03980000). Do not SetEvent GweApi or + // Launch30. Do not host CreateProcess(tv2clientce). + // ExtraROM FILE tv2clientce.exe is the 5120-byte stub, + // not the 90-byte root file. // // FSDMGR WFMO #2 (after BINBlk) is already waiting on the // BLOCK_DRIVER queue. Deliver HDProf there (7-char CE name). @@ -48,6 +103,129 @@ public static class HostHardDisk public const string FolderName = "Hard Disk"; public const uint Handle = 0xA15C0D15; public const uint KernelCreateFile = 0x8001D3A0; + // Inherit LIST path / VALLOC jal. Firmware skips a pair only + // when start==0 or start==end. Host filters leftovers at + // SaveList / memcpy of the 0x24 record. + public const uint InheritListPath = 0x8001B6EC; + public const uint InheritVallocJal = 0x8001B724; + public const uint InheritSaveList = 0x8001687C; + public const uint InheritMemcpy = 0x80016A44; + public const uint BinfsInheritFill = 0x03EA2B84; + public const uint InheritRecordSize = 0x24; + public const uint InheritSlotBytes = 0x02000000; + // hive-init 0x0002A5E8: Flags nibble gate, then the existing + // \Windows\default.hv helper. RunApps 0x00017BAC is the + // HKLM\init open that was ERROR_BADKEY on boot.hv alone. + public const uint HiveFlagsGate = 0x0002A7F8; + public const uint HiveDefaultOpen = 0x0002ACD0; + public const uint HiveDefaultOpenRet = 0x0002ACD8; + public const uint RunAppsInitChk = 0x00017BAC; + public const uint RunAppsLaunchCmp = 0x00017C58; + public const uint RunAppsDependMiss = 0x00017FB0; + public const uint RunAppsCprocRet = 0x00018080; + // FILESYS API: coredll SignalStarted. Writes launch +4. + public const uint FilesysSignalStarted = 0x000177EC; + public const uint LaunchCountPtr = 0x00059460; + public const uint LaunchReadyEvent = 0x00059468; + public const uint LaunchTablePtr = 0x0005946C; + public const uint LaunchRecordSize = 0x250; + // gwes preferred 0x00010000; lives in a CE 32MB slot. + // Slot 0 is filesys — do not treat 0x0001634C there as gwes. + public const uint GwesSignalStarted = 0x0001634C; + public const uint GwesGweApiReady = 0x00016354; + public const uint GwesVaEntry = 0x000163C8; + public const uint GwesVaWinMain = 0x00016014; + public const uint GwesVaDisplayDll = 0x00024CD4; + public const uint GwesVaDisplayFn = 0x00024BE8; + public const uint GwesVaWinMainJal = 0x00016088; + public const uint GwesVaWinMainSkip = 0x00016394; + public const uint GwesInitFlag = 0x000B7A1D; + public const uint GwesRomInitFlag = 0x801EAA1D; + public const uint FilesysRomText = 0x80105000; + public const uint CeSlotMask = 0x01FFFFFF; + public const uint CeSlotBase = 0xFE000000; + // TOC[7] o32[0] dataptr; VA = ROM - GwesRomText + 0x00011000. + public const uint GwesRomText = 0x80146000; + public const uint GwesRomTextEnd = 0x801EADE0; + public const uint GwesRomEntry = 0x8014B3C8; + public const uint GwesRomWinMain = 0x8014B014; + public const uint GwesRomSignal = 0x8014B34C; + public const uint GwesRomGweApi = 0x8014B354; + public const uint GwesRomDisplayDll = 0x80159CD4; + public const uint GwesRomDisplayFn = 0x80159BE8; + public const uint GwesSlot = 0x08000000; + public const uint DdiNopVbase = 0x03980000; + public const uint DdiNopVend = 0x039B0000; + public const uint DdiNopEntry = 0x03998014; + public const uint DdiNopSlot0 = 0x01980000; + public const uint DdiNopSlot0Vend = 0x019B0000; + public const uint DdiNopSlot0Entry = 0x01998014; + public const uint CoredllActivateDevice = 0x03F6AD08; + public const uint CoredllActivateDeviceEx = 0x03F6AD54; + public const uint CoredllExitThread = 0x03F74844; + public const uint CoredllLoadLibraryW = 0x03F6CB50; + public const uint CoredllLoadLibraryExW = 0x03F6C84C; + public const uint CoredllWaitSo = 0x03F6B9AC; + public const uint CoredllWaitMo = 0x03F6B914; + // WinMain first jal is SetKMode. The later INFINITE + // WFSO is ThreadExceptionExit waiting on its + // CreateThread handle (not an event). Do not SetEvent. + public const uint CoredllSetKMode = 0x03F71098; + public const uint CoredllCreateThread = 0x03F71E04; + public const uint CoredllThreadExceptionExit = 0x03F74B18; + public const uint CoredllIsApiReady = 0x03F73240; + public const uint CoredllLoadDriver = 0x03F70C74; + public const uint CoredllLoadDriverRet = 0x03F70C88; + public const uint CoredllMessageBoxW = 0x03F8A500; + public const uint ExceptionWorker = 0x03FBF69C; + public const uint GwesVaAfterKmode = 0x00016090; + public const uint GwesVaHeapCreate = 0x00048C8C; + public const uint GwesVaDisplayParent = 0x00023C60; + public const uint GwesVaAvHelper = 0x0005377C; + public const uint GwesVaAvCaller = 0x0005BCF8; + // wait46: C0000005 at 0x00053944 is lhu 4(a0). + // 0x0005BCA4 jal 0x00053938; delay lw a0, 0xC8(a0) + // (GDI +0xC8). Then lhu 4(a1) / lhu 4(a0). Not a dump + // 0x000E0000 page. Do not SetEvent. + public const uint GwesVaAvCompare = 0x00053938; + public const uint GwesVaAvCompareLhu = 0x00053944; + public const uint GwesVaAvCompareCaller = 0x0005BCA4; + // wait47: firmware writes GDI +0xC8. 0x000631D4 stores + // jal 0x00054038 (0x000E8370). 0x00063254 stores v0 + // (0 if later init failed). Do not poke +0xC8. + public const uint GwesVaC8StoreSet = 0x000631D4; + public const uint GwesVaC8StoreClr = 0x00063254; + public const uint GwesRomC8StoreSet = 0x801981D4; + public const uint GwesRomC8StoreClr = 0x80198254; + public const uint GwesDispObj = 0x000BA954; + public const uint GwesDispC8Off = 0xC8; + // 0x0005D24C addiu a0, 584; jal 0x000B4D20 (IAT 0x000B60D0). + // wait42: ExtraROM dest host-back [v0, dest+size] — LoadDriver + // v0=0x86F36EA0. DllMain dest+0x520 TLB $fp=0x080E1970 + // (slot-4 view of the GDI object). Do not invent 0x000E0000. + public const uint GwesVaDispAlloc = 0x0005D250; + public const uint GwesVaDispAllocRet = 0x0005D258; + public const uint GwesVaDispStore = 0x0005D288; + public const uint GwesIatLocalAlloc = 0x000B60D0; + public const uint GwesIatGetProc = 0x000B6008; + public const uint GwesIatLoadLib = 0x000B600C; + public const uint GwesIatHeapCreate = 0x000B621C; + public const uint ExceptionVector = 0x80000180; + public const uint OemIdle = 0x80059E98; + public const uint OemIdleLoop = 0x80059D20; + public const uint FilesysCreateProcess = 0x0004BCA4; + public const uint KernelCreateProcess = 0x80034D2C; + public const uint KernelValloc = 0x800283FC; + public const uint ThreadStartTrampoline = 0x8001FF38; + public const uint ThreadContextSetup = 0x80020BE4; + public const uint ThreadCtxPc = 0xEC; + public const uint ThreadStartip = 0x5C; + public const uint ThreadStack = 0x24; + public const uint ThreadProc = 0x0C; + public const uint ProcModule = 0x50; + public const uint ErrorBadKey = 0x3F2; + public const uint ThreadPtr = 0xFFFFDAC0; + public const uint ThreadLastErr = 56; // mspart PD_OpenStore calls this FSDMGR export, not binfs IAT 0x03EA4140. public const uint FsdmgrIoImpl = 0x03E83C08; // mspart GetDiskInfo / OpenStore uses these FSDMGR @@ -91,19 +269,61 @@ public static class HostHardDisk private static string _root = ""; private static string _offeredFeed = ""; - private static string _extraRom = ""; + private static string _nkDir = ""; + private static readonly List _extraRoms = new List(); private static byte[] _image = Array.Empty(); private static bool _notified; private static bool _detailFilled; private static bool _opened; private static bool _fatSeen; private static readonly HashSet _logged = new HashSet(StringComparer.OrdinalIgnoreCase); + private static bool _inheritListLogged; + private static readonly HashSet _vallocLogged = new HashSet(); + private static bool _extractLogged; + private static bool _hiveFlagsLogged; + private static string _cprocName = ""; + private static string _pendingLoadLib = ""; + private static uint _cprocRa; + private static uint _cprocThread; + private static bool _gwesWatch; + private static bool _gwesIn; + private static uint _gwesLastPc; + private static uint _stepPc; + private static bool _c8WriteBusy; + private static bool _gwesSummary; + private static bool _gwesSawExit; + private static bool _gwesSawWait; + private static bool _gwesSawDdi; + private static bool _gwesSawSignal; + private static bool _gwesSawThrEx; + private static bool _gwesSawCreateThr; + private static bool _gwesSawWorker; + private static int _gwesExnLogged; + private static int _ddiPcLogged; + private static uint _gwesThr; + private static uint _vallocRa; + private static uint _vallocA0; + private static uint _vallocA1; + private static uint _vallocA2; public static bool IsPresent => _image != null && _image.Length > 0; public static bool IsOpen => _opened; public static bool DetailFilled => _detailFilled; public static string Root => _root; - public static string ExtraRomPath => _extraRom; + public static string ExtraRomPath + { + get + { + foreach (string p in _extraRoms) + { + if (Path.GetFileName(p).Equals("etc.bin", StringComparison.OrdinalIgnoreCase)) + return p; + } + return _extraRoms.Count > 0 ? _extraRoms[0] : ""; + } + } + + public static IReadOnlyList ExtraRomPaths => _extraRoms; public static void OfferFeed(string path) { @@ -114,13 +334,38 @@ public static void OfferFeed(string path) public static void Attach() { _root = ""; - _extraRom = ""; + _nkDir = ""; + _extraRoms.Clear(); _image = Array.Empty(); _notified = false; _detailFilled = false; _opened = false; _fatSeen = false; _logged.Clear(); + _inheritListLogged = false; + _vallocLogged.Clear(); + _extractLogged = false; + _hiveFlagsLogged = false; + _cprocName = ""; + _cprocRa = 0; + _cprocThread = 0; + _gwesWatch = false; + _gwesIn = false; + _gwesLastPc = 0; + _stepPc = 0; + _c8WriteBusy = false; + _gwesSummary = false; + _gwesSawExit = false; + _gwesSawWait = false; + _gwesSawDdi = false; + _gwesSawSignal = false; + _gwesSawThrEx = false; + _gwesSawCreateThr = false; + _gwesSawWorker = false; + _gwesExnLogged = 0; + _ddiPcLogged = 0; + _gwesThr = 0; + CeRomTocFiles.ResetExeXipAlias(); string dir = ResolveRoot(); if (string.IsNullOrEmpty(dir)) { @@ -132,8 +377,11 @@ public static void Attach() _image = Fat16.Build(dir); _root = dir; System.Console.WriteLine($"[HardDisk] FAT {_image.Length} bytes root={dir} name={FolderName}"); - if (!string.IsNullOrEmpty(_extraRom)) - System.Console.WriteLine("[HardDisk] ExtraROM etc.bin at " + _extraRom + " (firmware names ETC.BIN; not mapped here)"); + NoteDumpImages(dir); + if (!string.IsNullOrEmpty(_nkDir)) + NoteDumpImages(_nkDir); + foreach (string extra in _extraRoms) + System.Console.WriteLine("[HardDisk] ExtraROM candidate " + extra); RememberLastUsed(dir); } catch (Exception ex) @@ -149,12 +397,401 @@ public static bool TryStep(uint[] registers, MipsBus bus, ref uint programCounte return false; uint pc = programCounter; + _stepPc = pc; + CeRomTocFiles.TryResumeTv2LeftoverFetch(bus, registers, ref programCounter); + // wait128: leftover dest-live I-fetch of leftover + // mid / ERET2 is logged here before leftover + // FetchInstruction. leftover dest-live keep hops + // leftover dest-live next / leftover ctxPC / + // leftover PC to dest-live next / PC+4 before + // leftover I-fetches leftover mid / ERET2. + // leftover after dest-live delay+4, including + // leftover interrupt, stays dest-live next / + // PC+4, not leftover mid / ERET2. + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(bus, registers, ref programCounter); + CeRomTocFiles.TryKeepLeftoverDestLiveDispatch(bus, programCounter); + pc = programCounter; + CeRomTocFiles.TryWatchExtraRomLoadE32(bus, registers, pc); + if (pc == BinfsInheritFill) + { + uint plus14 = registers[12]; + uint plus18 = registers[24]; + uint start = plus14 << 16; + if (BadInheritPair(start, plus18)) + System.Console.WriteLine("[Inherit] skip +14=0x" + plus14.ToString("X8") + + " +18=0x" + plus18.ToString("X8") + + " start=0x" + start.ToString("X8") + + " end=0x" + plus18.ToString("X8")); + return false; + } + if (pc == InheritSaveList) + { + if (registers[4] == InheritRecordSize) + CompactInheritRecord(bus, registers[5]); + return false; + } + if (pc == InheritMemcpy) + { + if (registers[6] == InheritRecordSize) + CompactInheritRecord(bus, registers[5]); + return false; + } + if (pc == InheritListPath) + { + LogInheritList(bus, registers[2]); + return false; + } + if (pc == InheritVallocJal) + { + uint a0 = registers[4]; + uint a1 = registers[5]; + uint a2 = registers[6]; + if (_vallocLogged.Add(a0)) + System.Console.WriteLine("[Inherit] VALLOC a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " a2=0x" + a2.ToString("X8")); + return false; + } + if (pc == KernelValloc) + CeRomTocFiles.TryReserveExtraRomValloc(registers); + if (pc == KernelValloc && (!string.IsNullOrEmpty(_cprocName) + || _logged.Contains("hive:ldde32") + || _gwesWatch + || CeRomTocFiles.IsTv2FileExpanded())) + { + uint a0 = registers[4]; + uint a1 = registers[5]; + uint a2 = registers[6]; + string who = !string.IsNullOrEmpty(_cprocName) ? _cprocName + : (_gwesWatch && !_logged.Contains("hive:ldde32") ? "gwes.exe" : "LoadE32"); + if (_logged.Add("hive:va:" + who + ":" + a0.ToString("X"))) + System.Console.WriteLine("[Hive] VALLOC \"" + who + + "\" a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " a2=0x" + a2.ToString("X8")); + // CreateProcess(gwes) VALLOC(NULL, 0x70) returns + // before _gwesWatch. That reservation is the + // LocalAlloc 0x000E1700 page. Capture gwes returns + // during load, not only after watch. + bool gwesLoad = !string.IsNullOrEmpty(_cprocName) + && _cprocName.IndexOf("gwes", StringComparison.OrdinalIgnoreCase) >= 0; + if ((_gwesWatch || gwesLoad || _logged.Contains("hive:ldde32")) + && registers.Length > 31) + { + _vallocRa = registers[31]; + _vallocA0 = a0; + _vallocA1 = a1; + _vallocA2 = a2; + } + if (registers.Length > 31) + CeRomTocFiles.NoteTv2PeImageValloc(a0, a1, a2, registers[31]); + return false; + } + if (CeRomTocFiles.TryFinishTv2PeImageValloc(pc, + registers != null && registers.Length > 2 ? registers[2] : 0)) + return false; + if (_vallocRa != 0 && pc == _vallocRa) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + LogVallocRet(bus, v0); + _vallocRa = 0; + return false; + } + if (pc == CeRomTocFiles.MapO32VallocRet + && (_logged.Contains("hive:ldde32") + || _logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32")) + && registers != null && registers.Length > 4) + { + uint dest = registers.Length > 20 ? registers[20] : 0; + if (dest == 0 && registers.Length > 4) + dest = registers[4]; + CeRomTocFiles.NoteExtraRomVallocRet(dest, registers[2]); + return false; + } + if (pc == ThreadContextSetup && !string.IsNullOrEmpty(_cprocName)) + { + LogCprocThreadCtx(registers, bus); + return false; + } + if (pc == CeRomTocFiles.C2SpFirstPc + || pc == CeRomTocFiles.ThreadCtxRestore + || pc == CeRomTocFiles.ThreadCtxRestore2 + || pc == CeRomTocFiles.ThreadCtxEret) + { + if (pc == CeRomTocFiles.ThreadCtxRestore + || pc == CeRomTocFiles.ThreadCtxRestore2) + CeRomTocFiles.TryNoteTv2ThreadRestore(bus, registers, pc); + if (CeRomTocFiles.TryRefuseC2SpResume(bus, registers, ref programCounter)) + return true; + if (pc == CeRomTocFiles.ThreadCtxRestore2 + && CeRomTocFiles.TryForceTv2EretSlowPath(bus, registers, ref programCounter)) + return true; + return false; + } + if (pc == CeRomTocFiles.ThreadSwitchProcChk) + { + CeRomTocFiles.TryKeepTv2ThreadOwner(bus, "switcher"); + if (CeRomTocFiles.TryForceTv2ProcSwitch(bus, registers, ref programCounter)) + return true; + return false; + } + if (pc == CeRomTocFiles.ThreadSwitchProcStore) + { + CeRomTocFiles.TryNoteTv2ProcSwitchStore(bus, registers, pc); + return false; + } + if (pc == ThreadStartTrampoline) + { + CeRomTocFiles.TryFillProcExeStartip(bus); + CeRomTocFiles.TryNoteTv2ProcSwitch(bus); + LogThreadTrampoline(registers, bus); + return false; + } + if (pc == CeRomTocFiles.LoadExeE32Ret) + { + CeRomTocFiles.TryLogExtraRomLoadE32(bus, registers, true, ReadLastError(bus)); + CeRomTocFiles.TryFinishNkLoadE32(bus, registers); + CeRomTocFiles.TryNoteTv2LoadExeE32(bus, registers, pc); + CeRomTocFiles.TryFillProcExeStartip(bus); + LogLoadExeStartip(bus); + return false; + } + if (pc == CeRomTocFiles.LoadExeStartipRet) + { + CeRomTocFiles.TryKeepTv2FileStartip(bus, registers, pc); + CeRomTocFiles.TryFillProcExeStartip(bus); + return false; + } + if (pc == CeRomTocFiles.LoadO32WrapStartip) + { + if (CeRomTocFiles.TryFeedCoredllCallDll(bus, registers, ref programCounter)) + return true; + return false; + } + if (pc == CeRomTocFiles.CallDllStartip) + { + CeRomTocFiles.NoteDdiNopCallDllPc(bus, registers, pc); + CeRomTocFiles.TryFeedCoredllCallDllStartip(bus, registers); + CeRomTocFiles.TryFillTocStartip(bus, registers[23], true); + LogCallDllStartip(registers, bus); + return false; + } + if (pc == CeRomTocFiles.CallDllAfterJalr + && _logged.Contains("hive:ldde32")) + { + LogCallDllAfterJalr(registers, bus); + return false; + } + if (pc == CeRomTocFiles.XipCallDllUsegChk) + { + CeRomTocFiles.NoteDdiNopCallDllPc(bus, registers, pc); + // Live c231655: hive:ddi:words is DumpDdiNopEntry + // of dump-XIP / slot0 entry observe, not a + // reason to refuse VALLOC CallDLL force. + if (CeRomTocFiles.TryForceDdiNopCallDll(bus, registers, ref programCounter)) + return true; + if (CeRomTocFiles.TryFeedCoredllCallDll(bus, registers, ref programCounter)) + return true; + return false; + } + if (pc == CeRomTocFiles.XipExeCallDllSkip) + { + CeRomTocFiles.NoteDdiNopCallDllPc(bus, registers, pc); + if (CeRomTocFiles.TryForceDdiNopCallDll(bus, registers, ref programCounter)) + return false; + LogXipExeCallDllSkip(registers, bus); + return false; + } + if (pc == HiveFlagsGate) + { + TryRomDefaultHive(registers, bus); + return false; + } + if (pc == HiveDefaultOpen) + { + LogHiveHelper(registers, bus); + return false; + } + if (pc == HiveDefaultOpenRet) + { + LogHiveHelperRet(registers); + return false; + } + if (pc == RunAppsInitChk) + { + LogRunAppsInit(registers); + return false; + } + if (pc == RunAppsLaunchCmp) + { + LogRunAppsLaunch(registers, bus); + return false; + } + if (pc == RunAppsDependMiss) + { + LogRunAppsDepend(registers, bus); + return false; + } + if (pc == FilesysSignalStarted) + { + LogSignalStarted(registers, bus); + return false; + } + // CE user slots are 0x02000000..0x20000000. 0x8001634C is + // KSEG0 filesys, not gwes (slot 0 / filesys owns 0x0001634C). + uint slot = pc >> 25; + if (slot >= 1 && slot <= 16) + { + uint gwesOff = pc & CeSlotMask; + if (gwesOff == GwesSignalStarted || gwesOff == GwesGweApiReady) + { + LogGwesReadySite(pc, gwesOff, registers, bus); + return false; + } + } + if (pc == CeRomTocFiles.BinaryDecompressRom) + CeRomTocFiles.TryNoteExtraRomDecompressEntry(bus, registers); + if (pc == CeRomTocFiles.BinaryDecompressInner) + CeRomTocFiles.TryNoteExtraRomInnerDest(bus, registers); + if (pc == CeRomTocFiles.BinaryDecompressAfterInner) + CeRomTocFiles.TryNoteExtraRomInnerRet(registers); + if (CeRomTocFiles.TryFinishTv2FileDecompress(bus, registers, pc)) + return false; + if (CeRomTocFiles.TryNoteExtraRomDecompressRet(bus, registers, pc)) + return false; + if (pc == CeRomTocFiles.KernelReadFile + && CeRomTocFiles.TryServeTv2FileRead(bus, registers, ref programCounter)) + return true; + if (pc == CeRomTocFiles.KernelCreateFileMapping + && CeRomTocFiles.TryServeTv2FileMap(registers, ref programCounter)) + return true; + if (_logged.Contains("hive:ldde32")) + CeRomTocFiles.TryNoteExtraRomBindImp(bus, registers, pc); + CeRomTocFiles.TryNoteTv2BindImp(bus, registers, pc); + if (pc == CeRomTocFiles.MapO32Decompress + && (_logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32")) + && CeRomTocFiles.TryRedirectExtraRomMapO32Decompress( + bus, registers, ref programCounter)) + return false; + if (pc == CeRomTocFiles.MapO32RomEpilogue + && (_logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32"))) + CeRomTocFiles.TryLogMscoreeMapO32Ret(bus, registers); + if (pc == CeRomTocFiles.MapO32VirtualCopy + && (_logged.Contains("hive:ldde32") + || _logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32")) + && CeRomTocFiles.TryRedirectExtraRomVirtualCopyToDecompress( + bus, registers, ref programCounter)) + return false; + CeRomTocFiles.TryCacheLiveCoredllSec(bus, pc); + CeRomTocFiles.TryNoteTv2StartipFetch(bus, pc); + CeRomTocFiles.TryNoteTv2StartipContinue(bus, pc); + CeRomTocFiles.TryNoteTv2CoredllFetch(bus, pc); + CeRomTocFiles.TryNoteTv2CoredllContinue(bus, pc); + CeRomTocFiles.TryNoteTv2HighContinue(bus, pc); + CeRomTocFiles.TryNoteTv2ImplicitContinue(bus, pc, registers); + CeRomTocFiles.TryNoteTv2ImplicitPast(bus, pc, registers); + CeRomTocFiles.TryNoteTv2StoreContinue(bus, pc, registers); + CeRomTocFiles.TryNoteTv2LeftoverPast(bus, pc); + CeRomTocFiles.TryNoteTv2LeftoverPastCae8(bus, registers, pc); + CeRomTocFiles.TryNoteTv2LeftoverPastCaf0(bus, pc); + if (CeRomTocFiles.TryRefuseLeftoverWait99Wrap(bus, registers, ref programCounter)) + return true; + if (CeRomTocFiles.TryFixWait99PlantRa(bus, registers, ref programCounter)) + return true; + CeRomTocFiles.TryNoteLeftoverCstkObserve(bus, registers, pc); + CeRomTocFiles.TryFixLeftoverCstkRa(bus, registers, pc); + CeRomTocFiles.TryNoteLeftoverCstkSpin(bus, registers, pc); + if (CeRomTocFiles.TryNoteLeftoverWait99Spin(bus, registers, pc)) + return true; + CeRomTocFiles.TryNoteLeftoverRetObserve(bus, registers, pc); + CeRomTocFiles.TryFixLeftoverRetRa(bus, registers, pc); + if (CeRomTocFiles.TryRefuseMinusOnePlant(bus, registers, ref programCounter)) + return true; + CeRomTocFiles.TryRestoreTv2LeftoverEret(bus, registers, pc); + CeRomTocFiles.TryRestoreTv2LeftoverDestLiveEret(bus, registers, pc); + CeRomTocFiles.TryResumeTv2LeftoverAfterCaf0(bus, registers, ref programCounter); + CeRomTocFiles.TryKeepTv2LeftoverS6(bus, registers, programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastAfterCaf0(bus, programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb0c(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb10(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb14(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb14(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb34(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb34(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb38(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb38(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb3c(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb3c(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb40(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb40(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb44(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb44(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb48(bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb48(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastCb4c(bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb4c(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastJrRa(bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterJrRa(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastBeqRaFt(bus, programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastBeqRaTk(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterBPlus2(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastBPlus2Delay(bus, programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastBPlus2Taken(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterBPlus2Taken(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastBPlus2Next(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterFp(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastFpNext(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS7(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastS7Next(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS6(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastS6Next(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS5(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastS5Next(bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS4(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastS4Next(bus, programCounter); + CeRomTocFiles.TryNoteTv2LeftoverDrop(bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastEpilogue(bus, registers, programCounter); + CeRomTocFiles.TryNoteTv2LeftoverPastEpilogueDelay(bus, registers, programCounter); + CeRomTocFiles.TryNoteTv2GwesFetch(bus, pc); + CeRomTocFiles.TryNoteTv2GwesContinue(bus, pc); + CeRomTocFiles.TryNoteTv2ZeroDestContinue(bus, pc); + CeRomTocFiles.TryNoteTv2AfterExnContinue(bus, pc); + CeRomTocFiles.TryNoteTv2ExnHelper(bus, registers, pc); + CeRomTocFiles.TryNoteTv2CurThread(bus); + ObserveGwesPath(pc, registers, bus); + if (pc == FilesysCreateProcess + || (pc == KernelCreateProcess && _cprocRa == 0)) + { + LogHiveCreateProcess(registers, bus); + return false; + } + if (_cprocRa != 0 && (pc == _cprocRa || pc == RunAppsCprocRet)) + { + LogHiveCreateProcessRet(registers, bus); + return false; + } if (pc == KernelCreateFile) { string kn = ReadUtf16(bus, registers[4]); + if (!string.IsNullOrEmpty(kn)) + CeRomTocFiles.NotePendingRomFile(kn); if ((_notified || IsHardDiskPath(kn)) && _logged.Add("k:" + kn)) System.Console.WriteLine($"[HardDisk] kCreateFile \"{kn}\""); + if (BootLog.IsGuestIoName(kn) && _logged.Add("rom:cf:" + kn)) + BootLog.Rom("ok", "ExtraROM", "", -1, kn, 0, 0, 0, 0, + "CreateFile guest IO name; no NIC on the MIPS bus; do not invent a NIC or UART"); LogKernelCreateFile(bus, registers[4]); + LogTv2CreateFile(registers, bus, kn); + return false; + } + if (pc == CeRomTocFiles.CreateFileFail) + { + LogCreateFileFail(registers, bus); return false; } @@ -526,7 +1163,89 @@ private static void LogKernelCreateFile(MipsBus bus, uint path) return; string host = MapHost(_root, name); bool hit = !string.IsNullOrEmpty(host) && File.Exists(host); - System.Console.WriteLine($"[HardDisk] CreateFile \"{name}\" host={(hit ? host : "miss")} fat={(IsPresent ? "yes" : "no")}"); + BootLog.Write("[HardDisk] CreateFile \"" + name + "\" host=" + (hit ? host : "miss") + + " fat=" + (IsPresent ? "yes" : "no")); + if (!hit) + BootLog.Rom("miss", "NK", "", -1, name, 0, 0, 0, 0, + "CreateFile host miss; do not invent the file"); + } + + // wait52: probe died at CreateFileFail 0x8001D400 reading + // s7=0x040851E8. Log the path and slot-0 view. Do not + // invent that page. Do not host CreateProcess tv2clientce. + private static void LogTv2CreateFile(uint[] registers, MipsBus bus, string name) + { + bool tv2 = (!string.IsNullOrEmpty(_cprocName) + && _cprocName.IndexOf("tv2", StringComparison.OrdinalIgnoreCase) >= 0) + || (!string.IsNullOrEmpty(name) + && name.IndexOf("tv2", StringComparison.OrdinalIgnoreCase) >= 0); + if (!tv2) + return; + if (!_logged.Add("hive:kcf:tv2:" + (name ?? ""))) + return; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + System.Console.WriteLine("[Hive] CreateFile tv2 a0=0x" + a0.ToString("X8") + + " \"" + (name ?? "") + "\"" + + " cproc=\"" + _cprocName + "\"" + + " a0-mapped=" + (DestMapped(bus, a0) ? "yes" : "no") + + " (firmware OpenExe; do not host CreateProcess)"); + if (!string.IsNullOrEmpty(name)) + CeRomTocFiles.NotePendingRomFile(name); + } + + private static void LogCreateFileFail(uint[] registers, MipsBus bus) + { + uint s7 = registers != null && registers.Length > 23 ? registers[23] : 0; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint fp = registers != null && registers.Length > 30 ? registers[30] : 0; + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + if (!_logged.Add("hive:cfile:fail:" + s7.ToString("X") + ":" + a0.ToString("X"))) + return; + string pathS7 = ReadUtf16(bus, s7); + string pathA0 = ReadUtf16(bus, a0); + uint slot0 = s7 & CeSlotMask; + uint proc = 0; + TryReadWord(bus, CeRomTocFiles.CurProc, out proc); + System.Console.WriteLine("[Hive] CreateFileFail pc=0x8001D400" + + " s7=0x" + s7.ToString("X8") + + " slot0=0x" + slot0.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " fp=0x" + fp.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " CurProc=0x" + proc.ToString("X8") + + " s7=\"" + pathS7 + "\"" + + " a0=\"" + pathA0 + "\"" + + " cproc=\"" + _cprocName + "\"" + + " (wait52 TLB; do not invent 0x040851E8)"); + string failName = !string.IsNullOrEmpty(pathS7) ? pathS7 : pathA0; + if (!string.IsNullOrEmpty(failName)) + { + CeRomTocFiles.NotePendingRomFile(failName); + BootLog.Write("[Hive] CreateFileFail \"" + failName + "\" pc=0x8001D400"); + } + LogSlotAliasVa(bus, s7, "CreateFileFail s7"); + if (slot0 != s7) + LogSlotAliasVa(bus, slot0, "CreateFileFail slot0"); + } + + private static void LogSlotAliasVa(MipsBus bus, uint va, string when) + { + if (va == 0) + return; + uint slot0 = va & CeSlotMask; + uint w = 0, w0 = 0; + bool m = DestMapped(bus, va); + bool m0 = DestMapped(bus, slot0); + bool r = m && TryReadWord(bus, va & ~3u, out w); + bool r0 = m0 && TryReadWord(bus, slot0 & ~3u, out w0); + System.Console.WriteLine("[Hive] slot-alias " + when + + " va=0x" + va.ToString("X8") + + (m ? " mapped" : " unmapped") + + (r ? " w=0x" + w.ToString("X8") : "") + + " slot0=0x" + slot0.ToString("X8") + + (m0 ? " mapped" : " unmapped") + + (r0 ? " w=0x" + w0.ToString("X8") : "") + + " (not ExtraROM/gwes/coredll/BINFS/tv2 dump unless proven)"); } private static bool TrySatisfyWfmo(uint[] registers, ref uint programCounter) @@ -935,137 +1654,2229 @@ private static void WriteSectors(MipsBus bus, uint dest, ulong off, uint want) } } - private const string LastUsedName = "last_dump_root.txt"; - private const int HuntMaxDepth = 3; - private const int HuntMaxVisit = 400; - - private static readonly HashSet VolumeNames = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "etc.bin", "BOOT.PRF", "tv2clientce", "tv2clientce.exe", "Application" - }; - - private static readonly HashSet HuntNames = new HashSet(StringComparer.OrdinalIgnoreCase) - { - "nk.bin", "etc.bin", "sec.bin", "XASEC.BIN", - "BOOT.PRF", "BOOTPRF.BAK", - "tv2clientce", "tv2clientce.exe", - "Application", "PlayReady", - "raven_fw.bin", "WirelessFirmware.img", "ContentVersion.txt", - "boot.sig", "runonce.sig", "Hard Disk" - }; - - internal static string ResolveRoot() - { - foreach (string raw in CandidateFeeds()) - { - string feed = NormalizeFeed(raw); - if (string.IsNullOrEmpty(feed)) - continue; - if (LooksLikeVolume(feed)) - { - NoteExtraRom(feed); - return feed; - } - System.Console.WriteLine("[HardDisk] hunt feed=" + feed); - string attach = HuntAttach(feed); - if (!string.IsNullOrEmpty(attach)) - return attach; - } - return ""; - } - - private static bool LooksLikeVolume(string dir) + // Do not rewrite slot +14/+18 into packed offsets. Drop the + // published pair when start/end cannot be a 32MB slot region. + private static bool BadInheritPair(uint start, uint end) { - try - { - foreach (string f in Directory.GetFiles(dir)) - { - string n = Path.GetFileName(f); - if (n.Equals("nk.bin", StringComparison.OrdinalIgnoreCase) - || n.Equals("etc.bin", StringComparison.OrdinalIgnoreCase) - || n.Equals("BOOT.PRF", StringComparison.OrdinalIgnoreCase) - || n.Equals("sec.bin", StringComparison.OrdinalIgnoreCase)) - return true; - } - } - catch - { - } - return false; + if (start == 0 || start == end) + return true; + if (end < start) + return true; + return (end - start) >= InheritSlotBytes; } - private static void NoteExtraRom(string dir) + private static void CompactInheritRecord(MipsBus bus, uint rec) { + if (bus == null || rec == 0) + return; try { - foreach (string f in Directory.GetFiles(dir)) + uint count = bus.Read32(rec + 8); + if (count == 0 || count > 8) + return; + uint write = 0; + for (uint i = 0; i < count; i++) { - if (Path.GetFileName(f).Equals("etc.bin", StringComparison.OrdinalIgnoreCase)) + uint pair = rec + 12 + i * 8; + uint start = bus.Read32(pair); + uint end = bus.Read32(pair + 4); + if (BadInheritPair(start, end)) + { + System.Console.WriteLine("[Inherit] drop pair start=0x" + start.ToString("X8") + + " end=0x" + end.ToString("X8")); + continue; + } + if (write != i) { - _extraRom = f; - return; + bus.Write32(rec + 12 + write * 8, start); + bus.Write32(rec + 16 + write * 8, end); } + write++; + } + if (write == count) + return; + bus.Write32(rec + 8, write); + for (uint i = write; i < count; i++) + { + bus.Write32(rec + 12 + i * 8, 0); + bus.Write32(rec + 16 + i * 8, 0); } + System.Console.WriteLine("[Inherit] compacted count=" + write + " (was " + count + ")"); } catch { } } - public static string HuntAttach(string feed) + // boot.hv Flags=3 takes Start DevMgr / device.exe and never + // calls the \Windows\default.hv helper. That hive is the NK + // FILESentry with Launch20/30/56. Clear the nibble so the + // existing beq at 0x0002A7F8 falls into 0x0002AB04. + private static void TryRomDefaultHive(uint[] registers, MipsBus bus) { - if (string.IsNullOrEmpty(feed) || !Directory.Exists(feed)) - return ""; - var scores = new Dictionary(StringComparer.OrdinalIgnoreCase); - var seenNames = new HashSet(StringComparer.OrdinalIgnoreCase); - WalkHunt(feed, 0, 0, scores, seenNames); - string bestVol = ""; - string bestLoose = ""; - int bestVolMark = 0; - int bestLooseMark = 0; - bool bestHasEtc = false; - foreach (var kv in scores) + if (registers == null || registers.Length <= 24 || bus == null) + return; + uint s3 = registers[19]; + if (!LooksLikePtr(s3)) + return; + uint flags; + try { flags = bus.Read32(s3); } + catch { return; } + if ((flags & 0xF) == 0) + return; + try { bus.Write32(s3, flags & ~0xFu); } + catch { return; } + registers[24] = 0; + if (!_hiveFlagsLogged) { - VolumeScore s = kv.Value; - if (s.Markers > 0) - { - bool take = s.Markers > bestVolMark; - if (!take && s.Markers == bestVolMark) - { - if (s.HasEtc && !bestHasEtc) - take = true; - else if (s.HasEtc == bestHasEtc - && (bestVol.Length == 0 || kv.Key.Length < bestVol.Length)) - take = true; - } - if (take) - { - bestVolMark = s.Markers; - bestHasEtc = s.HasEtc; - bestVol = kv.Key; - } - } - else if (s.Extra > 0 - && (s.Extra > bestLooseMark - || (s.Extra == bestLooseMark - && (bestLoose.Length == 0 || kv.Key.Length < bestLoose.Length)))) - { - bestLooseMark = s.Extra; - bestLoose = kv.Key; - } + _hiveFlagsLogged = true; + System.Console.WriteLine("[Hive] Flags 0x" + flags.ToString("X") + + " would skip \\Windows\\default.hv; take ROM FILESentry"); } - if (!string.IsNullOrEmpty(bestVol)) - return bestVol; - if (!string.IsNullOrEmpty(bestLoose)) - return bestLoose; - return ""; } - private static int WalkHunt(string dir, int depth, int visited, - Dictionary scores, HashSet seenNames) + private static void LogHiveHelper(uint[] registers, MipsBus bus) { - if (depth > HuntMaxDepth || visited >= HuntMaxVisit) - return visited; + if (registers == null || registers.Length <= 7 || bus == null) + return; + string path = ReadUtf16(bus, registers[5]); + if (string.IsNullOrEmpty(path)) + path = "(null)"; + if (_logged.Add("hive:open:" + path)) + System.Console.WriteLine("[Hive] helper \"" + path + "\" a3=" + registers[7]); + } + + private static void LogHiveHelperRet(uint[] registers) + { + if (registers == null || registers.Length <= 2) + return; + if (_logged.Add("hive:openret")) + System.Console.WriteLine("[Hive] helper v0=0x" + registers[2].ToString("X8")); + } + + private static void LogRunAppsInit(uint[] registers) + { + if (registers == null || registers.Length <= 2) + return; + uint v0 = registers[2]; + if (!_logged.Add("hive:init:" + v0.ToString("X"))) + return; + string note = v0 == 0 ? "OK" : (v0 == ErrorBadKey ? "ERROR_BADKEY" : ""); + System.Console.WriteLine("[Hive] RunApps HKLM\\init v0=0x" + v0.ToString("X8") + + (note.Length == 0 ? "" : " " + note)); + } + + private static void LogRunAppsLaunch(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 29 || bus == null) + return; + if (registers[2] != 0) + return; + string name = ReadUtf16(bus, registers[29] + 96); + if (string.IsNullOrEmpty(name)) + return; + if (_logged.Add("hive:launch:" + name)) + System.Console.WriteLine("[Hive] RunApps \"" + name + "\""); + } + + // RunApps 0x00017FB0: Depend WORD in v0, ready flag at + // record+4. Zero means WaitForMultipleObjects INFINITE + // (0x000180A4) instead of CreateProcess. Depend56 is + // 20/30/53. Do not SetEvent. + private static void LogRunAppsDepend(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 23 || bus == null) + return; + if (registers[13] != 0) + return; + uint need = registers[2]; + string img = ReadUtf16(bus, registers[23]); + if (string.IsNullOrEmpty(img)) + img = "(null)"; + if (!_logged.Add("hive:dep:" + img + ":" + need.ToString("X"))) + return; + System.Console.WriteLine("[Hive] Depend wait \"" + img + "\" need=" + need); + LogLaunchReadySlots(bus, need); + } + + // filesys 0x000177EC: the only success-path writer of + // launch record+4. a0 is the Launch number (20, 30, …). + // a0==0 pulses 0x00059468 and does not set any +4. + private static void LogSignalStarted(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 4) + return; + uint a0 = registers[4]; + if (!_logged.Add("hive:sig:" + a0.ToString("X"))) + return; + System.Console.WriteLine("[Hive] SignalStarted a0=" + a0 + + " (filesys 0x000177EC writes record+4, EventModify SET 0x00059468)"); + if (bus != null) + LogLaunchReadySlots(bus, a0); + } + + // Observe only. Do not SetEvent GweApi or Launch30. + private static void ObserveGwesPath(uint pc, uint[] registers, MipsBus bus) + { + if (pc == GwesRomEntry || pc == GwesVaEntry || IsSlottedVa(pc, GwesVaEntry)) + { + NoteGwesPc(pc, "entry", GwesRomEntry, bus); + return; + } + if (pc == GwesRomWinMain || pc == GwesVaWinMain || IsSlottedVa(pc, GwesVaWinMain)) + { + NoteGwesPc(pc, "WinMain", GwesRomWinMain, bus); + LogGwesInitFlag(bus); + return; + } + if (pc == GwesVaWinMainJal || IsSlottedVa(pc, GwesVaWinMainJal)) + { + NoteGwesPc(pc, "WinMain-jal", GwesRomWinMain + (GwesVaWinMainJal - GwesVaWinMain), bus); + LogGwesIat(bus); + return; + } + if (pc == GwesVaAfterKmode || IsSlottedVa(pc, GwesVaAfterKmode)) + { + NoteGwesPc(pc, "after-SetKMode", GwesRomWinMain + (GwesVaAfterKmode - GwesVaWinMain), bus); + return; + } + if (pc == GwesVaHeapCreate || IsSlottedVa(pc, GwesVaHeapCreate)) + { + NoteGwesPc(pc, "HeapCreate-site", GwesRomText + (GwesVaHeapCreate - 0x00011000), bus); + return; + } + if ((pc == GwesVaHeapCreate + 8 || IsSlottedVa(pc, GwesVaHeapCreate + 8)) + && _gwesWatch + && _logged.Add("hive:heapcreate:ret")) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + uint heap = 0; + bool heapOk = false; + try + { + if (bus != null) + { + heap = bus.Read32(CeRomTocFiles.ProcessHeapPtr); + heapOk = true; + } + } + catch + { + } + System.Console.WriteLine("[Hive] gwes HeapCreate ret v0=0x" + + v0.ToString("X8") + + (heapOk ? " *0x01FFFFA0=0x" + heap.ToString("X8") : " *0x01FFFFA0 unmapped")); + if (heapOk) + CeRomTocFiles.TryHostBackProcessHeap(bus, heap); + return; + } + if (pc == GwesVaDisplayParent || IsSlottedVa(pc, GwesVaDisplayParent)) + { + NoteGwesPc(pc, "display-parent", GwesRomText + (GwesVaDisplayParent - 0x00011000), bus); + LogGwesDispObj(bus, "display-parent"); + return; + } + if (pc == GwesVaDispAlloc || IsSlottedVa(pc, GwesVaDispAlloc)) + { + LogGwesDispAlloc(pc, registers, bus, false); + return; + } + if (pc == GwesVaDispAllocRet || IsSlottedVa(pc, GwesVaDispAllocRet)) + { + LogGwesDispAlloc(pc, registers, bus, true); + return; + } + if (pc == GwesVaDispStore || IsSlottedVa(pc, GwesVaDispStore)) + { + LogGwesDispStore(pc, registers, bus); + return; + } + if (pc == GwesVaWinMainSkip || IsSlottedVa(pc, GwesVaWinMainSkip)) + { + NoteGwesPc(pc, "WinMain-skip", GwesRomWinMain + (GwesVaWinMainSkip - GwesVaWinMain), bus); + return; + } + if (pc == CoredllThreadExceptionExit && _gwesWatch && IsGwesThread(registers, bus)) + { + LogThreadExceptionExit(pc, registers, bus); + return; + } + if (pc == CoredllCreateThread && _gwesWatch) + { + LogGwesCreateThread(pc, registers, bus); + return; + } + if (pc == ExceptionWorker) + { + _gwesSawWorker = true; + if (_logged.Add("hive:worker")) + System.Console.WriteLine("[Hive] exception-worker pc=0x" + + pc.ToString("X8") + " a0=0x" + + (registers != null && registers.Length > 4 + ? registers[4].ToString("X8") : "0") + + " (ThreadExceptionExit CreateThread start)"); + return; + } + if (pc == CoredllIsApiReady && _gwesSawThrEx) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + if (_logged.Add("hive:isapi:" + a0.ToString("X"))) + System.Console.WriteLine("[Hive] IsAPIReady a0=" + a0 + + " pc=0x" + pc.ToString("X8") + + " (worker uses 17 before MessageBoxW)"); + return; + } + if (pc == GwesRomDisplayFn || pc == GwesVaDisplayFn || IsSlottedVa(pc, GwesVaDisplayFn)) + { + NoteGwesPc(pc, "DisplayFn", GwesRomDisplayFn, bus); + return; + } + if (pc == GwesRomDisplayDll || pc == GwesVaDisplayDll || IsSlottedVa(pc, GwesVaDisplayDll)) + { + NoteGwesPc(pc, "DisplayDll", GwesRomDisplayDll, bus); + return; + } + if (pc == GwesRomSignal || pc == GwesRomGweApi) + { + NoteGwesPc(pc, pc == GwesRomSignal ? "SignalStarted-ROM" : "GweApi-ROM", + pc, bus); + return; + } + if (pc == DdiNopEntry || pc == DdiNopSlot0Entry + || (pc >= DdiNopVbase && pc < DdiNopVend) + || (pc >= DdiNopSlot0 && pc < DdiNopSlot0Vend)) + { + _gwesSawDdi = true; + bool entry = pc == DdiNopEntry || pc == DdiNopSlot0Entry; + if (entry && _logged.Add("hive:ddi:words")) + DumpDdiNopEntry(bus, pc, registers); + if (_ddiPcLogged >= 24 && !entry) + return; + if (_logged.Add("hive:ddi:" + pc.ToString("X"))) + { + _ddiPcLogged++; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + uint ra = registers != null && registers.Length > 31 ? registers[31] : 0; + System.Console.WriteLine("[Hive] ddi_nop pc=0x" + pc.ToString("X8") + + (entry ? " entry" : "") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " ra=0x" + ra.ToString("X8")); + } + return; + } + if (pc == CoredllActivateDevice || pc == CoredllActivateDeviceEx) + { + string n = registers != null && registers.Length > 4 && bus != null + ? ReadUtf16(bus, registers[4]) : ""; + if (string.IsNullOrEmpty(n)) + n = "(null)"; + if (_logged.Add("hive:act:" + n)) + { + if (!string.IsNullOrEmpty(n) && n != "(null)") + CeRomTocFiles.NotePendingRomFile(n); + System.Console.WriteLine("[Hive] ActivateDevice \"" + n + "\" pc=0x" + + pc.ToString("X8")); + BootLog.Rom("ok", "ExtraROM", "", -1, n, 0, 0, 0, 0, + BootLog.IsGuestIoName(n) + ? "ActivateDevice; guest IO name; no NIC on the MIPS bus; do not invent a device" + : "ActivateDevice name"); + } + return; + } + if (pc == CoredllLoadDriverRet && _logged.Contains("hive:ll:ddi_nop.dll")) + { + CeRomTocFiles.TryLogDdiNopCallDllMiss(bus, registers, pc); + if (_logged.Add("hive:ldret")) + System.Console.WriteLine("[Hive] LoadDriver ret v0=0x" + + (registers != null && registers.Length > 2 + ? registers[2].ToString("X8") : "0") + + " last-error=" + ReadLastError(bus) + + " ddi_nop@0x03998014 " + + (DdiNopMapped(bus) ? "mapped" : "unmapped")); + // wait45: dest+0x520 0x080E1970 is gone. Next miss + // 0x080E7ECC is later HEAP (GDI +0xC8=0x000E8370). + // Retry DestMapped pages only. Not a dump 0x000E0000. + RetryProcessHeapHost(bus, "LoadDriver-ret"); + return; + } + if (pc == CeRomTocFiles.LoadE32Rom + && registers != null && registers.Length > 4) + { + CeRomTocFiles.TryServeExtraRomLoadE32(bus, registers[4]); + CeRomTocFiles.TryLogExtraRomLoadE32(bus, registers, false, ReadLastError(bus)); + CeRomTocFiles.TryBeginNkLoadE32(bus, registers); + if (_logged.Contains("hive:ll:ddi_nop.dll") + && CeRomTocFiles.IsDdiNopTocObject(bus, registers[4])) + { + if (_logged.Add("hive:ldde32")) + { + CeRomTocFiles.TryMarkExtraRomO32Compressed(bus, CeRomTocFiles.DdiNopTocEntry); + CeRomTocFiles.NoteLoadE32("ddi_nop.dll", 33); + System.Console.WriteLine("[Hive] 0x800196E4 ExtraROM ddi_nop obj=0x" + + registers[4].ToString("X8") + + " entry=0x" + CeRomTocFiles.DdiNopTocEntry.ToString("X8") + + " (firmware decompress/map; do not invent 0x81360000)"); + } + return; + } + if (CeRomTocFiles.IsMscoreeTocObject(bus, registers[4]) + && _logged.Add("hive:ldde32:mscoree")) + { + CeRomTocFiles.TryMarkExtraRomO32Compressed(bus, CeRomTocFiles.MscoreeTocEntry); + CeRomTocFiles.NoteLoadE32("mscoree.dll", 46); + System.Console.WriteLine("[Hive] 0x800196E4 ExtraROM mscoree.dll obj=0x" + + registers[4].ToString("X8") + + " entry=0x" + CeRomTocFiles.MscoreeTocEntry.ToString("X8") + + " e32=0x" + CeRomTocFiles.MscoreeE32.ToString("X8") + + " (TOC[46] type 7; firmware LoadE32; not a FILE)"); + return; + } + if (CeRomTocFiles.IsOle32TocObject(bus, registers[4]) + && _logged.Add("hive:ldde32:ole32")) + { + CeRomTocFiles.TryMarkExtraRomO32Compressed(bus, CeRomTocFiles.Ole32TocEntry); + CeRomTocFiles.NoteLoadE32("ole32.dll", 34); + System.Console.WriteLine("[Hive] 0x800196E4 ExtraROM ole32.dll obj=0x" + + registers[4].ToString("X8") + + " entry=0x" + CeRomTocFiles.Ole32TocEntry.ToString("X8") + + " e32=0x" + CeRomTocFiles.Ole32E32.ToString("X8") + + " (TOC[34] type 7; firmware LoadE32; not a FILE)"); + return; + } + string tocName; + int tocIndex; + uint tocEntry; + uint tocE32; + if (CeRomTocFiles.TryDescribeExtraRomTocObject(bus, registers[4], + out tocName, out tocIndex, out tocEntry, out tocE32) + && _logged.Add("hive:ldde32:" + tocName)) + { + CeRomTocFiles.TryMarkExtraRomO32Compressed(bus, tocEntry); + CeRomTocFiles.NoteLoadE32(tocName, tocIndex); + System.Console.WriteLine("[Hive] 0x800196E4 ExtraROM " + tocName + + " obj=0x" + registers[4].ToString("X8") + + " entry=0x" + tocEntry.ToString("X8") + + " e32=0x" + tocE32.ToString("X8") + + " (TOC[" + tocIndex + "] type 7; firmware LoadE32; not a FILE)"); + return; + } + } + if (pc == CeRomTocFiles.LoadE32RomRet) + { + CeRomTocFiles.TryLogExtraRomLoadE32(bus, registers, true, ReadLastError(bus)); + CeRomTocFiles.TryFinishNkLoadE32(bus, registers); + } + if (pc == CeRomTocFiles.LoadE32RomRet + && _logged.Contains("hive:ldde32") + && _logged.Add("hive:ldde32ret")) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + System.Console.WriteLine("[Hive] 0x800196E4 ret v0=0x" + + v0.ToString("X8") + + " ddi_nop@0x03998014 " + + (DdiNopMapped(bus) ? "mapped" : "unmapped")); + BootLog.LoadE32("ddi_nop.dll", 33, v0, + CeRomTocFiles.NameLoadE32RetPublic(v0) + + "; firmware LoadE32; do not invent 0x81360000"); + return; + } + if (pc == CeRomTocFiles.LoadE32RomRet + && _logged.Contains("hive:ldde32:mscoree") + && _logged.Add("hive:ldde32ret:mscoree")) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + System.Console.WriteLine("[Hive] 0x800196E4 mscoree ret v0=0x" + + v0.ToString("X8") + + " last-error=" + ReadLastError(bus) + + " (TOC[46]; do not invent e32)"); + BootLog.LoadE32("mscoree.dll", 46, v0, + CeRomTocFiles.NameLoadE32RetPublic(v0) + + "; TOC[46]; firmware LoadE32; do not invent e32"); + return; + } + if (pc == CeRomTocFiles.LoadE32RomRet + && _logged.Contains("hive:ldde32:ole32") + && _logged.Add("hive:ldde32ret:ole32")) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + System.Console.WriteLine("[Hive] 0x800196E4 ole32 ret v0=0x" + + v0.ToString("X8") + + " last-error=" + ReadLastError(bus) + + " (TOC[34]; do not invent e32)"); + BootLog.LoadE32("ole32.dll", 34, v0, + CeRomTocFiles.NameLoadE32RetPublic(v0) + + "; TOC[34]; firmware LoadE32; do not invent e32"); + return; + } + if (pc == CeRomTocFiles.LoadE32RomRet) + { + string tocName; + int tocIndex; + if (CeRomTocFiles.TryPeekLoadE32(out tocName, out tocIndex) + && _logged.Add("hive:ldde32ret:" + tocName)) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + System.Console.WriteLine("[Hive] 0x800196E4 " + tocName + " ret v0=0x" + + v0.ToString("X8") + + " last-error=" + ReadLastError(bus) + + " (TOC[" + tocIndex + "]; do not invent e32)"); + BootLog.LoadE32(tocName, tocIndex, v0, + CeRomTocFiles.NameLoadE32RetPublic(v0) + + "; TOC[" + tocIndex + "]; firmware LoadE32; do not invent e32"); + return; + } + } + if (pc == CeRomTocFiles.LoadO32RomRet + && _logged.Contains("hive:ldde32") + && _logged.Add("hive:ldo32ret")) + { + System.Console.WriteLine("[Hive] 0x800165DC ret v0=0x" + + (registers != null && registers.Length > 2 + ? registers[2].ToString("X8") : "0") + + " ddi_nop@0x03998014 " + + (DdiNopMapped(bus) ? "mapped" : "unmapped")); + return; + } + if (pc == CeRomTocFiles.CopyO32Rom + && _logged.Contains("hive:ldde32")) + { + CeRomTocFiles.TryMarkExtraRomO32Compressed(bus, CeRomTocFiles.DdiNopTocEntry); + if (_logged.Add("hive:copyo32")) + System.Console.WriteLine("[Hive] 0x8001AFA4 CopyO32 ExtraROM ddi_nop" + + " (firmware MapO32; do not XIP-alias 0x80764CE0)"); + return; + } + if (pc == CeRomTocFiles.MapO32Rom + && registers != null && registers.Length > 5 + && (_logged.Contains("hive:ldde32") + || _logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32") + || CeRomTocFiles.IsTv2FileExpanded())) + { + if (_logged.Contains("hive:ldde32") + || _logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32")) + CeRomTocFiles.TrySteerExtraRomMapO32(bus, registers[5]); + if (_logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32")) + CeRomTocFiles.TryClearO32RomXipForMscoree(bus, registers); + CeRomTocFiles.TryMapTv2DumpPeO32(bus, registers[5]); + LogMapO32(registers, bus); + return; + } + if (pc == CeRomTocFiles.MapO32DecompressSrcChk + && _logged.Contains("hive:ldde32") + && _logged.Add("hive:decompsrc")) + { + System.Console.WriteLine("[Hive] 0x80028844 dest-walk passed; src-check fp=0x" + + (registers != null && registers.Length > 30 + ? registers[30].ToString("X8") : "0") + + " s2=0x" + (registers != null && registers.Length > 18 + ? registers[18].ToString("X8") : "0")); + return; + } + if (pc == CeRomTocFiles.MapO32DecompressCommitChk + && _logged.Contains("hive:ldde32")) + { + CeRomTocFiles.TryAcceptExtraRomDestCommit(registers); + return; + } + if (pc == CeRomTocFiles.MapO32DecompressFail + && _logged.Contains("hive:ldde32") + && _logged.Add("hive:decompfail")) + { + System.Console.WriteLine("[Hive] 0x80028844 fail-87 site ra=0x" + + (registers != null && registers.Length > 31 + ? registers[31].ToString("X8") : "0") + + " v0=0x" + (registers != null && registers.Length > 2 + ? registers[2].ToString("X8") : "0") + + " s4=0x" + (registers != null && registers.Length > 20 + ? registers[20].ToString("X8") : "0")); + return; + } + if (pc == CeRomTocFiles.MapO32CommitDest + && _logged.Contains("hive:ldde32") + && _logged.Add("hive:commitdest")) + { + System.Console.WriteLine("[Hive] 0x80026F50 commit dest a0=0x" + + (registers != null && registers.Length > 4 + ? registers[4].ToString("X8") : "0") + + " a1=0x" + (registers != null && registers.Length > 5 + ? registers[5].ToString("X8") : "0") + + " a2=0x" + (registers != null && registers.Length > 6 + ? registers[6].ToString("X8") : "0") + + " a3=0x" + (registers != null && registers.Length > 7 + ? registers[7].ToString("X8") : "0")); + return; + } + if (pc == CeRomTocFiles.MapO32Decompress + && (_logged.Contains("hive:ldde32") + || _logged.Contains("hive:ldde32:mscoree") + || _logged.Contains("hive:ldde32:ole32")) + && registers != null && registers.Length > 4) + { + uint dest = registers[4]; + uint src = registers.Length > 5 ? registers[5] : 0; + if (_logged.Add("hive:decomp:" + dest.ToString("X"))) + { + bool destOk = DestMapped(bus, dest); + System.Console.WriteLine("[Hive] 0x80028844 decompress dest=0x" + + dest.ToString("X8") + + " src=0x" + src.ToString("X8") + + " a2=0x" + (registers.Length > 6 + ? registers[6].ToString("X8") : "0") + + " a3=0x" + (registers.Length > 7 + ? registers[7].ToString("X8") : "0") + + " dest-" + (destOk ? "mapped" : "unmapped") + + " (firmware; do not host-alias XIP)"); + } + return; + } + if (pc == CeRomTocFiles.MapO32VirtualCopy + && _logged.Contains("hive:ldde32") + && _logged.Add("hive:vcopy")) + { + System.Console.WriteLine("[Hive] 0x80043298 VirtualCopy a0=0x" + + (registers != null && registers.Length > 4 + ? registers[4].ToString("X8") : "0") + + " a1=0x" + (registers != null && registers.Length > 5 + ? registers[5].ToString("X8") : "0") + + " a2=0x" + (registers != null && registers.Length > 6 + ? registers[6].ToString("X8") : "0") + + " (XIP path; ExtraROM o32 should decompress instead)"); + return; + } + if (pc == CeRomTocFiles.LoadLibSyscallRet) + { + CeRomTocFiles.TryLogDdiNopCallDllMiss(bus, registers, pc); + if (!string.IsNullOrEmpty(_pendingLoadLib)) + CeRomTocFiles.TryServeExtraRomLoadLibrary(bus, _pendingLoadLib, registers); + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + if (!string.IsNullOrEmpty(_pendingLoadLib) && v0 == 0 + && _logged.Add("rom:llmiss:" + _pendingLoadLib)) + { + BootLog.Rom("miss", "ExtraROM", "", -1, _pendingLoadLib, 0, 0, 0, 0, + BootLog.IsGuestIoName(_pendingLoadLib) + ? "LoadLibrary ret v0=0; guest IO name; do not invent a NIC or UART" + : "LoadLibrary ret v0=0; do not invent the DLL"); + } + if (_logged.Contains("hive:ll:ddi_nop.dll") + && _logged.Add("hive:ldsys")) + { + System.Console.WriteLine("[Hive] LoadLibraryExW syscall ret v0=0x" + + v0.ToString("X8") + + " last-error=" + ReadLastError(bus) + + " ddi_nop@0x03998014 " + + (DdiNopMapped(bus) ? "mapped" : "unmapped")); + } + return; + } + if (pc == CoredllLoadLibraryW || pc == CoredllLoadLibraryExW + || pc == CoredllLoadDriver) + { + string n = registers != null && registers.Length > 4 && bus != null + ? ReadUtf16(bus, registers[4]) : ""; + if (string.IsNullOrEmpty(n)) + return; + _pendingLoadLib = n; + CeRomTocFiles.NotePendingRomFile(n); + bool after = _logged.Contains("hive:gpc:WinMain"); + bool ddi = n.IndexOf("ddi", StringComparison.OrdinalIgnoreCase) >= 0 + || n.IndexOf("display", StringComparison.OrdinalIgnoreCase) >= 0 + || n.IndexOf("gwes", StringComparison.OrdinalIgnoreCase) >= 0 + || n.IndexOf("mon", StringComparison.OrdinalIgnoreCase) >= 0; + if (_logged.Add("hive:ll:" + n)) + { + string tag = pc == CoredllLoadDriver ? "LoadDriver" : "LoadLibrary"; + if (after || ddi) + System.Console.WriteLine("[Hive] " + tag + + " \"" + n + "\" pc=0x" + pc.ToString("X8")); + BootLog.Rom("ok", "ExtraROM", "", -1, n, 0, 0, 0, 0, + BootLog.IsGuestIoName(n) + ? tag + " guest IO name; no NIC on the MIPS bus; do not invent a NIC or UART" + : tag + " name; do not invent the DLL"); + } + return; + } + if ((pc == GwesVaAvHelper || IsSlottedVa(pc, GwesVaAvHelper) + || pc == GwesVaAvCaller || IsSlottedVa(pc, GwesVaAvCaller)) + && _gwesWatch) + { + LogGwesAvSite(pc, registers, bus); + return; + } + if ((pc == GwesVaAvCompare || IsSlottedVa(pc, GwesVaAvCompare) + || pc == GwesVaAvCompareCaller || IsSlottedVa(pc, GwesVaAvCompareCaller) + || pc == GwesVaAvCompareLhu || IsSlottedVa(pc, GwesVaAvCompareLhu)) + && _gwesWatch) + { + LogGwesAvCompare(pc, registers, bus); + return; + } + if ((pc == GwesVaC8StoreSet || IsSlottedVa(pc, GwesVaC8StoreSet) + || pc == GwesVaC8StoreClr || IsSlottedVa(pc, GwesVaC8StoreClr) + || pc == GwesRomC8StoreSet || pc == GwesRomC8StoreClr) + && _gwesWatch) + { + LogGwesC8Store(pc, registers, bus); + return; + } + if (pc == CoredllMessageBoxW && _gwesSawThrEx) + { + if (_logged.Add("hive:msgbox")) + System.Console.WriteLine("[Hive] MessageBoxW pc=0x" + pc.ToString("X8") + + " (exception worker; needs gwes)"); + return; + } + if (pc == CoredllExitThread && _gwesWatch && (_gwesIn || _gwesLastPc != 0)) + { + _gwesSawExit = true; + if (_logged.Add("hive:exit")) + System.Console.WriteLine("[Hive] ExitThread pc=0x" + pc.ToString("X8") + + " last-gwes=0x" + _gwesLastPc.ToString("X8")); + return; + } + if ((pc == CoredllWaitSo || pc == CoredllWaitMo) && _gwesWatch + && IsGwesThread(registers, bus)) + { + LogGwesWait(pc, registers, bus); + return; + } + if (pc >= GwesRomText && pc < GwesRomTextEnd) + { + _gwesIn = true; + _gwesLastPc = pc; + if (_logged.Add("hive:gwesrun")) + System.Console.WriteLine("[Hive] gwes first-ROM pc=0x" + pc.ToString("X8")); + return; + } + if (IsSlottedGwesText(pc) || IsGwesUsegPc(pc, bus)) + { + _gwesIn = true; + _gwesLastPc = pc; + if (IsSlottedGwesText(pc) && _logged.Add("hive:gwesslot")) + System.Console.WriteLine("[Hive] gwes first-slot pc=0x" + pc.ToString("X8")); + else if (IsGwesUsegPc(pc, bus) && _logged.Add("hive:gwesva")) + System.Console.WriteLine("[Hive] gwes first-VA pc=0x" + pc.ToString("X8")); + return; + } + if (_gwesWatch) + { + uint slot = pc >> 25; + if (slot >= 1 && slot <= 16 && _logged.Add("hive:userslot")) + { + uint off = pc & CeSlotMask; + System.Console.WriteLine("[Hive] first user-slot pc=0x" + pc.ToString("X8") + + " slot=" + slot + + (off >= 0x00011000 && off < 0x000BB000 + ? " (gwes .text range)" + : " (not gwes .text; coredll shared is 0x03F5xxxx)")); + } + } + // OEMIdle is hit during CreateProcess; only summarize + // after RunApps is already stuck on Depend30. + if (_gwesWatch && _logged.Contains("hive:dep:RunOnce.exe:1E") + && (pc == OemIdle || pc == OemIdleLoop)) + LogGwesSummary(pc); + } + + private static bool IsSlottedVa(uint pc, uint va) + { + uint slot = pc >> 25; + return slot >= 1 && slot <= 16 && (pc & CeSlotMask) == va; + } + + private static bool IsSlottedGwesText(uint pc) + { + uint slot = pc >> 25; + if (slot < 1 || slot > 16) + return false; + uint off = pc & CeSlotMask; + return off >= 0x00011000 && off < 0x000BB000; + } + + private static bool IsGwesUsegPc(uint pc, MipsBus bus) + { + if (!_gwesWatch || bus == null || pc < 0x00011000 || pc >= 0x000BB000) + return false; + try + { + uint got = bus.Read32(pc); + uint gwes = bus.Read32(GwesRomText + (pc - 0x00011000)); + uint filesys = bus.Read32(FilesysRomText + (pc - 0x00011000)); + return got != 0 && got == gwes && got != filesys; + } + catch + { + return false; + } + } + + private static void LogGwesIat(MipsBus bus) + { + if (bus == null || !_logged.Add("hive:iat")) + return; + uint[] addrs = + { + GwesIatGetProc, GwesIatLoadLib, 0x000B607C, GwesIatHeapCreate, + GwesIatLocalAlloc, 0x000B7A1C, GwesDispObj, + GwesSlot | GwesIatGetProc, GwesSlot | 0x000B607C + }; + for (int i = 0; i < addrs.Length; i++) + { + uint a = addrs[i]; + try + { + uint w = bus.Read32(a); + System.Console.WriteLine("[Hive] gwes data 0x" + a.ToString("X8") + + " =0x" + w.ToString("X8")); + } + catch + { + System.Console.WriteLine("[Hive] gwes data 0x" + a.ToString("X8") + + " unmapped"); + } + } + } + + private static void LogGwesInitFlag(MipsBus bus) + { + if (bus == null || !_logged.Add("hive:initflag")) + return; + try + { + uint word = bus.Read32(GwesInitFlag & ~3u); + uint b = ((GwesInitFlag & 3) == 0) + ? (word & 0xFF) + : ((word >> (8 * (int)(GwesInitFlag & 3))) & 0xFF); + System.Console.WriteLine("[Hive] WinMain already-init *0x000B7A1D=" + + b + " (nonzero skips to epilogue, no DisplayDll)"); + } + catch + { + System.Console.WriteLine("[Hive] WinMain already-init *0x000B7A1D unmapped"); + } + } + + private static bool IsGwesThread(uint[] registers, MipsBus bus) + { + uint sp = registers != null && registers.Length > 29 ? registers[29] : 0; + if ((sp & 0xFE000000u) == GwesSlot) + return true; + if (_gwesThr == 0 || bus == null) + return false; + try + { + uint thr = bus.Read32(ThreadPtr); + return thr == _gwesThr; + } + catch + { + return false; + } + } + + // 0x0005BCF8 jal 0x0005377C; delay lw a0, 0xC8(fp). + // Helper is lhu 8(a0). a0==0 is the C0000005. + private static void LogGwesAvSite(uint pc, uint[] registers, MipsBus bus) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + string key = "hive:av:" + (pc & CeSlotMask).ToString("X") + ":" + a0.ToString("X"); + if (!_logged.Add(key)) + return; + System.Console.WriteLine("[Hive] gwes AV-site pc=0x" + pc.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " (lhu 8(a0) / *(gdi+0xC8))"); + LogGwesDispObj(bus, "AV-site"); + // wait48: 0x080E7ECC TLB after skipping all AV-site + // host-back. That VA is heap 0x080E0000+0x7ECC + // (ddi_nop 0x03982DD4 load), DestMapped at AV-site + // (wait46/47). Skip only the GDI +0xC8 page + // (0x000E8370 / 0x080E8000). Do not poke +0xC8. + // Do not invent 0x000E0000. + uint skip = 0; + uint obj = 0, field = 0; + if (TryReadWord(bus, GwesDispObj, out obj) && obj != 0 + && TryReadWord(bus, obj + 0xC8, out field) && field != 0) + skip = field; + RetryProcessHeapHost(bus, "AV-site", skip); + } + + // wait46: 0x00053944 lhu 4(a0) after 0x0005BCA4 delay + // lw a0, 0xC8(a0). Compares GDI +0xC8 object vs a1. + // Host-back only DestMapped HEAP pages. Not a dump + // 0x000E0000 page. Do not SetEvent. + private static void LogGwesAvCompare(uint pc, uint[] registers, MipsBus bus) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + string key = "hive:avcmp:" + (pc & CeSlotMask).ToString("X") + ":" + + a0.ToString("X") + ":" + a1.ToString("X"); + if (!_logged.Add(key)) + return; + uint a0p4 = a0 + 4; + uint a1p4 = a1 + 4; + uint w0 = 0, w1 = 0; + bool m0 = DestMapped(bus, a0p4); + bool m1 = DestMapped(bus, a1p4); + bool r0 = m0 && TryReadWord(bus, a0p4 & ~3u, out w0); + bool r1 = m1 && TryReadWord(bus, a1p4 & ~3u, out w1); + System.Console.WriteLine("[Hive] gwes AV-compare pc=0x" + pc.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " lhu4(a0)=" + (m0 ? "mapped" : "unmapped") + + (r0 ? " w=0x" + w0.ToString("X8") : "") + + " lhu4(a1)=" + (m1 ? "mapped" : "unmapped") + + (r1 ? " w=0x" + w1.ToString("X8") : "") + + " (GDI +0xC8 vs a1; not a dump 0x000E0000 page)"); + LogGwesDispObj(bus, "AV-compare"); + RetryProcessHeapHost(bus, "AV-compare"); + } + + // 0x000631D4 / 0x00063254: sw $v0, 0xC8($v1) with + // $v1=*0x000BA954. Firmware path. Do not poke +0xC8. + private static void LogGwesC8Store(uint pc, uint[] registers, MipsBus bus) + { + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + uint v1 = registers != null && registers.Length > 3 ? registers[3] : 0; + string key = "hive:c8sw:" + (pc & CeSlotMask).ToString("X") + ":" + v0.ToString("X"); + if (!_logged.Add(key)) + return; + uint obj = 0, field = 0; + bool objOk = TryReadWord(bus, GwesDispObj, out obj); + bool fieldOk = objOk && obj != 0 && TryReadWord(bus, obj + 0xC8, out field); + System.Console.WriteLine("[Hive] gwes +0xC8 store pc=0x" + pc.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " v1=0x" + v1.ToString("X8") + + " *0x000BA954=" + (objOk ? "0x" + obj.ToString("X8") : "unmapped") + + " +0xC8=" + (fieldOk ? "0x" + field.ToString("X8") : "unmapped") + + " (firmware sw v0,0xC8(v1); do not poke +0xC8)"); + } + + // wait50: no Write32 of 0 after 0x000631D4. Watch sb/sh + // and slot-0 0x000E17C8 vs slot-4 0x080E17C8. Do not poke. + public static void NoteDispC8Write(uint va, uint value, MipsBus bus) + { + if (_c8WriteBusy || !_gwesWatch) + return; + uint off = va & 0x01FFFFFF; + uint word = off & ~3u; + if (word != 0x000E17C8u) + return; + uint slot = va; + uint host = va; + try + { + slot = CeRomTocFiles.MapProcessHeapSlotVa(bus, va); + host = CeRomTocFiles.MapVallocHostVa(slot); + } + catch + { + } + string key = "hive:c8wr:" + _stepPc.ToString("X") + ":" + value.ToString("X") + ":" + va.ToString("X"); + if (!_logged.Add(key)) + return; + System.Console.WriteLine("[Hive] GDI +0xC8 write pc=0x" + _stepPc.ToString("X8") + + " va=0x" + va.ToString("X8") + + " slot=0x" + slot.ToString("X8") + + " host=0x" + host.ToString("X8") + + " value=0x" + value.ToString("X8") + + " last-gwes=0x" + _gwesLastPc.ToString("X8") + + " (sb/sh/sw; do not poke +0xC8)"); + } + + private static void LogGwesDispAlloc(uint pc, uint[] registers, MipsBus bus, bool ret) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + string key = ret ? "hive:dispalloc:ret" : "hive:dispalloc"; + if (!_logged.Add(key)) + return; + string heapNote = HeapPtrNote(bus); + if (!ret) + { + System.Console.WriteLine("[Hive] gwes LocalAlloc-site pc=0x" + + pc.ToString("X8") + " a0=" + a0 + heapNote + + " (size 584 -> *0x000BA954; do not invent 0x000E0000)"); + return; + } + bool mapped = DestMapped(bus, v0); + uint heap = 0; + TryReadWord(bus, CeRomTocFiles.ProcessHeapPtr, out heap); + uint slot = heap & 0xFE000000u; + uint slotV0 = slot != 0 ? (slot | (v0 & 0x01FFFFFFu)) : 0; + bool slotMapped = slotV0 != 0 && DestMapped(bus, slotV0); + uint magic = 0; + bool magicOk = heap != 0 && TryReadWord(bus, heap, out magic); + System.Console.WriteLine("[Hive] gwes LocalAlloc-site ret pc=0x" + + pc.ToString("X8") + " v0=0x" + v0.ToString("X8") + + (mapped ? " mapped" : " unmapped") + + " slot-v0=0x" + slotV0.ToString("X8") + + (slotMapped ? " mapped" : " unmapped") + + " *heap=" + (magicOk ? "0x" + magic.ToString("X8") : "unmapped") + + heapNote + + " (do not invent 0x000E0000)"); + // wait44: HeapCreate host-back copied=0. Retry after + // LocalAlloc when the firmware HEAP page is DestMapped. + if (heap != 0) + CeRomTocFiles.TryHostBackProcessHeap(bus, heap); + } + + // wait45: 0x080E7ECC / GDI +0xC8=0x000E8370 are later + // pages in the same HEAP 64K. Host-back only if DestMapped. + // Not a dump ExtraROM page. Not a static 0x000E0000 map. + private static void RetryProcessHeapHost(MipsBus bus, string when) + { + RetryProcessHeapHost(bus, when, 0); + } + + private static void RetryProcessHeapHost(MipsBus bus, string when, uint skipVa) + { + uint heap = 0; + if (bus == null || !TryReadWord(bus, CeRomTocFiles.ProcessHeapPtr, out heap) || heap == 0) + return; + bool installed = CeRomTocFiles.TryHostBackProcessHeap(bus, heap, skipVa); + if (!_logged.Add("hive:heappages:" + when)) + return; + uint[] vas = { 0x080E1970u, 0x080E7ECCu, 0x000E7ECCu, 0x080E8370u, 0x000E8370u }; + System.Console.Write("[Hive] process-heap pages " + when + + " heap=0x" + heap.ToString("X8") + + (skipVa != 0 ? " skip=0x" + skipVa.ToString("X8") : "") + + (installed ? " new-host-back" : " no-new")); + for (int i = 0; i < vas.Length; i++) + { + System.Console.Write(" 0x" + vas[i].ToString("X8") + + (DestMapped(bus, vas[i]) ? "=mapped" : "=unmapped")); + } + System.Console.WriteLine(" (not a dump 0x000E0000 page)"); + } + + private static string HeapPtrNote(MipsBus bus) + { + uint heap = 0; + uint fn = 0; + bool heapOk = TryReadWord(bus, CeRomTocFiles.ProcessHeapPtr, out heap); + bool fnOk = TryReadWord(bus, 0x01FFF794u, out fn); + return " *0x01FFFFA0=" + (heapOk ? "0x" + heap.ToString("X8") : "unmapped") + + " *0x01FFF794=" + (fnOk ? "0x" + fn.ToString("X8") : "unmapped"); + } + + private static bool TryReadWord(MipsBus bus, uint va, out uint word) + { + word = 0; + if (bus == null || va == 0) + return false; + try + { + word = bus.Read32(va); + return true; + } + catch + { + return false; + } + } + + private static void LogVallocRet(MipsBus bus, uint v0) + { + bool mapped = DestMapped(bus, v0); + string key = "hive:varet:" + _vallocA0.ToString("X") + ":" + v0.ToString("X"); + if (_logged.Add(key)) + System.Console.WriteLine("[Hive] VALLOC ret a0=0x" + _vallocA0.ToString("X8") + + " a1=0x" + _vallocA1.ToString("X8") + + " a2=0x" + _vallocA2.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + (mapped ? " mapped" : " unmapped")); + if (v0 != 0) + { + CeRomTocFiles.TryHostBackValloc(v0, _vallocA0, _vallocA1, _vallocA2, mapped); + CeRomTocFiles.NoteExtraRomVallocRet(_vallocA0, v0); + } + } + + private static void LogGwesDispStore(uint pc, uint[] registers, MipsBus bus) + { + if (!_logged.Add("hive:dispstore")) + return; + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + uint s5 = registers != null && registers.Length > 21 ? registers[21] : 0; + bool mapped = DestMapped(bus, v0); + System.Console.WriteLine("[Hive] gwes *0x000BA954 store pc=0x" + + pc.ToString("X8") + " v0=0x" + v0.ToString("X8") + + " s5=0x" + s5.ToString("X8") + + (mapped ? " mapped" : " unmapped") + + " (LocalAlloc result; do not invent 0x000E0000)"); + LogGwesDispObj(bus, "disp-store"); + } + + private static void LogGwesDispObj(MipsBus bus, string when) + { + if (bus == null || !_logged.Add("hive:dispobj:" + when)) + return; + try + { + uint obj = bus.Read32(GwesDispObj); + uint field = 0; + bool have = false; + if (obj != 0 && obj != 0xDEADBEEFu) + { + try + { + field = bus.Read32(obj + 0xC8); + have = true; + } + catch + { + } + } + uint raw = obj + GwesDispC8Off; + uint slot = raw; + uint host = raw; + uint heap = 0; + TryReadWord(bus, CeRomTocFiles.ProcessHeapPtr, out heap); + try + { + slot = CeRomTocFiles.MapProcessHeapSlotVa(bus, raw); + host = CeRomTocFiles.MapVallocHostVa(slot); + } + catch + { + } + System.Console.WriteLine("[Hive] gwes *0x000BA954=0x" + obj.ToString("X8") + + " +0xC8=" + (have ? "0x" + field.ToString("X8") : "unmapped") + + " va=0x" + raw.ToString("X8") + + " slot=0x" + slot.ToString("X8") + + " host=0x" + host.ToString("X8") + + " *0x01FFFFA0=0x" + heap.ToString("X8") + + " (" + when + ")"); + } + catch + { + System.Console.WriteLine("[Hive] gwes *0x000BA954 unmapped (" + when + ")"); + } + } + + // Observe only. Handle is the CreateThread object; + // the worker's ExitThread signals it. Do not SetEvent. + private static void LogThreadExceptionExit(uint pc, uint[] registers, MipsBus bus) + { + _gwesSawThrEx = true; + if (!_logged.Add("hive:threx")) + return; + uint ra = registers != null && registers.Length > 31 ? registers[31] : 0; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + System.Console.WriteLine("[Hive] ThreadExceptionExit pc=0x" + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " last-gwes=0x" + _gwesLastPc.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " (CreateThread+WFSO; do not SetEvent)"); + } + + private static void LogGwesCreateThread(uint pc, uint[] registers, MipsBus bus) + { + uint start = registers != null && registers.Length > 6 ? registers[6] : 0; + bool gwes = IsGwesThread(registers, bus); + bool worker = start == ExceptionWorker; + if (!gwes && !worker && !_gwesSawThrEx) + return; + _gwesSawCreateThr = true; + string key = "hive:ct:" + start.ToString("X"); + if (!_logged.Add(key)) + return; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + uint a3 = registers != null && registers.Length > 7 ? registers[7] : 0; + System.Console.WriteLine("[Hive] CreateThread pc=0x" + pc.ToString("X8") + + " start=0x" + start.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " a3=0x" + a3.ToString("X8") + + (worker ? " (ThreadExceptionExit worker)" : "") + + " gwes-thr=" + gwes); + } + + private static void LogMapO32(uint[] registers, MipsBus bus) + { + uint o32 = registers != null && registers.Length > 5 ? registers[5] : 0; + uint dest = 0; + uint flags = 0; + uint dataptr = 0; + uint vsize = 0; + uint psize = 0; + try + { + if (bus != null && o32 != 0) + { + vsize = bus.Read32(o32); + dest = bus.Read32(o32 + 8); + flags = bus.Read32(o32 + 0x10); + psize = bus.Read32(o32 + 0x14); + dataptr = bus.Read32(o32 + 0x18); + } + } + catch + { + } + string key = "hive:mapo32:" + dest.ToString("X") + ":" + flags.ToString("X"); + if (!_logged.Add(key)) + return; + uint destWord = 0; + uint dataWord = 0; + bool mscoree = dest == 0x034B1000u || dest == 0x014B1000u + || dataptr == 0x809435ECu; + bool ole32 = dest == 0x03941000u || dest == 0x01941000u + || dataptr == 0x807752F4u; + if ((mscoree || ole32) && bus != null) + { + try + { + if (dest != 0) + destWord = bus.Read32(dest); + } + catch + { + } + try + { + if (dataptr != 0) + dataWord = bus.Read32(dataptr); + } + catch + { + } + } + System.Console.WriteLine("[Hive] 0x8001AC30 MapO32 dest=0x" + dest.ToString("X8") + + " dataptr=0x" + dataptr.ToString("X8") + + " flags=0x" + flags.ToString("X8") + + " vsize=0x" + vsize.ToString("X") + + " psize=0x" + psize.ToString("X") + + " dest-" + (DestMapped(bus, dest) ? "mapped" : "unmapped") + + " ddi_nop@0x03998014 " + + (DdiNopMapped(bus) ? "mapped" : "unmapped") + + (ole32 + ? " dest-word=0x" + destWord.ToString("X8") + + " dataptr-word=0x" + dataWord.ToString("X8") + + " (TOC[34] o32[0]; dump LZX at dataptr)" + : (mscoree + ? " dest-word=0x" + destWord.ToString("X8") + + " dataptr-word=0x" + dataWord.ToString("X8") + + " (TOC[46] o32[0]; dump LZX at dataptr)" + : ""))); + } + + // Refills stay on 0x80000000. Only the general vector + // after WinMain is the unhandled path into + // ThreadExceptionExit. Do not SetEvent that handle. + public static void NoteCpuException(uint code, uint epc, uint vaddr, uint vector) + { + NoteCpuException(code, epc, vaddr, vector, null, null); + } + + public static void NoteCpuException(uint code, uint epc, uint vaddr, uint vector, + uint[] registers, MipsBus bus) + { + bool ddi = _logged.Contains("hive:ldde32") + && ((epc >= DdiNopVbase && epc < DdiNopVend) + || (epc >= DdiNopSlot0 && epc < DdiNopSlot0Vend) + || (vaddr >= DdiNopVbase && vaddr < DdiNopVend) + || (vaddr >= DdiNopSlot0 && vaddr < DdiNopSlot0Vend) + || (vaddr >= 0x01F57000u && vaddr < 0x01F66000u) + || (vaddr >= 0x000E0000u && vaddr < 0x000F0000u && epc >= DdiNopVbase && epc < DdiNopVend)); + bool loader = _logged.Contains("hive:ldde32") + && ((epc >= 0x80016000u && epc < 0x8001C000u) + || (vaddr >= 0x03980000u && vaddr < 0x039B0000u) + || (vaddr >= 0x80764CE0u && vaddr < 0x80776000u) + || (vaddr >= 0x01F57000u && vaddr < 0x01F66000u) + || ddi); + if (ddi && code != 0) + { + string ddiKey = "hive:ddiexn:" + epc.ToString("X") + ":" + code.ToString("X") + ":" + vaddr.ToString("X"); + if (_logged.Add(ddiKey)) + System.Console.WriteLine("[Hive] ddi_nop exception code=" + code + + " epc=0x" + epc.ToString("X8") + + " vaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8")); + if (vaddr >= 0x000E0000u && vaddr < 0x000F0000u + && _logged.Add("hive:ddiexn:e000")) + LogDdiNopE000Store(code, epc, vaddr, registers, bus); + if ((vaddr & CeSlotMask) == 0x000C891Cu + && _logged.Add("hive:ddiexn:c891c")) + LogSlotAliasVa(bus, vaddr, "ddi_nop 0x03986FA8 gwes slot-4 data"); + } + if ((epc == CeRomTocFiles.CreateFileFail || (vaddr & ~0xFFFu) == 0x04085000u) + && code != 0 && _logged.Add("hive:cfile:tlb:" + vaddr.ToString("X"))) + { + System.Console.WriteLine("[Hive] CreateFileFail TLB code=" + code + + " epc=0x" + epc.ToString("X8") + + " vaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " (firmware refill; do not invent 0x040851E8)"); + LogSlotAliasVa(bus, vaddr, "CreateFileFail"); + } + if (code != 0 && CeRomTocFiles.IsTv2DumpPeDest(vaddr) + && _logged.Add("hive:tv2exn:" + epc.ToString("X") + ":" + vaddr.ToString("X"))) + { + uint startip = 0; + try + { + if (bus != null) + { + uint proc = bus.Read32(CeRomTocFiles.CurProc); + if (proc != 0 && proc != 0xDEADBEEFu) + startip = ReadModuleStartip(bus, proc); + } + } + catch + { + } + System.Console.WriteLine("[Hive] FILE[25] exception code=" + code + + " epc=0x" + epc.ToString("X8") + + " vaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " startip=0x" + startip.ToString("X8") + + " (dump PE dest; do not invent 0x81360000)"); + } + CeRomTocFiles.TryNoteBindImpException(code, epc, vaddr, vector, registers, bus); + CeRomTocFiles.TryNoteLeftoverWait99O32NkCoredllExn(code, epc, vaddr, + vector, registers, bus); + CeRomTocFiles.TryNoteTv2PostFetchException(code, epc, vaddr, vector, bus, registers); + if (!_gwesWatch || !_logged.Contains("hive:gpc:WinMain")) + return; + // 0 is a timer interrupt. Those ate the cap and hid the AV. + if (code == 0) + return; + if ((epc & CeSlotMask) == GwesVaAvCompareLhu + && _logged.Add("hive:exn:53944")) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + System.Console.WriteLine("[Hive] AV-compare exception code=" + code + + " epc=0x" + epc.ToString("X8") + + " vaddr=0x" + vaddr.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " (lhu 4(a0); not a dump 0x000E0000 page)"); + } + if (!ddi && vector != ExceptionVector && vector != 0xBFC00380u) + return; + if (!loader && _gwesExnLogged >= 8) + return; + string key = "hive:exn:" + epc.ToString("X") + ":" + code.ToString("X") + ":" + vaddr.ToString("X"); + if (!_logged.Add(key)) + return; + _gwesExnLogged++; + System.Console.WriteLine("[Hive] exception code=" + code + + " epc=0x" + epc.ToString("X8") + + " vaddr=0x" + vaddr.ToString("X8") + + " vec=0x" + vector.ToString("X8") + + " last-gwes=0x" + _gwesLastPc.ToString("X8")); + } + + // Observe only. Do not SetEvent the waited handle. + private static void LogGwesWait(uint pc, uint[] registers, MipsBus bus) + { + if (!IsGwesThread(registers, bus)) + return; + _gwesSawWait = true; + _gwesIn = false; + uint ra = registers != null && registers.Length > 31 ? registers[31] : 0; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + uint a2 = registers != null && registers.Length > 6 ? registers[6] : 0; + uint a3 = registers != null && registers.Length > 7 ? registers[7] : 0; + string kind = pc == CoredllWaitSo ? "WaitForSingleObject" : "WaitForMultipleObjects"; + string key = "hive:gwait:" + ra.ToString("X") + ":" + a0.ToString("X") + ":" + a1.ToString("X"); + if (!_logged.Add(key)) + return; + System.Console.WriteLine("[Hive] gwes wait " + kind + + " pc=0x" + pc.ToString("X8") + + " ra=0x" + ra.ToString("X8") + + " last-gwes=0x" + _gwesLastPc.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " a2=0x" + a2.ToString("X8") + + " a3=0x" + a3.ToString("X8")); + if (bus == null) + return; + try + { + if (pc == CoredllWaitSo) + { + System.Console.WriteLine("[Hive] gwes wait handle=0x" + a0.ToString("X8") + + " timeout=0x" + a1.ToString("X8")); + if (ra >= CoredllThreadExceptionExit && ra < CoredllThreadExceptionExit + 0x1B0) + System.Console.WriteLine("[Hive] gwes wait is ThreadExceptionExit CreateThread handle (not an event; do not SetEvent)"); + } + else + { + uint n = a0; + if (n > 8) + n = 8; + for (uint i = 0; i < n && a1 != 0; i++) + { + uint h = bus.Read32(a1 + i * 4); + System.Console.WriteLine("[Hive] gwes wait handle[" + i + "]=0x" + + h.ToString("X8")); + } + } + } + catch + { + } + } + + private static void NoteGwesPc(uint pc, string what, uint rom, MipsBus bus) + { + uint got = 0; + uint want = 0; + try + { + if (bus != null) + { + got = bus.Read32(pc); + want = bus.Read32(rom); + } + } + catch + { + } + if (want == 0 || got != want) + { + if (_logged.Add("hive:gpcmiss:" + what)) + System.Console.WriteLine("[Hive] " + what + " pc=0x" + pc.ToString("X8") + + " word=0x" + got.ToString("X8") + " (not gwes 0x" + want.ToString("X8") + ")"); + return; + } + _gwesIn = true; + _gwesLastPc = pc; + if (what.IndexOf("Signal", StringComparison.Ordinal) >= 0 + || what.IndexOf("GweApi", StringComparison.Ordinal) >= 0) + _gwesSawSignal = true; + if (_logged.Add("hive:gpc:" + what)) + System.Console.WriteLine("[Hive] gwes " + what + " pc=0x" + pc.ToString("X8") + + " word=0x" + got.ToString("X8")); + } + + private static bool DestMapped(MipsBus bus, uint dest) + { + if (bus == null || dest == 0) + return false; + try + { + bus.Read32(dest); + return true; + } + catch + { + return false; + } + } + + private static bool DdiNopMapped(MipsBus bus) + { + if (bus == null) + return false; + try + { + uint w = bus.Read32(DdiNopSlot0Entry); + if (w != 0 && w != 0xDEADBEEFu) + return true; + } + catch + { + } + try + { + uint w = bus.Read32(DdiNopEntry); + return w != 0 && w != 0xDEADBEEFu; + } + catch + { + return false; + } + } + + private static void LogDdiNopE000Store(uint code, uint epc, uint vaddr, + uint[] registers, MipsBus bus) + { + uint insn = 0; + bool insnOk = false; + try + { + if (bus != null) + { + insn = bus.Read32(epc); + insnOk = true; + } + } + catch + { + } + uint gp = registers != null && registers.Length > 28 ? registers[28] : 0; + uint fp = registers != null && registers.Length > 30 ? registers[30] : 0; + uint v0 = registers != null && registers.Length > 2 ? registers[2] : 0; + uint v1 = registers != null && registers.Length > 3 ? registers[3] : 0; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + uint a2 = registers != null && registers.Length > 6 ? registers[6] : 0; + uint a3 = registers != null && registers.Length > 7 ? registers[7] : 0; + uint s0 = registers != null && registers.Length > 16 ? registers[16] : 0; + uint s1 = registers != null && registers.Length > 17 ? registers[17] : 0; + uint parent = 0; + bool parentOk = false; + try + { + if (bus != null) + { + parent = bus.Read32(GwesDispObj); + parentOk = true; + } + } + catch + { + } + System.Console.WriteLine("[Hive] ddi_nop 0x000E store code=" + code + + " epc=0x" + epc.ToString("X8") + + (insnOk ? " insn=0x" + insn.ToString("X8") : " insn-unmapped") + + " vaddr=0x" + vaddr.ToString("X8") + + " gp=0x" + gp.ToString("X8") + + " fp=0x" + fp.ToString("X8") + + " v0=0x" + v0.ToString("X8") + + " v1=0x" + v1.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8") + + " a2=0x" + a2.ToString("X8") + + " a3=0x" + a3.ToString("X8") + + " s0=0x" + s0.ToString("X8") + + " s1=0x" + s1.ToString("X8") + + (parentOk ? " disp=0x" + parent.ToString("X8") : " disp-unmapped") + + " (jal delay sw $v0,0($fp); $fp is gwes GDI 0x000Exxxx; nk TOC[7] gwes e32 ends 0x000CB000; no ExtraROM/nk o32 or B000FF page at 0x000E0000; not in dump as LE word; do not invent that map)"); + } + + private static void LogDdiNopMapped(MipsBus bus) + { + if (bus == null || !_logged.Add("hive:ddimap")) + return; + try + { + uint w = bus.Read32(DdiNopEntry); + System.Console.WriteLine("[Hive] ddi_nop entry@0x03998014 word=0x" + + w.ToString("X8") + (w == 0 || w == 0xDEADBEEFu ? " (not mapped)" : "")); + } + catch + { + System.Console.WriteLine("[Hive] ddi_nop entry@0x03998014 unmapped"); + } + } + + private static void LogGwesSummary(uint idlePc) + { + if (_gwesSummary) + return; + _gwesSummary = true; + System.Console.WriteLine("[Hive] gwes summary idle=0x" + idlePc.ToString("X8") + + " last=0x" + _gwesLastPc.ToString("X8") + + " entry=" + _logged.Contains("hive:gpc:entry") + + " WinMain=" + _logged.Contains("hive:gpc:WinMain") + + " WinMain-jal=" + _logged.Contains("hive:gpc:WinMain-jal") + + " WinMain-skip=" + _logged.Contains("hive:gpc:WinMain-skip") + + " DisplayFn=" + _logged.Contains("hive:gpc:DisplayFn") + + " DisplayDll=" + _logged.Contains("hive:gpc:DisplayDll") + + " SignalStarted=" + _gwesSawSignal + + " first-wait=" + _gwesSawWait + + " ThreadExceptionExit=" + _gwesSawThrEx + + " CreateThread=" + _gwesSawCreateThr + + " exn-worker=" + _gwesSawWorker + + " ddi_nop=" + _gwesSawDdi + + " ExitThread=" + _gwesSawExit); + } + + // gwes slotted PCs only. 0x0001634C is SignalStarted(_wtol). + // 0x00016354 is OpenEvent(SYSTEM/GweApiSetReady) then + // EventModify SET. There is no GRAPHICS event name. + private static void LogGwesReadySite(uint pc, uint off, uint[] registers, MipsBus bus) + { + string key = "hive:gwes:" + off.ToString("X") + ":" + (pc & CeSlotBase).ToString("X"); + if (!_logged.Add(key)) + return; + _gwesSawSignal = true; + if (off == GwesSignalStarted) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + System.Console.WriteLine("[Hive] gwes SignalStarted site pc=0x" + + pc.ToString("X8") + " a0=" + a0); + } + else + { + string name = ""; + if (registers != null && registers.Length > 6 && bus != null) + name = ReadUtf16(bus, registers[6]); + System.Console.WriteLine("[Hive] gwes OpenEvent \"" + + (string.IsNullOrEmpty(name) ? "(null)" : name) + + "\" pc=0x" + pc.ToString("X8") + + " (SYSTEM/GweApiSetReady, not GRAPHICS)"); + } + } + + private static void LogLaunchReadySlots(MipsBus bus, uint need) + { + if (bus == null || !_logged.Add("hive:slots:" + need)) + return; + try + { + uint table = bus.Read32(LaunchTablePtr); + uint count = bus.Read32(LaunchCountPtr); + uint ev = bus.Read32(LaunchReadyEvent); + System.Console.WriteLine("[Hive] ready-slot table=0x" + table.ToString("X8") + + " count=" + count + " event=0x" + ev.ToString("X8") + + " (WFMO waits this unnamed handle)"); + if (!LooksLikePtr(table) || count == 0 || count > 32) + return; + for (uint i = 0; i < count; i++) + { + uint rec = table + i * LaunchRecordSize; + uint id = bus.Read32(rec); + uint ready = bus.Read32(rec + 4); + string img = ReadUtf16(bus, rec + 72); + if (string.IsNullOrEmpty(img)) + img = "?"; + System.Console.WriteLine("[Hive] ready-slot Launch" + id + + " +4=" + ready + " \"" + img + "\""); + } + LogGwesMappedSlots(bus); + } + catch + { + } + } + + // gwes image_base 0x00010000; SYSTEM/GweApiSetReady at +0x11020. + // Also walk 4KB pages in low RAM — CreateProcess v0=1 does not + // mean the PE was placed in a CE slot. + private static void LogGwesMappedSlots(MipsBus bus) + { + if (bus == null) + return; + int found = 0; + for (uint slot = 1; slot <= 16; slot++) + { + uint va32 = (slot * 0x02000000u) + 0x00011020u; + if (LooksLikeGweApi(bus, va32)) + { + System.Console.WriteLine("[Hive] gwes mapped 32MB slot=" + slot + + " GweApi@0x" + va32.ToString("X8") + + " \"" + ReadUtf16(bus, va32) + "\""); + found++; + } + if (slot <= 8) + { + uint va64 = (slot * 0x04000000u) + 0x00011020u; + if (va64 != va32 && LooksLikeGweApi(bus, va64)) + { + System.Console.WriteLine("[Hive] gwes mapped 64MB slot=" + slot + + " GweApi@0x" + va64.ToString("X8") + + " \"" + ReadUtf16(bus, va64) + "\""); + found++; + } + } + } + if (found == 0) + { + for (uint a = 0x00010000; a < 0x02000000; a += 0x1000) + { + if (!LooksLikeGweApi(bus, a)) + continue; + System.Console.WriteLine("[Hive] gwes GweApi@0x" + a.ToString("X8") + + " \"" + ReadUtf16(bus, a) + "\""); + found++; + break; + } + } + if (found == 0) + System.Console.WriteLine("[Hive] gwes SYSTEM/GweApiSetReady not in slots 1-16 or 0x00010000-0x02000000"); + } + + private static bool LooksLikeGweApi(MipsBus bus, uint va) + { + try + { + uint w0 = bus.Read32(va); + if ((w0 & 0xFFFF) != 0x0053 || (w0 >> 16) != 0x0059) + return false; + uint w1 = bus.Read32(va + 4); + return (w1 & 0xFFFF) == 0x0053 && (w1 >> 16) == 0x0054; + } + catch + { + return false; + } + } + + private static void LogHiveCreateProcess(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 31 || bus == null) + return; + string img = ReadUtf16(bus, registers[4]); + if (string.IsNullOrEmpty(img)) + return; + _cprocName = img; + _cprocRa = registers[31]; + if (_logged.Add("hive:cp:" + img)) + { + string cmd = ""; + if (registers.Length > 5) + cmd = ReadUtf16(bus, registers[5]); + System.Console.WriteLine("[Hive] CreateProcess \"" + img + "\"" + + (string.IsNullOrEmpty(cmd) ? "" : " cmd=\"" + cmd + "\"")); + } + } + + private static void LogHiveCreateProcessRet(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 2) + return; + string img = _cprocName; + uint v0 = registers[2]; + uint err = ReadLastError(bus); + _cprocName = ""; + _cprocRa = 0; + if (string.IsNullOrEmpty(img)) + img = "(null)"; + if (_logged.Add("hive:cpret:" + img)) + System.Console.WriteLine("[Hive] CreateProcess \"" + img + + "\" v0=0x" + v0.ToString("X8") + + " last-error=" + err); + if (v0 != 0 && img.IndexOf("gwes", StringComparison.OrdinalIgnoreCase) >= 0) + { + _gwesWatch = true; + System.Console.WriteLine("[Hive] gwes watch entry VA 0x000163C8 ROM 0x8014B3C8 " + + "WinMain 0x8014B014 Display=ddi_nop.dll (etc XIP vbase 0x03980000)"); + LogDdiNopMapped(bus); + } + if (v0 != 0) + LogCprocThreadAtRet(bus, img); + if (v0 != 0 + && img.IndexOf("tv2clientce", StringComparison.OrdinalIgnoreCase) >= 0) + { + uint threadIp = 0; + try + { + if (bus != null && _cprocThread != 0) + threadIp = bus.Read32(_cprocThread + ThreadStartip); + } + catch + { + } + CeRomTocFiles.NoteTv2Thread(bus, _cprocThread); + CeRomTocFiles.TryKeepTv2ThreadStartip(bus, threadIp); + CeRomTocFiles.TryNoteTv2ProcSwitch(bus); + } + _cprocThread = 0; + } + + private static void LogCprocThreadCtx(uint[]? registers, MipsBus? bus) + { + if (registers == null || registers.Length <= 4 || bus == null) + return; + uint thr = registers[4]; + if (thr == 0) + return; + if (_cprocThread == 0) + _cprocThread = thr; + if (!string.IsNullOrEmpty(_cprocName) + && _cprocName.IndexOf("tv2clientce", StringComparison.OrdinalIgnoreCase) >= 0) + CeRomTocFiles.NoteTv2Thread(bus, thr); + if (_gwesThr == 0 && !string.IsNullOrEmpty(_cprocName) + && _cprocName.IndexOf("gwes", StringComparison.OrdinalIgnoreCase) >= 0) + _gwesThr = thr; + if (!_logged.Add("hive:thr:" + _cprocName + ":" + thr.ToString("X"))) + return; + DumpThreadStart(bus, _cprocName, thr); + } + + private static void LogCprocThreadAtRet(MipsBus bus, string img) + { + if (bus == null || _cprocThread == 0) + return; + if (!_logged.Add("hive:thrret:" + img)) + return; + DumpThreadStart(bus, img + "-ret", _cprocThread); + } + + private static void LogThreadTrampoline(uint[] registers, MipsBus bus) + { + uint procKey = 0; + try + { + if (bus != null) + procKey = bus.Read32(CeRomTocFiles.CurProc); + } + catch + { + } + if (!_logged.Add("hive:tramp:" + procKey.ToString("X"))) + return; + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + uint proc = 0; + uint startip = 0; + try + { + proc = bus != null ? bus.Read32(CeRomTocFiles.CurProc) : 0; + if (proc != 0 && proc != 0xDEADBEEFu) + startip = ReadModuleStartip(bus, proc); + } + catch + { + } + System.Console.WriteLine("[Hive] thread trampoline 0x8001FF38 a0=0x" + + a0.ToString("X8") + " a1=0x" + a1.ToString("X8") + + " CurProc=0x" + proc.ToString("X8") + + " startip=0x" + startip.ToString("X8")); + } + + private static void DumpThreadStart(MipsBus bus, string tag, uint thr) + { + try + { + uint ip = bus.Read32(thr + ThreadStartip); + uint pc = bus.Read32(thr + ThreadCtxPc); + uint sp = bus.Read32(thr + ThreadStack); + uint proc = bus.Read32(thr + ThreadProc); + uint startip = ReadModuleStartip(bus, proc); + System.Console.WriteLine("[Hive] thread \"" + tag + + "\" thr=0x" + thr.ToString("X8") + + " +5C=0x" + ip.ToString("X8") + + " ctxPC=0x" + pc.ToString("X8") + + " sp=0x" + sp.ToString("X8") + + " proc=0x" + proc.ToString("X8") + + " startip=0x" + startip.ToString("X8")); + } + catch + { + } + } + + private static void LogCallDllStartip(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 23 || bus == null) + return; + uint module = registers[23]; + if (module == 0) + return; + uint ip = 0; + try + { + ip = bus.Read32(module + ThreadStartip); + } + catch + { + return; + } + if (!_logged.Add("hive:calldll:" + module.ToString("X") + ":" + ip.ToString("X"))) + return; + uint a1 = registers.Length > 5 ? registers[5] : 0; + System.Console.WriteLine("[Hive] CallDLL module=0x" + module.ToString("X8") + + " startip=0x" + ip.ToString("X8") + + " a1=" + a1); + } + + private static void LogCallDllAfterJalr(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 23) + return; + uint module = registers[23]; + uint v0 = registers.Length > 2 ? registers[2] : 0; + uint reason = registers.Length > 22 ? registers[22] : 0; + uint ip = 0; + try + { + if (bus != null && module != 0) + ip = bus.Read32(module + ThreadStartip); + } + catch + { + } + bool ddi = ip == DdiNopEntry || ip == DdiNopSlot0Entry + || (ip >= DdiNopSlot0 && ip < DdiNopSlot0Vend); + if (!ddi && !_logged.Contains("hive:ll:ddi_nop.dll")) + return; + if (!_logged.Add("hive:calldllret:" + module.ToString("X") + ":" + reason.ToString("X"))) + return; + System.Console.WriteLine("[Hive] CallDLL DllMain ret v0=0x" + v0.ToString("X8") + + " reason=" + reason + + " module=0x" + module.ToString("X8") + + " startip=0x" + ip.ToString("X8")); + } + + private static void DumpDdiNopEntry(MipsBus bus, uint pc, uint[] registers) + { + uint a0 = registers != null && registers.Length > 4 ? registers[4] : 0; + uint a1 = registers != null && registers.Length > 5 ? registers[5] : 0; + System.Console.WriteLine("[Hive] ddi_nop entry words pc=0x" + pc.ToString("X8") + + " a0=0x" + a0.ToString("X8") + + " a1=0x" + a1.ToString("X8")); + if (bus == null) + return; + for (uint i = 0; i < 8; i++) + { + uint va = pc + i * 4; + try + { + uint w = bus.Read32(va); + System.Console.WriteLine("[Hive] ddi_nop +" + (i * 4).ToString("X") + + " @0x" + va.ToString("X8") + " word=0x" + w.ToString("X8")); + } + catch + { + System.Console.WriteLine("[Hive] ddi_nop +" + (i * 4).ToString("X") + + " @0x" + va.ToString("X8") + " unmapped"); + break; + } + } + } + + private static void LogXipExeCallDllSkip(uint[] registers, MipsBus bus) + { + if (registers == null || registers.Length <= 30 || bus == null) + return; + uint module = registers[30]; + if (module == 0) + return; + uint p50 = 0; + uint ip = 0; + try + { + p50 = bus.Read32(module + ProcModule); + ip = bus.Read32(module + ThreadStartip); + } + catch + { + return; + } + if (!_logged.Add("hive:exeskip:" + module.ToString("X") + ":" + p50.ToString("X"))) + return; + System.Console.WriteLine("[Hive] EXE CallDLL-skip module=0x" + module.ToString("X8") + + " +50=0x" + p50.ToString("X8") + + " +5C=0x" + ip.ToString("X8")); + } + + private static void LogLoadExeStartip(MipsBus bus) + { + uint proc = 0; + uint startip = 0; + try + { + if (bus != null) + proc = bus.Read32(CeRomTocFiles.CurProc); + startip = ReadModuleStartip(bus, proc); + } + catch + { + } + if (!_logged.Add("hive:ldxe:" + proc.ToString("X") + ":" + startip.ToString("X"))) + return; + System.Console.WriteLine("[Hive] load-exe CurProc=0x" + proc.ToString("X8") + + " startip=0x" + startip.ToString("X8")); + } + + private static uint ReadModuleStartip(MipsBus bus, uint proc) + { + if (bus == null || proc == 0 || proc == 0xDEADBEEFu) + return 0; + try + { + uint ip = bus.Read32(proc + ThreadStartip); + if (ip != 0) + return ip; + uint mod = bus.Read32(proc + ProcModule); + if (mod != 0 && mod != 0xDEADBEEFu) + return bus.Read32(mod + ThreadStartip); + } + catch + { + } + return 0; + } + + private static uint ReadLastError(MipsBus bus) + { + if (bus == null) + return 0xFFFFFFFF; + try + { + uint thr = bus.Read32(ThreadPtr); + if (thr != 0 && thr != 0xDEADBEEFu) + return bus.Read32(thr + ThreadLastErr); + } + catch + { + } + return 0xFFFFFFFF; + } + + // Observe only after compact. Do not rewrite +14/+18. + private static void LogInheritList(MipsBus bus, uint list) + { + if (_inheritListLogged || bus == null || list == 0) + return; + _inheritListLogged = true; + try + { + uint count = bus.Read32(list + 8); + System.Console.WriteLine("[Inherit] LIST @0x" + list.ToString("X8") + " count=" + count); + if (count > 8) + count = 8; + for (uint i = 0; i < count; i++) + { + uint pair = list + 12 + i * 8; + uint start = bus.Read32(pair); + uint end = bus.Read32(pair + 4); + System.Console.WriteLine("[Inherit] pair" + i + + " start=0x" + start.ToString("X8") + + " end=0x" + end.ToString("X8")); + } + } + catch + { + } + } + + private const string LastUsedName = "last_dump_root.txt"; + private const int HuntMaxDepth = 3; + private const int HuntMaxVisit = 400; + + private static readonly HashSet VolumeNames = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "etc.bin", "BOOT.PRF", "tv2clientce", "tv2clientce.exe", "Application" + }; + + private static readonly HashSet HuntNames = new HashSet(StringComparer.OrdinalIgnoreCase) + { + "nk.bin", "etc.bin", "sec.bin", "XASEC.BIN", + "BOOT.PRF", "BOOTPRF.BAK", + "tv2clientce", "tv2clientce.exe", + "tv2clientcorece.dll", "tv2engine.dll", "iptvdriver.dll", + "default.hv", "hashes.bin", "gwes.exe", + "Application", "PlayReady", + "raven_fw.bin", "WirelessFirmware.img", "ContentVersion.txt", + "boot.sig", "runonce.sig", "Hard Disk" + }; + + internal static string ResolveRoot() + { + foreach (string raw in CandidateFeeds()) + { + string feed = NormalizeFeed(raw); + if (string.IsNullOrEmpty(feed)) + continue; + if (LooksLikeVolume(feed)) + { + NoteDumpImages(feed); + return feed; + } + System.Console.WriteLine("[HardDisk] hunt feed=" + feed); + string attach = HuntAttach(feed); + if (!string.IsNullOrEmpty(attach)) + return attach; + } + return ""; + } + + private static bool LooksLikeVolume(string dir) + { + try + { + foreach (string f in Directory.GetFiles(dir)) + { + string n = Path.GetFileName(f); + if (n.Equals("nk.bin", StringComparison.OrdinalIgnoreCase) + || n.Equals("etc.bin", StringComparison.OrdinalIgnoreCase) + || n.Equals("BOOT.PRF", StringComparison.OrdinalIgnoreCase) + || n.Equals("sec.bin", StringComparison.OrdinalIgnoreCase)) + return true; + } + } + catch + { + } + return false; + } + + // etc.bin by name (HD file + ExtraROM candidate). Other + // B000FF only when they sit next to nk.bin. sec.bin / + // raven_fw.bin / BOOT.PRF stay hunt names for FAT, not XIP. + private static void NoteDumpImages(string dir) + { + if (string.IsNullOrEmpty(dir) || !Directory.Exists(dir)) + return; + try + { + foreach (string f in Directory.GetFiles(dir)) + { + string name = Path.GetFileName(f); + if (name.Equals("nk.bin", StringComparison.OrdinalIgnoreCase)) + { + _nkDir = dir; + continue; + } + if (name.Equals("etc.bin", StringComparison.OrdinalIgnoreCase) || PeekB000Ff(f)) + AddExtraRom(f); + } + foreach (string d in Directory.GetDirectories(dir)) + { + string name = Path.GetFileName(d); + if (name.Equals("etc.bin", StringComparison.OrdinalIgnoreCase)) + NoteExtractedExtraRom(d); + } + } + catch + { + } + } + + // Extracted ExtraROM tree (Dumps\etc.bin\). Not a B000FF. + // Firmware sees those XIP files after the raw etc.bin map. + private static void NoteExtractedExtraRom(string dir) + { + if (string.IsNullOrEmpty(dir) || _extractLogged || !Directory.Exists(dir)) + return; + try + { + string marker = Path.Combine(dir, "tv2clientce.exe"); + if (!File.Exists(marker)) + marker = Path.Combine(dir, "tv2clientcorece.dll"); + if (!File.Exists(marker)) + return; + _extractLogged = true; + System.Console.WriteLine("[HardDisk] ExtraROM extract dir=" + dir + + " (not B000FF; firmware sees XIP after map at imageStart)"); + int n = 0; + foreach (string f in Directory.GetFiles(dir)) + { + string name = Path.GetFileName(f); + if (n < 16) + System.Console.WriteLine("[HardDisk] ExtraROM extract file " + name + + " " + new FileInfo(f).Length); + n++; + } + if (n > 16) + System.Console.WriteLine("[HardDisk] ExtraROM extract files=" + n); + } + catch + { + } + } + + private static void AddExtraRom(string path) + { + if (string.IsNullOrEmpty(path)) + return; + try { path = Path.GetFullPath(path); } + catch { return; } + foreach (string existing in _extraRoms) + { + if (existing.Equals(path, StringComparison.OrdinalIgnoreCase)) + return; + } + _extraRoms.Add(path); + } + + private static bool PeekB000Ff(string path) + { + try + { + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + if (fs.Length < 15) + return false; + byte[] h = new byte[7]; + return fs.Read(h, 0, 7) == 7 + && h[0] == (byte)'B' + && h[1] == (byte)'0' + && h[2] == (byte)'0' + && h[3] == (byte)'0' + && h[4] == (byte)'F' + && h[5] == (byte)'F' + && h[6] == (byte)'\n'; + } + } + catch + { + return false; + } + } + + public static string HuntAttach(string feed) + { + if (string.IsNullOrEmpty(feed) || !Directory.Exists(feed)) + return ""; + var scores = new Dictionary(StringComparer.OrdinalIgnoreCase); + var seenNames = new HashSet(StringComparer.OrdinalIgnoreCase); + WalkHunt(feed, 0, 0, scores, seenNames); + string bestVol = ""; + string bestLoose = ""; + int bestVolMark = 0; + int bestLooseMark = 0; + bool bestHasEtc = false; + foreach (var kv in scores) + { + VolumeScore s = kv.Value; + if (s.Markers > 0) + { + bool take = s.Markers > bestVolMark; + if (!take && s.Markers == bestVolMark) + { + if (s.HasEtc && !bestHasEtc) + take = true; + else if (s.HasEtc == bestHasEtc + && (bestVol.Length == 0 || kv.Key.Length < bestVol.Length)) + take = true; + } + if (take) + { + bestVolMark = s.Markers; + bestHasEtc = s.HasEtc; + bestVol = kv.Key; + } + } + else if (s.Extra > 0 + && (s.Extra > bestLooseMark + || (s.Extra == bestLooseMark + && (bestLoose.Length == 0 || kv.Key.Length < bestLoose.Length)))) + { + bestLooseMark = s.Extra; + bestLoose = kv.Key; + } + } + if (!string.IsNullOrEmpty(bestVol)) + { + NoteDumpImages(bestVol); + if (!string.IsNullOrEmpty(_nkDir)) + NoteDumpImages(_nkDir); + return bestVol; + } + if (!string.IsNullOrEmpty(bestLoose)) + { + NoteDumpImages(bestLoose); + if (!string.IsNullOrEmpty(_nkDir)) + NoteDumpImages(_nkDir); + return bestLoose; + } + return ""; + } + + private static int WalkHunt(string dir, int depth, int visited, + Dictionary scores, HashSet seenNames) + { + if (depth > HuntMaxDepth || visited >= HuntMaxVisit) + return visited; visited++; string[] ents; try { ents = Directory.GetFileSystemEntries(dir); } @@ -1094,8 +3905,15 @@ private static int WalkHunt(string dir, int depth, int visited, } if (HuntNames.Contains(name) && seenNames.Add(name)) System.Console.WriteLine("[HardDisk] found " + name + " at " + p); - if (name.Equals("etc.bin", StringComparison.OrdinalIgnoreCase) && string.IsNullOrEmpty(_extraRom)) - _extraRom = p; + if (name.Equals("nk.bin", StringComparison.OrdinalIgnoreCase) && !isDir) + _nkDir = Path.GetDirectoryName(p) ?? ""; + if (name.Equals("etc.bin", StringComparison.OrdinalIgnoreCase)) + { + if (isDir) + NoteExtractedExtraRom(p); + else + AddExtraRom(p); + } if (VolumeNames.Contains(name) || HuntNames.Contains(name)) { VolumeScore s; @@ -1151,6 +3969,7 @@ private static IEnumerable CandidateFeeds() // Shipped attach is the user feed + name hunt above. yield return "/workspace/UverseDriveE"; yield return @"E:\EVO backup 2026 august 26\DVR Stuff\UVERSE STUFF\Uverse Drive E"; + yield return @"E:\EVO backup 2026 august 26\DVR Stuff\UVERSE STUFF\Dumps"; } private static IEnumerable CommandLineFeeds() diff --git a/Core/NkBinLoader.cs b/Core/NkBinLoader.cs index 4dd48997..2bd22d7c 100644 --- a/Core/NkBinLoader.cs +++ b/Core/NkBinLoader.cs @@ -1,5 +1,7 @@ using System; +using System.Collections.Generic; using System.IO; +using System.Text; using ProcessorEmulator.Core.Emulation; using ProcessorEmulator.Core; @@ -27,6 +29,15 @@ public NkLoadResult(ulong entryPoint, uint imageStart, uint imageLength, int rec public static class NkBinLoader { + // nk.bin chain table 0x8006B9DC (16-byte records). Julian's + // dump etc.bin is B000FF at 0x80630000. Load every dump + // B000FF at THAT file's imageStart. Do not invent a map for + // a chain base with no matching dump B000FF (0x81360000 in + // this dump). Firmware has no skip for that missing image. + // Do not invent a map or a host skip. Do not zero-fill. + public const uint ChainTable = 0x8006B9DC; + public const int ChainRecords = 3; + public static bool IsB000Ff(byte[] data) { return data != null @@ -68,13 +79,464 @@ public static NkLoadResult Load(byte[] data, IMemoryManager memory) uint imageLength = BitConverter.ToUInt32(data, pos); pos += 4; - Console.WriteLine($"[NkBinLoader] Loading kernel. Image start: 0x{imageStart:X}, Length: 0x{imageLength:X}"); + Log("[NkBinLoader] Loading kernel. Image start: 0x" + imageStart.ToString("X") + ", Length: 0x" + imageLength.ToString("X")); + BootLog.Rom("ok", "NK", "image", -1, "nk.bin", 0, imageStart, 0, imageLength, + "B000FF map"); - ulong entryPoint = 0; - uint firstRecord = 0; - int records = 0; - bool truncated = false; + int records = WriteB000FfRecords(data, pos, imageLength, memory, "nk", out uint firstRecord, out ulong entryPoint, out bool truncated); + + if (entryPoint == 0) + entryPoint = firstRecord != 0 ? firstRecord : imageStart; + + if (entryPoint == 0) + throw new InvalidDataException("Could not determine kernel entry point from nk.bin file."); + + BinBlkMedia.Attach(data); + HostHardDisk.Attach(); + var mapped = new HashSet { imageStart }; + TryLoadDumpB000Ff(HostHardDisk.ExtraRomPaths, memory, mapped); + ReportMissingChainImages(memory, mapped); + return new NkLoadResult(entryPoint, imageStart, imageLength, records, truncated, data); + } + + // Hunt is HostHardDisk ExtraRomPaths: every etc.bin plus any + // other B000FF sitting next to nk.bin. Read-only. Load each + // file's records at THAT file's imageStart (same walk as nk). + // Skip stubs and non-B000FF (sec.bin, raven_fw.bin). Does not + // attach BINBlk. Does not invent a chain base with no dump + // B000FF. Firmware CreateFile of ETC.bin / BOOT.PRF / sec.bin + // stays the Hard Disk path, not a second XIP. + public static int TryLoadDumpB000Ff(IEnumerable paths, IMemoryManager memory, HashSet mappedStarts) + { + int loaded = 0; + if (memory == null || paths == null) + return 0; + var seen = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (string path in paths) + { + if (string.IsNullOrEmpty(path) || !seen.Add(Path.GetFullPath(path))) + continue; + if (TryLoadOneDumpB000Ff(path, memory, mappedStarts)) + loaded++; + } + return loaded; + } + + public static bool TryLoadExtraRom(string path, IMemoryManager memory) + { + var mapped = new HashSet(); + return TryLoadOneDumpB000Ff(path, memory, mapped); + } + + private static bool TryLoadOneDumpB000Ff(string path, IMemoryManager memory, HashSet mappedStarts) + { + if (memory == null || string.IsNullOrEmpty(path) || !File.Exists(path)) + return false; + + long len; + try { len = new FileInfo(path).Length; } + catch { return false; } + if (len < 15) + { + Log("[NkBinLoader] ExtraROM skip " + path + " (" + len + " bytes, stub)"); + BootLog.Rom("skip", "ExtraROM", "image", -1, Path.GetFileName(path), 0, 0, 0, 0, + "stub"); + return false; + } + + byte[] header; + try + { + header = new byte[15]; + using (var fs = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite)) + { + if (fs.Read(header, 0, 15) < 15) + { + Log("[NkBinLoader] ExtraROM skip " + path + " (short read, stub)"); + BootLog.Rom("skip", "ExtraROM", "image", -1, Path.GetFileName(path), 0, 0, 0, 0, + "short read, stub"); + return false; + } + } + } + catch (Exception ex) + { + Log("[NkBinLoader] ExtraROM read failed " + path + ": " + ex.Message); + BootLog.Rom("fail", "ExtraROM", "image", -1, Path.GetFileName(path), 0, 0, 0, 0, + ex.Message); + return false; + } + + if (!IsB000Ff(header)) + { + Log("[NkBinLoader] ExtraROM skip " + path + " (" + len + " bytes, not B000FF)"); + BootLog.Rom("skip", "ExtraROM", "image", -1, Path.GetFileName(path), 0, 0, 0, 0, + "not B000FF"); + return false; + } + + uint imageStart = BitConverter.ToUInt32(header, 7); + uint imageLength = BitConverter.ToUInt32(header, 11); + if (mappedStarts != null && mappedStarts.Contains(imageStart)) + { + Log("[NkBinLoader] ExtraROM skip " + path + + " imageStart=0x" + imageStart.ToString("X8") + " (already mapped)"); + BootLog.Rom("skip", "ExtraROM", "image", -1, Path.GetFileName(path), 0, imageStart, 0, 0, + "already mapped"); + return false; + } + + byte[] data; + try + { + data = File.ReadAllBytes(path); + } + catch (Exception ex) + { + Log("[NkBinLoader] ExtraROM read failed " + path + ": " + ex.Message); + BootLog.Rom("fail", "ExtraROM", "image", -1, Path.GetFileName(path), 0, 0, 0, 0, + ex.Message); + return false; + } + + string label = Path.GetFileName(path); + int records = WriteB000FfRecords(data, 15, imageLength, memory, label, out _, out _, out bool truncated); + if (records <= 0) + { + Log("[NkBinLoader] ExtraROM skip " + path + " (no records" + (truncated ? ", truncated" : "") + ")"); + BootLog.Rom("skip", "ExtraROM", "image", -1, label, 0, imageStart, 0, 0, + truncated ? "no records, truncated" : "no records"); + return false; + } + if (mappedStarts != null) + mappedStarts.Add(imageStart); + Log("[NkBinLoader] ExtraROM mapped records=" + records + + " imageStart=0x" + imageStart.ToString("X8") + + " path=" + path); + BootLog.Rom("ok", "ExtraROM", "image", -1, label, 0, imageStart, 0, imageLength, + "B000FF map; XIP at imageStart"); + CeRomTocFiles.NoteExtraRom(imageStart); + LogMappedRomHdr(memory, imageStart); + return true; + } + + // After a real map, ExtraROM XIP (tv2clientce.exe and the + // rest) lives in this ROMHDR/TOC. Firmware inherit does not + // peek that VA; +14/+18 stay leftovers unless the overlay + // compare matches. Log only. + private static void LogMappedRomHdr(IMemoryManager memory, uint imageStart) + { + if (memory == null || imageStart == 0) + return; + try + { + uint sig = memory.ReadMemory32(imageStart + 0x40); + uint romhdr = memory.ReadMemory32(imageStart + 0x44); + if (sig != 0x43454345 || romhdr == 0) + romhdr = imageStart; + uint dllfirst = memory.ReadMemory32(romhdr); + uint dlllast = memory.ReadMemory32(romhdr + 4); + uint nummods = memory.ReadMemory32(romhdr + 0x10); + uint numfiles = memory.ReadMemory32(romhdr + 0x30); + Log("[NkBinLoader] ExtraROM ROMHDR imageStart=0x" + imageStart.ToString("X8") + + " cece=0x" + sig.ToString("X8") + + " romhdr=0x" + romhdr.ToString("X8") + + " dllfirst=0x" + dllfirst.ToString("X8") + + " dlllast=0x" + dlllast.ToString("X8") + + " nummods=" + nummods + + " numfiles=" + numfiles); + CeRomTocFiles.LogExtraRomHdrAtMap(memory, romhdr); + bool sawCom16550Toc = false; + bool sawCom16550File = false; + if (nummods > 0 && nummods <= 128) + { + for (uint i = 0; i < nummods; i++) + { + uint entry = romhdr + 0x54 + i * 32; + uint namePtr = memory.ReadMemory32(entry + 0x10); + string name = ReadAscii(memory, namePtr); + if (string.IsNullOrEmpty(name)) + continue; + uint dest = 0; + uint vsize = 0; + uint psize = 0; + uint e32 = memory.ReadMemory32(entry + 0x14); + uint o32 = memory.ReadMemory32(entry + 0x18); + if (o32 != 0) + { + try + { + vsize = memory.ReadMemory32(o32); + psize = memory.ReadMemory32(o32 + 8); + dest = memory.ReadMemory32(o32 + 0x10); + } + catch + { + } + } + string why = "TOCentry type-7; dump o32 if present; do not invent 0x81360000"; + CeRomTocFiles.CacheExtraRomTocModule(memory, romhdr, entry, (int)i, name); + if (IsDdiNop(name)) + { + uint tocAttr = memory.ReadMemory32(entry); + CeRomTocFiles.NoteExtraRomModule(romhdr, entry, tocAttr); + CeRomTocFiles.CacheExtraRomDdiNop(memory, entry); + why = "LoadDriver; TOC type-7 Display=ddi_nop.dll stub; guest screen black; do not invent a framebuffer"; + } + if (IsMscoree(name)) + { + CeRomTocFiles.CacheExtraRomMscoree(memory, entry); + why = "OpenExe; TOC type-7; not a FILE; e32=0x" + e32.ToString("X8") + + "; do not invent 0x81360000"; + } + if (IsOle32(name)) + { + CeRomTocFiles.CacheExtraRomOle32(memory, entry); + why = "OpenExe; TOC type-7; not a FILE; e32=0x" + e32.ToString("X8") + + "; do not invent 0x81360000"; + } + if (IsCom16550(name)) + sawCom16550Toc = true; + if (IsIptvHal(name) || IsIptvDriver(name)) + why = "TOC[" + i + "] type-7; Prefix BTV; pixels IPTVDriver/iptvhal; Display stays ddi_nop.dll; ExtraROM has no second GDI DDI; do not invent a Display REG_SZ"; + else if (BootLog.IsGuestIoName(name) && !IsDdiNop(name)) + why = GuestIoWhy(name, i, true); + BootLog.Rom("ok", "ExtraROM", "TOC", (int)i, name, 7, dest, vsize, psize, why); + } + } + uint nfiles = memory.ReadMemory32(romhdr + 0x30); + if (nfiles > 0 && nfiles <= 128 && nummods <= 128) + { + uint first = romhdr + 0x54 + nummods * 32; + bool sawMscoreeFile = false; + bool sawOle32File = false; + for (uint i = 0; i < nfiles; i++) + { + uint entry = first + i * 28; + string fname = ReadAscii(memory, memory.ReadMemory32(entry + 0x14)); + if (string.IsNullOrEmpty(fname)) + continue; + uint realSz = memory.ReadMemory32(entry + 0x0C); + uint compSz = memory.ReadMemory32(entry + 0x10); + uint load = memory.ReadMemory32(entry + 0x18); + string why = "FILESentry type-8; dump record; do not invent 0x81360000"; + if (IsOle32(fname)) + { + sawOle32File = true; + why = "FILESentry; unexpected ole32 FILE; do not invent"; + } + else if (IsMscoree(fname)) + { + sawMscoreeFile = true; + why = "FILESentry; unexpected mscoree FILE; do not invent"; + } + if (IsCom16550(fname)) + sawCom16550File = true; + if (IsIptvHal(fname) || IsIptvDriver(fname)) + why = "FILE[" + i + "] type-8; Prefix BTV; pixels IPTVDriver/iptvhal; Display stays ddi_nop.dll; do not invent a Display REG_SZ"; + else if (BootLog.IsGuestIoName(fname)) + why = GuestIoWhy(fname, i, false); + BootLog.Rom("ok", "ExtraROM", "FILE", (int)i, fname, 8, load, realSz, compSz, why); + if (IsTv2ClientCeExe(fname)) + CeRomTocFiles.CacheExtraRomTv2File(memory, entry); + else + CeRomTocFiles.CacheExtraRomOpenFile(memory, entry, fname, (int)i); + } + if (!sawMscoreeFile) + Log("[NkBinLoader] ExtraROM FILE table has no mscoree.dll" + + " (TOC[46] is the dump module; do not invent a FILE)"); + if (!sawOle32File) + Log("[NkBinLoader] ExtraROM FILE table has no ole32.dll" + + " (TOC[34] is the dump module; do not invent a FILE)"); + } + if (!sawCom16550Toc && !sawCom16550File) + BootLog.Rom("miss", "ExtraROM", "", -1, "com16550.dll", 0, 0, 0, 0, + "not in ExtraROM TOC/FILE; hive Dllcom16550.dll may be leftover; do not claim it loads"); + CeRomTocFiles.LogExtraRomTocAttachCache(); + } + catch (Exception ex) + { + Log("[NkBinLoader] ExtraROM ROMHDR log skipped: " + ex.Message); + } + } + + private static bool IsIptvHal(string name) + { + return name != null + && name.IndexOf("iptvhal", StringComparison.OrdinalIgnoreCase) >= 0; + } + + private static bool IsIptvDriver(string name) + { + return name != null + && name.IndexOf("iptvdriver", StringComparison.OrdinalIgnoreCase) >= 0; + } + + private static bool IsCom16550(string name) + { + if (string.IsNullOrEmpty(name) || name.Length != 12) + return false; + return (name[0] == 'c' || name[0] == 'C') + && (name[1] == 'o' || name[1] == 'O') + && (name[2] == 'm' || name[2] == 'M') + && name[3] == '1' + && name[4] == '6' + && name[5] == '5' + && name[6] == '5' + && name[7] == '0' + && name[8] == '.' + && (name[9] == 'd' || name[9] == 'D') + && (name[10] == 'l' || name[10] == 'L') + && (name[11] == 'l' || name[11] == 'L'); + } + + private static string GuestIoWhy(string name, uint index, bool toc) + { + string kind = toc ? "TOC[" + index + "] type-7" : "FILE[" + index + "] type-8"; + if (name != null && name.IndexOf("serial", StringComparison.OrdinalIgnoreCase) >= 0 + && name.IndexOf("bcmuart", StringComparison.OrdinalIgnoreCase) < 0) + return kind + "; hive Dll Serial.dll / UART; MipsUart 0xB0000000 is the live TX log; do not invent a second UART"; + if (name != null && name.IndexOf("bcmuart", StringComparison.OrdinalIgnoreCase) >= 0) + return kind + "; hive Dll bcmuart.dll; MipsUart 0xB0000000 is the live TX log; do not invent a second UART"; + if (name != null && name.IndexOf("com16550", StringComparison.OrdinalIgnoreCase) >= 0) + return kind + "; hive Dllcom16550.dll; ExtraROM has this name"; + if (name != null && (name.IndexOf("rtl8139", StringComparison.OrdinalIgnoreCase) >= 0 + || name.IndexOf("bcm7038mac", StringComparison.OrdinalIgnoreCase) >= 0 + || name.IndexOf("ndis", StringComparison.OrdinalIgnoreCase) >= 0)) + return kind + "; hive ImagePath; no NIC on the MIPS bus; log only; do not invent a NIC"; + if (name != null && (name.IndexOf("iptvhal", StringComparison.OrdinalIgnoreCase) >= 0 + || name.IndexOf("iptvdriver", StringComparison.OrdinalIgnoreCase) >= 0)) + return kind + "; Prefix BTV; pixels IPTVDriver/iptvhal; Display stays ddi_nop.dll; do not invent a Display REG_SZ"; + return kind + "; guest IO name; do not invent a NIC or UART"; + } + + private static bool IsOle32(string name) + { + if (string.IsNullOrEmpty(name) || name.Length != 9) + return false; + return (name[0] == 'o' || name[0] == 'O') + && (name[1] == 'l' || name[1] == 'L') + && (name[2] == 'e' || name[2] == 'E') + && name[3] == '3' + && name[4] == '2' + && name[5] == '.' + && (name[6] == 'd' || name[6] == 'D') + && (name[7] == 'l' || name[7] == 'L') + && (name[8] == 'l' || name[8] == 'L'); + } + + private static bool IsMscoree(string name) + { + if (string.IsNullOrEmpty(name) || name.Length != 11) + return false; + return (name[0] == 'm' || name[0] == 'M') + && (name[1] == 's' || name[1] == 'S') + && (name[2] == 'c' || name[2] == 'C') + && (name[3] == 'o' || name[3] == 'O') + && (name[4] == 'r' || name[4] == 'R') + && (name[5] == 'e' || name[5] == 'E') + && (name[6] == 'e' || name[6] == 'E') + && name[7] == '.' + && (name[8] == 'd' || name[8] == 'D') + && (name[9] == 'l' || name[9] == 'L') + && (name[10] == 'l' || name[10] == 'L'); + } + + private static bool IsDdiNop(string name) + { + if (string.IsNullOrEmpty(name) || name.Length != 11) + return false; + return (name[0] == 'd' || name[0] == 'D') + && (name[1] == 'd' || name[1] == 'D') + && (name[2] == 'i' || name[2] == 'I') + && name[3] == '_' + && (name[4] == 'n' || name[4] == 'N') + && (name[5] == 'o' || name[5] == 'O') + && (name[6] == 'p' || name[6] == 'P') + && name[7] == '.' + && (name[8] == 'd' || name[8] == 'D') + && (name[9] == 'l' || name[9] == 'L') + && (name[10] == 'l' || name[10] == 'L'); + } + + private static bool IsTv2ClientCeExe(string name) + { + if (string.IsNullOrEmpty(name) || name.Length != 15) + return false; + return (name[0] == 't' || name[0] == 'T') + && (name[1] == 'v' || name[1] == 'V') + && name[2] == '2' + && (name[3] == 'c' || name[3] == 'C') + && (name[4] == 'l' || name[4] == 'L') + && (name[5] == 'i' || name[5] == 'I') + && (name[6] == 'e' || name[6] == 'E') + && (name[7] == 'n' || name[7] == 'N') + && (name[8] == 't' || name[8] == 'T') + && (name[9] == 'c' || name[9] == 'C') + && (name[10] == 'e' || name[10] == 'E') + && name[11] == '.' + && (name[12] == 'e' || name[12] == 'E') + && (name[13] == 'x' || name[13] == 'X') + && (name[14] == 'e' || name[14] == 'E'); + } + private static string ReadAscii(IMemoryManager memory, uint addr) + { + if (memory == null || addr == 0) + return ""; + var sb = new StringBuilder(); + for (int i = 0; i < 64; i += 4) + { + uint w = memory.ReadMemory32(addr + (uint)i); + for (int b = 0; b < 4; b++) + { + byte c = (byte)(w >> (8 * b)); + if (c == 0) + return sb.ToString(); + if (c < 32 || c > 126) + return sb.ToString(); + sb.Append((char)c); + } + } + return sb.ToString(); + } + + // Report only. Do not write bytes for a chain base the dump + // did not name as B000FF. + private static void ReportMissingChainImages(IMemoryManager memory, HashSet mappedStarts) + { + if (memory == null || mappedStarts == null) + return; + try + { + for (int i = 0; i < ChainRecords; i++) + { + uint rec = ChainTable + (uint)(i * 16); + uint imageStart = memory.ReadMemory32(rec); + uint imageLength = memory.ReadMemory32(rec + 4); + if (imageStart == 0) + continue; + if (mappedStarts.Contains(imageStart)) + continue; + Log("[NkBinLoader] ExtraROM missing dump B000FF for chain base=0x" + + imageStart.ToString("X8") + " size=0x" + imageLength.ToString("X") + + " (firmware has no skip; do not invent a map)"); + BootLog.Rom("miss", "ExtraROM", "image", -1, "", 0, imageStart, 0, imageLength, + "no dump B000FF for chain base; do not invent a map"); + } + } + catch (Exception ex) + { + Log("[NkBinLoader] ExtraROM chain report skipped: " + ex.Message); + } + } + + private static int WriteB000FfRecords(byte[] data, int pos, uint imageLength, IMemoryManager memory, string label, out uint firstRecord, out ulong entryPoint, out bool truncated) + { + firstRecord = 0; + entryPoint = 0; + truncated = false; + int records = 0; while (pos + 12 <= data.Length) { uint recordAddress = BitConverter.ToUInt32(data, pos); @@ -86,14 +548,16 @@ public static NkLoadResult Load(byte[] data, IMemoryManager memory) if (pos + 4 <= data.Length) { entryPoint = BitConverter.ToUInt32(data, pos); - Console.WriteLine($"[NkBinLoader] Found sync record. Entry Point: 0x{entryPoint:X}"); + Log("[NkBinLoader] " + label + " sync record. Entry Point: 0x" + entryPoint.ToString("X")); } break; } if (recordLength == 0 || recordLength > imageLength || pos + recordLength > data.Length) { - Console.WriteLine($"[NkBinLoader] Stopping at record {records}: addr=0x{recordAddress:X} len=0x{recordLength:X} remaining={data.Length - pos}"); + Log("[NkBinLoader] " + label + " stop at record " + records + + ": addr=0x" + recordAddress.ToString("X") + " len=0x" + recordLength.ToString("X") + + " remaining=" + (data.Length - pos)); truncated = true; break; } @@ -102,23 +566,19 @@ public static NkLoadResult Load(byte[] data, IMemoryManager memory) Buffer.BlockCopy(data, pos, record, 0, (int)recordLength); pos += (int)recordLength; - Console.WriteLine($"[NkBinLoader] Loading record at 0x{recordAddress:X}, Length: {recordLength}"); + Log("[NkBinLoader] " + label + " record at 0x" + recordAddress.ToString("X") + ", Length: " + recordLength); memory.WriteMemory(recordAddress, record); if (records == 0) firstRecord = recordAddress; records++; } + return records; + } - if (entryPoint == 0) - entryPoint = firstRecord != 0 ? firstRecord : imageStart; - - if (entryPoint == 0) - throw new InvalidDataException("Could not determine kernel entry point from nk.bin file."); - - BinBlkMedia.Attach(data); - HostHardDisk.Attach(); - return new NkLoadResult(entryPoint, imageStart, imageLength, records, truncated, data); + private static void Log(string line) + { + BootLog.Write(line); } } } diff --git a/Directory.Build.props b/Directory.Build.props new file mode 100644 index 00000000..ad4a2f74 --- /dev/null +++ b/Directory.Build.props @@ -0,0 +1,5 @@ + + + true + + diff --git a/MediaroomHostForm.cs b/MediaroomHostForm.cs index f541b6a1..8de59fe1 100644 --- a/MediaroomHostForm.cs +++ b/MediaroomHostForm.cs @@ -1,34 +1,37 @@ using System; using System.Drawing; +using System.IO; using System.Threading; using System.Windows.Forms; +using ProcessorEmulator.Core; namespace ProcessorEmulator { - // Thin Win7 host. Framebuffer pane is the surface. Black until - // the guest writes video RAM. No boot-log theater. + // Thin Win7 guest console. The window is the guest display + // (black until video RAM). Start/Stop + one attached folder. + // Same MediaroomSession path. No dump/boot theater. public sealed class MediaroomHostForm : Form { - private readonly TextBox _dumpBox; - private readonly Button _browse; - private readonly Button _boot; + private readonly TextBox _folderBox; + private readonly Button _folder; + private readonly Button _start; private readonly Button _stop; - private readonly Label _status; + private readonly TextBox _status; private readonly PictureBox _frame; - private readonly System.Windows.Forms.Timer _tick; private MediaroomSession _session; private Thread _worker; + private string _statusFull = "Stopped"; + private const int StatusDisplayMax = 400; - public string DumpPath + public string DiskFolder { - get { return _dumpBox.Text; } - set { _dumpBox.Text = value ?? ""; } + get { return _folderBox.Text; } + set { _folderBox.Text = value ?? ""; } } public MediaroomHostForm() { - Text = "Mediaroom"; - // Host chrome only. Not guest video and not a framebuffer size. + Text = "MIPS Guest"; Width = 900; Height = 640; StartPosition = FormStartPosition.CenterScreen; @@ -38,32 +41,44 @@ public MediaroomHostForm() MaximizeBox = true; var top = new Panel { Dock = DockStyle.Top, Height = 36 }; - _dumpBox = new TextBox { Left = 8, Top = 6, Width = 520, Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top }; - _browse = new Button { Text = "Dump", Left = 536, Top = 4, Width = 56, Anchor = AnchorStyles.Right | AnchorStyles.Top }; - _boot = new Button { Text = "Boot", Left = 596, Top = 4, Width = 56, Anchor = AnchorStyles.Right | AnchorStyles.Top }; + _folderBox = new TextBox { Left = 8, Top = 6, Width = 520, Anchor = AnchorStyles.Left | AnchorStyles.Right | AnchorStyles.Top }; + _folder = new Button { Text = "Folder", Left = 536, Top = 4, Width = 56, Anchor = AnchorStyles.Right | AnchorStyles.Top }; + _start = new Button { Text = "Start", Left = 596, Top = 4, Width = 56, Anchor = AnchorStyles.Right | AnchorStyles.Top }; _stop = new Button { Text = "Stop", Left = 656, Top = 4, Width = 56, Enabled = false, Anchor = AnchorStyles.Right | AnchorStyles.Top }; - _browse.Click += BrowseClick; - _boot.Click += BootClick; + _folder.Click += FolderClick; + _start.Click += StartClick; _stop.Click += StopClick; - top.Controls.Add(_dumpBox); - top.Controls.Add(_browse); - top.Controls.Add(_boot); + top.Controls.Add(_folderBox); + top.Controls.Add(_folder); + top.Controls.Add(_start); top.Controls.Add(_stop); top.Resize += (_, __) => { - _dumpBox.Width = Math.Max(80, top.ClientSize.Width - 200); - _browse.Left = top.ClientSize.Width - 184; - _boot.Left = top.ClientSize.Width - 124; + _folderBox.Width = Math.Max(80, top.ClientSize.Width - 200); + _folder.Left = top.ClientSize.Width - 184; + _start.Left = top.ClientSize.Width - 124; _stop.Left = top.ClientSize.Width - 64; }; - _status = new Label + _status = new TextBox { Dock = DockStyle.Bottom, - Height = 22, - Text = "idle", - TextAlign = ContentAlignment.MiddleLeft + Height = 24, + ReadOnly = true, + Multiline = false, + BorderStyle = BorderStyle.FixedSingle, + BackColor = SystemColors.Control, + ForeColor = SystemColors.ControlText, + Text = "Stopped", + TabStop = true, + ShortcutsEnabled = true, + Cursor = Cursors.IBeam }; + var statusCopy = new ToolStripMenuItem("Copy"); + statusCopy.Click += (_, __) => CopyFullStatus(); + _status.ContextMenuStrip = new ContextMenuStrip(); + _status.ContextMenuStrip.Items.Add(statusCopy); + _status.DoubleClick += (_, __) => CopyFullStatus(); _frame = new PictureBox { @@ -76,38 +91,100 @@ public MediaroomHostForm() Controls.Add(_status); Controls.Add(top); - string env = Environment.GetEnvironmentVariable(Core.HostHardDisk.EnvName); - if (!string.IsNullOrEmpty(env)) - DumpPath = env; - - _tick = new System.Windows.Forms.Timer { Interval = 250 }; - _tick.Tick += (_, __) => RefreshStatus(); - _tick.Start(); + AutoFillFolder(); HandleCreated += (_, __) => Win7VisualStyle.ApplyToHwnd(Handle); - FormClosing += (_, __) => + FormClosing += (_, __) => { _session?.RequestStop(); BootLog.UartFlush(); }; + } + + private void AutoFillFolder() + { + string env = Environment.GetEnvironmentVariable(HostHardDisk.EnvName); + if (string.IsNullOrEmpty(env)) + env = Environment.GetEnvironmentVariable(HostHardDisk.EnvNameAlt); + if (!string.IsNullOrEmpty(env) && Directory.Exists(env)) { - _tick.Stop(); - _session?.RequestStop(); - }; + DiskFolder = env; + return; + } + + string here = ShallowNkFolder(Environment.CurrentDirectory); + if (string.IsNullOrEmpty(here)) + here = ShallowNkFolder(AppDomain.CurrentDomain.BaseDirectory); + if (!string.IsNullOrEmpty(here)) + DiskFolder = here; + } + + private static string ShallowNkFolder(string dir) + { + if (string.IsNullOrEmpty(dir) || !Directory.Exists(dir)) + return ""; + try + { + if (File.Exists(Path.Combine(dir, "nk.bin"))) + return Path.GetFullPath(dir); + } + catch + { + } + return ""; + } + + private void SetRunning(bool running) + { + _start.Enabled = !running; + _stop.Enabled = running; + if (!running) + BootLog.Write("Stopped"); + } + + private void CopyFullStatus() + { + try + { + string text = _statusFull; + if (!string.IsNullOrEmpty(text)) + Clipboard.SetText(text); + } + catch + { + } } - private void RefreshStatus() + private void ShowStatus(string line) { - if (_session == null) + if (string.IsNullOrEmpty(line)) return; - string note = _session.MemsetNote; - _status.Text = "Hz=" + _session.Hertz - + " PC=0x" + _session.ProgramCounter.ToString("X8") - + " steps=" + _session.Steps - + (string.IsNullOrEmpty(note) ? "" : " " + note); + void apply() + { + _statusFull = line; + _status.Text = line.Length > StatusDisplayMax + ? line.Substring(0, StatusDisplayMax - 3) + "..." + : line; + } + try + { + if (IsHandleCreated && InvokeRequired) + BeginInvoke(new Action(apply)); + else + apply(); + } + catch + { + } } - private void BrowseClick(object sender, EventArgs e) + private void FolderClick(object sender, EventArgs e) { - using var d = new FolderBrowserDialog { Description = "Mediaroom / WinCE dump folder" }; + using var d = new FolderBrowserDialog + { + Description = "Guest disk folder" + }; + string current = DiskFolder?.Trim(); + if (!string.IsNullOrEmpty(current) && Directory.Exists(current)) + d.SelectedPath = current; if (d.ShowDialog(this) == DialogResult.OK) - DumpPath = d.SelectedPath; + DiskFolder = d.SelectedPath; } private void StopClick(object sender, EventArgs e) @@ -115,28 +192,19 @@ private void StopClick(object sender, EventArgs e) _session?.RequestStop(); } - private void BootClick(object sender, EventArgs e) + private void StartClick(object sender, EventArgs e) { if (_worker != null && _worker.IsAlive) return; - _boot.Enabled = false; - _stop.Enabled = true; - _status.Text = "booting"; + SetRunning(true); _frame.Image = null; _frame.BackColor = Color.Black; - string feed = _dumpBox.Text; - _session = new MediaroomSession(s => - { - if (IsDisposed || !IsHandleCreated) - return; - try - { - BeginInvoke(new Action(() => { _status.Text = s; })); - } - catch - { - } - }); + string feed = _folderBox.Text; + BootLog.Open(feed); + BootLog.Listener = ShowStatus; + BootLog.Write("start folder=" + (feed ?? "") + " log=" + BootLog.FilePath); + BootLog.Write("cli=tail that log (ExtraROM FILE/TOC attach + UART TX). guest frame black; no _frame.Image blit; GuestVideoWrote=false; Display=ddi_nop.dll ExtraROM TOC[33] stub; MipsUart 0xB0000000 TX -> this file; no NIC on the MIPS bus"); + _session = new MediaroomSession(BootLog.Write); _worker = new Thread(() => { try @@ -145,24 +213,13 @@ private void BootClick(object sender, EventArgs e) } catch (Exception ex) { - try - { - BeginInvoke(new Action(() => { _status.Text = ex.GetType().Name; })); - } - catch - { - } + BootLog.Write("Start: " + ex.GetType().Name + ": " + ex.Message); } finally { try { - BeginInvoke(new Action(() => - { - _boot.Enabled = true; - _stop.Enabled = false; - RefreshStatus(); - })); + BeginInvoke(new Action(() => { SetRunning(false); })); } catch { diff --git a/MediaroomSession.cs b/MediaroomSession.cs index 8dbced76..1778ae9f 100644 --- a/MediaroomSession.cs +++ b/MediaroomSession.cs @@ -7,8 +7,11 @@ namespace ProcessorEmulator { - // Honest dump -> NkBinLoader -> MIPS/CE step. No synthetic - // firmware, no CreateProcess, no ExtraROM map, no SetEvent. + // Honest dump -> NkBinLoader -> MIPS/CE step. Every dump B000FF + // next to nk.bin is loaded at that file's imageStart so ExtraROM + // XIP is in RAM. Leftover inherit pairs are dropped at SaveList. + // No invented 0x81360000 map, no host CreateProcess(tv2clientce), + // no SetEvent. public sealed class MediaroomSession { private const uint RamSize = 256u * 1024u * 1024u; @@ -109,6 +112,7 @@ public bool Run(string feed) KernelLoaded = true; DumpRoot = HostHardDisk.Root; GuestVideoWrote = false; + _status("display ddi_nop.dll ExtraROM TOC[33] stub; guest screen black until a real DDI writes pixels; GuestVideoWrote=false; no framebuffer blit"); _cpu.SetRegister(MipsCpuEmulator.Register.PC, (uint)loaded.EntryPoint); _cpu.SetRegister(MipsCpuEmulator.Register.SP, 0x80000000u + RamSize - 0x1000u); _lastPc = (uint)loaded.EntryPoint; @@ -175,10 +179,12 @@ public bool Run(string feed) catch (Exception ex) { _lastPc = _cpu != null ? _cpu.ProgramCounter : _lastPc; + BootLog.UartFlush(); _status("CPU " + ex.GetType().Name + " PC=0x" + _lastPc.ToString("X8")); return KernelLoaded; } + BootLog.UartFlush(); _status("stopped"); return true; } diff --git a/MipsBus.cs b/MipsBus.cs index c0932699..ee82cdf6 100644 --- a/MipsBus.cs +++ b/MipsBus.cs @@ -22,6 +22,62 @@ public MipsBus(CP0 cp0) _cp0 = cp0; } + public uint PeekEpc() + { + return _cp0 != null ? _cp0.EPC : 0; + } + + public void PokeEpc(uint epc) + { + if (_cp0 != null) + _cp0.EPC = epc; + } + + // Live f9afdbc: after heal=1 at + // 0x80057470, EXL left the jal + // unexecuted (fallthrough log-only). + // Clear EXL/Cause when EPC is that + // site so a re-fetch runs dump jal. + public void ClearExlIfEpc(uint epc) + { + if (_cp0 == null || epc == 0 || (epc & 3) != 0) + return; + uint cur = _cp0.EPC; + if (cur != epc && cur != epc + 4) + return; + _cp0.Status &= ~(1u << 1); + _cp0.Cause &= 0x7FFFFF83u; + _cp0.EPC = epc; + } + + // Dump-true trampoline 0x80014F40 + // mtc0 $0,$12 (Status:=0). Do not + // invent KSEG / pages. + public bool TryExecDumpMemMtc0ZeroStatus(uint insn) + { + if (insn != 0x40806000u || _cp0 == null) + return false; + _cp0.WriteRegister(12, 0); + return true; + } + + // Dump-true 0x80014F2C mtc0 $t0,$12 + // (Status:=rt). Do not invent + // KSEG / KData / pages. + public bool TryExecDumpMemMtc0Status(uint insn, uint value) + { + if ((insn >> 26) != 16 || ((insn >> 21) & 31) != 4 + || ((insn >> 11) & 31) != 12 || _cp0 == null) + return false; + _cp0.WriteRegister(12, value); + return true; + } + + public bool TryFindTlbPfn(uint vaddr, out uint pfn, out bool valid) + { + return _cp0.TryFindTlbPfn(vaddr, out pfn, out valid); + } + /// /// Maps a device to a specific range of the address space. /// @@ -89,6 +145,40 @@ private static uint Swap(uint value) public uint Read32(uint vaddr) { + vaddr = CeRomTocFiles.MapBindImpIatRealVa(vaddr); + vaddr = CeRomTocFiles.MapDdiNopProcessInfoVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispFetchVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesTextBaseVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData3Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesText2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopCoredllImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesysSlot2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesys48dVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopVallocDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopDestVa(vaddr); + vaddr = CeRomTocFiles.MapProcessHeapSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapCoredllSharedVa(this, vaddr); + vaddr = CeRomTocFiles.MapFirmwareSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapVallocHostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomE32HostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocSrcVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocDestVa(vaddr); + vaddr = CeRomTocFiles.MapExeXipVa(this, vaddr); + vaddr = CeRomTocFiles.MapUserKDataVa(vaddr); + vaddr = CeRomTocFiles.MapFfffF000Va(this, vaddr); + vaddr = CeRomTocFiles.MapFfffE000Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr7eb8Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr1db0Va(this, vaddr); + vaddr = CeRomTocFiles.MapStk2470Va(this, vaddr); + vaddr = CeRomTocFiles.MapC0000088Va(this, vaddr); + vaddr = CeRomTocFiles.MapBadAVa(this, vaddr); + if (CeRomTocFiles.TrySkipFfffFe54LoadZero(this, vaddr)) + return 0; + if (CeRomTocFiles.TrySkipBadALhuZero(this, vaddr)) + return 0; uint paddr = Translate(vaddr, isStore: false); IBusDevice device = _lookupTable[paddr >> 16]; @@ -102,20 +192,113 @@ public uint Read32(uint vaddr) public void Write32(uint vaddr, uint value) { - uint paddr = Translate(vaddr, isStore: true); - IBusDevice device = _lookupTable[paddr >> 16]; + HostHardDisk.NoteDispC8Write(vaddr, value, this); + uint origVa = vaddr; + vaddr = CeRomTocFiles.MapBindImpIatRealVa(vaddr); + vaddr = CeRomTocFiles.MapDdiNopProcessInfoVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispFetchVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesTextBaseVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData3Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesText2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopCoredllImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesysSlot2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesys48dVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopVallocDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopDestVa(vaddr); + vaddr = CeRomTocFiles.MapProcessHeapSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapCoredllSharedVa(this, vaddr); + vaddr = CeRomTocFiles.MapFirmwareSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapVallocHostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomE32HostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocSrcVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocDestVa(vaddr); + vaddr = CeRomTocFiles.MapUserKDataVa(vaddr); + vaddr = CeRomTocFiles.MapFfffF000Va(this, vaddr); + vaddr = CeRomTocFiles.MapFfffE000Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr7eb8Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr1db0Va(this, vaddr); + vaddr = CeRomTocFiles.MapStk2470Va(this, vaddr); + vaddr = CeRomTocFiles.MapC0000088Va(this, vaddr); + vaddr = CeRomTocFiles.MapBadAVa(this, vaddr); + if (CeRomTocFiles.TrySkipC0000088Store(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipFfffE000ListInsertStore(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipFfffF000ListInsertStore(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipPage0ListInsertStore(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipLowUsegListInsertStore(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipListInsertAnyDestMiss(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkip15C28StkStore(this, vaddr)) + return; + if (CeRomTocFiles.TrySkipBadABeforeE000DestMissStore(this, vaddr)) + return; + CeRomTocFiles.TryNoteDdiNopIatStore(origVa, vaddr, value); + CeRomTocFiles.TryNoteBindImpIatSw(origVa, value); + bool watch = CeRomTocFiles.TryNoteDdiNopDecompStore(vaddr, value); + try + { + uint paddr = Translate(vaddr, isStore: true); + IBusDevice device = _lookupTable[paddr >> 16]; - if (device != null) + if (device != null) + { + uint valueToStore = IsBigEndian ? Swap(value) : value; + device.Write32(paddr - device.StartAddress, valueToStore); + return; + } + throw new AddressErrorException($"Write to unmapped physical address 0x{paddr:X8}"); + } + catch { - uint valueToStore = IsBigEndian ? Swap(value) : value; - device.Write32(paddr - device.StartAddress, valueToStore); - return; + if (watch) + CeRomTocFiles.TryNoteDdiNopDecompStoreThrow(vaddr); + throw; } - throw new AddressErrorException($"Write to unmapped physical address 0x{paddr:X8}"); } public byte Read8(uint vaddr) { + vaddr = CeRomTocFiles.MapBindImpIatRealVa(vaddr); + vaddr = CeRomTocFiles.MapDdiNopProcessInfoVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispFetchVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesTextBaseVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData3Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesText2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopCoredllImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesysSlot2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesys48dVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopVallocDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopDestVa(vaddr); + vaddr = CeRomTocFiles.MapProcessHeapSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapCoredllSharedVa(this, vaddr); + vaddr = CeRomTocFiles.MapFirmwareSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapVallocHostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomE32HostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocSrcVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocDestVa(vaddr); + vaddr = CeRomTocFiles.MapExeXipVa(this, vaddr); + vaddr = CeRomTocFiles.MapUserKDataVa(vaddr); + vaddr = CeRomTocFiles.MapFfffF000Va(this, vaddr); + vaddr = CeRomTocFiles.MapFfffE000Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr7eb8Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr1db0Va(this, vaddr); + vaddr = CeRomTocFiles.MapStk2470Va(this, vaddr); + vaddr = CeRomTocFiles.MapC0000088Va(this, vaddr); + vaddr = CeRomTocFiles.MapBadAVa(this, vaddr); + if (CeRomTocFiles.TrySkipFfffFe54LoadZero(this, vaddr)) + return 0; + if (CeRomTocFiles.TrySkipBadALhuZero(this, vaddr)) + return 0; uint paddr = Translate(vaddr, isStore: false); IBusDevice device = _lookupTable[paddr >> 16]; @@ -130,15 +313,61 @@ public byte Read8(uint vaddr) public void Write8(uint vaddr, byte value) { - uint paddr = Translate(vaddr, isStore: true); - IBusDevice device = _lookupTable[paddr >> 16]; + HostHardDisk.NoteDispC8Write(vaddr, value, this); + vaddr = CeRomTocFiles.MapBindImpIatRealVa(vaddr); + vaddr = CeRomTocFiles.MapDdiNopProcessInfoVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispFetchVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesTextBaseVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesDispData3Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesText2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopGwesImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopCoredllImageVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesysSlot2Va(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopFilesys48dVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopVallocDataVa(this, vaddr); + vaddr = CeRomTocFiles.MapDdiNopDestVa(vaddr); + vaddr = CeRomTocFiles.MapProcessHeapSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapCoredllSharedVa(this, vaddr); + vaddr = CeRomTocFiles.MapFirmwareSlotVa(this, vaddr); + vaddr = CeRomTocFiles.MapVallocHostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomE32HostVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocSrcVa(vaddr); + vaddr = CeRomTocFiles.MapExtraRomTocDestVa(vaddr); + vaddr = CeRomTocFiles.MapUserKDataVa(vaddr); + vaddr = CeRomTocFiles.MapFfffF000Va(this, vaddr); + vaddr = CeRomTocFiles.MapFfffE000Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr7eb8Va(this, vaddr); + vaddr = CeRomTocFiles.MapJalr1db0Va(this, vaddr); + vaddr = CeRomTocFiles.MapStk2470Va(this, vaddr); + vaddr = CeRomTocFiles.MapC0000088Va(this, vaddr); + vaddr = CeRomTocFiles.MapBadAVa(this, vaddr); + if (CeRomTocFiles.TrySkipFfffE000SbZero(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipFfffE428SbJalr(this, vaddr, value)) + return; + if (CeRomTocFiles.TrySkipFfffEa88Sb(this, vaddr, value)) + return; + bool watch = CeRomTocFiles.TryNoteDdiNopDecompStore(vaddr, value); + try + { + uint paddr = Translate(vaddr, isStore: true); + IBusDevice device = _lookupTable[paddr >> 16]; - if (device != null) + if (device != null) + { + device.Write8(paddr - device.StartAddress, value); + return; + } + throw new AddressErrorException($"Write to unmapped physical address 0x{paddr:X8}"); + } + catch { - device.Write8(paddr - device.StartAddress, value); - return; + if (watch) + CeRomTocFiles.TryNoteDdiNopDecompStoreThrow(vaddr); + throw; } - throw new AddressErrorException($"Write to unmapped physical address 0x{paddr:X8}"); } public void WriteBytes(uint vaddr, byte[] data) diff --git a/MipsCpuEmulator.cs b/MipsCpuEmulator.cs index ac59c6da..4648f67b 100644 --- a/MipsCpuEmulator.cs +++ b/MipsCpuEmulator.cs @@ -89,6 +89,12 @@ public void Step(int count = 1) { for (int i = 0; i < count; i++) { + // Live b4b6454: poll sat after this continue, + // so an interrupt/TLB storm after BindImp + // skipped CallDLL-miss forever. Count here + // too. Keep the post-BinBlk poll. + CeRomTocFiles.TryPollDdiNopCallDllMiss(_bus, registers, programCounter); + // Check for and handle pending hardware interrupts before executing an instruction. if (_cp0.ShouldTriggerInterrupt()) { @@ -104,6 +110,8 @@ public void Step(int count = 1) continue; } + CeRomTocFiles.TryPollDdiNopCallDllMiss(_bus, registers, programCounter); + _currentPc = programCounter; try { @@ -124,22 +132,94 @@ public void Step(int count = 1) continue; } + if (programCounter == CeRomTocFiles.CreateFileWin32Chk) + CeRomTocFiles.TryRejectMscoreeFileHandle(_bus, registers); + if (programCounter == CeRomTocFiles.CreateFileFail) { - uint path = registers[23]; - if (CeRomTocFiles.TryContinueRomModule(_bus, path, out uint attr, out uint tocEntry)) + try + { + uint path = registers[23]; + if (!CeRomTocFiles.TryContinueRomModule(_bus, path, out uint attr, out uint tocEntry, out byte attachType)) + CeRomTocFiles.TryContinueRomModule(_bus, registers[4], out attr, out tocEntry, out attachType); + if (tocEntry != 0) + { + // Type 7: TOC module, e32 at entry+0x14. + // Type 8: ExtraROM FILE (wait55). object+5=1 + // skips name copy (s7 may be unmapped). + // Do not set ROMMODULE. Do not invent e32. + uint obj = registers[30]; + _bus.Write32(obj, tocEntry); + _bus.Write8(obj + 4, attachType); + if (attachType == CeRomTocFiles.FileAttachType) + _bus.Write8(obj + 5, 1); + if (attachType == CeRomTocFiles.TocAttachType) + CeRomTocFiles.TryPrepareExtraRomBuiltInLikeDdiNop(_bus, obj); + _bus.Write32(registers[29] + 40, attr); + registers[3] = attr; + if (attachType == CeRomTocFiles.FileAttachType + && CeRomTocFiles.TryStartTv2FileDecompress( + _bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + if (attachType == CeRomTocFiles.TocAttachType + && CeRomTocFiles.TryStartExtraRomTocDecompress( + _bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + // Type 7: NameCopyContinue CreateFileMappings + // the TOCentry (wait61 126). Return v0=0 with + // object+0=entry +4=7 so 0x800196E4 LoadE32s. + programCounter = attachType == CeRomTocFiles.TocAttachType + ? CeRomTocFiles.CreateFileOk + : CeRomTocFiles.NameCopyContinue; + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + catch (TlbMissException ex) + { + // wait52: hook Read32(s7=0x040851E8) aborted + // the probe. That VA is filesys slot-2, not a + // dump ExtraROM/gwes/coredll/BINFS/tv2 page. + // Do not invent a map. Firmware refill owns it. + TriggerTlbException(ex); + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + + // 0x80016AFC miss (v0=2). s3=UTF16 name, s4=object. + // ExtraROM TOC modules are not on *(0x80342B10) + // unless OEM published them on *(0x803429C8) for + // linker 0x8001728C. Do not invent a ROMChain_t. + // Attach any ExtraROM TOC type-7 name already in + // the dump ROMHDR (ddi_nop/mscoree/ole32 plus + // bcmuart/ndis/sipcfg and the rest). + if (programCounter == CeRomTocFiles.TocWalkMiss) + { + if (CeRomTocFiles.TryAttachExtraRomTocWalk(_bus, registers[19], registers[20])) + { + registers[2] = 0; + programCounter = CeRomTocFiles.TocWalkMissContinue; + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + + if (programCounter == CeRomTocFiles.LoadO32WrapStartip) + { + if (CeRomTocFiles.TryFeedCoredllCallDll(_bus, registers, ref programCounter)) { - // Same object layout as 0x80016AFC: +0 = TOC entry, - // +4 = 7. 0x800196E4 then uses e32 at TOC+0x14 - // instead of CreateFileMapping(INVALID_HANDLE). - // 40($sp) still needs FILE_ATTRIBUTE_ROMMODULE so - // 0x8001D4B8 takes the existing 0x2000 return. - uint obj = registers[30]; - _bus.Write32(obj, tocEntry); - _bus.Write8(obj + 4, CeRomTocFiles.TocAttachType); - _bus.Write32(registers[29] + 40, attr); - registers[3] = attr; - programCounter = CeRomTocFiles.NameCopyContinue; _cp0.UpdateTimer(1); _bus.Tick(1); continue; @@ -147,14 +227,89 @@ public void Step(int count = 1) } if (programCounter == CeRomTocFiles.CallDllStartip) - CeRomTocFiles.TryFillTocStartip(_bus, registers[23]); + { + CeRomTocFiles.NoteDdiNopCallDllPc(_bus, registers, programCounter); + CeRomTocFiles.TryFeedCoredllCallDllStartip(_bus, registers); + CeRomTocFiles.TryFillTocStartip(_bus, registers[23], true); + } + + // Live f13b33e: startip 0x01998014 on MODULE + // 0x86FACC50; mod+0x50=0x03980000 is useg. + // 0x8001DD6C skips CallDLL. Force the DLL jal + // (a1=1) here, same continue as EXE skip. + if (programCounter == CeRomTocFiles.XipCallDllUsegChk) + { + CeRomTocFiles.NoteDdiNopCallDllPc(_bus, registers, programCounter); + if (CeRomTocFiles.TryForceDdiNopCallDll(_bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + if (CeRomTocFiles.TryFeedCoredllCallDll(_bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + + if (programCounter == CeRomTocFiles.XipExeCallDllSkip) + { + CeRomTocFiles.NoteDdiNopCallDllPc(_bus, registers, programCounter); + if (CeRomTocFiles.TryForceDdiNopCallDll(_bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + if (CeRomTocFiles.TryForceXipExeCallDll(_bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + + if (programCounter == CeRomTocFiles.ThreadStartTrampoline + || programCounter == CeRomTocFiles.LoadExeE32Ret + || programCounter == CeRomTocFiles.LoadExeStartipRet) + CeRomTocFiles.TryFillProcExeStartip(_bus); + + if (programCounter == CeRomTocFiles.ThreadCtxRestore + || programCounter == CeRomTocFiles.ThreadCtxRestore2) + { + CeRomTocFiles.TryNoteTv2ThreadRestore(_bus, registers, programCounter); + if (programCounter == CeRomTocFiles.ThreadCtxRestore2 + && CeRomTocFiles.TryForceTv2EretSlowPath(_bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + + if (programCounter == CeRomTocFiles.ThreadSwitchProcChk) + { + CeRomTocFiles.TryKeepTv2ThreadOwner(_bus, "switcher"); + if (CeRomTocFiles.TryForceTv2ProcSwitch(_bus, registers, ref programCounter)) + { + _cp0.UpdateTimer(1); + _bus.Tick(1); + continue; + } + } + + if (programCounter == CeRomTocFiles.ThreadSwitchProcStore) + CeRomTocFiles.TryNoteTv2ProcSwitchStore(_bus, registers, programCounter); if (programCounter == CeRomTocFiles.ProcessAttachGate) CeRomTocFiles.TryEnableFilterProcessAttach(_bus, registers); if (programCounter == CeRomTocFiles.Win32CreateFile) { - if (CeRomTocFiles.TryMissMissingDevice(_bus, registers[4], registers, ref programCounter)) + if (CeRomTocFiles.TryMissMissingDevice(_bus, registers[4], registers, ref programCounter) + || CeRomTocFiles.TryMissMscoreeWin32(_bus, registers[4], registers, ref programCounter)) { _cp0.UpdateTimer(1); _bus.Tick(1); @@ -197,11 +352,39 @@ public void Step(int count = 1) } } + CeRomTocFiles.TryResumeTv2LeftoverFetch(_bus, registers, ref programCounter); + CeRomTocFiles.TryRestoreTv2LeftoverEret(_bus, registers, programCounter); + CeRomTocFiles.TryRestoreTv2LeftoverDestLiveEret(_bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCaf0(_bus, registers, ref programCounter); + CeRomTocFiles.TryKeepTv2LeftoverS6(_bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb10(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb14(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb34(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb38(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb3c(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb40(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb44(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb48(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterCb4c(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterJrRa(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterBPlus2(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterBPlus2Taken(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterFp(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS7(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS6(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS5(_bus, registers, ref programCounter); + CeRomTocFiles.TryResumeTv2LeftoverAfterS4(_bus, registers, ref programCounter); + CeRomTocFiles.TryNoteTv2LeftoverDrop(_bus, registers, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); _currentPc = programCounter; try { uint instruction = FetchInstruction(); + CeRomTocFiles.TryKeepLeftoverDestLiveDispatch(_bus, _currentPc); + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); DecodeAndExecute(instruction); + CeRomTocFiles.TryKeepLeftoverDestLiveDispatch(_bus, _currentPc); + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); } catch (TlbMissException ex) { @@ -244,6 +427,17 @@ private void TriggerException(uint exceptionCode) { programCounter = 0x80000180; } + HostHardDisk.NoteCpuException(exceptionCode, _cp0.EPC, 0, programCounter, registers, _bus); + // wait127: leftover dest-live I-fetch of dest-live + // next / PC+4 after dest-live delay+4 walk takes + // leftover interrupt. leftover exception handler + // I-fetches leftover mid / ERET2. leftover dest-live + // continue hops leftover exception / leftover mid / + // ERET2 to dest-live next / PC+4 before leftover + // I-fetches leftover mid / ERET2. leftover after + // dest-live delay+4 walk stays dest-live next / + // PC+4, not leftover mid / ERET2. + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); } private void TriggerTlbException(TlbMissException ex) @@ -270,6 +464,7 @@ private void TriggerTlbException(TlbMissException ex) programCounter = bev ? 0xBFC00200u : 0x80000000u; else programCounter = bev ? 0xBFC00380u : 0x80000180u; + HostHardDisk.NoteCpuException(code, _cp0.EPC, ex.FaultingAddress, programCounter, registers, _bus); } private void TriggerAddressError(uint vaddr) @@ -281,16 +476,407 @@ private void TriggerAddressError(uint vaddr) cause &= 0x7FFFFFFF; _cp0.Cause = cause; _cp0.Status |= (1 << 1); + CeRomTocFiles.TryClearImplicitApiK1(registers, vaddr); bool bev = (_cp0.Status & (1 << 22)) != 0; programCounter = bev ? 0xBFC00380u : 0x80000180u; + HostHardDisk.NoteCpuException(4, _cp0.EPC, vaddr, programCounter, registers, _bus); } private uint FetchInstruction() { + // wait128: leftover dest-live keep hops leftover + // I-fetch of leftover mid / ERET2 after dest-live + // delay+4 to dest-live next / PC+4 before leftover + // FetchInstruction. leftover dest-live continue + // after leftover interrupt is too late: leftover + // I-fetch of leftover mid / ERET2 is already + // logged. leftover after dest-live delay+4 stays + // dest-live next / PC+4, not leftover mid / ERET2. + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); + CeRomTocFiles.TryKeepLeftoverDestLiveDispatch(_bus, programCounter); if ((programCounter & 3) != 0) throw new CpuAlignmentException($"Unaligned fetch PC=0x{programCounter:X8}"); + if (CeRomTocFiles.TryTakeDumpMem15C28Na02IFetch(_bus, registers, + programCounter, 0, _inDelaySlot, ref programCounter)) + return 0; + uint fetchPc = programCounter; uint instruction = ReadMemory32(programCounter); + if (CeRomTocFiles.TryTakeDumpMemRomHdrLinkContinue(_bus, registers, + fetchPc, instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMemListInsertDestMiss(_bus, registers, + fetchPc, instruction, _inDelaySlot, ref programCounter)) + return 0; + CeRomTocFiles.TryFixE478SbAsDumpJr(_bus, registers, programCounter, + ref instruction); + CeRomTocFiles.TryFixStk2470SbAsDumpSw(_bus, registers, programCounter, + ref instruction); + CeRomTocFiles.TryFixNest1670SbAsDumpSb(_bus, registers, programCounter, + ref instruction); + CeRomTocFiles.TryFixDumpMem15C28After(_bus, registers, programCounter, + ref instruction); + CeRomTocFiles.TryFixDumpMem59488(_bus, registers, programCounter, + ref instruction); + CeRomTocFiles.TryFixLiveAbsStoreAsDumpMem(_bus, registers, programCounter, + ref instruction); + CeRomTocFiles.TryNoteDumpMemJalDest(_bus, registers, fetchPc); + CeRomTocFiles.TryFixBadA1Source(_bus, registers, fetchPc, + ref instruction); + if (CeRomTocFiles.TryTakeDumpMemBadAAfterRestore(_bus, registers, + fetchPc, instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMemBadACalleeContinue(_bus, registers, + fetchPc, instruction, _inDelaySlot, ref programCounter)) + return 0; + // Live 4577e0a: after dump-mem-jal, + // fallthrough re-fetch must not + // CPU-jal or restore stale $ra. + if (CeRomTocFiles.TryTakeDumpMemJal(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem59488(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28JalRet(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28JalS1(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterS1Alu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28StkSw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterStkSwBne(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28FpLw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28SpT9(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28JalRaEpi(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28OuterJal(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJal(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalDest(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalJr(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLhu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalS3(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalBne(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLand(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalSltu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalBeq(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalAddiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwT4(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS7(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalAddu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwFp(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS6(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS5(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS4(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS3(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS2(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS1(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwS0(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalLwRa(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiAddiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiJr(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiLui(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiV0Addiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiV1Addiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiSw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiA3Lui(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiLhu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiA2Addiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiA1Addiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiA2Sw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiA3Lhu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiSltu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeq(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqAddiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqSlt(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqBne(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFall(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallSw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallJr(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiuSw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiPrologueSw(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiPrologueJal(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiTrampoline(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRet(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetFall(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCaller(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRa(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaLhu(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaS3(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaT1(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCallerRaBne(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetCallerNextFn(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28AfterOuterJalEpiRetBne(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + if (CeRomTocFiles.TryTakeDumpMem15C28(_bus, registers, fetchPc, + instruction, _inDelaySlot, ref programCounter)) + return 0; + CeRomTocFiles.TryNoteDumpMem15C28After(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28Jal(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28JalDest(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28JalThr(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28JalRet(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterMemset(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28JalS1(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterS1(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterS1Next(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterS1Alu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterStkSw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterStkSwNext(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterFpLw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterSpT9(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterJalRaEpi(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJal(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalDest(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalInc(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalJr(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLhu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalS3(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalBne(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLand(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalSltu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalBeq(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalAddiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwT4(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS7(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalAddu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwFp(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS6(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS5(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS4(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS3(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS2(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS1(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwS0(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalLwRa(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiAddiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiJr(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiLui(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiV0Addiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiV1Addiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiSw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiA3Lui(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiLhu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiA2Addiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiA1Addiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiA2Sw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiA3Lhu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiSltu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeq(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqAddiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqSlt(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqBne(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFall(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallSw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallJr(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiu(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiBeqBneFallJrAddiuSw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiPrologueSw(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiPrologueJal(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiTrampoline(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiRet(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiRetFall(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiRetCaller(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiRetCallerRa(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiRetCallerNextFn(_bus, registers, fetchPc, + instruction); + CeRomTocFiles.TryNoteDumpMem15C28AfterOuterJalEpiRetBne(_bus, registers, fetchPc, + instruction); programCounter += 4; return instruction; } @@ -542,8 +1128,14 @@ private void ExecuteDelaySlotThenJump(uint target) _inDelaySlot = true; try { + CeRomTocFiles.TryRestoreTv2LeftoverEret(_bus, registers, programCounter); + CeRomTocFiles.TryRestoreTv2LeftoverDestLiveEret(_bus, registers, programCounter); uint delayInstr = FetchInstruction(); + CeRomTocFiles.TryKeepLeftoverDestLiveDispatch(_bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); DecodeAndExecute(delayInstr); + CeRomTocFiles.TryKeepLeftoverDestLiveDispatch(_bus, programCounter); + CeRomTocFiles.TryResumeTv2LeftoverDestLiveContinue(_bus, registers, ref programCounter); programCounter = target; } catch (TlbMissException ex) @@ -598,7 +1190,11 @@ private void ExecuteCOP0(uint instruction) // 1. Clear Status.EXL bit _cp0.Status &= ~(1u << 1); // 2. Jump back to where the exception occurred - programCounter = _cp0.EPC; + uint eretPc = _cp0.EPC; + if (_currentPc == CeRomTocFiles.LeftoverEret + && CeRomTocFiles.TryFixTv2LeftoverJump(_bus, registers, ref eretPc)) + _cp0.EPC = eretPc; + programCounter = eretPc; break; default: System.Diagnostics.Debug.WriteLine($"[MIPS] Unhandled COP0 funct: 0x{funct:X}"); @@ -1115,6 +1711,8 @@ private void ExecuteJumpRegister(uint instruction) uint oldPc = programCounter; uint rs = (instruction >> 21) & 0x1F; uint target = registers[rs]; + if (CeRomTocFiles.TryFixTv2LeftoverJump(_bus, registers, ref target) && rs != 0) + registers[rs] = target; ExecuteDelaySlotThenJump(target); LogBranch(oldPc, programCounter, "JR"); } @@ -1127,6 +1725,40 @@ private void ExecuteJumpAndLinkRegister(uint instruction) uint target = registers[rs]; if (rd != 0) registers[rd] = programCounter + 4; + if (CeRomTocFiles.TryFixJalrTableDest(_bus, registers, ref target) && rs != 0) + registers[rs] = target; + if (target == CeRomTocFiles.Win32SetFilePointer + && (CeRomTocFiles.IsTv2FileHandle(registers[4]) + || CeRomTocFiles.IsExtraRomOpenFileHandle(registers[4]))) + { + if (_inDelaySlot) + { + programCounter = target; + return; + } + _inDelaySlot = true; + try + { + uint delayInstr = FetchInstruction(); + DecodeAndExecute(delayInstr); + if (CeRomTocFiles.TryServeTv2SetFilePointer(registers, target, ref target)) + { + programCounter = target; + return; + } + programCounter = target; + } + catch (TlbMissException ex) + { + TriggerTlbException(ex); + } + finally + { + _inDelaySlot = false; + } + LogBranch(oldPc, programCounter, "JALR"); + return; + } ExecuteDelaySlotThenJump(target); LogBranch(oldPc, programCounter, "JALR"); } diff --git a/MipsUart.cs b/MipsUart.cs index 20ef1c60..2079d095 100644 --- a/MipsUart.cs +++ b/MipsUart.cs @@ -1,5 +1,6 @@ using System; using System.Diagnostics; +using ProcessorEmulator.Core; namespace ProcessorEmulator.Emulation { @@ -49,8 +50,9 @@ public void Write32(uint offset, uint value) switch (offset) { case UART_DR: - // Write to data register, treat as console output - Console.Write((char)value); + // WinExe hides Console.Write. Same boot.log as + // ExtraROM OpenFile. Do not invent a second UART. + BootLog.UartTx((byte)value); break; default: Debug.WriteLine($"[MipsUart] Write to unknown register offset 0x{offset:X} at 0x{StartAddress + offset:X8} with value 0x{value:X}"); diff --git a/MipsUverseEmulator.cs b/MipsUverseEmulator.cs index 562d7904..0cc42d28 100644 --- a/MipsUverseEmulator.cs +++ b/MipsUverseEmulator.cs @@ -5,7 +5,6 @@ using System.Threading; using System.Threading.Tasks; using System.Windows; -using ProcessorEmulator.Tools; namespace ProcessorEmulator.Emulation { diff --git a/ProcessorEmulator.csproj b/ProcessorEmulator.csproj index 65faa265..a668156d 100644 --- a/ProcessorEmulator.csproj +++ b/ProcessorEmulator.csproj @@ -18,35 +18,16 @@ - + - + - - - - - - - - - - - - - - - - - - - - - + + + + diff --git a/AeroGlassHelper.cs b/archive/AeroGlassHelper.cs similarity index 100% rename from AeroGlassHelper.cs rename to archive/AeroGlassHelper.cs diff --git a/AppThemeManager.cs b/archive/AppThemeManager.cs similarity index 100% rename from AppThemeManager.cs rename to archive/AppThemeManager.cs diff --git a/ArchiveExtractor.cs b/archive/ArchiveExtractor.cs similarity index 97% rename from ArchiveExtractor.cs rename to archive/ArchiveExtractor.cs index ae662277..528b7d25 100644 --- a/ArchiveExtractor.cs +++ b/archive/ArchiveExtractor.cs @@ -117,15 +117,14 @@ public static void ExtractArchive(string archivePath, string outputDir) ExtractFirmwareSections(archivePath, outputDir); return; } - // Try SharpCompress for common archive formats + // Try SharpCompress for common archive formats. + // 0.50.x: ArchiveFactory.Open → OpenArchive; WriteToDirectory + // + ExtractionOptions remain (archive-level or per-entry). try { - using var archive = ArchiveFactory.Open(archivePath); + using var archive = ArchiveFactory.OpenArchive(archivePath); var options = new ExtractionOptions { ExtractFullPath = true, Overwrite = true }; - foreach (var entry in archive.Entries.Where(e => !e.IsDirectory)) - { - entry.WriteToDirectory(outputDir, options); - } + archive.WriteToDirectory(outputDir, options); return; } catch diff --git a/ArmCpuEmulator.cs b/archive/ArmCpuEmulator.cs similarity index 100% rename from ArmCpuEmulator.cs rename to archive/ArmCpuEmulator.cs diff --git a/BOLT_README.md b/archive/BOLT_README.md similarity index 100% rename from BOLT_README.md rename to archive/BOLT_README.md diff --git a/BUILD_STATUS.md b/archive/BUILD_STATUS.md similarity index 100% rename from BUILD_STATUS.md rename to archive/BUILD_STATUS.md diff --git a/BcmUart.cs b/archive/BcmUart.cs similarity index 100% rename from BcmUart.cs rename to archive/BcmUart.cs diff --git a/BinaryScanner.cs b/archive/BinaryScanner.cs similarity index 100% rename from BinaryScanner.cs rename to archive/BinaryScanner.cs diff --git a/BoltBootloader.cs b/archive/BoltBootloader.cs similarity index 100% rename from BoltBootloader.cs rename to archive/BoltBootloader.cs diff --git a/BoltDemo.cs b/archive/BoltDemo.cs similarity index 100% rename from BoltDemo.cs rename to archive/BoltDemo.cs diff --git a/BoltDemo.csproj b/archive/BoltDemo.csproj similarity index 100% rename from BoltDemo.csproj rename to archive/BoltDemo.csproj diff --git a/BoltDemo_Standalone/BoltBootloader.cs b/archive/BoltDemo_Standalone/BoltBootloader.cs similarity index 100% rename from BoltDemo_Standalone/BoltBootloader.cs rename to archive/BoltDemo_Standalone/BoltBootloader.cs diff --git a/BoltDemo_Standalone/BoltDemo.csproj b/archive/BoltDemo_Standalone/BoltDemo.csproj similarity index 100% rename from BoltDemo_Standalone/BoltDemo.csproj rename to archive/BoltDemo_Standalone/BoltDemo.csproj diff --git a/BoltDemo_Standalone/Program.cs b/archive/BoltDemo_Standalone/Program.cs similarity index 100% rename from BoltDemo_Standalone/Program.cs rename to archive/BoltDemo_Standalone/Program.cs diff --git a/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.deps.json b/archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.deps.json similarity index 100% rename from BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.deps.json rename to archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.deps.json diff --git a/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.dll b/archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.dll similarity index 100% rename from BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.dll rename to archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.dll diff --git a/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.exe b/archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.exe similarity index 100% rename from BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.exe rename to archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.exe diff --git a/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.runtimeconfig.json b/archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.runtimeconfig.json similarity index 100% rename from BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.runtimeconfig.json rename to archive/BoltDemo_Standalone/bin/Debug/net6.0/BoltDemo.runtimeconfig.json diff --git a/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.dgspec.json b/archive/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.dgspec.json similarity index 100% rename from BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.dgspec.json rename to archive/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.dgspec.json diff --git a/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.props b/archive/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.props similarity index 100% rename from BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.props rename to archive/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.props diff --git a/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.targets b/archive/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.targets similarity index 100% rename from BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.targets rename to archive/BoltDemo_Standalone/obj/BoltDemo.csproj.nuget.g.targets diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs b/archive/BoltDemo_Standalone/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/.NETCoreApp,Version=v6.0.AssemblyAttributes.cs diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfo.cs b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfo.cs similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfo.cs rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfo.cs diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfoInputs.cache b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfoInputs.cache similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfoInputs.cache rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.AssemblyInfoInputs.cache diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GeneratedMSBuildEditorConfig.editorconfig b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GeneratedMSBuildEditorConfig.editorconfig similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GeneratedMSBuildEditorConfig.editorconfig rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GeneratedMSBuildEditorConfig.editorconfig diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GlobalUsings.g.cs b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GlobalUsings.g.cs similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GlobalUsings.g.cs rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.GlobalUsings.g.cs diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.assets.cache b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.assets.cache similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.assets.cache rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.assets.cache diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.CoreCompileInputs.cache b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.CoreCompileInputs.cache similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.CoreCompileInputs.cache rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.CoreCompileInputs.cache diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.FileListAbsolute.txt b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.FileListAbsolute.txt similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.FileListAbsolute.txt rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.csproj.FileListAbsolute.txt diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.dll b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.dll similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.dll rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.dll diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.genruntimeconfig.cache b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.genruntimeconfig.cache similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.genruntimeconfig.cache rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.genruntimeconfig.cache diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.sourcelink.json b/archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.sourcelink.json similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.sourcelink.json rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/BoltDemo.sourcelink.json diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/apphost.exe b/archive/BoltDemo_Standalone/obj/Debug/net6.0/apphost.exe similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/apphost.exe rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/apphost.exe diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/ref/BoltDemo.dll b/archive/BoltDemo_Standalone/obj/Debug/net6.0/ref/BoltDemo.dll similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/ref/BoltDemo.dll rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/ref/BoltDemo.dll diff --git a/BoltDemo_Standalone/obj/Debug/net6.0/refint/BoltDemo.dll b/archive/BoltDemo_Standalone/obj/Debug/net6.0/refint/BoltDemo.dll similarity index 100% rename from BoltDemo_Standalone/obj/Debug/net6.0/refint/BoltDemo.dll rename to archive/BoltDemo_Standalone/obj/Debug/net6.0/refint/BoltDemo.dll diff --git a/BoltDemo_Standalone/obj/project.assets.json b/archive/BoltDemo_Standalone/obj/project.assets.json similarity index 100% rename from BoltDemo_Standalone/obj/project.assets.json rename to archive/BoltDemo_Standalone/obj/project.assets.json diff --git a/BoltDemo_Standalone/obj/project.nuget.cache b/archive/BoltDemo_Standalone/obj/project.nuget.cache similarity index 100% rename from BoltDemo_Standalone/obj/project.nuget.cache rename to archive/BoltDemo_Standalone/obj/project.nuget.cache diff --git a/BoltEmulatorBridge.cs b/archive/BoltEmulatorBridge.cs similarity index 100% rename from BoltEmulatorBridge.cs rename to archive/BoltEmulatorBridge.cs diff --git a/BootValidationTest.cs b/archive/BootValidationTest.cs similarity index 100% rename from BootValidationTest.cs rename to archive/BootValidationTest.cs diff --git a/CMTSEmulator.cs b/archive/CMTSEmulator.cs similarity index 100% rename from CMTSEmulator.cs rename to archive/CMTSEmulator.cs diff --git a/COMCAST_X1_INTEGRATION.md b/archive/COMCAST_X1_INTEGRATION.md similarity index 100% rename from COMCAST_X1_INTEGRATION.md rename to archive/COMCAST_X1_INTEGRATION.md diff --git a/CarlContainmentProtocol.cs b/archive/CarlContainmentProtocol.cs similarity index 100% rename from CarlContainmentProtocol.cs rename to archive/CarlContainmentProtocol.cs diff --git a/CarlMode.xaml b/archive/CarlMode.xaml similarity index 100% rename from CarlMode.xaml rename to archive/CarlMode.xaml diff --git a/ClassicStyle.xaml b/archive/ClassicStyle.xaml similarity index 100% rename from ClassicStyle.xaml rename to archive/ClassicStyle.xaml diff --git a/ComcastDomainParser.cs b/archive/ComcastDomainParser.cs similarity index 100% rename from ComcastDomainParser.cs rename to archive/ComcastDomainParser.cs diff --git a/ComcastDomainParserDemo.cs b/archive/ComcastDomainParserDemo.cs similarity index 100% rename from ComcastDomainParserDemo.cs rename to archive/ComcastDomainParserDemo.cs diff --git a/ComcastServiceEmulator.cs b/archive/ComcastServiceEmulator.cs similarity index 100% rename from ComcastServiceEmulator.cs rename to archive/ComcastServiceEmulator.cs diff --git a/ComcastX1Emulator.cs b/archive/ComcastX1Emulator.cs similarity index 100% rename from ComcastX1Emulator.cs rename to archive/ComcastX1Emulator.cs diff --git a/ComcastX1Emulator_Universal.cs b/archive/ComcastX1Emulator_Universal.cs similarity index 100% rename from ComcastX1Emulator_Universal.cs rename to archive/ComcastX1Emulator_Universal.cs diff --git a/ComcastX1Test.cs b/archive/ComcastX1Test.cs similarity index 100% rename from ComcastX1Test.cs rename to archive/ComcastX1Test.cs diff --git a/ComprehensiveFirmwareExtractor.cs b/archive/ComprehensiveFirmwareExtractor.cs similarity index 100% rename from ComprehensiveFirmwareExtractor.cs rename to archive/ComprehensiveFirmwareExtractor.cs diff --git a/Core/BaseIrExecutor.cs b/archive/Core/BaseIrExecutor.cs similarity index 100% rename from Core/BaseIrExecutor.cs rename to archive/Core/BaseIrExecutor.cs diff --git a/Core/CpuState.cs b/archive/Core/CpuState.cs similarity index 100% rename from Core/CpuState.cs rename to archive/Core/CpuState.cs diff --git a/Core/Decoders/MipsDecoder.cs b/archive/Core/Decoders/MipsDecoder.cs similarity index 100% rename from Core/Decoders/MipsDecoder.cs rename to archive/Core/Decoders/MipsDecoder.cs diff --git a/Core/Decoders/MipsIrDecoder.cs b/archive/Core/Decoders/MipsIrDecoder.cs similarity index 100% rename from Core/Decoders/MipsIrDecoder.cs rename to archive/Core/Decoders/MipsIrDecoder.cs diff --git a/Core/Decoders/MipsIrDecoderLegacy.cs b/archive/Core/Decoders/MipsIrDecoderLegacy.cs similarity index 100% rename from Core/Decoders/MipsIrDecoderLegacy.cs rename to archive/Core/Decoders/MipsIrDecoderLegacy.cs diff --git a/Core/IntermediateRepresentation.cs b/archive/Core/IntermediateRepresentation.cs similarity index 100% rename from Core/IntermediateRepresentation.cs rename to archive/Core/IntermediateRepresentation.cs diff --git a/Core/IrRunner.cs b/archive/Core/IrRunner.cs similarity index 100% rename from Core/IrRunner.cs rename to archive/Core/IrRunner.cs diff --git a/Core/MipsCore.cs b/archive/Core/MipsCore.cs similarity index 100% rename from Core/MipsCore.cs rename to archive/Core/MipsCore.cs diff --git a/Core/MipsCpuState.cs b/archive/Core/MipsCpuState.cs similarity index 100% rename from Core/MipsCpuState.cs rename to archive/Core/MipsCpuState.cs diff --git a/Core/MipsDecoder.cs b/archive/Core/MipsDecoder.cs similarity index 100% rename from Core/MipsDecoder.cs rename to archive/Core/MipsDecoder.cs diff --git a/Core/MipsInstruction.cs b/archive/Core/MipsInstruction.cs similarity index 100% rename from Core/MipsInstruction.cs rename to archive/Core/MipsInstruction.cs diff --git a/Core/VirtualMmu.cs b/archive/Core/VirtualMmu.cs similarity index 100% rename from Core/VirtualMmu.cs rename to archive/Core/VirtualMmu.cs diff --git a/CortexA15Cpu.cs b/archive/CortexA15Cpu.cs similarity index 100% rename from CortexA15Cpu.cs rename to archive/CortexA15Cpu.cs diff --git a/CpuCore.cs b/archive/CpuCore.cs similarity index 100% rename from CpuCore.cs rename to archive/CpuCore.cs diff --git a/CustomArmBios.cs b/archive/CustomArmBios.cs similarity index 100% rename from CustomArmBios.cs rename to archive/CustomArmBios.cs diff --git a/DirecTVEmulator.cs b/archive/DirecTVEmulator.cs similarity index 100% rename from DirecTVEmulator.cs rename to archive/DirecTVEmulator.cs diff --git a/DiscoveryDevice.cs b/archive/DiscoveryDevice.cs similarity index 100% rename from DiscoveryDevice.cs rename to archive/DiscoveryDevice.cs diff --git a/DocsisSecurityFramework.cs b/archive/DocsisSecurityFramework.cs similarity index 100% rename from DocsisSecurityFramework.cs rename to archive/DocsisSecurityFramework.cs diff --git a/DvrVxWorksDetector.cs b/archive/DvrVxWorksDetector.cs similarity index 100% rename from DvrVxWorksDetector.cs rename to archive/DvrVxWorksDetector.cs diff --git a/Emulation.cs b/archive/Emulation.cs similarity index 100% rename from Emulation.cs rename to archive/Emulation.cs diff --git a/Emulation/ArmHypervisor.cs b/archive/Emulation/ArmHypervisor.cs similarity index 100% rename from Emulation/ArmHypervisor.cs rename to archive/Emulation/ArmHypervisor.cs diff --git a/Emulation/ArmToX86Translator.cs b/archive/Emulation/ArmToX86Translator.cs similarity index 100% rename from Emulation/ArmToX86Translator.cs rename to archive/Emulation/ArmToX86Translator.cs diff --git a/Emulation/BoltBootloader.cs b/archive/Emulation/BoltBootloader.cs similarity index 100% rename from Emulation/BoltBootloader.cs rename to archive/Emulation/BoltBootloader.cs diff --git a/Emulation/DisplayWindow.cs b/archive/Emulation/DisplayWindow.cs similarity index 100% rename from Emulation/DisplayWindow.cs rename to archive/Emulation/DisplayWindow.cs diff --git a/Emulation/EmulatorDisplay.cs b/archive/Emulation/EmulatorDisplay.cs similarity index 100% rename from Emulation/EmulatorDisplay.cs rename to archive/Emulation/EmulatorDisplay.cs diff --git a/Emulation/EmulatorWindow.xaml b/archive/Emulation/EmulatorWindow.xaml similarity index 100% rename from Emulation/EmulatorWindow.xaml rename to archive/Emulation/EmulatorWindow.xaml diff --git a/Emulation/EmulatorWindow.xaml.cs b/archive/Emulation/EmulatorWindow.xaml.cs similarity index 100% rename from Emulation/EmulatorWindow.xaml.cs rename to archive/Emulation/EmulatorWindow.xaml.cs diff --git a/Emulation/GenericFramebuffer.cs b/archive/Emulation/GenericFramebuffer.cs similarity index 100% rename from Emulation/GenericFramebuffer.cs rename to archive/Emulation/GenericFramebuffer.cs diff --git a/Emulation/HomebrewEmulator.cs b/archive/Emulation/HomebrewEmulator.cs similarity index 100% rename from Emulation/HomebrewEmulator.cs rename to archive/Emulation/HomebrewEmulator.cs diff --git a/Emulation/HomebrewEmulatorClean.cs b/archive/Emulation/HomebrewEmulatorClean.cs similarity index 100% rename from Emulation/HomebrewEmulatorClean.cs rename to archive/Emulation/HomebrewEmulatorClean.cs diff --git a/Emulation/HomebrewEmulator_New.cs b/archive/Emulation/HomebrewEmulator_New.cs similarity index 100% rename from Emulation/HomebrewEmulator_New.cs rename to archive/Emulation/HomebrewEmulator_New.cs diff --git a/Emulation/PXRenderer.cs b/archive/Emulation/PXRenderer.cs similarity index 100% rename from Emulation/PXRenderer.cs rename to archive/Emulation/PXRenderer.cs diff --git a/Emulation/SimpleBoltBridge.cs b/archive/Emulation/SimpleBoltBridge.cs similarity index 100% rename from Emulation/SimpleBoltBridge.cs rename to archive/Emulation/SimpleBoltBridge.cs diff --git a/Emulation/SoC/Bcm7449PeripheralStub.cs b/archive/Emulation/SoC/Bcm7449PeripheralStub.cs similarity index 100% rename from Emulation/SoC/Bcm7449PeripheralStub.cs rename to archive/Emulation/SoC/Bcm7449PeripheralStub.cs diff --git a/Emulation/SoC/Bcm7449SoCManager.cs b/archive/Emulation/SoC/Bcm7449SoCManager.cs similarity index 100% rename from Emulation/SoC/Bcm7449SoCManager.cs rename to archive/Emulation/SoC/Bcm7449SoCManager.cs diff --git a/Emulation/SoC/CableCardStub.cs b/archive/Emulation/SoC/CableCardStub.cs similarity index 100% rename from Emulation/SoC/CableCardStub.cs rename to archive/Emulation/SoC/CableCardStub.cs diff --git a/Emulation/SoC/CryptoEngineStub.cs b/archive/Emulation/SoC/CryptoEngineStub.cs similarity index 100% rename from Emulation/SoC/CryptoEngineStub.cs rename to archive/Emulation/SoC/CryptoEngineStub.cs diff --git a/Emulation/SoC/HdmiStub.cs b/archive/Emulation/SoC/HdmiStub.cs similarity index 100% rename from Emulation/SoC/HdmiStub.cs rename to archive/Emulation/SoC/HdmiStub.cs diff --git a/Emulation/SoC/MoCAControllerStub.cs b/archive/Emulation/SoC/MoCAControllerStub.cs similarity index 100% rename from Emulation/SoC/MoCAControllerStub.cs rename to archive/Emulation/SoC/MoCAControllerStub.cs diff --git a/Emulation/SoC/SecureBootStub.cs b/archive/Emulation/SoC/SecureBootStub.cs similarity index 100% rename from Emulation/SoC/SecureBootStub.cs rename to archive/Emulation/SoC/SecureBootStub.cs diff --git a/Emulation/SparcEmulator.cs b/archive/Emulation/SparcEmulator.cs similarity index 100% rename from Emulation/SparcEmulator.cs rename to archive/Emulation/SparcEmulator.cs diff --git a/Emulation/StubEmulators.cs b/archive/Emulation/StubEmulators.cs similarity index 100% rename from Emulation/StubEmulators.cs rename to archive/Emulation/StubEmulators.cs diff --git a/Emulation/SyncEngine/CMTSResponder.cs b/archive/Emulation/SyncEngine/CMTSResponder.cs similarity index 100% rename from Emulation/SyncEngine/CMTSResponder.cs rename to archive/Emulation/SyncEngine/CMTSResponder.cs diff --git a/Emulation/SyncEngine/ChannelMapper.cs b/archive/Emulation/SyncEngine/ChannelMapper.cs similarity index 100% rename from Emulation/SyncEngine/ChannelMapper.cs rename to archive/Emulation/SyncEngine/ChannelMapper.cs diff --git a/Emulation/SyncEngine/EntitlementManager.cs b/archive/Emulation/SyncEngine/EntitlementManager.cs similarity index 100% rename from Emulation/SyncEngine/EntitlementManager.cs rename to archive/Emulation/SyncEngine/EntitlementManager.cs diff --git a/Emulation/SyncEngine/GuideFetcher.cs b/archive/Emulation/SyncEngine/GuideFetcher.cs similarity index 100% rename from Emulation/SyncEngine/GuideFetcher.cs rename to archive/Emulation/SyncEngine/GuideFetcher.cs diff --git a/Emulation/SyncEngine/SyncScheduler.cs b/archive/Emulation/SyncEngine/SyncScheduler.cs similarity index 100% rename from Emulation/SyncEngine/SyncScheduler.cs rename to archive/Emulation/SyncEngine/SyncScheduler.cs diff --git a/Emulation/launch.json b/archive/Emulation/launch.json similarity index 100% rename from Emulation/launch.json rename to archive/Emulation/launch.json diff --git a/Emulation/tasks.json b/archive/Emulation/tasks.json similarity index 100% rename from Emulation/tasks.json rename to archive/Emulation/tasks.json diff --git a/EmulationLogPanel.cs b/archive/EmulationLogPanel.cs similarity index 100% rename from EmulationLogPanel.cs rename to archive/EmulationLogPanel.cs diff --git a/EmulatorConsole.cs b/archive/EmulatorConsole.cs similarity index 100% rename from EmulatorConsole.cs rename to archive/EmulatorConsole.cs diff --git a/EmulatorLauncher.cs b/archive/EmulatorLauncher.cs similarity index 100% rename from EmulatorLauncher.cs rename to archive/EmulatorLauncher.cs diff --git a/ErrorManager.cs b/archive/ErrorManager.cs similarity index 100% rename from ErrorManager.cs rename to archive/ErrorManager.cs diff --git a/ExoticFilesystemManager.cs b/archive/ExoticFilesystemManager.cs similarity index 100% rename from ExoticFilesystemManager.cs rename to archive/ExoticFilesystemManager.cs diff --git a/FEATURE_NOTES.md b/archive/FEATURE_NOTES.md similarity index 100% rename from FEATURE_NOTES.md rename to archive/FEATURE_NOTES.md diff --git a/FileSystemManager.cs b/archive/FileSystemManager.cs similarity index 100% rename from FileSystemManager.cs rename to archive/FileSystemManager.cs diff --git a/FileSystems.cs b/archive/FileSystems.cs similarity index 100% rename from FileSystems.cs rename to archive/FileSystems.cs diff --git a/FilesystemProber.cs b/archive/FilesystemProber.cs similarity index 100% rename from FilesystemProber.cs rename to archive/FilesystemProber.cs diff --git a/FirmwareAnalyzer.cs b/archive/FirmwareAnalyzer.cs similarity index 100% rename from FirmwareAnalyzer.cs rename to archive/FirmwareAnalyzer.cs diff --git a/FirmwareLoader.cs b/archive/FirmwareLoader.cs similarity index 100% rename from FirmwareLoader.cs rename to archive/FirmwareLoader.cs diff --git a/FirmwareRegionAnalyzer.cs b/archive/FirmwareRegionAnalyzer.cs similarity index 100% rename from FirmwareRegionAnalyzer.cs rename to archive/FirmwareRegionAnalyzer.cs diff --git a/FirmwareScanner.cs b/archive/FirmwareScanner.cs similarity index 100% rename from FirmwareScanner.cs rename to archive/FirmwareScanner.cs diff --git a/FirmwareStreamer.cs b/archive/FirmwareStreamer.cs similarity index 100% rename from FirmwareStreamer.cs rename to archive/FirmwareStreamer.cs diff --git a/FirmwareUnpackException.cs b/archive/FirmwareUnpackException.cs similarity index 100% rename from FirmwareUnpackException.cs rename to archive/FirmwareUnpackException.cs diff --git a/FirmwareUnpacker.cs b/archive/FirmwareUnpacker.cs similarity index 100% rename from FirmwareUnpacker.cs rename to archive/FirmwareUnpacker.cs diff --git a/FolderAnalysisWindow.cs b/archive/FolderAnalysisWindow.cs similarity index 100% rename from FolderAnalysisWindow.cs rename to archive/FolderAnalysisWindow.cs diff --git a/FolderAnalysisWindow.xaml b/archive/FolderAnalysisWindow.xaml similarity index 100% rename from FolderAnalysisWindow.xaml rename to archive/FolderAnalysisWindow.xaml diff --git a/FolderAnalysisWindow.xaml.cs b/archive/FolderAnalysisWindow.xaml.cs similarity index 100% rename from FolderAnalysisWindow.xaml.cs rename to archive/FolderAnalysisWindow.xaml.cs diff --git a/HypervisorWindow.cs b/archive/HypervisorWindow.cs similarity index 100% rename from HypervisorWindow.cs rename to archive/HypervisorWindow.cs diff --git a/HypervisorWindow.xaml b/archive/HypervisorWindow.xaml similarity index 100% rename from HypervisorWindow.xaml rename to archive/HypervisorWindow.xaml diff --git a/HypervisorWindow.xaml.cs b/archive/HypervisorWindow.xaml.cs similarity index 100% rename from HypervisorWindow.xaml.cs rename to archive/HypervisorWindow.xaml.cs diff --git a/IEmulator.cs b/archive/IEmulator.cs similarity index 100% rename from IEmulator.cs rename to archive/IEmulator.cs diff --git a/IManifestProvider.cs b/archive/IManifestProvider.cs similarity index 100% rename from IManifestProvider.cs rename to archive/IManifestProvider.cs diff --git a/ISP_DVR_Research_Integration.cs b/archive/ISP_DVR_Research_Integration.cs similarity index 100% rename from ISP_DVR_Research_Integration.cs rename to archive/ISP_DVR_Research_Integration.cs diff --git a/InstructionDispatcher.cs b/archive/InstructionDispatcher.cs similarity index 100% rename from InstructionDispatcher.cs rename to archive/InstructionDispatcher.cs diff --git a/InstructionTranslator.cs b/archive/InstructionTranslator.cs similarity index 100% rename from InstructionTranslator.cs rename to archive/InstructionTranslator.cs diff --git a/InstructionTranslator_Archive.cs b/archive/InstructionTranslator_Archive.cs similarity index 100% rename from InstructionTranslator_Archive.cs rename to archive/InstructionTranslator_Archive.cs diff --git a/LinuxFileSystems.cs b/archive/LinuxFileSystems.cs similarity index 100% rename from LinuxFileSystems.cs rename to archive/LinuxFileSystems.cs diff --git a/MainWindow.Themes.cs b/archive/MainWindow.Themes.cs similarity index 100% rename from MainWindow.Themes.cs rename to archive/MainWindow.Themes.cs diff --git a/MainWindow.xaml b/archive/MainWindow.xaml similarity index 100% rename from MainWindow.xaml rename to archive/MainWindow.xaml diff --git a/MainWindow.xaml.cs b/archive/MainWindow.xaml.cs similarity index 100% rename from MainWindow.xaml.cs rename to archive/MainWindow.xaml.cs diff --git a/MediaroomBootManager.cs b/archive/MediaroomBootManager.cs similarity index 100% rename from MediaroomBootManager.cs rename to archive/MediaroomBootManager.cs diff --git a/MemoryMap.cs b/archive/MemoryMap.cs similarity index 100% rename from MemoryMap.cs rename to archive/MemoryMap.cs diff --git a/MocaTunersStub.cs b/archive/MocaTunersStub.cs similarity index 100% rename from MocaTunersStub.cs rename to archive/MocaTunersStub.cs diff --git a/NetworkRedirector.cs b/archive/NetworkRedirector.cs similarity index 100% rename from NetworkRedirector.cs rename to archive/NetworkRedirector.cs diff --git a/NvRamDevice.cs b/archive/NvRamDevice.cs similarity index 100% rename from NvRamDevice.cs rename to archive/NvRamDevice.cs diff --git a/PEImageLoader.cs b/archive/PEImageLoader.cs similarity index 100% rename from PEImageLoader.cs rename to archive/PEImageLoader.cs diff --git a/PartitionEntry.cs b/archive/PartitionEntry.cs similarity index 100% rename from PartitionEntry.cs rename to archive/PartitionEntry.cs diff --git a/PlatformDetector.cs b/archive/PlatformDetector.cs similarity index 100% rename from PlatformDetector.cs rename to archive/PlatformDetector.cs diff --git a/PlatformManager.cs b/archive/PlatformManager.cs similarity index 100% rename from PlatformManager.cs rename to archive/PlatformManager.cs diff --git a/PowerPCBootloaderManager.cs b/archive/PowerPCBootloaderManager.cs similarity index 100% rename from PowerPCBootloaderManager.cs rename to archive/PowerPCBootloaderManager.cs diff --git a/PowerPCEmulator.cs b/archive/PowerPCEmulator.cs similarity index 100% rename from PowerPCEmulator.cs rename to archive/PowerPCEmulator.cs diff --git a/Program.cs b/archive/Program.cs similarity index 100% rename from Program.cs rename to archive/Program.cs diff --git a/QemuManager.cs b/archive/QemuManager.cs similarity index 100% rename from QemuManager.cs rename to archive/QemuManager.cs diff --git a/RDKVEmulator.cs b/archive/RDKVEmulator.cs similarity index 100% rename from RDKVEmulator.cs rename to archive/RDKVEmulator.cs diff --git a/RDKVPlatformConfig.cs b/archive/RDKVPlatformConfig.cs similarity index 100% rename from RDKVPlatformConfig.cs rename to archive/RDKVPlatformConfig.cs diff --git a/archive/README.md b/archive/README.md new file mode 100644 index 00000000..4193213d --- /dev/null +++ b/archive/README.md @@ -0,0 +1,31 @@ +# Archive (unused, not deleted) + +These files were moved out of the live ExtraROM / U-verse MIPS CE working set. +They are unused by `ProcessorEmulator.csproj` (`net8.0-windows` WinForms host that +boots `nk.bin` + ExtraROM `etc.bin`). Original relative paths are preserved under +this folder. Nothing here was `git rm`'d. + +Restore a file with `git mv archive/ ` if the live emulator needs it. + +## What moved + +- BoltDemo / BoltDemo_Standalone (net6.0 Linux-style demo, including committed `obj/` and `bin/` cruft) +- Dead WPF UI (`MainWindow`, `HypervisorWindow`, `FolderAnalysisWindow`, `CarlMode`, Classic/Win7 XAML) +- Non-U-verse platform trees (DirecTV, Comcast X1, RDK-V, PowerPC, SPARC, ARM hypervisor, XG1v4, SWM LNB) +- Linux / VxWorks / exotic filesystem demos and firmware unpacker/scanner toolkit files +- QEMU / Unicorn / RetDec helper projects and stubs under `Tools/` and `Emulation/` +- Unused JSON (`mips_files.json`), sample `test.elf`, extra docs (`BOLT_README.md`, `BUILD_STATUS.md`, …) +- IR/decoder leftovers under `Core/` that the ExtraROM `NkBinLoader` / `MipsCpuEmulator` path does not compile + +Dump bins (`nk.bin`, `etc.bin`, U-verse firmware) were not added here. Existing +`nk.bin` / `UverseDriveE/nk.bin` stay in the live tree. + +## What stayed in the live tree (the program needs it) + +- WinForms ExtraROM host: `App.cs` / `App.xaml`, `MediaroomHostForm.cs`, `MediaroomSession.cs` +- MIPS32 / CE boot: `MipsCpuEmulator.cs`, `MipsBus.cs`, `CP0.cs`, `RamDevice.cs`, `MipsUart.cs`, BCM MMIO, `IBusDevice.cs`, `VirtualRegistry.cs` +- ExtraROM load/attach: `Core/NkBinLoader.cs`, `Core/CeRomTocFiles.cs`, `Core/HostHardDisk.cs`, `Core/BinBlkMedia.cs`, `Core/Abstractions.cs`, `Core/Exceptions.cs`, `Core/MemoryMap.cs` +- `ConfigManager.cs` (HostHardDisk reads `Config.FirmwarePath`) +- `UverseEmulatorTest.cs` / `MipsUverseEmulator.cs` / `IChipsetEmulator.cs` (`App` `--test-uverse`) +- `Directory.Build.props` (`EnableWindowsTargeting`), `ProcessorEmulator.csproj`, solution, `app.manifest` +- Leftover dest-live / FILE type-8 attach code was not stripped diff --git a/RdkVStack.cs b/archive/RdkVStack.cs similarity index 100% rename from RdkVStack.cs rename to archive/RdkVStack.cs diff --git a/RealHypervisorDisplay.cs b/archive/RealHypervisorDisplay.cs similarity index 100% rename from RealHypervisorDisplay.cs rename to archive/RealHypervisorDisplay.cs diff --git a/RealHypervisorManager.cs b/archive/RealHypervisorManager.cs similarity index 100% rename from RealHypervisorManager.cs rename to archive/RealHypervisorManager.cs diff --git a/RealMipsHypervisor.cs b/archive/RealMipsHypervisor.cs similarity index 100% rename from RealMipsHypervisor.cs rename to archive/RealMipsHypervisor.cs diff --git a/RealQemuEmulator.cs b/archive/RealQemuEmulator.cs similarity index 100% rename from RealQemuEmulator.cs rename to archive/RealQemuEmulator.cs diff --git a/SatelliteStreamEmulator.cs b/archive/SatelliteStreamEmulator.cs similarity index 100% rename from SatelliteStreamEmulator.cs rename to archive/SatelliteStreamEmulator.cs diff --git a/SimpleFirmwareEmulator.cs b/archive/SimpleFirmwareEmulator.cs similarity index 100% rename from SimpleFirmwareEmulator.cs rename to archive/SimpleFirmwareEmulator.cs diff --git a/StandaloneBoltDemo.cs b/archive/StandaloneBoltDemo.cs similarity index 100% rename from StandaloneBoltDemo.cs rename to archive/StandaloneBoltDemo.cs diff --git a/StandaloneBoltDemo.csproj b/archive/StandaloneBoltDemo.csproj similarity index 100% rename from StandaloneBoltDemo.csproj rename to archive/StandaloneBoltDemo.csproj diff --git a/SwmLnbEmulator.cs b/archive/SwmLnbEmulator.cs similarity index 100% rename from SwmLnbEmulator.cs rename to archive/SwmLnbEmulator.cs diff --git a/TestHypervisor.cs b/archive/TestHypervisor.cs similarity index 100% rename from TestHypervisor.cs rename to archive/TestHypervisor.cs diff --git a/Tools.cs b/archive/Tools.cs similarity index 100% rename from Tools.cs rename to archive/Tools.cs diff --git a/Tools/BinaryTranslator.cs b/archive/Tools/BinaryTranslator.cs similarity index 100% rename from Tools/BinaryTranslator.cs rename to archive/Tools/BinaryTranslator.cs diff --git a/Tools/ChipReferenceManager.cs b/archive/Tools/ChipReferenceManager.cs similarity index 100% rename from Tools/ChipReferenceManager.cs rename to archive/Tools/ChipReferenceManager.cs diff --git a/Tools/DeviceTreeManager.cs b/archive/Tools/DeviceTreeManager.cs similarity index 100% rename from Tools/DeviceTreeManager.cs rename to archive/Tools/DeviceTreeManager.cs diff --git a/Tools/HardwareHealthProbe.cs b/archive/Tools/HardwareHealthProbe.cs similarity index 100% rename from Tools/HardwareHealthProbe.cs rename to archive/Tools/HardwareHealthProbe.cs diff --git a/Tools/HybridSwmLnbEmulator.cs b/archive/Tools/HybridSwmLnbEmulator.cs similarity index 100% rename from Tools/HybridSwmLnbEmulator.cs rename to archive/Tools/HybridSwmLnbEmulator.cs diff --git a/Tools/ISatelliteLnbEmulator.cs b/archive/Tools/ISatelliteLnbEmulator.cs similarity index 100% rename from Tools/ISatelliteLnbEmulator.cs rename to archive/Tools/ISatelliteLnbEmulator.cs diff --git a/Tools/QemuInstaller.cs b/archive/Tools/QemuInstaller.cs similarity index 100% rename from Tools/QemuInstaller.cs rename to archive/Tools/QemuInstaller.cs diff --git a/Tools/SwmLnbEmulator.cs b/archive/Tools/SwmLnbEmulator.cs similarity index 100% rename from Tools/SwmLnbEmulator.cs rename to archive/Tools/SwmLnbEmulator.cs diff --git a/Tools/TrxExtractor.cs b/archive/Tools/TrxExtractor.cs similarity index 100% rename from Tools/TrxExtractor.cs rename to archive/Tools/TrxExtractor.cs diff --git a/Tools/UnicornChipsetEmulator.cs b/archive/Tools/UnicornChipsetEmulator.cs similarity index 100% rename from Tools/UnicornChipsetEmulator.cs rename to archive/Tools/UnicornChipsetEmulator.cs diff --git a/Tools/UnicornStubs.cs b/archive/Tools/UnicornStubs.cs similarity index 100% rename from Tools/UnicornStubs.cs rename to archive/Tools/UnicornStubs.cs diff --git a/Tools/XmiExtractor.cs b/archive/Tools/XmiExtractor.cs similarity index 100% rename from Tools/XmiExtractor.cs rename to archive/Tools/XmiExtractor.cs diff --git a/Tools/YaffsExtractor.cs b/archive/Tools/YaffsExtractor.cs similarity index 100% rename from Tools/YaffsExtractor.cs rename to archive/Tools/YaffsExtractor.cs diff --git a/UPDATE PLEASE READ b/archive/UPDATE PLEASE READ similarity index 100% rename from UPDATE PLEASE READ rename to archive/UPDATE PLEASE READ diff --git a/UniversalUart.cs b/archive/UniversalUart.cs similarity index 100% rename from UniversalUart.cs rename to archive/UniversalUart.cs diff --git a/UverseDvrEmulator.cs b/archive/UverseDvrEmulator.cs similarity index 100% rename from UverseDvrEmulator.cs rename to archive/UverseDvrEmulator.cs diff --git a/UverseEmulator.cs b/archive/UverseEmulator.cs similarity index 100% rename from UverseEmulator.cs rename to archive/UverseEmulator.cs diff --git a/UverseEmulatorOriginal.cs b/archive/UverseEmulatorOriginal.cs similarity index 100% rename from UverseEmulatorOriginal.cs rename to archive/UverseEmulatorOriginal.cs diff --git a/UverseFileParser.cs b/archive/UverseFileParser.cs similarity index 100% rename from UverseFileParser.cs rename to archive/UverseFileParser.cs diff --git a/UverseFileSystem.cs b/archive/UverseFileSystem.cs similarity index 100% rename from UverseFileSystem.cs rename to archive/UverseFileSystem.cs diff --git a/UverseFirmwareExtractor.cs b/archive/UverseFirmwareExtractor.cs similarity index 100% rename from UverseFirmwareExtractor.cs rename to archive/UverseFirmwareExtractor.cs diff --git a/VirtualMachineHypervisor.cs b/archive/VirtualMachineHypervisor.cs similarity index 100% rename from VirtualMachineHypervisor.cs rename to archive/VirtualMachineHypervisor.cs diff --git a/VirtualMemoryManager.cs b/archive/VirtualMemoryManager.cs similarity index 100% rename from VirtualMemoryManager.cs rename to archive/VirtualMemoryManager.cs diff --git a/VxWorksFilesystem.cs b/archive/VxWorksFilesystem.cs similarity index 100% rename from VxWorksFilesystem.cs rename to archive/VxWorksFilesystem.cs diff --git a/Win7Chrome.cs b/archive/Win7Chrome.cs similarity index 100% rename from Win7Chrome.cs rename to archive/Win7Chrome.cs diff --git a/Win7Styles.xaml b/archive/Win7Styles.xaml similarity index 100% rename from Win7Styles.xaml rename to archive/Win7Styles.xaml diff --git a/WinCEEmulator.cs b/archive/WinCEEmulator.cs similarity index 100% rename from WinCEEmulator.cs rename to archive/WinCEEmulator.cs diff --git a/Windows7ThemeManager.cs b/archive/Windows7ThemeManager.cs similarity index 100% rename from Windows7ThemeManager.cs rename to archive/Windows7ThemeManager.cs diff --git a/WindowsCEApiEmulator.cs b/archive/WindowsCEApiEmulator.cs similarity index 100% rename from WindowsCEApiEmulator.cs rename to archive/WindowsCEApiEmulator.cs diff --git a/WindowsCEExecutor.cs b/archive/WindowsCEExecutor.cs similarity index 100% rename from WindowsCEExecutor.cs rename to archive/WindowsCEExecutor.cs diff --git a/X86CpuEmulator.cs b/archive/X86CpuEmulator.cs similarity index 100% rename from X86CpuEmulator.cs rename to archive/X86CpuEmulator.cs diff --git a/XG1v4Emulator.cs b/archive/XG1v4Emulator.cs similarity index 100% rename from XG1v4Emulator.cs rename to archive/XG1v4Emulator.cs diff --git a/dotnet-install.ps1 b/archive/dotnet-install.ps1 similarity index 100% rename from dotnet-install.ps1 rename to archive/dotnet-install.ps1 diff --git a/mips_files.json b/archive/mips_files.json similarity index 100% rename from mips_files.json rename to archive/mips_files.json diff --git a/test.elf b/archive/test.elf similarity index 100% rename from test.elf rename to archive/test.elf