diff --git a/Core/CMakeLists.txt b/Core/CMakeLists.txt
index 316cec432c..0e938539bc 100644
--- a/Core/CMakeLists.txt
+++ b/Core/CMakeLists.txt
@@ -538,6 +538,8 @@ add_library(Core STATIC
HLE/proAdhocServer.cpp
HLE/sceOpenPSID.cpp
HLE/sceOpenPSID.h
+ HLE/sceResmgr.cpp
+ HLE/sceResmgr.h
HLE/sceP3da.cpp
HLE/sceP3da.h
HLE/sceMt19937.cpp
diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj
index 574123cdad..f493c40f25 100644
--- a/Core/Core.vcxproj
+++ b/Core/Core.vcxproj
@@ -645,6 +645,7 @@
+
@@ -1155,6 +1156,7 @@
+
diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters
index 7b7bf9c5cf..c26c14f463 100644
--- a/Core/Core.vcxproj.filters
+++ b/Core/Core.vcxproj.filters
@@ -375,6 +375,9 @@
HLE\Libraries
+
+ HLE\Libraries
+
HLE\Libraries
@@ -1698,6 +1701,9 @@
HLE\Libraries
+
+ HLE\Libraries
+
HLE\Libraries
diff --git a/Core/ELF/PrxDecrypter.cpp b/Core/ELF/PrxDecrypter.cpp
index 795dab1865..c199970e6f 100644
--- a/Core/ELF/PrxDecrypter.cpp
+++ b/Core/ELF/PrxDecrypter.cpp
@@ -293,8 +293,13 @@ static const u32 g_keyUPDATER_PSAR[] = {
0x62E86C81, 0x03299B96, 0x73AFAE5A, 0x40A05320, 0x10664BE8, 0xE5B76A99,
0x29E0DD70, 0xEA602428, 0x2042AE30, 0x946F8D32, 0xA29E5F71, 0x7C0C7FD5};
-struct TAG_INFO
-{
+// Used by sceResmgr_9DC14891, which is how the VSH decrypts flash0:/vsh/etc/index_XXg.dat - the
+// XMB item index, and the only thing on the boot path that needs these.
+static const u8 keys_9DC14891_1[] = {0x39, 0xF7, 0xDF, 0x19, 0xD7, 0x10, 0xEA, 0x9F, 0x02, 0xDB, 0x3F, 0xB1, 0x10, 0x9F, 0x26, 0x6B};
+static const u8 keys_9DC14891_2[] = {0x46, 0x1D, 0xC9, 0xC2, 0x1D, 0x44, 0xA6, 0x68, 0xF2, 0x06, 0x37, 0xBF, 0x62, 0xCD, 0x11, 0x9E};
+static const u8 keys_9DC14891_3[] = {0x11, 0x0D, 0x1A, 0x4C, 0x8A, 0x19, 0x17, 0xDC, 0xD0, 0x5A, 0x65, 0x47, 0xA5, 0x03, 0x85, 0x22};
+
+struct TAG_INFO {
u32 tag; // 4 byte value at offset 0xD0 in the PRX file
const u32 *key; // "step1_result" use for XOR step
u8 code;
@@ -347,6 +352,9 @@ struct TAG_INFO2
static const TAG_INFO2 g_tagInfo2[] =
{
+ { 0x0B2B90F0, keys_9DC14891_1, 0x5C },
+ { 0x0B2B91F0, keys_9DC14891_2, 0x5C },
+ { 0x0B2B92F0, keys_9DC14891_3, 0x5C },
{ 0x4C9494F0, keys660_k1, 0x43 },
{ 0x4C9495F0, keys660_k2, 0x43 },
{ 0x4C9490F0, keys660_k3, 0x43 },
diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp
index 03b4318dfe..d76e9eb3ac 100644
--- a/Core/HLE/HLETables.cpp
+++ b/Core/HLE/HLETables.cpp
@@ -58,6 +58,7 @@
#include "sceNp.h"
#include "sceMpeg.h"
#include "sceOpenPSID.h"
+#include "sceResmgr.h"
#include "sceP3da.h"
#include "sceParseHttp.h"
#include "sceParseUri.h"
@@ -332,6 +333,8 @@ void RegisterAllModules() {
Register_sceHprm_driver();
Register_sceChkreg();
Register_sceVshBridge();
+ Register_sceResmgr();
+
// add new modules here.
// Not ready to enable this due to apparent softlocks in Patapon 3.
diff --git a/Core/HLE/sceImpose.cpp b/Core/HLE/sceImpose.cpp
index d01be2228a..7ac71c349a 100644
--- a/Core/HLE/sceImpose.cpp
+++ b/Core/HLE/sceImpose.cpp
@@ -153,7 +153,7 @@ static int sceImpose_driver_B497314D(int param, u32 resultAddr) {
// The settings sceImposeGetParam/SetParam address, as a bitfield - sceImposeChanges reports which
// of them have been changed since it was last asked, so the VSH can refresh only what moved.
-enum {
+enum : u32 {
PSP_IMPOSE_MAIN_VOLUME = 0x1,
PSP_IMPOSE_BACKLIGHT_BRIGHTNESS = 0x2,
PSP_IMPOSE_EQUALIZER_MODE = 0x4,
@@ -162,16 +162,33 @@ enum {
PSP_IMPOSE_TIME_FORMAT = 0x20,
PSP_IMPOSE_DATE_FORMAT = 0x40,
PSP_IMPOSE_LANGUAGE = 0x80,
+ PSP_IMPOSE_00000100 = 0x100,
PSP_IMPOSE_BACKLIGHT_OFF_INTERVAL = 0x200,
PSP_IMPOSE_SOUND_REDUCTION = 0x400,
+ // Named after their own values, as in JPCSP - real meanings unknown.
+ PSP_IMPOSE_20000000 = 0x20000000,
+ PSP_IMPOSE_80000001 = 0x80000001,
+ PSP_IMPOSE_80000002 = 0x80000002,
+ PSP_IMPOSE_80000003 = 0x80000003,
+ PSP_IMPOSE_80000004 = 0x80000004,
+ PSP_IMPOSE_80000005 = 0x80000005,
+ PSP_IMPOSE_80000006 = 0x80000006,
+ PSP_IMPOSE_80000007 = 0x80000007,
+ PSP_IMPOSE_80000008 = 0x80000008,
+ PSP_IMPOSE_80000009 = 0x80000009,
+ PSP_IMPOSE_8000000A = 0x8000000A,
+ PSP_IMPOSE_8000000B = 0x8000000B,
};
// Returns the current value of one setting. Values follow JPCSP's, which are the plausible
-// defaults for a console with nothing unusual configured. Anything we don't model reads as 0
-// rather than failing - the VSH polls this every frame for its indicators, so returning an error
-// would be far more disruptive than returning a quiet default.
+// defaults for a console with nothing unusual configured.
+//
+// The split between the last two cases matters and matches JPCSP: a parameter that exists but that
+// we don't model reads as 0, while one that isn't a parameter at all is rejected. Answering 0 to
+// everything tells a caller probing for a feature that the feature is there and switched off,
+// which is a different thing from "no such setting".
static int sceImposeGetParam(int param) {
- switch (param) {
+ switch ((u32)param) {
case PSP_IMPOSE_MAIN_VOLUME:
return hleLogDebug(Log::sceUtility, 30); // Full, on a 0-30 scale.
case PSP_IMPOSE_BACKLIGHT_BRIGHTNESS:
@@ -182,8 +199,26 @@ static int sceImposeGetParam(int param) {
case PSP_IMPOSE_SOUND_REDUCTION:
case PSP_IMPOSE_BACKLIGHT_OFF_INTERVAL:
return hleLogDebug(Log::sceUtility, 0);
+ case PSP_IMPOSE_EQUALIZER_MODE:
+ case PSP_IMPOSE_TIME_FORMAT:
+ case PSP_IMPOSE_DATE_FORMAT:
+ case PSP_IMPOSE_LANGUAGE:
+ case PSP_IMPOSE_00000100:
+ case PSP_IMPOSE_20000000:
+ case PSP_IMPOSE_80000001:
+ case PSP_IMPOSE_80000002:
+ case PSP_IMPOSE_80000003:
+ case PSP_IMPOSE_80000004:
+ case PSP_IMPOSE_80000005:
+ case PSP_IMPOSE_80000006:
+ case PSP_IMPOSE_80000007:
+ case PSP_IMPOSE_80000008:
+ case PSP_IMPOSE_80000009:
+ case PSP_IMPOSE_8000000A:
+ case PSP_IMPOSE_8000000B:
+ return hleLogDebug(Log::sceUtility, 0, "param %08x not modelled", param);
default:
- return hleLogDebug(Log::sceUtility, 0, "unmodelled param %08x", param);
+ return hleLogWarning(Log::sceUtility, SCE_KERNEL_ERROR_INVALID_MODE, "invalid param %08x", param);
}
}
diff --git a/Core/HLE/sceResmgr.cpp b/Core/HLE/sceResmgr.cpp
new file mode 100644
index 0000000000..e816c4ddd5
--- /dev/null
+++ b/Core/HLE/sceResmgr.cpp
@@ -0,0 +1,76 @@
+// 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
+
+// MemMap.h first: PrxDecrypter.h's PSP_Header is written in u32_le and friends, and doesn't pull
+// in the header that defines them.
+#include "Core/MemMap.h"
+#include "Core/Debugger/MemBlockInfo.h"
+#include "Core/ELF/PrxDecrypter.h"
+#include "Core/HLE/FunctionWrappers.h"
+#include "Core/HLE/HLE.h"
+#include "Core/HLE/sceResmgr.h"
+
+// The resource manager. Games never touch this - it exists for the VSH, which uses the one
+// function below to decrypt flash0:/vsh/etc/index_XXg.dat, the index of what the XMB shows. With
+// this unresolved the call traps, the index stays encrypted, the job thread building the top menu
+// gives up, and the shell ends on an error screen instead.
+
+// Decrypts a buffer in place. Named after its NID, as in JPCSP - the real name isn't known, though
+// the index file is the only caller we've seen.
+//
+// Parameters:
+// - bufferAddr: encrypted data in, decrypted data out.
+// - bufferSize: how much is there.
+// - resultLengthAddr: receives the decrypted length, which is smaller - the header goes away.
+static int sceResmgr_9DC14891(u32 bufferAddr, int bufferSize, u32 resultLengthAddr) {
+ if (bufferSize < 0 || !Memory::IsValidRange(bufferAddr, bufferSize))
+ return hleLogError(Log::sceMisc, -1, "bad buffer");
+
+ u8 *buffer = Memory::GetPointerWriteUnchecked(bufferAddr);
+
+ // Already plaintext - the check JPCSP uses, and cheap insurance against decrypting twice.
+ if (bufferSize >= 8 && !memcmp(buffer, "release:", 8)) {
+ if (Memory::IsValidAddress(resultLengthAddr))
+ Memory::WriteUnchecked_U32(bufferSize, resultLengthAddr);
+ return hleLogDebug(Log::sceMisc, 0, "already decrypted");
+ }
+
+ // Decrypting in place is fine for the caller, but pspDecryptPRX walks the input while writing
+ // the output, so give it somewhere separate to write and copy back on success. On failure the
+ // guest buffer is left exactly as it was.
+ std::vector decrypted(bufferSize);
+ const int decryptedSize = pspDecryptPRX(buffer, decrypted.data(), bufferSize);
+ if (decryptedSize <= 0) {
+ return hleLogError(Log::sceMisc, -1, "failed to decrypt %d bytes", bufferSize);
+ }
+
+ memcpy(buffer, decrypted.data(), decryptedSize);
+ NotifyMemInfo(MemBlockFlags::WRITE, bufferAddr, decryptedSize, "sceResmgrDecrypt");
+ if (Memory::IsValidAddress(resultLengthAddr))
+ Memory::WriteUnchecked_U32(decryptedSize, resultLengthAddr);
+ return hleLogInfo(Log::sceMisc, 0, "decrypted %d bytes to %d", bufferSize, decryptedSize);
+}
+
+const HLEFunction sceResmgr[] = {
+ {0X9DC14891, &WrapI_UIU, "sceResmgr_9DC14891", 'i', "xix"},
+};
+
+void Register_sceResmgr() {
+ RegisterHLEModule("sceResmgr", ARRAY_SIZE(sceResmgr), sceResmgr);
+}
diff --git a/Core/HLE/sceResmgr.h b/Core/HLE/sceResmgr.h
new file mode 100644
index 0000000000..c8f911d5fc
--- /dev/null
+++ b/Core/HLE/sceResmgr.h
@@ -0,0 +1,20 @@
+// 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/.
+
+#pragma once
+
+void Register_sceResmgr();
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj
index 0bf4da7707..75b29f0a7d 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj
+++ b/UWP/CoreUWP/CoreUWP.vcxproj
@@ -227,6 +227,7 @@
+
@@ -506,6 +507,7 @@
+
diff --git a/UWP/CoreUWP/CoreUWP.vcxproj.filters b/UWP/CoreUWP/CoreUWP.vcxproj.filters
index 7b40a69b42..918fc06cb4 100644
--- a/UWP/CoreUWP/CoreUWP.vcxproj.filters
+++ b/UWP/CoreUWP/CoreUWP.vcxproj.filters
@@ -136,6 +136,7 @@
+
@@ -562,6 +563,7 @@
+
diff --git a/android/jni/Android.mk b/android/jni/Android.mk
index 6467be4647..02f45dcd91 100644
--- a/android/jni/Android.mk
+++ b/android/jni/Android.mk
@@ -761,6 +761,7 @@ EXEC_AND_LIB_FILES := \
$(SRC)/Core/HLE/sceNetInet.cpp \
$(SRC)/Core/HLE/sceNetResolver.cpp \
$(SRC)/Core/HLE/sceOpenPSID.cpp \
+ $(SRC)/Core/HLE/sceResmgr.cpp \
$(SRC)/Core/HLE/sceP3da.cpp \
$(SRC)/Core/HLE/sceMt19937.cpp \
$(SRC)/Core/HLE/sceParseHttp.cpp \
diff --git a/libretro/Makefile.common b/libretro/Makefile.common
index 69f4c31415..fb201a2080 100644
--- a/libretro/Makefile.common
+++ b/libretro/Makefile.common
@@ -812,6 +812,7 @@ SOURCES_CXX += \
$(COREDIR)/HLE/proAdhocServer.cpp \
$(COREDIR)/HLE/proAdhoc.cpp \
$(COREDIR)/HLE/sceOpenPSID.cpp \
+ $(COREDIR)/HLE/sceResmgr.cpp \
$(COREDIR)/HLE/sceP3da.cpp \
$(COREDIR)/HLE/sceMt19937.cpp \
$(COREDIR)/HLE/sceMd5.cpp \