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>
The flash0 PRXes we swap in for our HLE took the lowest free block, which sits
right where a game's own EBOOT wants to go. That pushes the game up, shifting
every address in it - invalidating cheats and RetroAchievements - and for a game
whose EBOOT has to load at a fixed low address it fails outright: Tekken 6 wants
0x08804018 and got "block taken", so it didn't boot at all.
Give KernelLoadModule a fromTop flag and use it for the modules we inject. The
game keeps its normal load address and the firmware sits out of the way at the
top.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GgACRqkQNpfJQ4fjwyoEup
Adds SceKernelLoadExecVSHParam and fills in the rest of LoadExecForKernel's
NIDs: real implementations for sceKernelExitVSHVSH/Kernel
(mirrors sceKernelExitGame) and sceKernelLoadExecBufferVSHUsbWlan (loads
an exec from an in-RAM buffer instead of a file, plus UNIMPL stubs.
sceKernelLoadExecBufferVSHUsbWlan needed __KernelLoadExec split into a
file-reading front end and a shared __KernelLoadExecFromPtr back end
that both it and the new buffer-based path call into.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSNaZnHCjmryS3ziVN9gZU
(cherry picked from commit 4adbedec9e2e3221113c9e5ad00b248bba1153e1)
Load and start VSH's kernel modules before booting vshmain.prx
A few flash0 modules (vshbridge.prx, paf.prx, common_gui.prx,
common_util.prx) should run for real once we know we're
actually booting the VSH rather than a game, since our fakes are unlikely
to be good substitutes for the genuine thing.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSNaZnHCjmryS3ziVN9gZU
Adds SceKernelLoadExecVSHParam (matching JPCSP's reference layout - its
first four fields line up with the existing SceKernelLoadExecParam,
which is why the plain sceKernelLoadExec already worked for
sceKernelLoadExecVSHMs2) and fills in the rest of LoadExecForKernel's
NIDs from JPCSP: real implementations for sceKernelExitVSHVSH/Kernel
(mirrors sceKernelExitGame) and sceKernelLoadExecBufferVSHUsbWlan (loads
an exec from an in-RAM buffer instead of a file - the VSH's "push a game
over USB/WLAN" path), plus UNIMPL stubs for everything JPCSP itself only
knows by NID.
sceKernelLoadExecBufferVSHUsbWlan needed __KernelLoadExec split into a
file-reading front end and a shared __KernelLoadExecFromPtr back end
that both it and the new buffer-based path call into - a pure
extract-method refactor of the single most heavily used boot path in the
emulator. Verified no regression: same 11 passed / 9 pre-existing-failed
split on pspautotests/tests/cpu/*, and loader/bss still passes, before
and after this change.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01PSNaZnHCjmryS3ziVN9gZU
Added KernelModuleAddressDescription() (Core/HLE/sceKernelModule.cpp),
which looks up which currently loaded module (and text/data/bss/segment
section within it) an address falls in, e.g. "EBOOT.BIN.text+1234".
Wired it into:
- Core_MemoryException/Core_ExecException/Core_BreakException
(Core/Core.cpp), appended next to every address/pc/ra shown in their
log lines.
- FormatStackTrace (Core/MemFault.cpp), appended per-frame next to the
existing symbol description.
This makes crash/exception logs actionable even when there's no symbol
at the faulting address - you at least get which module and section
it's in, useful for reverse engineering unfamiliar code.
Verified live via headless: injected a MIPS break instruction at the
current PC (through Tools/wsdbg) and confirmed the log line changed from
"break instruction hit at 088040ac" to "break instruction hit at 088040ac
[sceDisplayWaitVblank Test.text+ac]".
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01XDNwPPuidmNxQGRJxBuRL6
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>
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.
* Add draft sceKernelFindModuleByUID
#13205
* Add KERNEL_SYSCALL flag
* oop
* oop2
* Not sure why make this change before
* Last night I might be too tried
This tries to execute them within the context of the emulator as much as
possible, so we don't have weird bugs. Going with a file type so we can
easily load the dump by opening the file directly.
Couldn't think of a better way to do this, maybe there's some fancy
one I don't know about.
Also finished up a couple left over kernel objects.
Maybe a quarter the way there?