diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index 37b67fdfb5..b5958abfe3 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -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(); diff --git a/Core/HLE/sceNet.cpp b/Core/HLE/sceNet.cpp index b7b6f8789d..663c3a7785 100644 --- a/Core/HLE/sceNet.cpp +++ b/Core/HLE/sceNet.cpp @@ -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", 'x', "xxpx" }, +}; + +void Register_sceIdStorage_driver() { + RegisterHLEModule("sceIdStorage_driver", ARRAY_SIZE(sceIdStorage_driver), sceIdStorage_driver); +} diff --git a/Core/HLE/sceNet.h b/Core/HLE/sceNet.h index 5418efa2fb..12ad744854 100644 --- a/Core/HLE/sceNet.h +++ b/Core/HLE/sceNet.h @@ -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(); diff --git a/docs/VSHBootInvestigation.md b/docs/VSHBootInvestigation.md index b1561a8b5e..9f289c313e 100644 --- a/docs/VSHBootInvestigation.md +++ b/docs/VSHBootInvestigation.md @@ -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).