Skip to content

fix(libkernel): check the module load and unload arguments as firmware 13.42 does - #15556

Open
BunnyFl wants to merge 2 commits into
boykopovar:mainfrom
BunnyFl:fix/libkernel-module-call-arguments
Open

BunnyFl wants to merge 2 commits into
boykopovar:mainfrom
BunnyFl:fix/libkernel-module-call-arguments

Conversation

@BunnyFl

@BunnyFl BunnyFl commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

What

sceKernelLoadStartModule and sceKernelStopUnloadModule ignored their flags and opt arguments, and sceKernelStopUnloadModule treated handle 0 like any unknown handle. Firmware 13.42 refuses these with 0x80020016 (EINVAL) before it does anything else, and this change does the same:

  • sceKernelLoadStartModule: nonzero flags or a non-null opt returns 0x80020016, and res is left alone.
  • sceKernelStopUnloadModule: nonzero flags, a non-null opt or handle 0 returns 0x80020016, and res is left alone.
  • sceKernelLoadStartModuleForSysmodule forwards flags as 0. The firmware export adds 0x10000 to flags and jumps past the public entry's flags check, so a sysmodule load with flags still loads. A non-null opt is refused on both paths.

Firmware 13.42 system/common/lib/libkernel_sys.sprx (sha256 3d361753f6c472cd5442bf92652b4a1dee04051297a0155fe197ede0c2002d4a), read from disassembly, not run on a console:

sceKernelLoadStartModule (wzvqT4UqKX8), 0x35c70
35c70: test %ecx,%ecx            ; flags
35c72: je   0x35c7a
35c74: mov  $0x80020016,%eax
35c7a: xor  %ecx,%ecx
35c7c: jmp  0x35c90              ; shared body

sceKernelLoadStartModuleForSysmodule (Gg3+yWL6DWU), 0x363e0
363e0: or   $0x10000,%ecx
363e6: jmp  0x35c90

shared body, 0x35c90
35ca4: mov  $0x80020016,%eax
35ca9: test %r8,%r8              ; opt
35cac: jne  0x35e0a              ; return

sceKernelStopUnloadModule (QKd0qM58Qes), 0x36400
36411: test %ecx,%ecx            ; flags
36415: mov  $0x80020016,%eax
3641d: test %r8,%r8              ; opt
36427: jne  0x367ea              ; return
3642d: test %ebx,%ebx            ; handle
3642f: je   0x364db              ; 0x80020016 at 0x36502

The debt file gains the gap this doesn't close. sceKernelStopUnloadModule never runs the module's module_stop and stores 0 in res. At 0x36657 firmware calls module_stop with args and argp and stores its result in res (0x36663). It skips that call while a count at +0x6c is above 1 (0x364b1–0x36557), which reads like a load count. It returns 0x80020010 on a path (0x3648d–0x36583) that appears to cover another thread still starting the module. The loader reads only a start entry and initializers from the guest lifecycle metadata (core/libs/prx/libkernel/Module/src/DynamicLoader.cpp:221 and :267), with no stop entry, so a follow-up needs the relinker to record one.

Tested

Checklist

  • Based on current main; no other open PR implements the same functions
  • One topic per PR; follow-ups go in a new PR
  • No comments in code except technical debt
  • Unimplemented paths throw (NotImplemented_nid_no_patch); silent stubs are listed under Silent stubs in their library's technical debt file
  • No notes, investigation .md files or images added to the repository (attach them to this PR)
  • New third-party code is a submodule built from source
  • Generic behaviour, not specific to one title
  • Depends on: none
  • Fixes: none
  • Unblocks: none
  • GPUs tested: n/a
  • AI-assisted: yes

🤖 Generated with Claude Code

…e 13.42 does

Firmware 13.42's libkernel_sys.sprx returns 0x80020016 from
sceKernelLoadStartModule for nonzero flags or a non-null opt, and from
sceKernelStopUnloadModule for nonzero flags, a non-null opt or handle 0.
Both ignored these arguments. sceKernelLoadStartModuleForSysmodule
accepts flags there, so it no longer forwards them.

Record that sceKernelStopUnloadModule never runs module_stop.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
…entry

The module info entry went over the 1000-character debt limit.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added the needs rebase Conflicts with main, rebase needed label Nov 6, 2026

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

docs libkernel needs rebase Conflicts with main, rebase needed prx

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant