Four places were each computing the same sizes and 64-byte-aligned offsets:
the allocation, the recovery sceMpegbase uses, and the readers on both sides.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Doing this was written once, for sceMp4, remembering the two UIDs it had
loaded in a static. That static was the only thing stopping a second copy
being loaded on top of the first, and it didn't survive a savestate: resuming
in a fresh process left it at zero while the restored module list already had
the modules in it. Ask the module list instead, which needs no state of its
own and is right after a savestate load and across games.
With the mechanism shared, sceMp3 and sceAtrac get it too. libmp3.prx and
libatrac3plus.prx each import nothing but the kernel and sceAudiocodec, so
both run against what we already have. The sceAtrac checkbox previously led
to an error log and a debug assert saying it wouldn't work, with a note that
we could go and find the file - which is what this does.
This is only ever the path for a game that ships no copy of the library. One
that does loads it directly and never asks sceUtility for it.
Also:
- a module we're really loading no longer reserves its stand-in block as
well. That block only stands in for memory we aren't otherwise taking, so
reserving both charges the game twice, at the top of user memory where
thread stacks come from.
- the module loads at the bottom of the user partition. fromTop is for a
module injected before the game's executable is placed; by the time a game
calls sceUtility nothing moves either way, and the firmware's utility.prx
allocates AV module memory as PSP_SMEM_Low.
- NotifyLoadStatusAtrac read the raw setting rather than the effective
flags, so it could fire for a flag that wasn't in effect.
- the missing-firmware case now says so on screen, naming the library and
pointing at installing a firmware, rather than only logging.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
A survey of disc images found these shipped on a lot of them: LIBDEFLT and
LIBMT19937, LIBADLER, LIBMD5 on about 1/6, LIBSHA256 on 1/7, LIBHEAP on
1/12, LIBSFMT19937 on 1/24. None appears in any firmware dump and none is loadable
through sceUtility, so a game that imports one has to carry it - which makes
running the game's own module the safe default, the same argument psmfplayer
graduated on. Read off real discs with --re-module disc0:/..., all but sceHeap
import nothing at all, and sceHeap only Kernel_Library and ThreadManForUser.
sceFont joins them with a condition. Its module is on the disc like the others -
the most-shipped of all, on a third of the discs - but it reads its fonts from
flash0:/font and has nothing to fall back on, so it is only usable with a
firmware dump installed (our own fallback fonts are just not good enough anyway, it
chokes on them). CheckDisableHLEAvailability puts the HLE back when
those fonts are missing, since ours does have a fallback.
sceParseUri and sceParseHttp look like candidates and aren't: they are in the
firmware and sceUtility can load them, so a game may import them without
shipping one. Their headers say so.
The HLE implementations stay - old savestates index these tables by syscall
opcode - and are marked legacy the way scePsmf is.
Also: Move HLEInit after the filesystems are mounted
It ran before MountFileSystems, so the checks in it deciding whether a library
can run its real module instead of our HLE couldn't ask the PSP filesystem and
had to reach for host paths under the NAND directory. Nothing between
CoreTiming::Init and here touches HLE, and the kernel and the game's modules are
both loaded later, so it can simply move.
Two things fall out. The checks now spell their paths flash0:/... like the rest
of the emulator. And they run after AutoInstallFirmwareFromDisc, so a disc that
carries a firmware counts on the launch that installs it rather than the next
one - verified with an empty NAND and a disc carrying 3.11: the fonts land and
sceFont runs the game's own module the same boot.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Loads a single module standalone - no game, no boot - and writes a report:
module header and segments, the export and import tables with NIDs resolved to
names through the HLE tables, one annotated disassembly file per function, and
a call graph as JSON.
Reuses the emulator's own loader rather than parsing PRXes a second time, so
decryption, decompression, relocation and import resolution can't drift from
what actually runs. Only enough of the system is brought up to load a module:
memory map, timing, HLE tables and the kernel allocators. Nothing executes.
Two things beyond a plain disassembly, both aimed at the questions that come up
when reading unfamiliar MIPS:
- lui/addiu (and lui/load) pairs are folded and reported as the address they
form, which is how every global and constant table gets reached.
- Per function, a register evidence block instead of a guessed signature. A
MIPS function that takes two arguments and passes the second one down often
never reads it, so 'never read but live across a call' is reported as
forwarded rather than quietly dropped from the signature.
SetForceRealModuleLoads() is needed because modules like sceAudiocodec_Driver
have no DisableHLEFlags bit and so can't be turned off the normal way - they'd
fake-load and there would be nothing to look at.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Which modules we HLE is decided when each module is loaded, and the syscall
stubs written into memory then are what a savestate captures. But the setting
was read live, so loading a state re-resolved its imports against whatever the
config said now - and if that disagreed with how the state was made, every call
into the module landed on an unresolved stub returning LIBRARY_NOT_YET_LINKED.
Thrillville just retried sceMpegInit forever.
Latch the flags on first use after boot, save them in the state, and restore
them on load. Changing the setting now takes effect on the next boot, which is
the only point it could have taken effect anyway.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
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>
A call through a still-pending import gets written as a generic "invalid
syscall" opcode (WriteFuncMissingStub) that no longer carries the
original module name or NID by the time it's actually invoked - but the
address of the syscall instruction itself is exactly the stubAddr every
pending FuncSymbolImport already records. Added
KernelFindImportByStubAddr() to search loaded modules' importedFuncs for
a match, and use it in GetSyscallFuncPointer's unknown-syscall path.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Testing has shown that this seems to work great and fixes issues. These
two modules are just a parser and a shim over sceMpeg, and we're better
off running the original code, instead of re-implementing it.
sceMpeg still needs accuracy improvements though, and it's built on some
pretty low level components so it will be harder to peel off the next
level of the HLE onion.
Se #20200.
Some games survive with a loaded sceAtrac, and start talking to
sceAudioCodec instead, the underlying library, though unsuccessfully
since it's not properly implemented yet.
Fixes#19935. Forgot to update the formatting for the reporting case.
I'll clean this up in a more general way later, I don't like how this code currently looks.