Commit Graph
832 Commits
Author SHA1 Message Date
Henrik RydgårdandClaude Opus 5.5 1288c294fd Savedata dialog: Draw icons over black, with alpha blending
The PSP blends save icons over a black background, so their transparent
parts come out black. 0a5fa27957 turned blending off instead, which is
wrong for icons that rely on it. Revert that, and draw a black rectangle
under each icon. Fixes #22280.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-29 13:21:24 -06:00
Henrik RydgårdandClaude Opus 5.5 8663ce2a33 Savestate: Save state that was missing from several modules
sceMpeg's AVC resource flag, whether the VSH is running, sceReg's handle
counter, sceNet's pending apctl events and product code block, and the
save dialog's copy of the original request (without which the first
Update after a load reloaded the request and lost its results).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 11:32:07 -06:00
Henrik RydgårdandClaude Opus 5.5 0a687b9435 Savestate: Bounds-check sizes from the file, and plug leaks on load
Reject sizes past the end of the state before allocating (FPL, PGF,
achievements, SAS grain, savedata list, the memory fast path), fail
instead of desyncing on a SAS voice count mismatch, and free what old
states' paths and shrinking pointer containers dropped.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 09:34:06 -06:00
Henrik RydgårdandClaude Opus 5.5 84f64a9fdf Savedata: Don't free stale icon textures after a state load
The old icons stayed in PPGe's decimation list with kernel addresses from
before the load, and got freed out of whatever the loaded state had there.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 09:34:05 -06:00
Henrik RydgårdandClaude Opus 5.5 797957ea25 OSK: Fix a use-after-free when loading a savestate
DoState replaced native_ while holding a lock_guard on its mutex, so the
old NativeInput could be freed before the guard unlocked it. Crashed every
state load (e.g. Splinter Cell Essentials, anywhere in the game).

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-28 09:34:05 -06:00
Henrik RydgårdandClaude Opus 5.5 76eceac7fb Netconf: Don't hold back the fade-in while joining the access point
While apctl was in JOINING, every Update restarted the fade-in, so the dialog
sat at its first, barely visible step until the state moved on to getting an
IP. It now keeps the fade-in it started with.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:59:00 -06:00
Henrik RydgårdandClaude Opus 5.5 b9e7d9e0a0 Netconf: Report success, and don't get stuck without a way out
- The result was only ever written on cancel, so a connection that worked
  gave the game back whatever was in the field, which some fill with -1.
- Infrastructure mode drew a Cancel button that did nothing, so if the
  access point never gave an IP there was no way out. Cancelling now also
  disconnects the connect it started, so the game isn't left connected
  after being told the dialog was aborted.
- An unknown netAction went down neither path and never finished.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:41 -06:00
Henrik RydgårdandClaude Opus 5.5 1d07fdba86 Utility: Small fixes from reviewing the dialogs
- Loading a utility module without room for our (rough) memory block stored
  (u32)-1 as its address, which av_atrac3plus then memset. It now loads
  without the block, which HLE doesn't need.
- LoadNetModule's module id was unsigned, so a load error was passed on to
  sceKernelStartModule as an id.
- The dialog helper threads put the game's priorities straight into ORI
  immediates; ones that aren't a priority at all now fall back to 0x20.
- A fade never finished with an animSpeed of 0 or less.
- MsgDialog V3 button captions filling all 64 bytes ran on into the next
  field.
- GamedataInstall: a file shorter than it claimed was retried forever, Abort
  worked in any state and wrote through an unchecked pointer, and the game
  and data names were read as C strings from fixed-size fields.
- NpSignin: a cancel was overwritten with SUCCESS in the same frame, so the
  game saw a sign-in. The status is reset on start, so a reused struct no
  longer hangs.
- Unloading av_atrac3plus never reached __AtracNotifyUnloadModule, leaving
  the atrac state pointing at freed memory.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:41 -06:00
Henrik RydgårdandClaude Opus 5.5 52e47f8e39 OSK: Check the request and output like the firmware, fix native box races
- InitStart checks the address and size the way sceUtility_Driver does
  (0x40 and 0x44 are both fine, utility/dialog/sizes) and that the field
  struct is in memory.
- The input text was read up to a terminator with no limit and no memory
  check, and the output was written through an unchecked pointer every
  Update. Both are bounded and checked now.
- Converting a string to UTF-8 checked for room before each character, then
  wrote up to three bytes and a terminator, overflowing a 2048-byte stack
  buffer on long non-ASCII text (both conversions did).
- An output buffer of length 0 made FieldMaxLength wrap around, and the
  keyboard preview then indexed the text at -1.
- The native input box's callbacks captured the dialog and could write into
  it after it was deleted, and its status was read and written without the
  lock. They now share a small state object instead, a new one per start
  and per state load (unless a box is still open, which answers into the
  loaded state).
- Savestates keep the current keyboard and the Korean combining state. With
  older ones, it picks a keyboard the field allows, as Init does.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:41 -06:00
Henrik RydgårdandClaude Opus 5.5 41b5074a98 Utility: Release volatile memory on a forced shutdown, fix dialog savestates
- The Yugioh savedata workaround force-stopped the other dialog without
  releasing the volatile memory it held, so the savedata helper then waited
  for it forever.
- Screenshot's ShutdownStart and Update succeeded when no screenshot was
  running, putting it back into SHUTDOWN.
