diff --git a/CMakeLists.txt b/CMakeLists.txt index cb88266791..042303f79a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2298,6 +2298,8 @@ add_library(${CoreLibName} ${CoreLinkType} Core/HLE/scePower.h Core/HLE/scePsmf.cpp Core/HLE/scePsmf.h + Core/HLE/sceReg.cpp + Core/HLE/sceReg.h Core/HLE/sceRtc.cpp Core/HLE/sceRtc.h Core/HLE/sceSas.cpp diff --git a/Common/StringUtils.h b/Common/StringUtils.h index e2424ba1b8..1bfccb2521 100644 --- a/Common/StringUtils.h +++ b/Common/StringUtils.h @@ -63,6 +63,10 @@ inline bool endsWithNoCase(std::string_view str, std::string_view key) { return strncasecmp(str.data() + offset, key.data(), key.size()) == 0; } +inline bool equals(std::string_view str, std::string_view key) { + return str == key; +} + inline bool equalsNoCase(std::string_view str, std::string_view key) { if (str.size() != key.size()) return false; diff --git a/Core/Core.vcxproj b/Core/Core.vcxproj index 9fb5aab8aa..b8160f184e 100644 --- a/Core/Core.vcxproj +++ b/Core/Core.vcxproj @@ -578,6 +578,7 @@ + @@ -1201,6 +1202,7 @@ + diff --git a/Core/Core.vcxproj.filters b/Core/Core.vcxproj.filters index 496f07b415..4ef4ec1600 100644 --- a/Core/Core.vcxproj.filters +++ b/Core/Core.vcxproj.filters @@ -1348,6 +1348,9 @@ Core + + HLE\Libraries + @@ -2181,6 +2184,9 @@ HLE\Kernel + + HLE\Libraries + diff --git a/Core/HLE/AtracCtx2.cpp b/Core/HLE/AtracCtx2.cpp index 655a074b4b..1457083199 100644 --- a/Core/HLE/AtracCtx2.cpp +++ b/Core/HLE/AtracCtx2.cpp @@ -1048,7 +1048,7 @@ void Atrac2::CheckForSas() { if (info.state != 0x10) { WARN_LOG(Log::ME, "Caller forgot to set state to 0x10"); } - sas_.isStreaming = info.fileDataEnd > info.bufferByte; + sas_.isStreaming = info.fileDataEnd > (s32)info.bufferByte; if (sas_.isStreaming) { INFO_LOG(Log::ME, "SasAtrac stream mode"); } else { diff --git a/Core/HLE/ErrorCodes.h b/Core/HLE/ErrorCodes.h index a443ca8b81..afbc2eabbb 100644 --- a/Core/HLE/ErrorCodes.h +++ b/Core/HLE/ErrorCodes.h @@ -495,4 +495,10 @@ enum PSPErrorCode : u32 { SCE_SAS_ERROR_NOT_INIT = 0x80420100, SCE_AVCODEC_ERROR_INVALID_DATA = 0x807f00fd, + + // These are inferred from behavior. + SCE_REG_ERROR_CATEGORY_INACCESSIBLE = 0x80082712, + SCE_REG_ERROR_REGISTRY_NOT_FOUND = 0x80082715, + SCE_REG_ERROR_ROOT_NOT_ACCESSIBLE = 0x80082716, + SCE_REG_ERROR_CATEGORY_NOT_FOUND = 0x80082718, }; diff --git a/Core/HLE/FunctionWrappers.h b/Core/HLE/FunctionWrappers.h index 3f6351a529..8bfc6e9fcd 100644 --- a/Core/HLE/FunctionWrappers.h +++ b/Core/HLE/FunctionWrappers.h @@ -523,6 +523,21 @@ template void WrapI_ICIU() { RETURN(retval); } +template void WrapI_ICUU() { + int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3)); + RETURN(retval); +} + +template void WrapI_ICUUU() { + int retval = func(PARAM(0), Memory::GetCharPointer(PARAM(1)), PARAM(2), PARAM(3), PARAM(4)); + RETURN(retval); +} + +template void WrapI_IIUU() { + int retval = func(PARAM(0), PARAM(1), PARAM(2), PARAM(3)); + RETURN(retval); +} + template void WrapI_CIU() { int retval = func(Memory::GetCharPointer(PARAM(0)), PARAM(1), PARAM(2)); RETURN(retval); diff --git a/Core/HLE/HLETables.cpp b/Core/HLE/HLETables.cpp index ec896920ad..0439520898 100644 --- a/Core/HLE/HLETables.cpp +++ b/Core/HLE/HLETables.cpp @@ -64,6 +64,7 @@ #include "scePower.h" #include "scePspNpDrm_user.h" #include "scePsmf.h" +#include "sceReg.h" #include "sceRtc.h" #include "sceSas.h" #include "sceSircs.h" @@ -323,6 +324,7 @@ void RegisterAllModules() { Register_InterruptManagerForKernel(); Register_sceSircs(); Register_sceNet_lib(); + Register_sceReg(); // Not ready to enable this due to apparent softlocks in Patapon 3. // Register_sceNpMatching2(); diff --git a/Core/HLE/sceKernel.cpp b/Core/HLE/sceKernel.cpp index 8b0f8ae2d5..afd5d48f87 100644 --- a/Core/HLE/sceKernel.cpp +++ b/Core/HLE/sceKernel.cpp @@ -75,6 +75,7 @@ #include "scePower.h" #include "sceUtility.h" #include "sceUmd.h" +#include "sceReg.h" #include "sceRtc.h" #include "sceSsl.h" #include "sceSas.h" @@ -164,6 +165,7 @@ void __KernelInit() __OpenPSIDInit(); __HttpInit(); __NpInit(); + __RegInit(); SaveState::Init(); // Must be after IO, as it may create a directory Reporting::Init(); @@ -188,6 +190,7 @@ void __KernelShutdown() hleCurrentThreadName = NULL; kernelObjects.Clear(); + __RegShutdown(); __HttpShutdown(); __OpenPSIDShutdown(); __UsbCamShutdown(); @@ -303,6 +306,7 @@ void __KernelDoState(PointerWrap &p) __AACDoState(p); __UsbGpsDoState(p); __UsbMicDoState(p); + __RegDoState(p); // IMPORTANT! Add new sections last! } @@ -1492,6 +1496,10 @@ const char *KernelErrorToString(u32 err) { case SCE_AVCODEC_ERROR_INVALID_DATA: return "SCE_AVCODEC_ERROR_INVALID_DATA"; + case SCE_REG_ERROR_CATEGORY_INACCESSIBLE: return "SCE_REG_ERROR_CATEGORY_INACCESSIBLE"; + case SCE_REG_ERROR_CATEGORY_NOT_FOUND: return "SCE_REG_ERROR_CATEGORY_NOT_FOUND"; + case SCE_REG_ERROR_REGISTRY_NOT_FOUND: return "SCE_REG_ERROR_REGISTRY_NOT_FOUND"; + default: return nullptr; } diff --git a/Core/HLE/sceKernelModule.cpp b/Core/HLE/sceKernelModule.cpp index ecb81fa31c..9a7b596a48 100644 --- a/Core/HLE/sceKernelModule.cpp +++ b/Core/HLE/sceKernelModule.cpp @@ -715,7 +715,7 @@ void ExportFuncSymbol(const FuncSymbolExport &func) { for (SceUID moduleId : loadedModules) { PSPModule *module = kernelObjects.Get(moduleId, error); if (!module || !module->ImportsOrExportsModuleName(func.moduleName)) { - continue; + continue; } // Look for imports currently loaded modules already have, hook it up right away. diff --git a/Core/HLE/sceReg.cpp b/Core/HLE/sceReg.cpp new file mode 100644 index 0000000000..0750aceba9 --- /dev/null +++ b/Core/HLE/sceReg.cpp @@ -0,0 +1,699 @@ +#include +#include +#include "Core/HLE/sceReg.h" +#include "Core/HLE/HLE.h" +#include "Core/HLE/FunctionWrappers.h" +#include "Core/HLE/ErrorCodes.h" +#include "Common/Serialize/Serializer.h" +#include "Common/Serialize/SerializeMap.h" +#include "Common/StringUtils.h" + +#define SYSTEM_REGISTRY "/system" +#define REG_KEYNAME_SIZE 27 + +enum RegKeyTypes { + REG_TYPE_DIR = 1, + REG_TYPE_INT = 2, + REG_TYPE_STR = 3, + REG_TYPE_BIN = 4, +}; + +typedef unsigned int REGHANDLE; + +struct RegParam +{ + unsigned int regtype; /* 0x0, set to 1 only for system */ + char name[256]; /* 0x4-0x104 */ + unsigned int namelen; /* 0x104 */ + unsigned int unk2; /* 0x108 */ + unsigned int unk3; /* 0x10C */ +}; + +struct OpenCategory { + std::string path; + int openMode; + void DoState(PointerWrap &p) { + Do(p, path); + Do(p, openMode); + } +}; + +static int g_openRegistryMode; +static int g_handleGen; // TODO: The real PSP seems to use memory addresses. Probably it's doing allocations, which we don't really want to do unless we can match them exactly. +static std::map g_openCategories; + +enum class ValueType { + FAIL = 0, + DIR = 1, + INT = 2, + STR = 3, + BIN = 4, +}; + +struct KeyValue { + std::string name; + ValueType type; + std::string strValue; // also can be used for bin + int intValue; + const KeyValue *dirContents; // intValue is the count. +}; + + +// Dump of the PSP registry using tests/misc/reg.prx in pspautotests + +// Dump of /DATA/FONT/PROPERTY/INFO0 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO0[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000067 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000001 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro DB" }, + { "file_name", ValueType::STR, "jpn0.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO1 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO1[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000001 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, + { "file_name", ValueType::STR, "ltn0.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO2 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO2[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000002 }, + { "style", ValueType::INT, "", (int)0x00000001 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, + { "file_name", ValueType::STR, "ltn1.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO3 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO3[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000002 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, + { "file_name", ValueType::STR, "ltn2.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO4 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO4[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000002 }, + { "style", ValueType::INT, "", (int)0x00000002 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, + { "file_name", ValueType::STR, "ltn3.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO5 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO5[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000005 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, + { "file_name", ValueType::STR, "ltn4.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO6 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO6[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000002 }, + { "style", ValueType::INT, "", (int)0x00000005 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, + { "file_name", ValueType::STR, "ltn5.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO7 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO7[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000006 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, + { "file_name", ValueType::STR, "ltn6.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO8 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO8[] = { + { "h_size", ValueType::INT, "", (int)0x00000288 }, + { "v_size", ValueType::INT, "", (int)0x00000288 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000002 }, + { "style", ValueType::INT, "", (int)0x00000006 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, + { "file_name", ValueType::STR, "ltn7.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO9 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO9[] = { + { "h_size", ValueType::INT, "", (int)0x000001c0 }, + { "v_size", ValueType::INT, "", (int)0x000001c0 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000001 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, + { "file_name", ValueType::STR, "ltn8.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO10 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO10[] = { + { "h_size", ValueType::INT, "", (int)0x000001c0 }, + { "v_size", ValueType::INT, "", (int)0x000001c0 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000002 }, + { "style", ValueType::INT, "", (int)0x00000001 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, + { "file_name", ValueType::STR, "ltn9.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO11 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO11[] = { + { "h_size", ValueType::INT, "", (int)0x000001c0 }, + { "v_size", ValueType::INT, "", (int)0x000001c0 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000001 }, + { "style", ValueType::INT, "", (int)0x00000002 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-NewRodin Pro Latin" }, + { "file_name", ValueType::STR, "ltn10.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA/FONT/PROPERTY/INFO12 +static const KeyValue tree_DATA_FONT_PROPERTY_INFO12[] = { + { "h_size", ValueType::INT, "", (int)0x000001c0 }, + { "v_size", ValueType::INT, "", (int)0x000001c0 }, + { "h_resolution", ValueType::INT, "", (int)0x00002000 }, + { "v_resolution", ValueType::INT, "", (int)0x00002000 }, + { "extra_attributes", ValueType::INT, "", (int)0x00000000 }, + { "weight", ValueType::INT, "", (int)0x00000000 }, + { "family_code", ValueType::INT, "", (int)0x00000002 }, + { "style", ValueType::INT, "", (int)0x00000002 }, + { "sub_style", ValueType::INT, "", (int)0x00000000 }, + { "language_code", ValueType::INT, "", (int)0x00000002 }, + { "region_code", ValueType::INT, "", (int)0x00000000 }, + { "country_code", ValueType::INT, "", (int)0x00000001 }, + { "font_name", ValueType::STR, "FTT-Matisse Pro Latin" }, + { "file_name", ValueType::STR, "ltn11.pgf" }, + { "expire_date", ValueType::INT, "", (int)0x00000000 }, + { "shadow_option", ValueType::INT, "", (int)0x00000000 }, +}; + +// /DATA/FONT/PROPERTY/INFO13 was not accessible (returned 80082712) +static const KeyValue tree_DATA_FONT_PROPERTY_INFO13[1] = { "", ValueType::FAIL, "", (int)0x80082712 }; + +// /DATA/FONT/PROPERTY/INFO14 was not accessible (returned 80082712) +static const KeyValue tree_DATA_FONT_PROPERTY_INFO14[1] = { "", ValueType::FAIL, "", (int)0x80082712 }; + +// /DATA/FONT/PROPERTY/INFO15 was not accessible (returned 80082712) +static const KeyValue tree_DATA_FONT_PROPERTY_INFO15[1] = { "", ValueType::FAIL, "", (int)0x80082712 }; + +// /DATA/FONT/PROPERTY/INFO16 was not accessible (returned 80082712) +static const KeyValue tree_DATA_FONT_PROPERTY_INFO16[1] = { "", ValueType::FAIL, "", (int)0x80082712 }; + +// /DATA/FONT/PROPERTY/INFO17 was not accessible (returned 80082712) +static const KeyValue tree_DATA_FONT_PROPERTY_INFO17[1] = { "", ValueType::FAIL, "", (int)0x80082712 }; + +// Dump of /DATA/FONT/PROPERTY +static const KeyValue tree_DATA_FONT_PROPERTY[] = { + { "INFO0", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO0), tree_DATA_FONT_PROPERTY_INFO0 }, + { "INFO1", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO1), tree_DATA_FONT_PROPERTY_INFO1 }, + { "INFO2", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO2), tree_DATA_FONT_PROPERTY_INFO2 }, + { "INFO3", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO3), tree_DATA_FONT_PROPERTY_INFO3 }, + { "INFO4", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO4), tree_DATA_FONT_PROPERTY_INFO4 }, + { "INFO5", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO5), tree_DATA_FONT_PROPERTY_INFO5 }, + { "INFO6", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO6), tree_DATA_FONT_PROPERTY_INFO6 }, + { "INFO7", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO7), tree_DATA_FONT_PROPERTY_INFO7 }, + { "INFO8", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO8), tree_DATA_FONT_PROPERTY_INFO8 }, + { "INFO9", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO9), tree_DATA_FONT_PROPERTY_INFO9 }, + { "INFO10", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO10), tree_DATA_FONT_PROPERTY_INFO10 }, + { "INFO11", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO11), tree_DATA_FONT_PROPERTY_INFO11 }, + { "INFO12", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO12), tree_DATA_FONT_PROPERTY_INFO12 }, + { "INFO13", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO13), tree_DATA_FONT_PROPERTY_INFO13 }, + { "INFO14", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO14), tree_DATA_FONT_PROPERTY_INFO14 }, + { "INFO15", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO15), tree_DATA_FONT_PROPERTY_INFO15 }, + { "INFO16", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO16), tree_DATA_FONT_PROPERTY_INFO16 }, + { "INFO17", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY_INFO17), tree_DATA_FONT_PROPERTY_INFO17 }, +}; + +// Dump of /DATA/FONT +static const KeyValue tree_DATA_FONT[] = { + { "path_name", ValueType::STR, "flash0:/font" }, + { "num_fonts", ValueType::INT, "", (int)0x00000012 }, + { "PROPERTY", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT_PROPERTY), tree_DATA_FONT_PROPERTY }, +}; + +// Dump of /DATA/COUNT +static const KeyValue tree_DATA_COUNT[] = { + { "boot_count", ValueType::INT, "", (int)0x00000000 }, + { "game_exec_count", ValueType::INT, "", (int)0x00000046 }, + { "slide_count", ValueType::INT, "", (int)0x00000000 }, + { "usb_connect_count", ValueType::INT, "", (int)0x000000ec }, + { "wifi_connect_count", ValueType::INT, "", (int)0x00000000 }, + { "psn_access_count", ValueType::INT, "", (int)0x00000000 }, +}; + +// Dump of /DATA +static const KeyValue tree_DATA[] = { + { "FONT", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_FONT), tree_DATA_FONT }, + { "COUNT", ValueType::DIR, "", ARRAY_SIZE(tree_DATA_COUNT), tree_DATA_COUNT }, +}; + +// /SYSPROFILE was not accessible (returned 80082712) +static const KeyValue tree_SYSPROFILE[1] = { "", ValueType::FAIL, "", (int)0x80082712 }; + +const KeyValue ROOT[] = { + { "DATA", ValueType::DIR, "", ARRAY_SIZE(tree_DATA), tree_DATA }, + { "SYSPROFILE", ValueType::DIR, "", ARRAY_SIZE(tree_SYSPROFILE), tree_SYSPROFILE }, +}; + +void __RegInit() { + g_openRegistryMode = 0; + g_handleGen = 1337; + g_openCategories.clear(); +} + +void __RegShutdown() { + g_openCategories.clear(); +} + +static const KeyValue *LookupCategory(std::string_view path, int *count) { + path = StripPrefix("/", path); + std::vector parts; + SplitString(path, '/', parts); + + const KeyValue *curDir = ROOT; + int curCount = ARRAY_SIZE(ROOT); + + for (const auto part : parts) { + bool found = false; + for (int i = 0; i < curCount; i++) { + if (equals(curDir[i].name, part)) { + // Found the subdir. + if (curDir[i].type == ValueType::DIR) { + // Must update curCount before curDir, of course (since that line accesses it). + curCount = curDir[i].intValue; + curDir = curDir[i].dirContents; + found = true; + break; + } else { + ERROR_LOG(Log::System, "Not a dir"); + return nullptr; + } + } + } + if (!found) { + WARN_LOG(Log::System, "Path not found: %.*s", (int)path.size(), path.data()); + return nullptr; + } + } + + *count = curCount; + return curDir; +} + +void __RegDoState(PointerWrap &p) { + auto s = p.Section("sceReg", 1, 1); + if (!s) + return; + Do(p, g_openRegistryMode); + Do(p, g_openCategories); +} + +// Registry level (it seems only /system can exist, so kinda pointless) +int sceRegOpenRegistry(u32 regParamAddr, int mode, u32 regHandleAddr) { + // There's only one registry and its handle is 0. + if (Memory::IsValid4AlignedAddress(regHandleAddr)) { + Memory::WriteUnchecked_U32(0, regHandleAddr); + } + g_openRegistryMode = mode; + return hleLogInfo(Log::System, 0); +} + +int sceRegCloseRegistry(int regHandle) { + if (regHandle != 0) { + return hleLogError(Log::System, SCE_REG_ERROR_REGISTRY_NOT_FOUND); + } + g_openCategories.clear(); + return hleLogInfo(Log::System, 0); +} + +int sceRegFlushRegistry(int regHandle) { + if (regHandle != 0) { + return hleLogError(Log::System, SCE_REG_ERROR_REGISTRY_NOT_FOUND); + } + // For us this is a no-op. + return hleLogInfo(Log::System, 0); +} + +// Seems dangerous! Have not dared to test this on hardware. +int sceRegRemoveRegistry(u32 regParamAddr) { + return hleLogError(Log::System, 0, "UNIMPL"); +} + +int sceRegOpenCategory(int regHandle, const char *name, int mode, u32 regHandleAddr) { + if (!Memory::IsValid4AlignedAddress(regHandleAddr)) { + return -1; + } + if (regHandle != 0) { + Memory::WriteUnchecked_U32(-1, regHandleAddr); + return hleLogError(Log::System, SCE_REG_ERROR_REGISTRY_NOT_FOUND, "Invalid registry"); + } + + if (equals(name, "") || equals(name, "/")) { + return hleLogError(Log::System, SCE_REG_ERROR_ROOT_NOT_ACCESSIBLE); + } + + int count = 0; + const KeyValue *keyvals = LookupCategory(name, &count); + if (!keyvals) { + Memory::WriteUnchecked_U32(-1, regHandleAddr); + return hleLogError(Log::System, SCE_REG_ERROR_CATEGORY_NOT_FOUND); + } + + // Let's see if this category is marked as inaccessible (presumably from user mode).. + if (count == 1 && keyvals[0].type == ValueType::FAIL) { + const int errorCode = keyvals[0].intValue; + return hleLogWarning(Log::System, errorCode, "Inaccessible category"); + } + + int handle = g_handleGen++; + OpenCategory cat{ name, mode }; + g_openCategories[handle] = cat; + Memory::WriteUnchecked_U32(handle, regHandleAddr); + return hleLogInfo(Log::System, 0, "open handle: %d", handle); +} + +int sceRegCloseCategory(int regHandle) { + auto iter = g_openCategories.find(regHandle); + if (iter == g_openCategories.end()) { + // Not found + return hleLogError(Log::System, 0, "Not an open category"); + } + + g_openCategories.erase(iter); + return hleLogInfo(Log::System, 0); +} + +int sceRegRemoveCategory(int regHandle, const char *name) { + return hleLogError(Log::System, 0, "UNIMPL"); +} + +int sceRegFlushCategory(int regHandle) { + return hleLogError(Log::System, 0, "UNIMPL"); +} + +// Key level + +int sceRegGetKeysNum(int catHandle, u32 numAddr) { + auto iter = g_openCategories.find(catHandle); + if (iter == g_openCategories.end()) { + return hleLogError(Log::System, 0, "Not an open category"); + } + + if (!Memory::IsValid4AlignedAddress(numAddr)) { + return -1; + } + + int count = 0; + const KeyValue *keyvals = LookupCategory(iter->second.path, &count); + if (!keyvals) { + Memory::WriteUnchecked_U32(-1, numAddr); + return hleLogWarning(Log::System, SCE_REG_ERROR_CATEGORY_NOT_FOUND); + } + + Memory::WriteUnchecked_U32(count, numAddr); + return hleLogInfo(Log::System, 0); +} + +int sceRegGetKeys(int catHandle, u32 bufAddr, int num) { + auto iter = g_openCategories.find(catHandle); + if (iter == g_openCategories.end()) { + return hleLogError(Log::System, 0, "Not an open category"); + } + + if (!Memory::IsValidRange(bufAddr, num * 27)) { + return hleLogError(Log::System, -1, "bad output addr"); + } + + const int addrLen = 27; // for some reason + + int count = 0; + const KeyValue *keyvals = LookupCategory(iter->second.path, &count); + if (!keyvals) { + return hleLogWarning(Log::System, SCE_REG_ERROR_CATEGORY_NOT_FOUND); + } + + count = std::min(count, num); + + for (int i = 0; i < num; i++) { + char *dest = (char *)Memory::GetPointerWrite(bufAddr + i * 27); + strncpy(dest, keyvals[i].name.c_str(), 27); + } + + return hleLogInfo(Log::System, 0); +} + +int sceRegGetKeyInfo(int catHandle, const char *name, u32 outKeyHandleAddr, u32 outTypeAddr, u32 outSizeAddr) { + auto iter = g_openCategories.find(catHandle); + if (iter == g_openCategories.end()) { + return hleLogError(Log::System, 0, "Not found"); + } + + int count = 0; + const KeyValue *keyvals = LookupCategory(iter->second.path, &count); + if (!keyvals) { + return hleLogWarning(Log::System, SCE_REG_ERROR_CATEGORY_NOT_FOUND); + } + + for (int i = 0; i < count; i++) { + if (equals(keyvals[i].name, name)) { + // Found it! + if (Memory::IsValid4AlignedAddress(outKeyHandleAddr)) { + // Let's just make the index the key handle. + Memory::WriteUnchecked_U32(i, outKeyHandleAddr); + } + if (Memory::IsValid4AlignedAddress(outTypeAddr)) { + // Let's just make the index the key handle. + Memory::WriteUnchecked_U32((int)keyvals[i].type, outTypeAddr); + } + int size = 0; + if (Memory::IsValid4AlignedAddress(outSizeAddr)) { + switch (keyvals[i].type) { + case ValueType::BIN: size = (int)keyvals[i].strValue.size(); break; + case ValueType::STR: size = (int)keyvals[i].strValue.size() + 1; break; + case ValueType::DIR: size = 0; break; + case ValueType::INT: size = 4; break; + default: break; + } + // Let's just make the index the key handle. + Memory::WriteUnchecked_U32(size, outSizeAddr); + } + return hleLogInfo(Log::System, 0, "handle: %d type: %d size: %d", i, (int)keyvals[i].type, size); + } + } + + return hleLogWarning(Log::System, -1, "key with name '%s' not found", name); +} + +int sceRegGetKeyInfoByName(int catHandle, const char *name, u32 typeAddr, u32 sizeAddr) { + return hleLogError(Log::System, 0); +} + +int sceRegGetKeyValue(int catHandle, int keyHandle, u32 bufAddr, u32 size) { + if (!Memory::IsValidRange(bufAddr, size)) { + return -1; + } + + auto iter = g_openCategories.find(catHandle); + if (iter == g_openCategories.end()) { + return hleLogError(Log::System, 0, "Not found"); + } + + int count = 0; + const KeyValue *keyvals = LookupCategory(iter->second.path, &count); + if (!keyvals) { + return hleLogWarning(Log::System, SCE_REG_ERROR_CATEGORY_NOT_FOUND); + } + + if (keyHandle < 0 || keyHandle >= count) { + return hleLogWarning(Log::System, SCE_REG_ERROR_CATEGORY_NOT_FOUND); + } + + const KeyValue &keyval = keyvals[keyHandle]; + switch (keyval.type) { + case ValueType::BIN: + Memory::MemcpyUnchecked(bufAddr, keyval.strValue.data(), std::min(size, (u32)keyval.strValue.size())); + return hleLogInfo(Log::System, 0); + case ValueType::STR: + Memory::MemcpyUnchecked(bufAddr, keyval.strValue.data(), std::min(size, (u32)keyval.strValue.size() + 1)); + return hleLogInfo(Log::System, 0, "value: '%s'", keyval.strValue.data()); + case ValueType::INT: + Memory::WriteUnchecked_U32(keyval.intValue, bufAddr); + return hleLogInfo(Log::System, 0, "value: %d (0x%08x)", keyval.intValue, keyval.intValue); + case ValueType::DIR: + case ValueType::FAIL: + default: + // Return an error? + return hleLogWarning(Log::System, 0, "Unexpected type for sceRegGetKeyValue"); + } +} + +int sceRegGetKeyValueByName(int catHandle, const char *name, u32 bufAddr, u32 size) { + return hleLogError(Log::System, 0); +} + +int sceRegSetKeyValue(int catHandle, const char *name, u32 bufAddr, u32 size) { + return hleLogError(Log::System, 0); +} + +int sceRegCreateKey(int catHandle, const char *name, int type, u32 size) { + return hleLogError(Log::System, 0); +} + +const HLEFunction sceReg[] = { + { 0x92E41280, &WrapI_UIU, "sceRegOpenRegistry", 'i', "xix" }, + { 0xFA8A5739, &WrapI_I, "sceRegCloseRegistry", 'i', "i" }, + { 0xDEDA92BF, &WrapI_U, "sceRegRemoveRegistry", 'i', "x" }, + { 0x1D8A762E, &WrapI_ICIU, "sceRegOpenCategory", 'i', "isix" }, + { 0x0CAE832B, &WrapI_I, "sceRegCloseCategory", 'i', "i" }, + { 0x39461B4D, &WrapI_I, "sceRegFlushRegistry", 'i', "i" }, + { 0x0D69BF40, &WrapI_I, "sceRegFlushCategory", 'i', "i" }, + { 0x57641A81, &WrapI_ICIU, "sceRegCreateKey", 'i', "isix" }, + { 0x17768E14, &WrapI_ICUU, "sceRegSetKeyValue", 'i', "isxx" }, + { 0xD4475AA8, &WrapI_ICUUU, "sceRegGetKeyInfo", 'i', "isxxx" }, + { 0x28A8E98A, &WrapI_IIUU, "sceRegGetKeyValue", 'i', "iixx" }, + { 0x2C0DB9DD, &WrapI_IU, "sceRegGetKeysNum", 'i', "ix" }, + { 0x2D211135, &WrapI_IUI, "sceRegGetKeys", 'i', "ipi" }, + { 0xC5768D02, &WrapI_ICUU, "sceRegGetKeyInfoByName", 'i', "isxx" }, + { 0x30BE0259, &WrapI_ICUU, "sceRegGetKeyValueByName", 'i', "isxx" }, + // { 0x4CA16893, &WrapI_I, "sceRegRemoveCategory", 'i', "i" }, + // { 0x3615BC87, &WrapI_I, "sceRegRemoveKey", 'i', "i" }, + // { 0x9B25EDF1, &WrapI_I, "sceRegExit", 'i', "i" }, +}; + +void Register_sceReg() { + RegisterHLEModule("sceReg", ARRAY_SIZE(sceReg), sceReg); +} diff --git a/Core/HLE/sceReg.h b/Core/HLE/sceReg.h new file mode 100644 index 0000000000..8cae0a7400 --- /dev/null +++ b/Core/HLE/sceReg.h @@ -0,0 +1,9 @@ +#pragma once + +class PointerWrap; + +void Register_sceReg(); + +void __RegInit(); +void __RegShutdown(); +void __RegDoState(PointerWrap &p); diff --git a/UI/ImDebugger/ImDebugger.cpp b/UI/ImDebugger/ImDebugger.cpp index 1317ec92bd..3774512ef3 100644 --- a/UI/ImDebugger/ImDebugger.cpp +++ b/UI/ImDebugger/ImDebugger.cpp @@ -1500,6 +1500,7 @@ static void DrawModules(const MIPSDebugInterface *debug, ImConfig &cfg, ImContro ImGui::PushStyleColor(ImGuiCol_Text, IM_COL32(255, 255, 255, 170)); } ImGui::Text("%s %d.%d (%s)\n", mod->GetName(), mod->nm.version[1], mod->nm.version[0], mod->isFake ? "FAKE/HLE" : "normal"); + ImGui::Text("Attr: %08x (%s)\n", (mod->nm.attribute & 0x1000) ? "Kernel" : "User"); char buf[512]; mod->GetLongInfo(buf, sizeof(buf)); ImGui::TextUnformatted(buf); diff --git a/UWP/CoreUWP/CoreUWP.vcxproj b/UWP/CoreUWP/CoreUWP.vcxproj index f26a67573e..b68c89d8b7 100644 --- a/UWP/CoreUWP/CoreUWP.vcxproj +++ b/UWP/CoreUWP/CoreUWP.vcxproj @@ -182,6 +182,7 @@ + @@ -447,6 +448,7 @@ + diff --git a/android/jni/Android.mk b/android/jni/Android.mk index 3a8bb39c7e..6dfeb08e05 100644 --- a/android/jni/Android.mk +++ b/android/jni/Android.mk @@ -722,6 +722,7 @@ EXEC_AND_LIB_FILES := \ $(SRC)/Core/HLE/sceParseHttp.cpp \ $(SRC)/Core/HLE/sceParseUri.cpp \ $(SRC)/Core/HLE/scePower.cpp \ + $(SRC)/Core/HLE/sceReg.cpp \ $(SRC)/Core/HLE/sceRtc.cpp \ $(SRC)/Core/HLE/scePsmf.cpp \ $(SRC)/Core/HLE/sceSas.cpp \ diff --git a/libretro/Makefile.common b/libretro/Makefile.common index 933bfeac07..0155518796 100644 --- a/libretro/Makefile.common +++ b/libretro/Makefile.common @@ -759,6 +759,7 @@ SOURCES_CXX += \ $(COREDIR)/HLE/sceParseUri.cpp \ $(COREDIR)/HLE/scePower.cpp \ $(COREDIR)/HLE/scePsmf.cpp \ + $(COREDIR)/HLE/sceReg.cpp \ $(COREDIR)/HLE/sceRtc.cpp \ $(COREDIR)/HLE/sceSas.cpp \ $(COREDIR)/HLE/sceSsl.cpp \ diff --git a/pspautotests b/pspautotests index 4e317b856c..3ce1862628 160000 --- a/pspautotests +++ b/pspautotests @@ -1 +1 @@ -Subproject commit 4e317b856c2e62741d018d553df1c8181267741c +Subproject commit 3ce1862628fdb3c332c2400e0089a46f2a73f591 diff --git a/test.py b/test.py index 164ad8c356..5cb399db3c 100755 --- a/test.py +++ b/test.py @@ -222,6 +222,7 @@ tests_good = [ "misc/sdkver", "misc/testgp", "misc/timeconv", + "misc/reg", "mstick/mstick", "power/cpu", "power/power",