Same three functions, one more NID each. Those two shells started no plugins at
all and sat on a black screen; both reach an interactive XMB now.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sceKernelLoadModuleVSH, sceKernelGetModel and sceImposeSetStatus each appear
under a different NID in 3.95/4.05, 6.00/6.20 and 6.31/6.39. Without the load
one those shells started no plugins at all and sat on a black screen.
Identified the same way as the 5.xx set: for each firmware, the modulemgr export
with sceKernelLoadModuleVSH's callee set, and the vshbridge export whose body is
the user-level check 6.61 wraps sceKernelGetModel in - which is also the only
SysMemForKernel import those shells actually call.
3.95 and 4.05 now reach an interactive XMB.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
sceKernelLoadModuleVSH, sceKernelGetModel, and four of sceImpose_driver's calls
already have implementations; 5.xx just asks for them under different NIDs, so
the 5.50 shell got nothing back. Each one was identified by disassembling that
firmware's own module and comparing the body against 6.61's, where the same
function is exported under a name - the pairs are instruction-for-instruction
identical apart from context-struct offsets.
GetModel was the one that mattered most: unresolved, vshbridge handed the shell
a garbage model number, and it went looking for PSP-3000 resources on a dump
that has none.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
The new sysmem tests run the same partition sweep from both privilege levels, which settles
several things that were guesses:
The valid range is 1-6, not 1-9-except-7. sceKernelCreateVpl, CreateFpl, CreateMsgPipe and
AllocPartitionMemory all let 8 and 9 through to the permission check, so a caller asking for
partition 8 got ILLEGAL_PERM where hardware says ILLEGAL_ARGUMENT. Privilege changes the
permission check, not the range - 1, 3 and 4 are refused from user mode and work from kernel mode
in every one of these APIs, which is the evidence the earlier BlockAllocatorFromID change was
missing.
sceKernelAllocPartitionMemory reports an out-of-range partition differently depending on which
entry point was used - ILLEGAL_ARGUMENT through SysMemUserForUser, ILLEGAL_PARTITION through
SysMemForKernel. Both NIDs land on the same function here, and hleIsKernelMode() is precisely
"came in through the kernel NID", so it picks the right one.
sceKernelCreateHeap had four "TODO: Validate error code" comments and no test at all - it's
kernel-only, which is why. All four are now recorded: out-of-range partitions are
ILLEGAL_PARTITION, a size of zero or less is HEAPBLOCK_ALLOC_FAILED before anything is allocated,
a NULL name is refused with ERROR, and flags really are ignored. sceKernelAllocHeapMemoryWithOption
had its validation backwards: the option struct's size field isn't checked at all, while the
alignment must be a power of two from 4 to 0x80.
Not fixed, and split into sysmem/kernel/heapgrow in tests_next: a real heap will hand out a block
larger than the heap itself, so the size isn't a cap. Ours is a fixed allocator over the reserved
block. Worth establishing how far the real one grows before implementing that.
Risk: the range change makes partitions 8 and 9 fail earlier and with a different code than
before. Nothing in tests_good depended on the old behaviour except two expectations that had
drifted from hardware, corrected in the submodule.
sceKernelAllocHeapMemory and sceKernelAllocHeapMemoryWithOption return a
pointer, so failure has to be 0 - JPCSP documents it as "the address of the
allocated memory block, or NULL on error". We passed BlockAllocator::Alloc's
result straight out, which is (u32)-1 when the allocation fails, and returned
UID error codes for a bad heap id. Anything checking for a null pointer took
those for success.
Mostly small stubs:
- sceImpose: GetParam/SetParam/Changes/SetStatus, plus the 6.60 alias of
sceImposeGetBatteryIconStatus. Also fixes that function's first output - it
is a plain "is it charging" boolean, not a BATTICON_ value. We wrote
PSP_IMPOSE_BATTICON_NONE (0x80000000) there, which games ignore but which the
VSH reads as "no battery" and draws the empty-battery indicator for. These
are the bulk of the traffic: the VSH calls sceImposeChanges once a frame, so
this alone removes ~10000 trapped calls from a boot.
- SysMemForKernel: sceKernelSetRebootKernel, sceKernelSetUmdCacheOn.
- scePower_driver: scePowerSetWakeupCondition.
- sceHprm_driver, sceUsb: one NID-named call each, as in JPCSP.
Three groups are deliberately left unresolved, with comments explaining why,
because resolving them lets real flash0 drivers walk into hardware we do not
emulate and the boot dies where it used to reach the shell:
- ThreadManForKernel mutex/fpl NIDs: the NAND and ID storage drivers use these
to init, then poll the NAND controller at 0xbd101300 forever.
- InterruptManagerForKernel intr registration: 31 calls, then a stall in GE
list execution with no plugin module ever started.
73 unresolved import hits over 37 distinct module/NID pairs remain in a VSH
boot, mostly sceSysEventForKernel, sceSuspendForKernel and the various
*_driver modules that need real hardware behind them.
The sceImpose savestate section goes to v2 for the two new state variables.
Co-Authored-By: Claude Opus 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