libs: port entitlement requests and fixed-refresh VRR status

This commit is contained in:
shadowbeat070
2026-10-16 00:13:41 +02:00
committed by nmzik
parent a5ceb48184
commit 30a4673c60
5 changed files with 569 additions and 162 deletions
+1
View File
@@ -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
View File
@@ -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);
+494
View File
@@ -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
-16
View File
@@ -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
+71
View File
@@ -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