VSH: Show the configured MAC address in System Information

- See #22924

The page reads IdStorage key 0x44 (6 bytes at offset 0) through
vshbridge.prx, as does wlan.prx's sceWlanGetEtherAddr. The real
idstorage.prx never finishes its init (it stops at the kernel mutexes we
leave unresolved), so every lookup failed and the page showed "-".

sceIdStorageLookup is now HLE, answering key 0x44 from the same MAC
sceWlanGetEtherAddr uses. Other keys fail with 0x80000108, what the real
driver returns uninitialized, and the rest of the library still resolves
to idstorage.prx. Taken from the 6.61 modules' disassembly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
Henrik RydgårdandClaude Opus 5.5 committed 2026-11-06 12:34:02 +01:00
1 parent 22bc3f9db4
commit a3cbbd086b
4 files changed
+57 -11

No files matched your search

+1
View File
@@ -441,6 +441,7 @@ void RegisterAllModules() {
Register_sceVaudio_driver();
Register_sceNetApctl_lib();
Register_sceMeCore_driver();
Register_sceIdStorage_driver();
// Not ready to enable this due to apparent softlocks in Patapon 3.
// Register_sceNpMatching2();
+50 -9
View File
@@ -1103,29 +1103,61 @@ static int sceNetThreadAbort(SceUID thid) {
return hleLogError(Log::sceNet, 0, "UNIMPL");
}
static u32 sceWlanGetEtherAddr(u32 addrAddr) {
if (!Memory::IsValidRange(addrAddr, 6)) {
// More correctly, it should crash.
return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "illegal address");
}
u8 *addr = Memory::GetPointerWriteUnchecked(addrAddr);
// The console's MAC address: the configured one, or one made from the instance ID when several run.
static void GetEtherAddr(u8 addr[6]) {
if (PPSSPP_ID > 1) {
Memory::Memset(addrAddr, PPSSPP_ID, 6);
memset(addr, PPSSPP_ID, 6);
// Making sure the 1st 2-bits on the 1st byte of OUI are zero to prevent issue with some games (ie. Gran Turismo)
addr[0] &= 0xfc;
} else {
// Read MAC Address from config
if (!ParseMacAddress(g_Config.sMACAddress, addr)) {
ERROR_LOG(Log::sceNet, "Error parsing mac address %s", g_Config.sMACAddress.c_str());
Memory::Memset(addrAddr, 0, 6);
memset(addr, 0, 6);
}
}
}
static u32 sceWlanGetEtherAddr(u32 addrAddr) {
if (!Memory::IsValidRange(addrAddr, 6)) {
// More correctly, it should crash.
return hleLogError(Log::sceNet, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "illegal address");
}
GetEtherAddr(Memory::GetPointerWriteUnchecked(addrAddr));
NotifyMemInfo(MemBlockFlags::WRITE, addrAddr, 6, "WlanEtherAddr");
return hleDelayResult(hleLogDebug(Log::sceNet, 0), "get ether mac", 200);
}
// Reads len bytes at offset from the 512-byte IdStorage leaf for key. We only have the leaf that
// holds the MAC address, key 0x44, which the VSH's wlan.prx (sceWlanGetEtherAddr) and
// sysconf_plugin.prx (System Information, through vshbridge.prx's sceVshBridge_4db43867) both read
// as 6 bytes at offset 0. Every other key gets the error flash0:/kd/idstorage.prx returned before
// this existed: its init stops at the kernel mutexes we leave unresolved (see ThreadManForKernel),
// so it never sets its initialized flag. The argument checks come from that function, too.
static u32 sceIdStorageLookup(u32 key, u32 offset, u32 bufAddr, u32 len) {
key &= 0xFFFF;
if (key > 0xFFEF) {
return hleLogError(Log::sceMisc, 0x80000100, "bad key");
}
if (offset >= 0x200 || offset + len > 0x200) {
return hleLogError(Log::sceMisc, 0x800001FE, "out of range");
}
if (key != 0x44) {
return hleLogDebug(Log::sceMisc, 0x80000108, "key not available");
}
if (!Memory::IsValidRange(bufAddr, len)) {
return hleLogError(Log::sceMisc, SCE_KERNEL_ERROR_ILLEGAL_ADDR, "illegal address");
}
u8 leaf[0x200]{};
GetEtherAddr(leaf);
Memory::MemcpyUnchecked(bufAddr, leaf + offset, len);
NotifyMemInfo(MemBlockFlags::WRITE, bufAddr, len, "IdStorageLookup");
return hleLogInfo(Log::sceMisc, 0);
}
static u32 sceNetGetLocalEtherAddr(u32 addrAddr) {
// FIXME: Return 0x80410180 (pspnet[_core] error code?) before successful attempt to Create/Connect/Join a Group? (ie. adhocctlCurrentMode == ADHOCCTL_MODE_NONE)
// Fails while apctl is initialized but not connected (pspautotests net/adhoc/apctlinit). PES 2009 polls it
@@ -1975,3 +2007,12 @@ void Register_sceNetUpnp() {
void Register_sceNetIfhandle() {
RegisterHLEModule("sceNetIfhandle", ARRAY_SIZE(sceNetIfhandle), sceNetIfhandle);
}
// Just the one function. The rest of the library still resolves to flash0:/kd/idstorage.prx.
const HLEFunction sceIdStorage_driver[] = {
{0x6FE062D1, &WrapU_UUUU<sceIdStorageLookup>, "sceIdStorageLookup", 'x', "xxpx" },
};
void Register_sceIdStorage_driver() {
RegisterHLEModule("sceIdStorage_driver", ARRAY_SIZE(sceIdStorage_driver), sceIdStorage_driver);
}
+1
View File
@@ -109,6 +109,7 @@ void Register_sceNetApctl_lib();
void Register_sceWlanDrv();
void Register_sceNetUpnp();
void Register_sceNetIfhandle();
void Register_sceIdStorage_driver();
void __NetInit();
void __NetShutdown();
+5 -2
View File
@@ -101,8 +101,11 @@ Two separate things:
that hands each buffer to the ME (`sceVaudio_E8E78DC8`, then `sceVaudio_504E4745` many times a
second). Its Motion JPEG thumbnails replace the frame's Huffman tables with the standard ones, so
a file encoded with optimised tables (ffmpeg's default) gets a garbled thumbnail.
- **Settings**: the menus open. System Information shows "-" for the MAC address: wlan.prx reads it
from IdStorage key 0x44, and IdStorage is left failing on purpose (see below).
- **Settings**: the menus open. System Information shows the configured MAC address. It reads
IdStorage key 0x44 itself (6 bytes at offset 0, through vshbridge.prx's `sceVshBridge_4db43867`),
as does wlan.prx's `sceWlanGetEtherAddr`. The real idstorage.prx is left failing on purpose (see
below), so `sceIdStorageLookup` is HLE: it answers key 0x44 from the config and fails every other
key with the 0x80000108 the real driver returns uninitialized.
- **Network**: the browser and the online manuals reach their Network Connection screen once
`sceNetApctl_lib` is there, then stop at 8002013A on `sceHttp` functions only the NetFront browser
uses (06488A1C, 2C3C82CF, 3A67F306, 739C2D79, 77EE5319, 8046E250, A461A167, B0257723).