Files
ppsspp/Core/HLE/sceHprm.cpp
T
Henrik RydgårdandClaude Opus 5 63eb3d5b21 Boot the VSH on every firmware, 1.50 through 6.61
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>
2026-09-09 14:43:39 -06:00

114 lines
5.0 KiB
C++

// Copyright (c) 2012- PPSSPP Project.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 2.0 or later versions.
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License 2.0 for more details.
// A copy of the GPL 2.0 should have been included with the program.
// If not, see http://www.gnu.org/licenses/
// Official git repository and contact information can be found at
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Core/HLE/HLE.h"
#include "Core/HLE/FunctionWrappers.h"
#include "Core/HLE/sceHprm.h"
#include "Core/MemMap.h"
#include "Core/MIPS/MIPS.h"
static u32 sceHprmPeekCurrentKey(u32 keyAddress) {
Memory::WriteOrException_U32(0, keyAddress);
return hleLogDebug(Log::HLE, 0);
}
// TODO: Might make sense to reflect the headphone status of the host here,
// if the games adjust their sound.
static u32 sceHprmIsHeadphoneExist() {
return hleLogDebug(Log::HLE, 0);
}
static u32 sceHprmIsMicrophoneExist() {
return hleLogDebug(Log::HLE, 0);
}
static u32 sceHprmIsRemoteExist() {
return hleLogDebug(Log::HLE, 0);
}
static u32 sceHprmRegisterCallback() {
return hleLogError(Log::HLE, 0, "UNIMPL");
}
static u32 sceHprmUnregisterCallback() {
return hleLogError(Log::HLE, 0, "UNIMPL");
}
static u32 sceHprmPeekLatch(u32 latchAddr) {
return hleLogDebug(Log::HLE,0, "latchAddr %08x", latchAddr);
}
static u32 sceHprmReadLatch(u32 latchAddr) {
// Real hardware/JPCSP: 4 x u32 output struct, dummied out to all-zero (nothing held/pressed).
for (int i = 0; i < 4; i++)
Memory::WriteOrException_U32(0, latchAddr + i * 4);
return hleLogDebug(Log::HLE, 0, "latchAddr %08x", latchAddr);
}
const HLEFunction sceHprm[] =
{
{0X089FDFA4, nullptr, "sceHprm_089fdfa4", '?', "" },
{0X1910B327, &WrapU_U<sceHprmPeekCurrentKey>, "sceHprmPeekCurrentKey", 'x', "x"},
{0X208DB1BD, &WrapU_V<sceHprmIsRemoteExist>, "sceHprmIsRemoteExist", 'x', "" },
{0X7E69EDA4, &WrapU_V<sceHprmIsHeadphoneExist>, "sceHprmIsHeadphoneExist", 'x', "" },
{0X219C58F1, &WrapU_V<sceHprmIsMicrophoneExist>, "sceHprmIsMicrophoneExist", 'x', "" },
{0XC7154136, &WrapU_V<sceHprmRegisterCallback>, "sceHprmRegisterCallback", 'x', "" },
{0xFD7DE6CD, &WrapU_V<sceHprmUnregisterCallback>,"sceHprmUnregisterCallback", 'x', "" },
{0X444ED0B7, nullptr, "sceHprmUnregitserCallback", '?', "" }, // Typo.
{0X2BCEC83E, &WrapU_U<sceHprmPeekLatch>, "sceHprmPeekLatch", 'x', "x"},
{0X40D2F9F0, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"},
};
void Register_sceHprm()
{
RegisterHLEModule("sceHprm", ARRAY_SIZE(sceHprm), sceHprm);
}
// Kernel-mode variant library used by VSH modules (e.g. vshbridge). NID 0xE9B776BE is the
// firmware 6.60+ alias of sceHprmReadLatch, listed as nid=0xE9B776BE version=660 alongside the
// 0x40D2F9F0 version=150 NID in JPCSP's sceHprm.java - both resolve to the same function there.
static u32 sceHprm_driver_DC895B2B() {
return hleLogWarning(Log::sceMisc, 0, "UNIMPL");
}
const HLEFunction sceHprm_driver[] =
{
{0XE9B776BE, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"},
// Purpose unknown - JPCSP names it after its NID too, and returns 0. Present so the VSH's
// one startup call resolves instead of trapping.
{0XDC895B2B, &WrapU_V<sceHprm_driver_DC895B2B>, "sceHprm_driver_DC895B2B", 'x', ""},
// Older firmwares number these two differently. Same functions - matched by address against
// the same module's user-mode sceHprm exports (sceHprmReadLatch is sceHprm/0x40D2F9F0 in
// every build). The VSH calls ReadLatch once a frame, so without these an older firmware's
// XMB spends the whole boot trapping on an unresolved import.
// NOTE: new entries go at the end - the syscall opcode in a savestate is an index into this array.
{0XA3A87975, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 6.31 - 6.39
{0X5FC5E53B, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 6.00 - 6.20
{0X748FC3C8, &WrapU_V<sceHprm_driver_DC895B2B>, "sceHprm_driver_DC895B2B", 'x', ""}, // 6.31 - 6.39
{0X605DEA7A, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 5.03 - 5.55
{0XA6E8D4F0, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 3.95 - 4.05
{0X8C728076, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 3.72 - 3.90
{0XF0AA1FB9, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 3.71
// Same story as sceRtc_driver: 3.51 and older export it to kernel mode under the user-mode NID.
{0X40D2F9F0, &WrapU_U<sceHprmReadLatch>, "sceHprmReadLatch", 'x', "x"}, // 1.50 - 3.51
};
void Register_sceHprm_driver()
{
RegisterHLEModule("sceHprm_driver", ARRAY_SIZE(sceHprm_driver), sceHprm_driver);
}