- Savestates: Netconf didn't keep its request address, and a DNS json
  download going on was gone after a load, so it could wait for it forever;
  it now fetches the json again (it's cached). NpSignin didn't keep its
  request address either. Both restart their timeouts instead of timing out
  at once. With states from before, they keep the current address as they
  used to.
- Loading a state from before NpSignin, GameSharing or HtmlViewer were saved
  resets them rather than keeping this session's state (including the
  HtmlViewer's memory block), and without Shutdown's side effects, which
  would write to the loaded memory and release its volatile lock.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:41 -06:00
Henrik RydgårdandClaude Opus 5.5 6dffcc91d2 Utility: Check request sizes like the firmware
InitStart sizes: Netconf and NpSignin accepted any size, then wrote
common.size bytes back from a 64-68 byte host struct, copying host memory
into PSP RAM. GamedataInstall looked for install files before checking the
size, and the HtmlViewer read options before checking the whole request was
in memory. All the dialogs now check the address, then the sizes
sceUtility_Driver accepts (utility/dialog/sizes), before anything else, as
the firmware does (a bad address is INVALID_ADDRESS), and write back no more
than the struct.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:41 -06:00
Henrik RydgårdandClaude Opus 5.5 9e69c1f9aa Savedata: Keep the IO thread out of the dialog's state
Replaces the temporary fix that did the hidden modes' IO inside Update.

The IO thread read and wrote the dialog's request, display state and save
list, all shared with the emulator thread, which kept using them to draw the
dialog and reload the request from the game.

Now the IO thread works on its own copy of the request, its own SavedataParam
and directory names resolved up front, and shares nothing else with the
emulator thread but the (locked) file system, MemoryStick_FreeSpace's cached
use and sceChnnlsv's scratch buffer and kirk state, the last two now under
locks too. It still reads and writes the game's buffers directly, like a PSP's
utility threads and sceIoReadAsync do, so a savestate waits for it before it
saves or loads memory. Save
bookkeeping, the save indicator and display changes happen on the emulator
thread when the results are taken, and only the request fields the IO changed
are copied back, so a game's own edits in the meantime survive.

Hidden modes take the results at the next Update (or, with Host IO timing,
the first Update that finds them done). The visible dialogs keep drawing and
take them once the IO is done; save and load used to stall the emulator
thread for the whole operation. Savestates keep results that haven't been
taken yet.

When the results land in PSP memory doesn't matter to games, so
utility/savedata/filelist now only prints them once the utility has finished.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:39 -06:00
Henrik RydgårdandClaude Opus 5.5 1f1c478c92 MsgDialog: An Abort takes effect from the 8th Update, like on a PSP
Until then the dialog runs normally (and writes result = 0, which an
immediate abort skipped). Measured with one Update per vblank; at one every
other vblank a PSP took 6, so it isn't purely a count.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:23 -06:00
Henrik RydgårdandClaude Opus 5.5 5f261bd7ff Utility: Stand in for the HtmlViewer, offering to open the page in a browser
Instead of the PSP's web browser, a dialog shows the URL the game wants
and opens it in the host's browser on X, or backs out on O. Either way the
game sees the browser closed normally. Platforms that can't open a URL
(the new SYSPROP_CAN_LAUNCH_URL) only offer to back out. Only plain
printable-ASCII http(s) addresses are handed over, and on Linux without a
shell.

What the firmware does (sceUtility_Driver, 6.61, plus
utility/dialog/htmlviewer): the HtmlViewer has its own state apart from the
other dialogs, so they don't block each other, and its calls return
WRONG_TYPE until one has started. The request size picks the 2.00 to 3.00
layout, and InitStart allocates 3.5MB of user memory (4.5MB with options
bit 0x400 from 2.70 on), failing with 800200d9 without it.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:23 -06:00
Henrik RydgårdandClaude Opus 5.5 3c15b2b112 Utility: One dialog at a time whatever its type, like the firmware
On a PSP, every InitStart fails with INVALID_STATUS until the last dialog
started is back at NONE, including while it's shutting down, and before
its params are checked. A failed InitStart leaves the current type alone.
We returned WRONG_TYPE instead, and a failed InitStart (e.g. a bad size)
still switched the current type, so every later dialog was refused. (One of
ours that fails after already starting, as savedata can, still becomes the
current type, since the game may poll it.)

The busy check applies status changes that are due, but doesn't use up an
auto status dialog's one-time INITIALIZE/SHUTDOWN reports; one that only
waits to report SHUTDOWN is let finish. Auto status dialogs now release
volatile memory on the way to NONE, including when the game saw RUNNING
before the init thread was done, which used to leave it locked for the next
dialog. GamedataInstall no longer requires currentDialogActive, which its
ShutdownStart cleared even when it then failed, so it could never finish -
and would now have blocked every other dialog.

Also: MsgDialog accepts exactly the three sizes sceUtility_Driver does (we
memcpy'd whatever size was given), and HtmlViewer GetStatus answers
WRONG_TYPE.

Adds utility/dialog/status and utility/dialog/priority, recorded on a PSP.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-25 12:50:23 -06:00
Henrik RydgårdandClaude Opus 5.5 157b233865 Savedata: TEMP TEST FIX: Do the hidden modes' IO inside Update, not on a host thread
The IO thread wrote results (file lists, sizes, loaded data) straight into
PSP memory while the game kept running, so they landed at an arbitrary
point in its code. utility/savedata/filelist caught it now and then: a
poll saw the entries written but the counts still zero. On a PSP it's all
there when Update returns. Host IO timing still uses the thread.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 19:41:41 -06:00
Henrik RydgårdandClaude Opus 5.5 30fada5833 Utility: Run GameSharing through a placeholder dialog, quiet its WRONG_TYPE logs
GameSharing InitStart used to return 0 without starting anything, so its
GetStatus stayed at NONE and a game waiting for the dialog to finish
would hang. It now goes through the normal lifecycle (INIT, RUNNING,
FINISHED, SHUTDOWN, NONE) and reports that the user cancelled.

PSPPlaceholderDialog was abstract and unused (and missing from CMake);
it's now that stand-in.

WRONG_TYPE from GameSharing GetStatus/Update/ShutdownStart is what a PSP
returns whenever another dialog type was the last one started, so log it
at debug like the other dialogs. Sega Rally polls it every frame.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 5a23bb2d94 Savedata: Pick the crypt mode the way the firmware does
secureVersion and the key only matter for the full 1536-byte request; the
older sizes always save without a key. Otherwise SDK 2.07+ uses the new
keyed hash for versions 0 and 3, older SDKs the old keyed hash for 0 and
no key for 3, and version 2 is always the old keyed hash.

Versions 0, 2 and 3 all require a key, and are rejected with SAVE_PARAM
otherwise - including 0, which we used to save without a key. Matches the
SFO modes and save errors recorded in utility/savedata/secureversion; what
remains there is load strictness when secureVersion doesn't match the
file, which we keep lenient for older saves.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 ec00700730 Dialog: Fade in 200ms like the firmware, and accept input while fading in
On a PSP, dialog animations advance by animSpeed frames per Update and the
fades take about 200ms. Ours took 500ms (1/30 s per animSpeed, over
FADE_TIME 1.0), and all input was ignored until it finished, which made
dialogs feel sluggish, noticeably so in 30fps games. Input is still
ignored while fading out, once a choice has been made.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 74c5cbf503 Savedata: Leave GetSize's needed strings alone when nothing is needed
Matches hardware; moves utility/savedata/getsize to tests_good.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 19:25:24 -06:00
Henrik RydgårdandClaude Opus 5.5 20970d5fad Dialog: Follow the firmware's thread priorities in init/shutdown
On a PSP, dialog init and shutdown happen partly at the accessThread
priority and partly at the graphicsThread priority, one phase after the
other. Model that with one helper thread that switches priority per phase,
and let starting it reschedule normally instead of disabling interrupts.

A caller with worse priority than both now sees shutdown complete inside
ShutdownStart, as on hardware. NFL Street 3 (graphics 17, access 19,
caller 111) calls the next InitStart right after ShutdownStart and used to
loop forever on 'A save request is already running' (#19957). The utility
pspautotests, where the caller has better priority, are unchanged.

Also logs the dialog thread priorities at debug level.

Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
2026-09-23 19:25:24 -06:00
Henrik Rydgård 0a5fa27957 Disable alpha for save/load icons in sceUtility UI 2026-09-21 10:41:35 -06:00
Artem Lytkin 4c749a31cf Savedata: use PARAM.SFO's time as the save date in the dialog
GetSaveInfo() took the date from whichever file the directory listing
returned first, so a save whose ICON0.PNG is older than the rest showed
the icon's date in the save/load dialog. The savedata manager already
uses PARAM.SFO's time. Use that here too, keeping the first file as the
fallback when there's no PARAM.SFO.
2026-09-19 17:17:55 +03:00
keycross 0c95caccea Avoid validating unused savedata name lists 2026-08-28 21:38:58 +09:00
Nemoumbra 2bdf72511e Fixed the template deducing to pspUtilityDialogCommon instead of SceUtilityNetconfParam 2026-08-18 22:44:09 +03: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 c5e4d0d90d Rename the get-memory-pointer functions to make it clear where CPU exceptions can happen. 2026-08-12 14:06:16 +02:00
Henrik Rydgård e9a3449ede More MIPSState * plumbing (manual) 2026-08-12 14:02:19 +02:00
Henrik Rydgård 5198317e24 Back out some excessive checking in the latest changes. Change TOOD: to TODO: . 2026-08-11 22:27:44 +02:00
Henrik Rydgård 3c81d6b121 More manual Read_U32 cleanup
Buildfix
2026-08-11 10:28:36 +02:00
Henrik Rydgård 66c8bfbcb2 Improve semantics 2026-08-10 10:11:24 +02:00
Henrik Rydgård 8cd7e1b2c0 Delete all support for Qt
Our Qt backend has long been left behind and doesn't even support Vulkan
currently. There would be a lot of work to make it viable, and I don't
think anyone is really interested.

ImGui on SDL will soon fulfill the need for a more classic user interface
with a menu bar on Linux, and on Mac we already have a native UI.
2026-08-08 18:18:28 +02:00
Henrik Rydgård 68ec34ad54 Build and warning fixes 2026-08-03 19:11:07 +02:00
Henrik Rydgård 0eef5d0164 Use shared HasPathTraversal utility for savedata name validation
Replace the inline lambdas in the savedata dialog with the new
HasPathTraversal() helper in Core/Util/PathUtil.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 779cae6232 Reject path traversal in savedata name fields
gameName/saveName/fileName and the saveNameList entries are
guest-controlled and get concatenated into host filesystem paths, so a
crafted request could escape the save directory with ../ sequences.

- PSPSaveDialog::Init rejects requests whose name fields contain a path
  separator ('/' or '\') or are bare dot components.
- SavedataParam::SetPspParam rejects saveNameList entries the same way.
2026-08-01 13:16:21 +02:00
Henrik Rydgård 5194382b7b Fix out-of-bounds reads in PARAM.SFO parser
ReadSFO dereferenced index table entries without checking the table fit
within the buffer, and GetDataOffset had no bounds checks at all (reading
attacker-controlled offsets and strcmp'ing without a terminator guard).

- Validate the index table fits entirely within the buffer in ReadSFO.
- Add a size parameter to GetDataOffset and validate the index table,
  key/data table positions, and key string termination before use.
2026-07-31 20:54:17 +02:00
Ren 459aefb48b Savedata dialog: serialize ioThreadStatus (bump section to v3)
The s > 2 branch in PSPSaveDialog::DoState has been dead code since it
was written - the section version was never raised past 2, so
ioThreadStatus was reset to SAVEIO_NONE on every savestate load.
Loading a state that was saved while a savedata operation was in
flight then repeated the operation (or left the dialog waiting on a
completion that had already happened), instead of resuming from the
recorded status.

Restoring the value is safe: DoState joins the IO thread before
serializing, so the stored status is only ever SAVEIO_NONE or
SAVEIO_DONE, and the operation's effects are already part of the
serialized emulated RAM. Old (v2) states still load through the reset
path.
2026-07-27 16:19:26 +02:00
Henrik Rydgård beeafb92b9 Add more symbols to the Latin OSK keyboard
A few dupes, but meh.
2026-06-25 15:14:08 +02:00
Henrik Rydgård 95ce95e489 Add a new "Net" log category, do assorted cleanup 2026-06-13 14:43:59 +02:00
Henrik Rydgård cc0ece038c Clean up the string type in RequestCallback - somehow was both char* and std::string????
Might be related to #21695
2026-05-18 14:16:34 +02:00
Henrik Rydgård e23d866a95 Plumb through an error code for missing activity. Will later be used to improve the UI. 2026-05-11 10:52:36 +02:00
Henrik Rydgård 8304d8622a Hide the save/load indicator by default, add a (developer) setting. Also sneak in an adhoc server list bug fix.
Fixes #21523
2026-04-06 10:04:09 -06:00
Henrik Rydgård 133c36f145 Minor logging cleanup in savedata 2026-03-02 00:24:19 +01:00
Henrik Rydgård 3dc7aa4a65 Add workaround for the Silent Hill: Shattered Memories. Thanks fcrwr!
Fixes #13781
2026-02-23 15:19:03 +01:00
Henrik Rydgård dac2407a36 sceIo: Add support for microseconds in filetimes (not implemented in platforms yet) 2026-02-23 11:04:17 +01:00
Henrik Rydgård 40a5cd1509 Minor logging improvement, refresh gamescreen on deleted savedata 2026-02-19 16:05:00 +01:00
Henrik Rydgård 5a5c7028b9 Assorted warning fixes and data initialization to please valgrind 2026-02-19 11:24:46 +01:00
Henrik Rydgård 0dd77f896a A few more string length safety fixes in SavedataParam.cpp 2026-02-18 11:24:55 +01:00
Henrik Rydgård f97a3d09bd Savedata: Fix rare crash bug found in Google Play reports 2026-02-18 11:24:36 +01:00
Henrik Rydgård dad8df3860 More logspam reduction 2026-02-10 15:05:29 +01:00