Commit Graph
425 Commits
Author SHA1 Message Date
Henrik Rydgård 78ef1eae82 Instead of flash0directory, have a NAND subdirectory under PSP, where you can keep flash0, flash1 etc.
Also make it configurable via command line.
2026-08-24 09:53:37 +02:00
Henrik Rydgård 786a1530de Correct host0: mount 2026-08-24 09:30:44 +02:00
Henrik Rydgård 1910be0b47 Fix booting from extracted directories specified on the command line, reported by Kotcrab 2026-08-20 00:54:26 +02:00
Henrik RydgårdandClaude Opus 5 3463789597 Find the companion ELF when a game is launched by folder, and keep line info
Two things kept the companion ELF from doing its job.

The first is the one that mattered: fileToStart is the game's own *directory*
for folder-launched homebrew (IdentifiedFileType::PSP_PBP_DIRECTORY), which is
the normal case when you pick a homebrew in the UI. The search navigated up from
it regardless, landing in PSP/GAME and listing sibling games - all directories,
all skipped - so app.elf sitting right next to the EBOOT was never found. It only
ever worked when the path pointed at the EBOOT itself, which is how headless is
invoked, which is why it looked fine from there. Searches the directory itself
now when that's what it's given.

The second: line info didn't survive loading a savestate. Modules aren't just
re-registered there, they're destroyed and rebuilt (KernelObjectPool::Clear), so
removing a module's lines in ~PSPModule threw the table away on every state
load. The previous commit worked around it by re-reading the companion, which
was both wasteful and no help at all to an ELF launched directly - those bytes
are long gone by then.

SymbolMap already solves this and line info now does it the same way: keep what
you have, and let whatever next claims the address range replace it. AddModule
replaces by key and is called for every module load, including ones with no line
info of their own, so a range gets retired when it's genuinely reused. The whole
table goes when the game does, in PSP_Shutdown. That also means the savestate
path has nothing to re-read, so state loads no longer pay to re-parse a
multi-megabyte ELF.

The tradeoff is a window between a module unloading and its range being reclaimed
where a lookup can still answer for it. For a debugger that's a stale file:line
on an address nothing owns, against certain and total loss on every state load.

Verified with --auto-save-load-symbols off, launched both ways: by directory
(the case that was broken) and by EBOOT path, both give 3734 symbols and 98383
line rows.

pspautotests 314/314, UnitTest 55/55.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-18 14:19:58 +02:00
Henrik RydgårdandClaude Opus 5 05f5668dfe Save symbols outside any module to a per-game file, and only save real names
Module symbols are keyed by module+crc so they're shared by every game that
loads that module. But symbols the user attaches to addresses that aren't in
any module - the heap, the stack, scratchpad, a hardware register, typically
after a memory.search - describe one game's own memory layout and are worthless
to any other game. Those now go to PSP/SYSTEM/SYMBOLS/<gameID>_syms.ppsym.

They're module index 0 ("absolute"), which already round-trips through the
existing per-module code: GetModuleRelativeAddr/GetModuleAbsoluteAddr are
identity for it, so the file format is unchanged, just with absolute addresses.
SaveModuleSymbols only needed to stop requiring a ModuleEntry. Auto-load/save
hang off CPU_Init/CPU_Shutdown rather than module load/unload, gated on the same
bAutoSaveLoadSymbols setting - and deliberately not on SYSPROP_HAS_DEBUGGER,
which only the Windows port reports true for, so LoadSymbolsIfSupported next to
it does nothing at all on headless. hle.game.saveSymbols/loadSymbols expose it.

Four things found while doing it:

- Symbols outside any module were being dropped on the floor. AddFunction/
  AddData/AddLabel take moduleIndex -1 as "work it out", pass it to
  GetModuleIndex(), and store whatever comes back - but that returns -1 when no
  module contains the address, and -1 is never an active module, so the symbol
  never reached the active maps: invisible to every lookup and to any save.
  hle.data.add had spotted this and normalized -1 to 0 locally; nothing else
  did, so e.g. hle.func.add outside a module silently did nothing. Fixed
  centrally in a new ResolveModuleIndex() the three of them share.
  (This only became reachable with the GetModuleIndex() fix in 29a38af37e -
  before that it returned a wrong-but-valid module index instead.)

- The saved files were almost entirely noise. Every function the analyzer finds
  is named z_un_<addr> and every import stub zz_<name>, both regenerated from
  scratch on each load. One real module wrote 13KB - 443 unnamed functions and
  64 stub names - for the four names a human had actually chosen. Worse, on the
  next run those were loaded back as authoritative and would beat the module's
  own symbols to the address. Now only names that aren't regenerated get saved,
  and a module with none writes no file at all (and removes a stale one, so
  deleting a symbol sticks). That module's file went 13020 -> 81 bytes.

- LoadModuleSymbols trusted the addresses in the file. It's meant to be
  hand-edited and can outlive the build it came from, so relative addresses past
  the end of the module are now skipped with a warning instead of landing at
  nonsense addresses.

