mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-28 13:56:59 +01: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 flags = 0;
|
||||||
uint64_t reserved[3] = {};
|
uint64_t reserved[3] = {};
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(VideoOutOutputStatus) == 0x30); // Also used by VideoOutVrrStatus.
|
||||||
|
|
||||||
struct VideoOutOutputOptions {
|
struct VideoOutOutputOptions {
|
||||||
uint32_t internalData[16] = {};
|
uint32_t internalData[16] = {};
|
||||||
|
|||||||
+3
-146
@@ -18,6 +18,9 @@
|
|||||||
|
|
||||||
namespace Libs {
|
namespace Libs {
|
||||||
|
|
||||||
|
namespace LibNpEntitlementAccess {
|
||||||
|
void InitNet_1_NpEntitlementAccess(Loader::SymbolDatabase* s);
|
||||||
|
}
|
||||||
namespace LibNpTrophy2 {
|
namespace LibNpTrophy2 {
|
||||||
void InitNet_1_NpTrophy2(Loader::SymbolDatabase* s);
|
void InitNet_1_NpTrophy2(Loader::SymbolDatabase* s);
|
||||||
}
|
}
|
||||||
@@ -1663,152 +1666,6 @@ LIB_DEFINE(InitNet_1_NpSessionSignaling) {
|
|||||||
|
|
||||||
} // namespace LibNpSessionSignaling
|
} // 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 {
|
namespace LibNpAuth {
|
||||||
|
|
||||||
LIB_VERSION("NpAuth", 1, "NpAuth", 1, 1);
|
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
|
||||||
|
|
||||||
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
|
} // 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