diff --git a/kernel/orbis/include/orbis/KernelContext.hpp b/kernel/orbis/include/orbis/KernelContext.hpp index 4e4334601..f081cd2c4 100644 --- a/kernel/orbis/include/orbis/KernelContext.hpp +++ b/kernel/orbis/include/orbis/KernelContext.hpp @@ -137,6 +137,7 @@ public: rx::shared_mutex regMgrMtx; kmap regMgrInt; + kmap> regMgrStr; std::vector> dialogs{}; FwType fwType = FwType::Unknown; diff --git a/kernel/orbis/src/sys/sys_sce.cpp b/kernel/orbis/src/sys/sys_sce.cpp index 86c778ebe..a63be76b1 100644 --- a/kernel/orbis/src/sys/sys_sce.cpp +++ b/kernel/orbis/src/sys/sys_sce.cpp @@ -128,6 +128,107 @@ orbis::sys_mtypeprotect(Thread *thread, uintptr_t addr, size_t len, return vmem::setTypeAndProtect(thread->tproc, range, type, prot); } + +struct RegMgrComKey { + std::uint8_t data[4]{}; + std::uint8_t table{}; + std::uint8_t index{}; + + [[nodiscard]] static constexpr RegMgrComKey unpack(std::uint64_t key) { + RegMgrComKey result; + result.data[0] = static_cast(key & 0xff); + result.data[1] = static_cast((key >> 8) & 0xff); + result.data[2] = static_cast((key >> 16) & 0xff); + result.data[3] = static_cast((key >> 24) & 0xff); + result.table = static_cast(key >> 32); + result.index = static_cast(key >> 40); + return result; + } + + [[nodiscard]] constexpr std::uint64_t pack() const { + std::uint64_t result = data[0]; + result |= static_cast(data[0]) << 0; + result |= static_cast(data[1]) << 8; + result |= static_cast(data[2]) << 16; + result |= static_cast(data[3]) << 24; + result |= static_cast(table) << 32; + result |= static_cast(index) << 40; + result |= static_cast(calcChecksum()) << 48; + return result; + } + + [[nodiscard]] constexpr bool validate(std::uint64_t key) const { + return calcChecksum() == static_cast(key >> 48); + } + + [[nodiscard]] constexpr std::uint16_t calcChecksum() const { + return std::uint16_t(data[0]) + data[1] + data[2] + data[3] + table * index; + } +}; + +constexpr std::int32_t regMgrGetRegId(std::uint64_t encoded) { + constexpr std::uint8_t kRegMgrScrambSdk[] = { + 0x6b, 0xe8, 0x98, 0x03, 0x9a, 0x70, 0x23, 0x5a, + 0x63, 0xee, 0xf5, 0x7b, 0xff, 0xa4, 0x4c, 0x8c, + }; + constexpr std::uint8_t kRegMgrScrambLib[] = { + 0x14, 0xee, 0xde, 0xe1, 0x80, 0xac, 0xf3, 0x78, + 0x47, 0x43, 0xdb, 0x40, 0x93, 0xdd, 0xb1, 0x34, + }; + + auto key = RegMgrComKey::unpack(encoded); + auto slot = key.index ^ 0x6b; + + const std::uint8_t *table = kRegMgrScrambSdk; + + switch ((key.table ^ table[0xf - slot])) { + case 0x19: + table = kRegMgrScrambLib; + break; + case 0x72: + table = kRegMgrScrambSdk; + break; + + default: + return 0x800d0205; + } + + std::uint32_t decodedKey = (key.data[1] ^ table[slot + 0]) * 0x1000000 + + (key.data[3] ^ table[slot + 1]) * 0x10000 + + (key.data[2] ^ table[slot + 2]) * 0x100 + + (key.data[0] ^ table[slot + 3]); + + return decodedKey; +} + +struct RegMgrComInt { + uint64_t encodedId; + uint32_t unk; + uint32_t value; +}; + +static_assert(sizeof(RegMgrComInt) == 0x10); + +struct RegMgrComStr { + uint64_t encodedId; + uint32_t unk; + uint32_t padding; + uint64_t len; + rx::StaticCString<2048> string; +}; + +static_assert(sizeof(RegMgrComStr) == 0x818); + +struct RegMgrComBin { + uint64_t encodedId; + uint32_t unk; + uint32_t padding; + uint64_t len; + std::uint8_t data[2048]; +}; + +static_assert(sizeof(RegMgrComBin) == 0x818); + orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, uint32_t id, ptr result, ptr value, uint64_t len) { @@ -146,6 +247,7 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, g_context->regMgrInt[id] = *(std::uint32_t *)value; return {}; } + if (op == 2) { // get int if (len != sizeof(uint32_t)) { @@ -158,10 +260,20 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, thread->where(); // return ErrorCode::NOENT; return uwrite((ptr)value, 0u); - return {}; } - return uwrite((ptr)value, intValIt->second); + return uwrite((ptr)value, intValIt->second); + } + + if (op == 3) { + // set string + + rx::StaticCString<2048> string; + ORBIS_RET_ON_ERROR(ureadString( + string.data(), std::min(string.max_size(), len), ptr(value))); + + ORBIS_LOG_WARNING(__FUNCTION__, op, id, string.data()); + g_context->regMgrStr[id] = string; return {}; } @@ -173,63 +285,146 @@ orbis::SysResult orbis::sys_regmgr_call(Thread *thread, uint32_t op, return ErrorCode::INVAL; } - std::memset(value, 0, len); + auto it = g_context->regMgrStr.find(id); + if (it == g_context->regMgrStr.end()) { + ORBIS_LOG_ERROR("registry string entry not exists", op, id); + thread->where(); + std::memset(value, 0, len); + return {}; + } - ORBIS_LOG_ERROR(__FUNCTION__, op, id, len); + if (it->second.length() > len) { + return ErrorCode(-0x800d0606); + } + + ORBIS_LOG_WARNING(__FUNCTION__, op, id, len, it->second.data()); thread->where(); + ORBIS_RET_ON_ERROR( + uwriteRaw(value, it->second.data(), it->second.length() + 1)); + + return {}; + } + + if (op == 24) { + // com: set int + RegMgrComInt _request; + ORBIS_RET_ON_ERROR(uread(_request, ptr(value))); + + auto id = regMgrGetRegId(_request.encodedId); + + if (id < 0) { + return ErrorCode(-id); + } + + ORBIS_LOG_WARNING(__FUNCTION__, op, id, _request.unk, _request.value); + g_context->regMgrInt[id] = _request.value; + return {}; } if (op == 25) { - struct nonsys_int { - union { - uint64_t encoded_id; - struct { - uint8_t data[4]; - uint8_t table; - uint8_t index; - uint16_t checksum; - } encoded_id_parts; - }; - uint32_t unk; - uint32_t value; - }; + // com: get int + RegMgrComInt _request; + ORBIS_RET_ON_ERROR(uread(_request, ptr(value))); - auto int_value = reinterpret_cast(value); - ORBIS_LOG_TODO( - __FUNCTION__, int_value->encoded_id, - int_value->encoded_id_parts.data[0], - int_value->encoded_id_parts.data[1], - int_value->encoded_id_parts.data[2], - int_value->encoded_id_parts.data[3], int_value->encoded_id_parts.table, - int_value->encoded_id_parts.index, int_value->encoded_id_parts.checksum, - int_value->unk, int_value->value); + auto id = regMgrGetRegId(_request.encodedId); - // HACK: set default system language and gamepad layout to US/EU region - // 0x12356328ECF5617B -> language where is 0 is Japanese, 1 is English - // 0x22666251FE7BECFF -> confirm button layout, 0 is Circle, 1 is Cross - if (int_value->encoded_id == 0x12356328ECF5617B || - int_value->encoded_id == 0x22666251FE7BECFF) { - int_value->value = 1; - return {}; + if (id < 0) { + return ErrorCode(-id); } - if (int_value->encoded_id == 0x1ac46343411b3f40) { - int_value->value = 0; // allow debug libraries - return {}; + auto it = g_context->regMgrInt.find(id); + if (it == g_context->regMgrInt.end()) { + ORBIS_LOG_ERROR("registry int entry not exists", op, id); + thread->where(); + // return ErrorCode::NOENT; + _request.value = 0; + } else { + _request.value = it->second; } - if (int_value->encoded_id == 0x29b56169422aa3dd) { - int_value->value = 2; - return {}; - } - - // 0x503f69bde385a6ac // allow loading from dev machine? - // 0x2d946f62aef8f878 - - int_value->value = 0; + ORBIS_LOG_WARNING(__FUNCTION__, op, id, _request.unk, _request.value); + return uwrite((ptr)value, _request); } + if (op == 26) { + // com: set string + RegMgrComStr _request; + ORBIS_RET_ON_ERROR(uread(_request, ptr(value))); + + auto id = regMgrGetRegId(_request.encodedId); + + if (id < 0) { + return ErrorCode(-id); + } + + if (_request.len > 2048 || _request.string[_request.len - 1] != '\0' || + _request.string.length() + 1 != _request.len) { + return ErrorCode(-0x800d0205); + } + + ORBIS_LOG_WARNING(__FUNCTION__, op, id, _request.unk, + _request.string.data()); + g_context->regMgrStr[id] = _request.string; + return {}; + } + + if (op == 27) { + // com: get string + RegMgrComStr _request; + ORBIS_RET_ON_ERROR(uread(_request, ptr(value))); + + auto id = regMgrGetRegId(_request.encodedId); + + if (id < 0) { + return ErrorCode(-id); + } + + auto it = g_context->regMgrStr.find(id); + if (it == g_context->regMgrStr.end()) { + ORBIS_LOG_ERROR("registry string entry not exists", op, id); + thread->where(); + _request.string = ""; + } else { + _request.len = it->second.length(); + _request.string = it->second; + } + + ORBIS_LOG_WARNING(__FUNCTION__, op, id, _request.string.data()); + return uwrite((ptr)value, _request); + } + + if (op == 28) { + // com: set bin + RegMgrComBin _request; + ORBIS_RET_ON_ERROR(uread(_request, ptr(value))); + + auto id = regMgrGetRegId(_request.encodedId); + + if (id < 0) { + return ErrorCode(-id); + } + + ORBIS_LOG_TODO(__FUNCTION__, op, id, _request.unk); + return {}; + } + + if (op == 29) { + // com: get bin + RegMgrComBin _request; + ORBIS_RET_ON_ERROR(uread(_request, ptr(value))); + + auto id = regMgrGetRegId(_request.encodedId); + + if (id < 0) { + return ErrorCode(-id); + } + + ORBIS_LOG_TODO(__FUNCTION__, op, id, _request.unk); + return {}; + } + + ORBIS_LOG_TODO(__FUNCTION__, op, id); return {}; } orbis::SysResult orbis::sys_jitshm_create(Thread *thread /* TODO */) {