- AddFunction and AddData both erased the map entry they were updating and then
  read back through the now-dangling iterator to refresh the active copy. Only
  latent: the refresh is guarded on the active copy's module matching the new
  one, which is false exactly when the erase happens. Re-point the iterator at
  the entry's new home instead, so it can't rot if that guard ever changes.
  AddLabel already did the equivalent correctly, via a local copy.

Filename sanitizing goes through SanitizeString with a new FileName restriction
rather than being open-coded; unlike the existing restrictions it substitutes
'_' instead of dropping, so two module names can't collapse onto one file.

Verified end to end on headless with cpu_alu.prx: named a function inside the
module and data/functions in scratchpad and the heap, let it exit, checked both
files, rebooted and confirmed all of it came back at the right addresses.
Unit tests 51/51, pspautotests 314/314.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 16:53:48 +02:00
Henrik RydgårdandClaude Opus 5 75ff0d406c Rename Memory::Lock() to Core_LockAgainstShutdown(), move it to Core
It stopped being about memory when CPU_Shutdown started holding it across the
whole teardown - it's what keeps kernel objects, the symbol map and the memory
map from being freed while another thread reads them. The old name invited the
reading that it locks memory *access*, which it has never done.

Memory::Reinit() now holds it across both halves rather than relying on
Memory::Shutdown()'s own acquire: between Shutdown() and Init() there is no
memory map at all, and a reader could slip into that gap.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 4a10fa2808 Hold the shutdown lock across all of CPU_Shutdown
It was only held across Memory::Shutdown(), but everything else in there frees
state the debugger UIs read from other threads - kernel objects
(__KernelShutdown), the symbol map, replacements - so a Win32 debugger window
painting while a game is reset could read freed memory. It's recursive, so the
nested acquire in Memory::Shutdown() is unaffected.

No lock-order risk: on the paths where CPU_Shutdown already runs under
g_frameMutex it now takes these in the same frame-then-shutdown order the GUI
side uses, and on the paths where it doesn't (EmuScreen::sendMessage,
ProcessScreenSwitches - both above where NativeFrame takes the guard) it takes
only this one.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik RydgårdandClaude Opus 5 a0f223d933 Move the last debugger core access onto the CPU thread
Three things still touched CPU-thread-owned state from the WebSocket thread:

- Breakpoint conditions were compiled in Parse(), and resolving symbols in an
  expression goes through g_symbolMap, which is destroyed on shutdown. Compiled
  inside the queued callback now, before anything is mutated, so a bad
  expression still fails without leaving a breakpoint behind.
- gpu.record.dump dereferenced the gpu pointer, which is created and destroyed
  on the CPU thread.
- gpu.stats.feed bumped PSP_ForceDebugStats' plain counter.

Also makes g_bootState atomic - it's read as a fast-fail from the debugger
thread all over while the CPU and loader threads move it along.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
2026-08-17 13:11:16 +02:00
Henrik Rydgård 9f90512ef6 Make instruction cache invalidation (for us, jit cache invalidation) clearer 2026-08-16 16:59:52 +02:00
Henrik Rydgård 5cffcd34ad Get rid of the confusing old USING_WIN_UI define. Make a more clear system property for headless. 2026-08-16 12:19:41 +02:00
Henrik Rydgård 2096179dce Drive-by code cleanup 2026-08-15 18:31:20 +02:00
Henrik Rydgård 95f1dc648d Simplification: Mount filesystems earlier in init, and don't remount on LoadExec
This is needed for an upcoming PR.
2026-08-12 23:38:48 +02:00
Henrik Rydgård e9a3449ede More MIPSState * plumbing (manual) 2026-08-12 14:02:19 +02:00
Henrik Rydgård 04ef18a9d9 Send the crash dump output to the debug output stream in headless. This makes it so that crash-failed test output will contain crash details.
Also fix some warnings and stuff.
2026-08-11 22:36:47 +02:00
Henrik Rydgård 54618c67c6 Headless improvements 2026-07-29 16:27:33 +02:00
Henrik Rydgård 34454f9d03 Claude's crazy exception handler hack 2026-07-27 23:41:13 +02:00
Henrik Rydgård 3eb056ad86 Move Common/GraphicsContext.h to Common/GPU/GraphicsContext.h 2026-07-26 13:58:17 +02:00
Henrik Rydgård b07fce1566 Warning fix, shutdown fix 2026-06-02 17:16:45 +02:00
Henrik Rydgård a317890c08 Remove the GPUDebugInterface class
Just a pointless extra layer in the class hiearchy, making it
unnecessarily hard to modify the interface.

