Backwards from 5.01, one release at a time, against all 39 versions that ship
on a disc plus the download-only 6.61. Nothing here is an offset - it's almost
entirely Sony renumbering the kernel *_driver NIDs, which sends an import we
mean to HLE into the real firmware module instead.
Four more NIDs each for sceRtc_driver/sceRtcSetAlarmTick and
sceHprm_driver/sceHprmReadLatch, covering 1.50 up. The rtc one is what parked
every thread on a SceSysconSync semaphore; the hprm one runs once a frame, so
unresolved it was most of the boot log. Also sceImposeGetParam/sceImposeChanges
(1.50 - 2.xx) and sceKernelLoadModuleVSH (1.x, which is how the shell loads its
own plugins - unresolved it got module id 0 and StartModule failed).
sceRtcIsAlarmed had to be implemented too; it returns 0, as in JPCSP. As a null
entry it returned LIBRARY_NOT_YET_LINKED, and the 3.0x-3.5x VSH read that as
"ask the hardware instead" and went back to blocking on syscon.
Two structural findings:
- Up to 4.05, scePaf's heap allocator is a separate heaparea1.prx that paf
imports as scePafHeaparea. Load it when it's there. Its pool pointer needs
the same pre-fill paf's does, at gp - 0x7FCC rather than gp - 0x7E88.
- 1.50's vshmain.prx declares no module attributes at all - PSP_MODULE_VSH_MODE
only appears from 1.52 - so the whole VSH bootstrap was being skipped. Accept
the module name too.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
The blocker below 6.60 wasn't offsets, it was that Sony renumbered the kernel
*_driver NIDs between versions. A function we HLE under its 6.6x NID is a
stranger on an older build, so the import lands in the real firmware module
instead - and that's where it goes wrong:
- sceRtc_driver sceRtcSetAlarmTick. Without the HLE the VSH's alarm call ran
the real rtc.prx, which called on into syscon.prx and blocked forever on a
SceSysconSync semaphore. That was the whole "stalls with every thread parked"
symptom; the tell was a fourth SceSysconSync waiter a healthy boot lacks.
- sceHprm_driver sceHprmReadLatch, called once a frame - so before this an
older firmware's 12-second boot logged ~20000 lines of one unresolved import.
Three extra NIDs each, found by disassembling the module from both firmwares
and matching on the address of the user-mode export whose NID never changed
(sceRtc/0x7D1FBED3, sceHprm/0x40D2F9F0).
5.55 additionally needed two PRX decryption keys we didn't have (0x4C941AF0
and 0x4C941BF0) - without them none of flash0:/kd decrypted and the shell came
up with no drivers behind it at all.
Checked one release at a time against every version that ships on a disc, plus
6.61. 4.05 and below still die on a null write inside vsh_module.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This is stuff encountered in the VSH boot research.
sceRtc_driver, scePower_driver, sceImpose_driver, ThreadManForKernel funcs,
sceRtcGetAlarmTick, sceHprm_driver/sceHprmReadLatch
sceVshBridge_Driver imports sceKernelResumeDispatchThread, SuspendDispatchThread,
and NotifyCallback from ThreadManForKernel, but they were only registered under
ThreadManForUser. Added sceKernelGetUserLevel and sceKernelIsUserModeThread (new).
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GZq8ZtJmFY7bkX5FVkr3P9
* 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
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.
This may be safer in case a game thinks funny business is going on if the
user changed the clock very recently, which wouldn't be the case on a
real PSP.