mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
libs: port entitlement requests and fixed-refresh VRR status
This commit is contained in:
@@ -145,6 +145,7 @@ struct VideoOutOutputStatus {
|
||||
uint64_t flags = 0;
|
||||
uint64_t reserved[3] = {};
|
||||
};
|
||||
static_assert(sizeof(VideoOutOutputStatus) == 0x30); // Also used by VideoOutVrrStatus.
|
||||
|
||||
struct VideoOutOutputOptions {
|
||||
uint32_t internalData[16] = {};
|
||||
|
||||
+3
-146
@@ -18,6 +18,9 @@
|
||||
|
||||
namespace Libs {
|
||||
|
||||
namespace LibNpEntitlementAccess {
|
||||
void InitNet_1_NpEntitlementAccess(Loader::SymbolDatabase* s);
|
||||
}
|
||||
namespace LibNpTrophy2 {
|
||||
void InitNet_1_NpTrophy2(Loader::SymbolDatabase* s);
|
||||
}
|
||||
@@ -1663,152 +1666,6 @@ LIB_DEFINE(InitNet_1_NpSessionSignaling) {
|
||||
|
||||
} // namespace LibNpSessionSignaling
|
||||
|
||||
namespace LibNpEntitlementAccess {
|
||||
|
||||
LIB_VERSION("NpEntitlementAccess", 1, "NpEntitlementAccess", 1, 1);
|
||||
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER = -2122514430; /* 0x817D0002 */
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT = -2122514425; /* 0x817D0007 */
|
||||
constexpr uint32_t NP_ENTITLEMENT_ACCESS_SKU_FLAG_FULL = 3;
|
||||
|
||||
struct NpEntitlementAccessInitParam {
|
||||
char reserved[32];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessBootParam {
|
||||
char reserved[32];
|
||||
};
|
||||
|
||||
struct NpUnifiedEntitlementLabel {
|
||||
char data[17];
|
||||
char padding[3];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessAddcontEntitlementInfo {
|
||||
NpUnifiedEntitlementLabel entitlement_label;
|
||||
uint32_t package_type;
|
||||
uint32_t download_status;
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessEntitlementKey {
|
||||
uint8_t data[16];
|
||||
};
|
||||
|
||||
static constexpr NpEntitlementAccessAddcontEntitlementInfo NP_ENTITLEMENT_ACCESS_ADDON_LIST[] = {
|
||||
{{{"85y-je"}, {}}, 3, 4}, // GTA V hash 0xf4315381
|
||||
{{{"5d5c48"}, {}}, 3, 4}, // GTA V hash 0x961c34b0
|
||||
{{{"_mtqu6"}, {}}, 3, 4}, // GTA V hash 0x9cd1bcad
|
||||
};
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessInitialize(
|
||||
const NpEntitlementAccessInitParam* init_param, NpEntitlementAccessBootParam* boot_param) {
|
||||
PRINT_NAME();
|
||||
|
||||
if (init_param == nullptr || boot_param == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
memset(boot_param, 0, sizeof(*boot_param));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetSkuFlag(uint32_t* sku_flag) {
|
||||
PRINT_NAME();
|
||||
|
||||
if (sku_flag == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
*sku_flag = NP_ENTITLEMENT_ACCESS_SKU_FLAG_FULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetAddcontEntitlementInfoList(
|
||||
uint32_t service_label, NpEntitlementAccessAddcontEntitlementInfo* list, uint32_t list_num,
|
||||
uint32_t* hit_num) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t service_label = %" PRIu32 "\n", service_label);
|
||||
LOGF("\t list = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(list));
|
||||
LOGF("\t list_num = %" PRIu32 "\n", list_num);
|
||||
LOGF("\t hit_num = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(hit_num));
|
||||
|
||||
if (hit_num == nullptr || (list == nullptr && list_num != 0)) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
*hit_num = static_cast<uint32_t>(sizeof(NP_ENTITLEMENT_ACCESS_ADDON_LIST) /
|
||||
sizeof(NP_ENTITLEMENT_ACCESS_ADDON_LIST[0]));
|
||||
|
||||
if (list != nullptr && list_num != 0) {
|
||||
memset(list, 0, sizeof(*list) * list_num);
|
||||
|
||||
const auto copy_num = (list_num < *hit_num ? list_num : *hit_num);
|
||||
for (uint32_t i = 0; i < copy_num; i++) {
|
||||
list[i] = NP_ENTITLEMENT_ACCESS_ADDON_LIST[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetAddcontEntitlementInfo(
|
||||
uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label,
|
||||
NpEntitlementAccessAddcontEntitlementInfo* info) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t service_label = %" PRIu32 "\n", service_label);
|
||||
LOGF("\t entitlement_label = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(entitlement_label));
|
||||
LOGF("\t info = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(info));
|
||||
|
||||
if (entitlement_label == nullptr || info == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
for (const auto& entitlement: NP_ENTITLEMENT_ACCESS_ADDON_LIST) {
|
||||
if (strncmp(entitlement_label->data, entitlement.entitlement_label.data,
|
||||
sizeof(entitlement_label->data)) == 0) {
|
||||
*info = entitlement;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetEntitlementKey(
|
||||
uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label,
|
||||
NpEntitlementAccessEntitlementKey* key) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t service_label = %" PRIu32 "\n"
|
||||
"\t entitlement_label = 0x%016" PRIx64 "\n"
|
||||
"\t key = 0x%016" PRIx64 "\n",
|
||||
service_label, reinterpret_cast<uint64_t>(entitlement_label),
|
||||
reinterpret_cast<uint64_t>(key));
|
||||
|
||||
if (entitlement_label == nullptr || key == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT;
|
||||
}
|
||||
|
||||
LIB_DEFINE(InitNet_1_NpEntitlementAccess) {
|
||||
LIB_FUNC("jO8DM8oyego", LibNpEntitlementAccess::NpEntitlementAccessInitialize);
|
||||
LIB_FUNC("lPDO62PpJIA", LibNpEntitlementAccess::NpEntitlementAccessGetSkuFlag);
|
||||
LIB_FUNC("TFyU+KFBv54",
|
||||
LibNpEntitlementAccess::NpEntitlementAccessGetAddcontEntitlementInfoList);
|
||||
LIB_FUNC("xddD23+8TfQ", LibNpEntitlementAccess::NpEntitlementAccessGetAddcontEntitlementInfo);
|
||||
LIB_FUNC("5LiMEPuW0DQ", LibNpEntitlementAccess::NpEntitlementAccessGetEntitlementKey);
|
||||
}
|
||||
|
||||
} // namespace LibNpEntitlementAccess
|
||||
|
||||
namespace LibNpAuth {
|
||||
|
||||
LIB_VERSION("NpAuth", 1, "NpAuth", 1, 1);
|
||||
|
||||
@@ -0,0 +1,494 @@
|
||||
#include "common/abi.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "libs/libs.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
|
||||
#include <atomic>
|
||||
#include <cinttypes>
|
||||
#include <cstddef>
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <limits>
|
||||
#include <map>
|
||||
#include <mutex>
|
||||
|
||||
namespace Libs {
|
||||
|
||||
namespace LibNpEntitlementAccess {
|
||||
|
||||
LIB_VERSION("NpEntitlementAccess", 1, "NpEntitlementAccess", 1, 1);
|
||||
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED = -2122514431; // 0x817D0001
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_OUT_OF_MEMORY = -2122514416; // 0x817D0010
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_REQUEST_NOT_FOUND = -2122514411; // 0x817D0015
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER = -2122514430; /* 0x817D0002 */
|
||||
constexpr int NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT = -2122514425; /* 0x817D0007 */
|
||||
constexpr uint32_t NP_ENTITLEMENT_ACCESS_SKU_FLAG_FULL = 3;
|
||||
constexpr uint32_t NP_ENTITLEMENT_ACCESS_GAME_TRIALS_FLAG_OFF = 0;
|
||||
constexpr int32_t NP_ENTITLEMENT_ACCESS_INVALID_OFFSET = -1;
|
||||
constexpr int32_t NP_ENTITLEMENT_ACCESS_ENTITLEMENT_INFO_LIST_MAX_SIZE = 100;
|
||||
|
||||
struct NpEntitlementAccessInitParam {
|
||||
char reserved[32];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessBootParam {
|
||||
char reserved[32];
|
||||
};
|
||||
|
||||
struct NpUnifiedEntitlementLabel {
|
||||
char data[17];
|
||||
char padding[3];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessAddcontEntitlementInfo {
|
||||
NpUnifiedEntitlementLabel entitlement_label;
|
||||
uint32_t package_type;
|
||||
uint32_t download_status;
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessEntitlementKey {
|
||||
uint8_t data[16];
|
||||
};
|
||||
|
||||
struct NpServiceEntitlementLabel {
|
||||
char data[7];
|
||||
char padding[13];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessTransactionId {
|
||||
char data[65];
|
||||
char padding[7];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessRequestEntitlementInfoListParam {
|
||||
size_t size;
|
||||
uint32_t entitlement_type;
|
||||
int32_t offset;
|
||||
int32_t limit;
|
||||
uint32_t sort;
|
||||
uint32_t direction;
|
||||
uint32_t package_type;
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessUnifiedEntitlementInfo {
|
||||
NpUnifiedEntitlementLabel entitlement_label;
|
||||
uint64_t active_date;
|
||||
uint64_t inactive_date;
|
||||
uint32_t entitlement_type;
|
||||
int32_t use_count;
|
||||
int32_t use_limit;
|
||||
uint32_t package_type;
|
||||
bool active_flag;
|
||||
int8_t reserved[3];
|
||||
};
|
||||
|
||||
struct NpEntitlementAccessServiceEntitlementInfo {
|
||||
NpServiceEntitlementLabel entitlement_label;
|
||||
uint64_t active_date;
|
||||
uint64_t inactive_date;
|
||||
uint32_t entitlement_type;
|
||||
int32_t use_count;
|
||||
int32_t use_limit;
|
||||
uint32_t reserved1;
|
||||
bool active_flag;
|
||||
bool is_consumable;
|
||||
int8_t reserved2[2];
|
||||
};
|
||||
|
||||
static_assert(sizeof(NpUnifiedEntitlementLabel) == 20);
|
||||
static_assert(sizeof(NpServiceEntitlementLabel) == 20);
|
||||
static_assert(sizeof(NpEntitlementAccessTransactionId) == 72);
|
||||
static_assert(sizeof(NpEntitlementAccessRequestEntitlementInfoListParam) == 32);
|
||||
static_assert(sizeof(NpEntitlementAccessUnifiedEntitlementInfo) == 64);
|
||||
static_assert(offsetof(NpEntitlementAccessUnifiedEntitlementInfo, active_date) == 24);
|
||||
static_assert(sizeof(NpEntitlementAccessServiceEntitlementInfo) == 64);
|
||||
static_assert(offsetof(NpEntitlementAccessServiceEntitlementInfo, active_date) == 24);
|
||||
|
||||
enum class EntitlementRequestKind { UnifiedInfo, UnifiedList, ServiceList, ConsumeUnified };
|
||||
|
||||
struct EntitlementRequest {
|
||||
EntitlementRequestKind kind;
|
||||
int32_t result;
|
||||
};
|
||||
|
||||
static std::atomic<bool> g_np_entitlement_initialized {false};
|
||||
static std::mutex g_np_entitlement_request_mutex;
|
||||
static uint64_t g_np_entitlement_next_request_id = 1;
|
||||
static uint64_t g_np_entitlement_next_transaction = 1;
|
||||
static std::map<int64_t, EntitlementRequest> g_np_entitlement_requests;
|
||||
|
||||
static int np_entitlement_create_request(EntitlementRequestKind kind, int32_t result,
|
||||
int64_t* request_id) {
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (request_id == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
std::scoped_lock lock(g_np_entitlement_request_mutex);
|
||||
if (g_np_entitlement_next_request_id >
|
||||
static_cast<uint64_t>(std::numeric_limits<int64_t>::max())) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
const auto id = static_cast<int64_t>(g_np_entitlement_next_request_id);
|
||||
g_np_entitlement_requests.emplace(id, EntitlementRequest {kind, result});
|
||||
++g_np_entitlement_next_request_id;
|
||||
*request_id = id;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int np_entitlement_poll_request(int64_t request_id, EntitlementRequestKind kind,
|
||||
int32_t* result) {
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (result == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
std::scoped_lock lock(g_np_entitlement_request_mutex);
|
||||
const auto it = g_np_entitlement_requests.find(request_id);
|
||||
if (it == g_np_entitlement_requests.end()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_REQUEST_NOT_FOUND;
|
||||
}
|
||||
if (it->second.kind != kind) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
*result = it->second.result;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static constexpr NpEntitlementAccessAddcontEntitlementInfo NP_ENTITLEMENT_ACCESS_ADDON_LIST[] = {
|
||||
{{{"85y-je"}, {}}, 3, 4}, // GTA V hash 0xf4315381
|
||||
{{{"5d5c48"}, {}}, 3, 4}, // GTA V hash 0x961c34b0
|
||||
{{{"_mtqu6"}, {}}, 3, 4}, // GTA V hash 0x9cd1bcad
|
||||
};
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessInitialize(
|
||||
const NpEntitlementAccessInitParam* init_param, NpEntitlementAccessBootParam* boot_param) {
|
||||
PRINT_NAME();
|
||||
|
||||
if (init_param == nullptr || boot_param == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
std::scoped_lock lock(g_np_entitlement_request_mutex);
|
||||
memset(boot_param, 0, sizeof(*boot_param));
|
||||
g_np_entitlement_initialized.store(true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetSkuFlag(uint32_t* sku_flag) {
|
||||
PRINT_NAME();
|
||||
|
||||
if (sku_flag == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
*sku_flag = NP_ENTITLEMENT_ACCESS_SKU_FLAG_FULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetGameTrialsFlag(uint32_t* flag) {
|
||||
PRINT_NAME();
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (flag == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
*flag = NP_ENTITLEMENT_ACCESS_GAME_TRIALS_FLAG_OFF;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI
|
||||
NpEntitlementAccessGenerateTransactionId(NpEntitlementAccessTransactionId* transaction_id) {
|
||||
PRINT_NAME();
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (transaction_id == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
std::scoped_lock lock(g_np_entitlement_request_mutex);
|
||||
if (g_np_entitlement_next_transaction == 0) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_OUT_OF_MEMORY;
|
||||
}
|
||||
memset(transaction_id, 0, sizeof(*transaction_id));
|
||||
std::snprintf(transaction_id->data, sizeof(transaction_id->data), "6b797479%024" PRIx64,
|
||||
g_np_entitlement_next_transaction++);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
np_entitlement_request_list(EntitlementRequestKind kind, const void* list, uint32_t list_num,
|
||||
const NpEntitlementAccessRequestEntitlementInfoListParam* param,
|
||||
int64_t* request_id) {
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (param == nullptr || request_id == nullptr || (list == nullptr && list_num != 0)) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
if (param->size != sizeof(*param) || param->offset < 0 || param->limit < 1 ||
|
||||
param->limit > NP_ENTITLEMENT_ACCESS_ENTITLEMENT_INFO_LIST_MAX_SIZE || param->sort > 1 ||
|
||||
param->direction > 2) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
const bool unified = kind == EntitlementRequestKind::UnifiedList;
|
||||
if (param->entitlement_type != (unified ? 2u : 1u) ||
|
||||
(unified
|
||||
? (param->package_type != 0 && (param->package_type < 4 || param->package_type > 6))
|
||||
: param->package_type != 0)) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
// The offline implementation has no server entitlements. These completed requests
|
||||
// remain available to their matching poll function until explicitly deleted.
|
||||
return np_entitlement_create_request(kind, 0, request_id);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessRequestUnifiedEntitlementInfoList(
|
||||
int32_t user_id, uint32_t service_label, const NpUnifiedEntitlementLabel* list,
|
||||
uint32_t list_num, const NpEntitlementAccessRequestEntitlementInfoListParam* param,
|
||||
int64_t* request_id) {
|
||||
PRINT_NAME();
|
||||
LOGF("\t user_id = %" PRId32 ", service_label = %" PRIu32 "\n", user_id, service_label);
|
||||
return np_entitlement_request_list(EntitlementRequestKind::UnifiedList, list, list_num, param,
|
||||
request_id);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessRequestServiceEntitlementInfoList(
|
||||
int32_t user_id, uint32_t service_label, const NpServiceEntitlementLabel* list,
|
||||
uint32_t list_num, const NpEntitlementAccessRequestEntitlementInfoListParam* param,
|
||||
int64_t* request_id) {
|
||||
PRINT_NAME();
|
||||
LOGF("\t user_id = %" PRId32 ", service_label = %" PRIu32 "\n", user_id, service_label);
|
||||
return np_entitlement_request_list(EntitlementRequestKind::ServiceList, list, list_num, param,
|
||||
request_id);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessRequestUnifiedEntitlementInfo(
|
||||
int32_t user_id, uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label,
|
||||
int64_t* request_id) {
|
||||
PRINT_NAME();
|
||||
LOGF("\t user_id = %" PRId32 ", service_label = %" PRIu32 "\n", user_id, service_label);
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (entitlement_label == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
return np_entitlement_create_request(EntitlementRequestKind::UnifiedInfo,
|
||||
NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT, request_id);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessRequestConsumeUnifiedEntitlement(
|
||||
int32_t user_id, uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label,
|
||||
const NpEntitlementAccessTransactionId* transaction_id, int32_t use_count,
|
||||
int64_t* request_id) {
|
||||
PRINT_NAME();
|
||||
LOGF("\t user_id = %" PRId32 ", service_label = %" PRIu32 ", use_count = %" PRId32 "\n",
|
||||
user_id, service_label, use_count);
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (entitlement_label == nullptr || transaction_id == nullptr || use_count <= 0) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
return np_entitlement_create_request(EntitlementRequestKind::ConsumeUnified,
|
||||
NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT, request_id);
|
||||
}
|
||||
|
||||
template <typename Info>
|
||||
static int np_entitlement_poll_list(int64_t request_id, EntitlementRequestKind kind,
|
||||
int32_t* result, Info* list, uint32_t list_num,
|
||||
uint32_t* hit_num, int32_t* next_offset,
|
||||
int32_t* previous_offset) {
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (result == nullptr || hit_num == nullptr || next_offset == nullptr ||
|
||||
previous_offset == nullptr || (list == nullptr && list_num != 0)) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
if (const int ret = np_entitlement_poll_request(request_id, kind, result); ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
*hit_num = 0;
|
||||
*next_offset = NP_ENTITLEMENT_ACCESS_INVALID_OFFSET;
|
||||
*previous_offset = NP_ENTITLEMENT_ACCESS_INVALID_OFFSET;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessPollUnifiedEntitlementInfoList(
|
||||
int64_t request_id, int32_t* result, NpEntitlementAccessUnifiedEntitlementInfo* list,
|
||||
uint32_t list_num, uint32_t* hit_num, int32_t* next_offset, int32_t* previous_offset) {
|
||||
PRINT_NAME();
|
||||
return np_entitlement_poll_list(request_id, EntitlementRequestKind::UnifiedList, result, list,
|
||||
list_num, hit_num, next_offset, previous_offset);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessPollServiceEntitlementInfoList(
|
||||
int64_t request_id, int32_t* result, NpEntitlementAccessServiceEntitlementInfo* list,
|
||||
uint32_t list_num, uint32_t* hit_num, int32_t* next_offset, int32_t* previous_offset) {
|
||||
PRINT_NAME();
|
||||
return np_entitlement_poll_list(request_id, EntitlementRequestKind::ServiceList, result, list,
|
||||
list_num, hit_num, next_offset, previous_offset);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessPollUnifiedEntitlementInfo(
|
||||
int64_t request_id, int32_t* result, NpEntitlementAccessUnifiedEntitlementInfo* info) {
|
||||
PRINT_NAME();
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (info == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
// No info is written when the offline request result is NO_ENTITLEMENT.
|
||||
return np_entitlement_poll_request(request_id, EntitlementRequestKind::UnifiedInfo, result);
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessPollConsumeEntitlement(int64_t request_id,
|
||||
int32_t* result,
|
||||
int32_t* use_limit) {
|
||||
PRINT_NAME();
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
if (use_limit == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
if (const int ret =
|
||||
np_entitlement_poll_request(request_id, EntitlementRequestKind::ConsumeUnified, result);
|
||||
ret != 0) {
|
||||
return ret;
|
||||
}
|
||||
if (*result == 0) {
|
||||
*use_limit = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessAbortRequest(int64_t request_id) {
|
||||
PRINT_NAME();
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
std::scoped_lock lock(g_np_entitlement_request_mutex);
|
||||
// Offline requests finish at creation, so there is no running work to abort.
|
||||
return g_np_entitlement_requests.contains(request_id)
|
||||
? 0
|
||||
: NP_ENTITLEMENT_ACCESS_ERROR_REQUEST_NOT_FOUND;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessDeleteRequest(int64_t request_id) {
|
||||
PRINT_NAME();
|
||||
if (!g_np_entitlement_initialized.load()) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NOT_INITIALIZED;
|
||||
}
|
||||
std::scoped_lock lock(g_np_entitlement_request_mutex);
|
||||
return g_np_entitlement_requests.erase(request_id) != 0
|
||||
? 0
|
||||
: NP_ENTITLEMENT_ACCESS_ERROR_REQUEST_NOT_FOUND;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetAddcontEntitlementInfoList(
|
||||
uint32_t service_label, NpEntitlementAccessAddcontEntitlementInfo* list, uint32_t list_num,
|
||||
uint32_t* hit_num) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t service_label = %" PRIu32 "\n", service_label);
|
||||
LOGF("\t list = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(list));
|
||||
LOGF("\t list_num = %" PRIu32 "\n", list_num);
|
||||
LOGF("\t hit_num = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(hit_num));
|
||||
|
||||
if (hit_num == nullptr || (list == nullptr && list_num != 0)) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
*hit_num = static_cast<uint32_t>(sizeof(NP_ENTITLEMENT_ACCESS_ADDON_LIST) /
|
||||
sizeof(NP_ENTITLEMENT_ACCESS_ADDON_LIST[0]));
|
||||
|
||||
if (list != nullptr && list_num != 0) {
|
||||
memset(list, 0, sizeof(*list) * list_num);
|
||||
|
||||
const auto copy_num = (list_num < *hit_num ? list_num : *hit_num);
|
||||
for (uint32_t i = 0; i < copy_num; i++) {
|
||||
list[i] = NP_ENTITLEMENT_ACCESS_ADDON_LIST[i];
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetAddcontEntitlementInfo(
|
||||
uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label,
|
||||
NpEntitlementAccessAddcontEntitlementInfo* info) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t service_label = %" PRIu32 "\n", service_label);
|
||||
LOGF("\t entitlement_label = 0x%016" PRIx64 "\n",
|
||||
reinterpret_cast<uint64_t>(entitlement_label));
|
||||
LOGF("\t info = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(info));
|
||||
|
||||
if (entitlement_label == nullptr || info == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
memset(info, 0, sizeof(*info));
|
||||
|
||||
for (const auto& entitlement: NP_ENTITLEMENT_ACCESS_ADDON_LIST) {
|
||||
if (strncmp(entitlement_label->data, entitlement.entitlement_label.data,
|
||||
sizeof(entitlement_label->data)) == 0) {
|
||||
*info = entitlement;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT;
|
||||
}
|
||||
|
||||
static int KYTY_SYSV_ABI NpEntitlementAccessGetEntitlementKey(
|
||||
uint32_t service_label, const NpUnifiedEntitlementLabel* entitlement_label,
|
||||
NpEntitlementAccessEntitlementKey* key) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t service_label = %" PRIu32 "\n"
|
||||
"\t entitlement_label = 0x%016" PRIx64 "\n"
|
||||
"\t key = 0x%016" PRIx64 "\n",
|
||||
service_label, reinterpret_cast<uint64_t>(entitlement_label),
|
||||
reinterpret_cast<uint64_t>(key));
|
||||
|
||||
if (entitlement_label == nullptr || key == nullptr) {
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_PARAMETER;
|
||||
}
|
||||
|
||||
return NP_ENTITLEMENT_ACCESS_ERROR_NO_ENTITLEMENT;
|
||||
}
|
||||
|
||||
LIB_DEFINE(InitNet_1_NpEntitlementAccess) {
|
||||
LIB_FUNC("jO8DM8oyego", LibNpEntitlementAccess::NpEntitlementAccessInitialize);
|
||||
LIB_FUNC("lPDO62PpJIA", LibNpEntitlementAccess::NpEntitlementAccessGetSkuFlag);
|
||||
LIB_FUNC("TFyU+KFBv54",
|
||||
LibNpEntitlementAccess::NpEntitlementAccessGetAddcontEntitlementInfoList);
|
||||
LIB_FUNC("xddD23+8TfQ", LibNpEntitlementAccess::NpEntitlementAccessGetAddcontEntitlementInfo);
|
||||
LIB_FUNC("5LiMEPuW0DQ", LibNpEntitlementAccess::NpEntitlementAccessGetEntitlementKey);
|
||||
LIB_FUNC("y7JD1gfwyfA", NpEntitlementAccessGetGameTrialsFlag);
|
||||
LIB_FUNC("IQtb-TaIjSM", NpEntitlementAccessGenerateTransactionId);
|
||||
LIB_FUNC("uCZf2L27th8", NpEntitlementAccessRequestUnifiedEntitlementInfoList);
|
||||
LIB_FUNC("brbRxzr7qyI", NpEntitlementAccessRequestServiceEntitlementInfoList);
|
||||
LIB_FUNC("jautSRs4OdQ", NpEntitlementAccessRequestUnifiedEntitlementInfo);
|
||||
LIB_FUNC("eOxGbG3sPb0", NpEntitlementAccessRequestConsumeUnifiedEntitlement);
|
||||
LIB_FUNC("nAEqawEZG5s", NpEntitlementAccessPollUnifiedEntitlementInfoList);
|
||||
LIB_FUNC("aFv8qms6XTM", NpEntitlementAccessPollServiceEntitlementInfoList);
|
||||
LIB_FUNC("M4XlLFnzQaQ", NpEntitlementAccessPollUnifiedEntitlementInfo);
|
||||
LIB_FUNC("69u+XqsoNd0", NpEntitlementAccessPollConsumeEntitlement);
|
||||
LIB_FUNC("HFcQl9TMcFQ", NpEntitlementAccessAbortRequest);
|
||||
LIB_FUNC("Z0eQj8m7XA8", NpEntitlementAccessDeleteRequest);
|
||||
}
|
||||
|
||||
} // namespace LibNpEntitlementAccess
|
||||
|
||||
} // namespace Libs
|
||||
@@ -53,20 +53,4 @@ LIB_DEFINE(InitVideoOut_1) {
|
||||
|
||||
} // namespace LibGen5
|
||||
|
||||
namespace LibGen5::VrrStatus {
|
||||
|
||||
LIB_VERSION("VideoOutVrrStatus", 1, "VideoOut", 1, 1);
|
||||
|
||||
static KYTY_SYSV_ABI int VideoOutVrrStatus_kP2L8t3j_aM() {
|
||||
// The observed guest call passes no arguments.
|
||||
// Return success for Kyty's fixed-refresh path.
|
||||
return OK;
|
||||
}
|
||||
|
||||
LIB_DEFINE(InitVideoOutVrrStatus_1) {
|
||||
LIB_FUNC("kP2L8t3j-aM", VideoOutVrrStatus_kP2L8t3j_aM);
|
||||
}
|
||||
|
||||
} // namespace LibGen5::VrrStatus
|
||||
|
||||
} // namespace Libs
|
||||
|
||||
@@ -0,0 +1,71 @@
|
||||
#include "common/abi.h"
|
||||
#include "graphics/presentation/videoOut.h"
|
||||
#include "libs/errno.h"
|
||||
#include "libs/libs.h"
|
||||
#include "loader/symbolDatabase.h"
|
||||
|
||||
#include <cinttypes>
|
||||
#include <cstring>
|
||||
|
||||
namespace Libs::LibGen5::VrrStatus {
|
||||
|
||||
LIB_VERSION("VideoOutVrrStatus", 1, "VideoOut", 1, 1);
|
||||
|
||||
static KYTY_SYSV_ABI int VideoOutVrrStatus_kP2L8t3j_aM() {
|
||||
// The observed guest call passes no arguments.
|
||||
// Return success for Kyty's fixed-refresh path.
|
||||
return OK;
|
||||
}
|
||||
|
||||
static KYTY_SYSV_ABI int VideoOutVrrStatus_LibwuIonIBw(LibKernel::EventQueue::KernelEqueue eq,
|
||||
int handle, void* udata) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t eq = 0x%016" PRIx64 "\n", static_cast<uint64_t>(eq));
|
||||
LOGF("\t handle = %d\n", handle);
|
||||
LOGF("\t udata = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(udata));
|
||||
|
||||
// Fixed-refresh output has no VRR status changes to signal.
|
||||
return OK;
|
||||
}
|
||||
|
||||
static KYTY_SYSV_ABI int VideoOutVrrStatus__q_vbO859Tw(LibKernel::EventQueue::KernelEqueue eq,
|
||||
int handle) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t eq = 0x%016" PRIx64 "\n", static_cast<uint64_t>(eq));
|
||||
LOGF("\t handle = %d\n", handle);
|
||||
|
||||
return OK;
|
||||
}
|
||||
|
||||
static KYTY_SYSV_ABI int VideoOutVrrStatus_gWT7X8H0bYs(int handle, void* status) {
|
||||
PRINT_NAME();
|
||||
|
||||
LOGF("\t handle = %d\n", handle);
|
||||
LOGF("\t status = 0x%016" PRIx64 "\n", reinterpret_cast<uint64_t>(status));
|
||||
|
||||
if (status == nullptr) {
|
||||
return VideoOut::VIDEO_OUT_ERROR_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
const int result = VideoOut::VideoOutGetOutputStatus(
|
||||
handle, static_cast<VideoOut::VideoOutOutputStatus*>(status));
|
||||
if (result != OK) {
|
||||
return result;
|
||||
}
|
||||
|
||||
// The guest's private status layout extends the 0x30-byte output status
|
||||
// with an 8-byte VRR range. GetOutputStatus clears flags, including bit 4 (VRR off).
|
||||
std::memset(static_cast<uint8_t*>(status) + 0x30, 0, 0x08);
|
||||
return OK;
|
||||
}
|
||||
|
||||
LIB_DEFINE(InitVideoOutVrrStatus_1) {
|
||||
LIB_FUNC("kP2L8t3j-aM", VideoOutVrrStatus_kP2L8t3j_aM);
|
||||
LIB_FUNC("LibwuIonIBw", VideoOutVrrStatus_LibwuIonIBw);
|
||||
LIB_FUNC("-q-vbO859Tw", VideoOutVrrStatus__q_vbO859Tw);
|
||||
LIB_FUNC("gWT7X8H0bYs", VideoOutVrrStatus_gWT7X8H0bYs);
|
||||
}
|
||||
|
||||
} // namespace Libs::LibGen5::VrrStatus
|
||||
Reference in New Issue
Block a user