Might as well hit GPUCommon directly.
2026-06-02 11:15:08 +02:00
Henrik Rydgård 6377c0bb06 Implement optional dumping of NPDRM isos (PBP demos) on game startup 2026-03-19 16:07:24 +01:00
Henrik Rydgård 445dd0bc0c Fix support for custom game configs for homebrews
Fixes #21429
2026-03-14 14:03:33 +01:00
Henrik Rydgård 5dc169ecbe Fix more race conditions if you exit during game bootup 2026-02-24 00:56:45 +01:00
Henrik Rydgård 25392ef6fd Add a workaround for boot-up crashes caused by switching away from the app while waiting for the boot-up thread to finish 2026-02-24 00:56:45 +01:00
Henrik Rydgård 5be7a43b86 Revert "Check for valid draw context a little earlier in boot."
This reverts commit 045368656f.
2026-02-23 11:53:50 +01:00
Henrik Rydgård 8b0144dbfc Get libretro integration working again.
- Fixes #21275

- Fixes #21274
2026-02-18 10:14:37 +01:00
Henrik Rydgård 045368656f Check for valid draw context a little earlier in boot. 2026-02-17 10:18:08 +01:00
Henrik Rydgård a92ff89d5f Clean up the OSD click callback code 2026-02-09 13:08:44 +01:00
Henrik Rydgård 2b6be8090c Cancel compatibility warning popups if you start another game in the meantime 2026-02-08 16:38:07 +01:00
Henrik Rydgård b1fa6b4671 Remove some uses of textScale 2026-02-06 14:30:47 +01:00
Henrik Rydgård 998d385119 Bubble up CSO corruption errors so the user can see them 2026-02-03 11:57:05 +01:00
Henrik Rydgård db0a557590 Make it possible to have RetroAchievements enabled in a game config.
Fixes #21175
2026-01-30 09:43:31 +01:00
Henrik Rydgård 0f85b06908 Add basic support for installing savestate ZIPs (useful for iOS testing) 2026-01-29 22:10:46 +01:00
Henrik Rydgård 4fb3a0e370 Bubble up more error messages to the user 2026-01-29 00:25:25 +01:00
Henrik Rydgård 8f76b191cd More improvements to ISO detection 2026-01-28 23:48:49 +01:00
Henrik Rydgård 19a6232b48 Improve handling of the UMD VIDEO error case (no, we still don't support them) 2026-01-28 14:32:38 +01:00
Henrik Rydgård 24f2deeb2e Improve file identification.
Fixes #21154
2026-01-28 10:21:09 +01:00
Henrik Rydgård 68a8ba856f Warning fix, delete unused code 2026-01-24 10:43:48 +01:00
Henrik Rydgård 34473fc621 Add a compat flag to map some extra memory at address 0.
Can be used to work around certain types of crashes without having to
disable fast memory.
2026-01-23 15:14:15 +01:00
Henrik Rydgård b8fced5b41 Path code cleanup, move some UI code (#21037)
* Move a bunch of path logic into Core/Util/PathUtil.cpp/h

.

* Move GameImageView out from SaveDataScreen

* More cleanup, add a translation string
2025-11-25 00:44:24 +01:00
Henrik Rydgård b71ee0ba89 Fix some bugs around game-specific config load/save (#21033) 2025-11-24 14:05:23 +01:00
oltolm b488c17518 fix GCC warning
C:/src/ppsspp/Core/System.cpp: In function 'void DumpFileIfEnabled(const u8*, u32, std::string_view, DumpFileType)':
C:/src/ppsspp/Core/System.cpp:938:29: warning: 'void free(void*)' called on pointer returned from a mismatched allocation function [-Wmismatched-new-delete]
  938 |                         free(path);
      |                         ~~~~^~~~~~
C:/src/ppsspp/Core/System.cpp:924:67: note: returned from 'void* operator new [](std::size_t)'
  924 |                 char *path = new char[strlen(fullPath.c_str()) + 1];
      |
2025-11-07 22:46:18 +01:00
Henrik Rydgård 75020e2ed7 Add ability to put icons on tabs 2025-11-05 14:42:49 +01:00
Henrik Rydgård 4edb8e53cd Just some renaming and cleanup 2025-11-04 23:39:56 +01:00
Henrik Rydgård 54a7095522 Fix an issue where game-specific configs didn't affect the software renderer setting properly.
Fixes #20923
2025-11-04 13:52:01 +01:00
Henrik Rydgård 198d86a9b1 Move the PSP system language logic into sceUtility. 2025-11-04 11:48:47 +01:00
Henrik Rydgård 461f8586b6 Use config defaults in the headless binary.
Fixes #19332
2025-09-24 11:56:51 -06:00
Henrik Rydgård 14016f84df Comments 2025-09-04 11:24:43 +02:00
Henrik Rydgård 6c238e0109 Small upgrade to the ParamSFO window: Show the original params, add copy to clipboard 2025-09-02 00:50:12 +02:00
Henrik Rydgård a107d75e38 Fix lifecycle-notification assert problem (was called from wrong thread) 2025-08-24 11:17:19 +02:00
Henrik Rydgård 6df9e513c1 Logging, comments and debugger fixes, plus simple dumping of the first block of streaming Atrac3 2025-06-25 01:08:47 +02:00