The MP4 libraries turn out to be the easiest place to hand a game Sony's own
code: libmp4.prx needs only sceAudiocodecInit and sceAudiocodecDecode from us
plus ordinary kernel calls, and mp4msv.prx - where the 41 functions libmp4
leans on live - imports nothing at all. So with a firmware dump present the
pair can be loaded for real and left to decode through our sceAudiocodec.
Adds DisableHLEFlags::sceMp4, which loads and starts both modules when the
game asks sceUtility for the MP4 module, and a --disable-hle bitmask so a
headless run can ask for this without a config file.
Two things had to be fixed to make it work at all:
- ModuleMgrForUser 0xD2FBC957 was unimplemented, and libmp4 calls it to get
the gp of each callback it is handed. Implemented as
sceKernelGetModuleGPByAddress.
- Headless forced every module to HLE unconditionally, which silently undid
the flag, and it did so before ApplyToConfig() had even parsed it.
Tested with Speedball 2 - Evolution, which uses sceMp4 for its music: the game
goes from 255645 calls into our stubs and 39 unresolved imports, to zero of
each and 1943 AAC frames decoded through sceAudiocodec.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Two things utility/systemparam caught:
A negative size passed to sceUtilityGetSystemParamString went through
Memory::IsValidRange, where it became an enormous range and came back
as a generic -1. The PSP just reports that the string doesn't fit, same
as any other size too small to hold it.
sceUtilityGetSystemParamInt returned 0x800ADF4 for an automatic adhoc
channel unconditionally. The FIXME there wondered whether the hardware
only does that once adhocctl is initialized - it does. Before any adhoc
module is up, which is the state nearly every game asks this in, the
hardware returns 0 and writes the channel out.
Fixes utility/systemparam/systemparam, moved to tests_good.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JvJR8oJNSCimCM9KXVLjfq
On savestate load, two sites delete a pre-load host object that owns an
HLEHelperThread without calling Forget() first, so ~HLEHelperThread runs
__KernelDeleteThread and kernelMemory.Free() with thread ids and block
addresses from before the load, against the freshly restored kernel
state:
- sceUtility: Do(p, accessThread) deletes the stale accessThread inside
DoClass before recreating it from the stream.
- scePsmf: Do(p, psmfPlayerMap) deletes every existing PsmfPlayer, and
~PsmfPlayer -> AbortFinish() deletes its finishThread raw.
When the stale id or block happens to be absent from the restored state
this only logs errors ("... does not exist" / "BlockAllocator: invalid
free"). When it has been recycled, a live thread is terminated or a
live allocation is freed, silently corrupting the loaded state. Easiest
to hit by loading a state while a savedata operation or PSMF player is
active, into a session where those ids were reused.
__IoDoState and __PsmfShutdown already Forget() before deleting; do the
same at these two sites. Worst case behavior change is a leaked
kernel-side thread record where one was previously (incorrectly)
freed.
Driver 76 uses sceKernelGetModuleIdList to get a module list
after calling sceUtilityLoadNetModule, then go module by module
with sceKernelQueryModuleInfo to check if at least pspnet_adhoc.prx
was loaded.
Load modules during sceUtilityLoadNetModule, expand success lying
modules to have real names, add adhoc modules to the success lying
list, list lied modules during sceKernelGetModuleIdList.
* Rename LogType to Log
* Explicitly use the Log:: enum when logging. Allows for autocomplete when editing.
* Mac/ARM64 buildfix
* Do the same with the hle result log macros
* Rename the log names to mixed case while at it.
* iOS buildfix
* Qt buildfix attempt, ARM32 buildfix
The bug is in the game, it uses the wrong vblank wait, but it only works
because the dialog processing takes so much time that it misses the
vblank period anyway.
Fixes#12044, and hopefully won't break anything else.
Probably not worth it for performance reasons, but some semantic cleanup
is good, especially the accidental GetPointer -> writable casts without
using GetPointerWrite.
Using Unchecked on already checked pointers, or when we'd crash anyway
if it returned nullptr, is good for clarity.
Seems the game might not handle the case of confirm button being set to
cross properly, so force it to circle if this game is running.
Fixes#15663 (hopefully..)