Compare commits
20 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ee47642488 | ||
|
|
8688c59239 | ||
|
|
63e7957bce | ||
|
|
63ed7d9af7 | ||
|
|
3c8c17be4d | ||
|
|
aed5878dd3 | ||
|
|
e5291e2031 | ||
|
|
3be87bed8d | ||
|
|
31b9797296 | ||
|
|
5299554bb0 | ||
|
|
2dbef58eeb | ||
|
|
494e34af6a | ||
|
|
ad8afaf1ef | ||
|
|
2686bf6734 | ||
|
|
33e92c15eb | ||
|
|
7461196839 | ||
|
|
b769bea61b | ||
|
|
da6673e79a | ||
|
|
60a3980561 | ||
|
|
d4cab35533 |
@@ -33,8 +33,6 @@ option(ENABLE_CUBEB "Enables the cubeb audio backend" ON)
|
||||
|
||||
option(USE_DISCORD_PRESENCE "Enables Discord Rich Presence" OFF)
|
||||
|
||||
option(YUZU_USE_OPENSSL_CRYPTO "Use OpenSSL/libressl for cryptography backend" ON)
|
||||
|
||||
# Default to a Release build
|
||||
get_property(IS_MULTI_CONFIG GLOBAL PROPERTY GENERATOR_IS_MULTI_CONFIG)
|
||||
if (NOT IS_MULTI_CONFIG AND NOT CMAKE_BUILD_TYPE)
|
||||
|
||||
20
externals/CMakeLists.txt
vendored
20
externals/CMakeLists.txt
vendored
@@ -36,6 +36,10 @@ add_subdirectory(glad)
|
||||
# inih
|
||||
add_subdirectory(inih)
|
||||
|
||||
# mbedtls
|
||||
add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
|
||||
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||
|
||||
# MicroProfile
|
||||
add_library(microprofile INTERFACE)
|
||||
target_include_directories(microprofile INTERFACE ./microprofile)
|
||||
@@ -89,11 +93,10 @@ endif()
|
||||
# Sirit
|
||||
add_subdirectory(sirit)
|
||||
|
||||
if (ENABLE_WEB_SERVICE OR YUZU_USE_OPENSSL_CRYPTO)
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
find_package(OpenSSL 1.1)
|
||||
if (OPENSSL_FOUND)
|
||||
set(OPENSSL_LIBRARIES OpenSSL::SSL OpenSSL::Crypto)
|
||||
set(YUZU_CRYPTO_BACKEND OpenSSL::Crypto)
|
||||
else()
|
||||
# LibreSSL
|
||||
set(LIBRESSL_SKIP_INSTALL ON CACHE BOOL "")
|
||||
@@ -104,10 +107,7 @@ if (ENABLE_WEB_SERVICE OR YUZU_USE_OPENSSL_CRYPTO)
|
||||
get_directory_property(OPENSSL_LIBRARIES
|
||||
DIRECTORY libressl
|
||||
DEFINITION OPENSSL_LIBS)
|
||||
target_include_directories(crypto INTERFACE ./libressl/include)
|
||||
set(YUZU_CRYPTO_BACKEND crypto)
|
||||
endif()
|
||||
set(YUZU_CRYPTO_DEFINITION -DYUZU_USE_OPENSSL_CRYPTO)
|
||||
|
||||
# httplib
|
||||
add_library(httplib INTERFACE)
|
||||
@@ -117,18 +117,8 @@ if (ENABLE_WEB_SERVICE OR YUZU_USE_OPENSSL_CRYPTO)
|
||||
if (WIN32)
|
||||
target_link_libraries(httplib INTERFACE crypt32 cryptui ws2_32)
|
||||
endif()
|
||||
else()
|
||||
# mbedtls
|
||||
add_subdirectory(mbedtls EXCLUDE_FROM_ALL)
|
||||
target_include_directories(mbedtls PUBLIC ./mbedtls/include)
|
||||
set(YUZU_CRYPTO_BACKEND mbedtls)
|
||||
set(YUZU_CRYPTO_DEFINITION -DYUZU_USE_MBEDTLS_CRYPTO)
|
||||
endif()
|
||||
|
||||
add_library(crypto-backend INTERFACE)
|
||||
target_compile_definitions(crypto-backend INTERFACE ${YUZU_CRYPTO_DEFINITION})
|
||||
target_link_libraries(crypto-backend INTERFACE ${YUZU_CRYPTO_BACKEND})
|
||||
|
||||
# Opus
|
||||
find_package(opus 1.3)
|
||||
if (NOT opus_FOUND)
|
||||
|
||||
@@ -22,12 +22,8 @@ add_library(core STATIC
|
||||
core_timing_util.h
|
||||
cpu_manager.cpp
|
||||
cpu_manager.h
|
||||
crypto/aes_util_mbedtls.cpp
|
||||
crypto/aes_util_openssl.cpp
|
||||
crypto/aes_util.cpp
|
||||
crypto/aes_util.h
|
||||
crypto/crypto.h
|
||||
crypto/crypto_mbedtls.cpp
|
||||
crypto/crypto_openssl.cpp
|
||||
crypto/encryption_layer.cpp
|
||||
crypto/encryption_layer.h
|
||||
crypto/key_manager.cpp
|
||||
@@ -686,7 +682,7 @@ endif()
|
||||
create_target_directory_groups(core)
|
||||
|
||||
target_link_libraries(core PUBLIC common PRIVATE audio_core video_core)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json Opus::Opus crypto-backend)
|
||||
target_link_libraries(core PUBLIC Boost::boost PRIVATE fmt::fmt nlohmann_json::nlohmann_json mbedtls Opus::Opus)
|
||||
|
||||
if (ENABLE_WEB_SERVICE)
|
||||
target_compile_definitions(core PRIVATE -DENABLE_WEB_SERVICE)
|
||||
|
||||
@@ -263,7 +263,7 @@ void ARM_Dynarmic_64::Run() {
|
||||
}
|
||||
|
||||
void ARM_Dynarmic_64::Step() {
|
||||
cb->InterpreterFallback(jit->GetPC(), 1);
|
||||
jit->Step();
|
||||
}
|
||||
|
||||
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
|
||||
|
||||
@@ -2,8 +2,6 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef YUZU_USE_MBEDTLS_CRYPTO
|
||||
|
||||
#include <array>
|
||||
#include <mbedtls/cipher.h>
|
||||
#include "common/assert.h"
|
||||
@@ -130,5 +128,3 @@ void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
|
||||
template class AESCipher<Key128>;
|
||||
template class AESCipher<Key256>;
|
||||
} // namespace Core::Crypto
|
||||
|
||||
#endif
|
||||
@@ -1,121 +0,0 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef YUZU_USE_OPENSSL_CRYPTO
|
||||
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <openssl/evp.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
|
||||
namespace Core::Crypto {
|
||||
namespace {
|
||||
using NintendoTweak = std::array<u8, 16>;
|
||||
|
||||
NintendoTweak CalculateNintendoTweak(std::size_t sector_id) {
|
||||
NintendoTweak out{};
|
||||
for (std::size_t i = 0xF; i <= 0xF; --i) {
|
||||
out[i] = sector_id & 0xFF;
|
||||
sector_id >>= 8;
|
||||
}
|
||||
return out;
|
||||
}
|
||||
} // Anonymous namespace
|
||||
|
||||
struct EvpCipherContextFree {
|
||||
void operator()(EVP_CIPHER_CTX* ctx) {
|
||||
EVP_CIPHER_CTX_free(ctx);
|
||||
}
|
||||
};
|
||||
|
||||
using EvpCipherContext = std::unique_ptr<EVP_CIPHER_CTX, EvpCipherContextFree>;
|
||||
|
||||
struct CipherContext {
|
||||
const EVP_CIPHER* cipher;
|
||||
EvpCipherContext encrypt_ctx;
|
||||
EvpCipherContext decrypt_ctx;
|
||||
std::vector<u8> key;
|
||||
std::vector<u8> iv;
|
||||
|
||||
CipherContext(EVP_CIPHER_CTX* encrypt_ctx_in, EVP_CIPHER_CTX* decrypt_ctx_in)
|
||||
: encrypt_ctx(encrypt_ctx_in), decrypt_ctx(decrypt_ctx_in) {}
|
||||
};
|
||||
|
||||
const static std::map<Mode, decltype(&EVP_aes_128_ctr)> cipher_map = {
|
||||
{Mode::CTR, EVP_aes_128_ctr}, {Mode::ECB, EVP_aes_128_ecb}, {Mode::XTS, EVP_aes_128_xts}};
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
Crypto::AESCipher<Key, KeySize>::AESCipher(Key key, Mode mode)
|
||||
: ctx(std::make_unique<CipherContext>(EVP_CIPHER_CTX_new(), EVP_CIPHER_CTX_new())) {
|
||||
ASSERT_MSG((ctx->encrypt_ctx.get() != NULL), "Failed to initialize OpenSSL ciphers.");
|
||||
ASSERT_MSG((ctx->decrypt_ctx.get() != NULL), "Failed to initialize OpenSSL ciphers.");
|
||||
ctx->cipher = cipher_map.at(mode)();
|
||||
ctx->key.resize(KeySize);
|
||||
std::memcpy(ctx->key.data(), key.data(), KeySize);
|
||||
EVP_EncryptInit(ctx->encrypt_ctx.get(), ctx->cipher, ctx->key.data(), nullptr);
|
||||
EVP_DecryptInit(ctx->decrypt_ctx.get(), ctx->cipher, ctx->key.data(), nullptr);
|
||||
EVP_CIPHER_CTX_set_padding(ctx->encrypt_ctx.get(), 0);
|
||||
EVP_CIPHER_CTX_set_padding(ctx->decrypt_ctx.get(), 0);
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
AESCipher<Key, KeySize>::~AESCipher() = default;
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
|
||||
EVP_CIPHER_CTX* cipher_ctx =
|
||||
op == Op::Encrypt ? ctx->encrypt_ctx.get() : ctx->decrypt_ctx.get();
|
||||
int written, last_written;
|
||||
if (EVP_CIPHER_mode(ctx->cipher) == EVP_CIPH_XTS_MODE) {
|
||||
EVP_CipherUpdate(cipher_ctx, dest, &written, src, static_cast<int>(size));
|
||||
if (written != static_cast<int>(size)) {
|
||||
LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
|
||||
size, written);
|
||||
}
|
||||
} else {
|
||||
std::size_t block_size = EVP_CIPHER_block_size(ctx->cipher);
|
||||
std::size_t remain = size % block_size;
|
||||
EVP_CipherUpdate(cipher_ctx, dest, &written, src, static_cast<int>(size - remain));
|
||||
if (remain != 0) {
|
||||
std::vector<u8> block(block_size);
|
||||
std::memcpy(block.data(), src + size - remain, remain);
|
||||
EVP_CipherUpdate(cipher_ctx, dest + written, &last_written, block.data(),
|
||||
static_cast<int>(block_size));
|
||||
written += last_written;
|
||||
}
|
||||
if (written != static_cast<int>(size)) {
|
||||
LOG_WARNING(Crypto, "Not all data was decrypted requested={:016X}, actual={:016X}.",
|
||||
size, written + last_written);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8* dest,
|
||||
std::size_t sector_id, std::size_t sector_size, Op op) {
|
||||
ASSERT_MSG(size % sector_size == 0, "XTS decryption size must be a multiple of sector size.");
|
||||
|
||||
for (std::size_t i = 0; i < size; i += sector_size) {
|
||||
SetIV(CalculateNintendoTweak(sector_id++));
|
||||
Transcode(src + i, sector_size, dest + i, op);
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIV(std::span<const u8> data) {
|
||||
ctx->iv.resize(data.size());
|
||||
std::memcpy(ctx->iv.data(), data.data(), data.size());
|
||||
EVP_EncryptInit(ctx->encrypt_ctx.get(), nullptr, nullptr, ctx->iv.data());
|
||||
EVP_DecryptInit(ctx->decrypt_ctx.get(), nullptr, nullptr, ctx->iv.data());
|
||||
}
|
||||
|
||||
template class AESCipher<Key128>;
|
||||
template class AESCipher<Key256>;
|
||||
} // namespace Core::Crypto
|
||||
|
||||
#endif
|
||||
@@ -1,26 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "common/common_types.h"
|
||||
|
||||
bool CalculateHMACSHA256(u8* out, const u8* key, std::size_t key_length, const u8* data,
|
||||
std::size_t data_length);
|
||||
|
||||
void CalculateMD5(const u8* data, std::size_t data_length, u8* hash);
|
||||
|
||||
void CalculateSHA256(const u8* data, std::size_t data_length, u8* hash);
|
||||
|
||||
// CMAC with AES-128, key_length = 16 bytes
|
||||
void CalculateCMAC(const u8* source, size_t size, const u8* key, u8* cmac);
|
||||
|
||||
// Calculate m = (s^d) mod n
|
||||
void CalculateModExp(const u8* d, std::size_t d_length, const u8* n, std::size_t n_length,
|
||||
const u8* s, std::size_t s_length, u8* m, std::size_t m_length);
|
||||
|
||||
void GenerateRandomBytesWithSeed(u8* out, std::size_t out_length, const u8* seed,
|
||||
std::size_t seed_length);
|
||||
@@ -1,82 +0,0 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef YUZU_USE_MBEDTLS_CRYPTO
|
||||
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <mbedtls/cmac.h>
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/md5.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
|
||||
bool CalculateHMACSHA256(u8* out, const u8* key, std::size_t key_length, const u8* data,
|
||||
std::size_t data_length) {
|
||||
mbedtls_md_context_t context;
|
||||
mbedtls_md_init(&context);
|
||||
|
||||
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
|
||||
mbedtls_md_hmac_starts(&context, key, key_length) ||
|
||||
mbedtls_md_hmac_update(&context, data, data_length) ||
|
||||
mbedtls_md_hmac_finish(&context, out)) {
|
||||
mbedtls_md_free(&context);
|
||||
return false;
|
||||
}
|
||||
|
||||
mbedtls_md_free(&context);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CalculateMD5(const u8* data, std::size_t data_length, u8* hash) {
|
||||
mbedtls_md5_ret(data, data_length, hash);
|
||||
}
|
||||
|
||||
void CalculateSHA256(const u8* data, std::size_t data_length, u8* hash) {
|
||||
mbedtls_sha256_ret(data, data_length, hash, 0);
|
||||
}
|
||||
|
||||
void CalculateCMAC(const u8* source, size_t size, const u8* key, u8* cmac) {
|
||||
mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key, 128, source,
|
||||
size, cmac);
|
||||
}
|
||||
|
||||
void CalculateModExp(const u8* d, std::size_t d_length, const u8* n, std::size_t n_length,
|
||||
const u8* s, std::size_t s_length, u8* m, std::size_t m_length) {
|
||||
mbedtls_mpi D; // RSA Private Exponent
|
||||
mbedtls_mpi N; // RSA Modulus
|
||||
mbedtls_mpi S; // Input
|
||||
mbedtls_mpi M; // Output
|
||||
|
||||
mbedtls_mpi_init(&D);
|
||||
mbedtls_mpi_init(&N);
|
||||
mbedtls_mpi_init(&S);
|
||||
mbedtls_mpi_init(&M);
|
||||
|
||||
mbedtls_mpi_read_binary(&D, d, d_length);
|
||||
mbedtls_mpi_read_binary(&N, n, n_length);
|
||||
mbedtls_mpi_read_binary(&S, s, s_length);
|
||||
|
||||
mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr);
|
||||
mbedtls_mpi_write_binary(&M, m, m_length);
|
||||
}
|
||||
|
||||
void GenerateRandomBytesWithSeed(u8* out, std::size_t out_length, const u8* seed,
|
||||
std::size_t seed_length) {
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy, seed, seed_length));
|
||||
ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, out, out_length) == 0);
|
||||
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -1,62 +0,0 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#ifdef YUZU_USE_OPENSSL_CRYPTO
|
||||
|
||||
#include <openssl/bn.h>
|
||||
#include <openssl/cmac.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/hmac.h>
|
||||
#include <openssl/rand.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
|
||||
bool CalculateHMACSHA256(u8* out, const u8* key, std::size_t key_length, const u8* data,
|
||||
std::size_t data_length) {
|
||||
HMAC(EVP_sha256(), key, static_cast<int>(key_length), data, data_length, out, NULL);
|
||||
return true;
|
||||
}
|
||||
|
||||
void CalculateMD5(const u8* data, std::size_t data_length, u8* hash) {
|
||||
EVP_Digest(data, data_length, hash, NULL, EVP_md5(), NULL);
|
||||
}
|
||||
|
||||
void CalculateSHA256(const u8* data, std::size_t data_length, u8* hash) {
|
||||
EVP_Digest(data, data_length, hash, NULL, EVP_sha256(), NULL);
|
||||
}
|
||||
|
||||
void CalculateCMAC(const u8* source, size_t size, const u8* key, u8* cmac) {
|
||||
size_t outlen;
|
||||
CMAC_CTX* ctx = CMAC_CTX_new();
|
||||
CMAC_Init(ctx, key, 16, EVP_aes_128_cbc(), NULL);
|
||||
CMAC_Update(ctx, source, size);
|
||||
CMAC_Final(ctx, cmac, &outlen);
|
||||
CMAC_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void CalculateModExp(const u8* d, std::size_t d_length, const u8* n, std::size_t n_length,
|
||||
const u8* s, std::size_t s_length, u8* m, std::size_t m_length) {
|
||||
BN_CTX* ctx = BN_CTX_new();
|
||||
BN_CTX_start(ctx);
|
||||
BIGNUM* D = BN_CTX_get(ctx);
|
||||
BIGNUM* N = BN_CTX_get(ctx);
|
||||
BIGNUM* S = BN_CTX_get(ctx);
|
||||
BIGNUM* M = BN_CTX_get(ctx);
|
||||
BN_bin2bn(d, static_cast<int>(d_length), D);
|
||||
BN_bin2bn(n, static_cast<int>(n_length), N);
|
||||
BN_bin2bn(s, static_cast<int>(s_length), S);
|
||||
BN_mod_exp(M, S, D, N, ctx);
|
||||
BN_bn2bin(M, m);
|
||||
BN_CTX_end(ctx);
|
||||
BN_CTX_free(ctx);
|
||||
}
|
||||
|
||||
void GenerateRandomBytesWithSeed(u8* out, std::size_t out_length, const u8* seed,
|
||||
std::size_t seed_length) {
|
||||
RAND_seed(static_cast<const void*>(seed), static_cast<int>(seed_length));
|
||||
ASSERT(RAND_bytes(out, static_cast<int>(out_length)) == 1);
|
||||
}
|
||||
|
||||
#endif
|
||||
@@ -13,6 +13,10 @@
|
||||
#include <string_view>
|
||||
#include <tuple>
|
||||
#include <vector>
|
||||
#include <mbedtls/bignum.h>
|
||||
#include <mbedtls/cipher.h>
|
||||
#include <mbedtls/cmac.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/fs/file.h"
|
||||
#include "common/fs/fs.h"
|
||||
@@ -22,7 +26,6 @@
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/crypto/partition_data_manager.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
@@ -482,7 +485,7 @@ static std::array<u8, target_size> MGF1(const std::array<u8, in_size>& seed) {
|
||||
while (out.size() < target_size) {
|
||||
out.resize(out.size() + 0x20);
|
||||
seed_exp[in_size + 3] = static_cast<u8>(i);
|
||||
CalculateSHA256(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20);
|
||||
mbedtls_sha256_ret(seed_exp.data(), seed_exp.size(), out.data() + out.size() - 0x20, 0);
|
||||
++i;
|
||||
}
|
||||
|
||||
@@ -527,10 +530,24 @@ std::optional<std::pair<Key128, Key128>> ParseTicket(const Ticket& ticket,
|
||||
return std::make_pair(rights_id, ticket.GetData().title_key_common);
|
||||
}
|
||||
|
||||
mbedtls_mpi D; // RSA Private Exponent
|
||||
mbedtls_mpi N; // RSA Modulus
|
||||
mbedtls_mpi S; // Input
|
||||
mbedtls_mpi M; // Output
|
||||
|
||||
mbedtls_mpi_init(&D);
|
||||
mbedtls_mpi_init(&N);
|
||||
mbedtls_mpi_init(&S);
|
||||
mbedtls_mpi_init(&M);
|
||||
|
||||
mbedtls_mpi_read_binary(&D, key.decryption_key.data(), key.decryption_key.size());
|
||||
mbedtls_mpi_read_binary(&N, key.modulus.data(), key.modulus.size());
|
||||
mbedtls_mpi_read_binary(&S, ticket.GetData().title_key_block.data(), 0x100);
|
||||
|
||||
mbedtls_mpi_exp_mod(&M, &S, &D, &N, nullptr);
|
||||
|
||||
std::array<u8, 0x100> rsa_step;
|
||||
CalculateModExp(key.decryption_key.data(), key.decryption_key.size(), key.modulus.data(),
|
||||
key.modulus.size(), ticket.GetData().title_key_block.data(), 0x100,
|
||||
rsa_step.data(), rsa_step.size());
|
||||
mbedtls_mpi_write_binary(&M, rsa_step.data(), rsa_step.size());
|
||||
|
||||
u8 m_0 = rsa_step[0];
|
||||
std::array<u8, 0x20> m_1;
|
||||
@@ -878,6 +895,14 @@ void KeyManager::DeriveSDSeedLazy() {
|
||||
}
|
||||
}
|
||||
|
||||
static Key128 CalculateCMAC(const u8* source, size_t size, const Key128& key) {
|
||||
Key128 out{};
|
||||
|
||||
mbedtls_cipher_cmac(mbedtls_cipher_info_from_type(MBEDTLS_CIPHER_AES_128_ECB), key.data(),
|
||||
key.size() * 8, source, size, out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
void KeyManager::DeriveBase() {
|
||||
if (!BaseDeriveNecessary()) {
|
||||
return;
|
||||
@@ -943,8 +968,7 @@ void KeyManager::DeriveBase() {
|
||||
key, GetKey(S128KeyType::Source, static_cast<u64>(SourceKeyType::KeyblobMAC)));
|
||||
SetKey(S128KeyType::KeyblobMAC, mac_key, i);
|
||||
|
||||
Key128 cmac;
|
||||
CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key.data(), cmac.data());
|
||||
Key128 cmac = CalculateCMAC(encrypted_keyblobs[i].data() + 0x10, 0xA0, mac_key);
|
||||
if (std::memcmp(cmac.data(), encrypted_keyblobs[i].data(), cmac.size()) != 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -11,6 +11,7 @@
|
||||
#include <array>
|
||||
#include <cctype>
|
||||
#include <cstring>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/common_funcs.h"
|
||||
#include "common/common_types.h"
|
||||
@@ -18,7 +19,6 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
#include "common/swap.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/crypto/partition_data_manager.h"
|
||||
#include "core/crypto/xts_encryption_layer.h"
|
||||
@@ -180,7 +180,7 @@ std::array<u8, key_size> FindKeyFromHex(const std::vector<u8>& binary,
|
||||
|
||||
std::array<u8, 0x20> temp{};
|
||||
for (size_t i = 0; i < binary.size() - key_size; ++i) {
|
||||
CalculateSHA256(binary.data() + i, key_size, temp.data());
|
||||
mbedtls_sha256_ret(binary.data() + i, key_size, temp.data(), 0);
|
||||
|
||||
if (temp != hash)
|
||||
continue;
|
||||
@@ -208,7 +208,7 @@ static std::array<Key128, 0x20> FindEncryptedMasterKeyFromHex(const std::vector<
|
||||
AESCipher<Key128> cipher(key, Mode::ECB);
|
||||
for (size_t i = 0; i < binary.size() - 0x10; ++i) {
|
||||
cipher.Transcode(binary.data() + i, dec_temp.size(), dec_temp.data(), Op::Decrypt);
|
||||
CalculateSHA256(dec_temp.data(), dec_temp.size(), temp.data());
|
||||
mbedtls_sha256_ret(dec_temp.data(), dec_temp.size(), temp.data(), 0);
|
||||
|
||||
for (size_t k = 0; k < out.size(); ++k) {
|
||||
if (temp == master_key_hashes[k]) {
|
||||
|
||||
@@ -5,11 +5,11 @@
|
||||
#include <algorithm>
|
||||
#include <random>
|
||||
#include <regex>
|
||||
#include <mbedtls/sha256.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/file_sys/card_image.h"
|
||||
#include "core/file_sys/common_funcs.h"
|
||||
@@ -64,7 +64,7 @@ static std::string GetRelativePathFromNcaID(const std::array<u8, 16>& nca_id, bo
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
CalculateSHA256(nca_id.data(), nca_id.size(), hash.data());
|
||||
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
|
||||
const auto format_str =
|
||||
fmt::runtime(cnmt_suffix ? "/000000{:02X}/{}.cnmt.nca" : "/000000{:02X}/{}.nca");
|
||||
@@ -146,7 +146,7 @@ bool PlaceholderCache::Create(const NcaID& id, u64 size) const {
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
CalculateSHA256(id.data(), id.size(), hash.data());
|
||||
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
@@ -170,7 +170,7 @@ bool PlaceholderCache::Delete(const NcaID& id) const {
|
||||
}
|
||||
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
CalculateSHA256(id.data(), id.size(), hash.data());
|
||||
mbedtls_sha256_ret(id.data(), id.size(), hash.data(), 0);
|
||||
const auto dirname = fmt::format("000000{:02X}", hash[0]);
|
||||
|
||||
const auto dir2 = GetOrCreateDirectoryRelative(dir, dirname);
|
||||
@@ -652,7 +652,7 @@ InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type,
|
||||
const OptionalHeader opt_header{0, 0};
|
||||
ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}};
|
||||
const auto& data = nca.GetBaseFile()->ReadBytes(0x100000);
|
||||
CalculateSHA256(data.data(), data.size(), c_rec.hash.data());
|
||||
mbedtls_sha256_ret(data.data(), data.size(), c_rec.hash.data(), 0);
|
||||
std::memcpy(&c_rec.nca_id, &c_rec.hash, 16);
|
||||
const CNMT new_cnmt(header, opt_header, {c_rec}, {});
|
||||
if (!RawInstallYuzuMeta(new_cnmt)) {
|
||||
@@ -727,7 +727,7 @@ InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFuncti
|
||||
id = *override_id;
|
||||
} else {
|
||||
const auto& data = in->ReadBytes(0x100000);
|
||||
CalculateSHA256(data.data(), data.size(), hash.data());
|
||||
mbedtls_sha256_ret(data.data(), data.size(), hash.data(), 0);
|
||||
memcpy(id.data(), hash.data(), 16);
|
||||
}
|
||||
|
||||
|
||||
@@ -8,11 +8,13 @@
|
||||
#include <regex>
|
||||
#include <string>
|
||||
|
||||
#include <mbedtls/md.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
|
||||
#include "common/fs/path_util.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
#include "core/crypto/xts_encryption_layer.h"
|
||||
#include "core/file_sys/content_archive.h"
|
||||
@@ -27,8 +29,19 @@ constexpr u64 NAX_HEADER_PADDING_SIZE = 0x4000;
|
||||
template <typename SourceData, typename SourceKey, typename Destination>
|
||||
static bool CalculateHMAC256(Destination* out, const SourceKey* key, std::size_t key_length,
|
||||
const SourceData* data, std::size_t data_length) {
|
||||
return CalculateHMACSHA256(reinterpret_cast<u8*>(out), reinterpret_cast<const u8*>(key),
|
||||
key_length, reinterpret_cast<const u8*>(data), data_length);
|
||||
mbedtls_md_context_t context;
|
||||
mbedtls_md_init(&context);
|
||||
|
||||
if (mbedtls_md_setup(&context, mbedtls_md_info_from_type(MBEDTLS_MD_SHA256), 1) ||
|
||||
mbedtls_md_hmac_starts(&context, reinterpret_cast<const u8*>(key), key_length) ||
|
||||
mbedtls_md_hmac_update(&context, reinterpret_cast<const u8*>(data), data_length) ||
|
||||
mbedtls_md_hmac_finish(&context, reinterpret_cast<u8*>(out))) {
|
||||
mbedtls_md_free(&context);
|
||||
return false;
|
||||
}
|
||||
|
||||
mbedtls_md_free(&context);
|
||||
return true;
|
||||
}
|
||||
|
||||
NAX::NAX(VirtualFile file_)
|
||||
@@ -53,7 +66,7 @@ NAX::NAX(VirtualFile file_, std::array<u8, 0x10> nca_id)
|
||||
: header(std::make_unique<NAXHeader>()),
|
||||
file(std::move(file_)), keys{Core::Crypto::KeyManager::Instance()} {
|
||||
Core::Crypto::SHA256Hash hash{};
|
||||
CalculateSHA256(nca_id.data(), nca_id.size(), hash.data());
|
||||
mbedtls_sha256_ret(nca_id.data(), nca_id.size(), hash.data(), 0);
|
||||
status = Parse(fmt::format("/registered/000000{:02X}/{}.nca", hash[0],
|
||||
Common::HexToString(nca_id, false)));
|
||||
}
|
||||
|
||||
@@ -49,6 +49,11 @@ public:
|
||||
/// Gets the current running thread
|
||||
[[nodiscard]] KThread* GetCurrentThread() const;
|
||||
|
||||
/// Gets the idle thread
|
||||
[[nodiscard]] KThread* GetIdleThread() const {
|
||||
return idle_thread;
|
||||
}
|
||||
|
||||
/// Returns true if the scheduler is idle
|
||||
[[nodiscard]] bool IsIdle() const {
|
||||
return GetCurrentThread() == idle_thread;
|
||||
|
||||
@@ -886,7 +886,24 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle
|
||||
*result = out_ticks;
|
||||
return ResultSuccess;
|
||||
}
|
||||
case GetInfoType::IdleTickCount: {
|
||||
if (handle == 0) {
|
||||
LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}",
|
||||
static_cast<Handle>(handle));
|
||||
return ResultInvalidHandle;
|
||||
}
|
||||
|
||||
if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id != system.CurrentCoreIndex()) {
|
||||
LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id);
|
||||
return ResultInvalidCombination;
|
||||
}
|
||||
|
||||
const auto& scheduler = *system.Kernel().CurrentScheduler();
|
||||
const auto* const idle_thread = scheduler.GetIdleThread();
|
||||
|
||||
*result = idle_thread->GetCpuTime();
|
||||
return ResultSuccess;
|
||||
}
|
||||
default:
|
||||
LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id);
|
||||
return ResultInvalidEnumValue;
|
||||
|
||||
@@ -3,12 +3,12 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <cctype>
|
||||
#include <mbedtls/md5.h>
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/settings.h"
|
||||
#include "common/string_util.h"
|
||||
#include "core/core.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
@@ -46,7 +46,7 @@ u64 GetCurrentBuildID(const Core::System::CurrentBuildProcessID& id) {
|
||||
BCATDigest DigestFile(const FileSys::VirtualFile& file) {
|
||||
BCATDigest out{};
|
||||
const auto bytes = file->ReadAllBytes();
|
||||
CalculateMD5(bytes.data(), bytes.size(), out.data());
|
||||
mbedtls_md5_ret(bytes.data(), bytes.size(), out.data());
|
||||
return out;
|
||||
}
|
||||
|
||||
|
||||
@@ -4,12 +4,12 @@
|
||||
|
||||
#include <memory>
|
||||
#include <fmt/format.h>
|
||||
#include <mbedtls/sha256.h>
|
||||
|
||||
#include "common/alignment.h"
|
||||
#include "common/hex_util.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_page_table.h"
|
||||
#include "core/hle/kernel/k_process.h"
|
||||
@@ -469,7 +469,7 @@ public:
|
||||
system.Memory().ReadBlock(nro_address, nro_data.data(), nro_size);
|
||||
|
||||
SHA256Hash hash{};
|
||||
CalculateSHA256(nro_data.data(), nro_data.size(), hash.data());
|
||||
mbedtls_sha256_ret(nro_data.data(), nro_data.size(), hash.data(), 0);
|
||||
|
||||
// NRO Hash is already loaded
|
||||
if (std::any_of(nro.begin(), nro.end(), [&hash](const std::pair<VAddr, NROInfo>& info) {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@@ -7,6 +8,7 @@
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/scope_exit.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
@@ -72,98 +74,127 @@ NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool is_async) {
|
||||
bool is_allocation) {
|
||||
IocCtrlEventWaitParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
|
||||
params.syncpt_id, params.threshold, params.timeout, is_async);
|
||||
LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_allocation={}",
|
||||
params.fence.id, params.fence.value, params.timeout, is_allocation);
|
||||
|
||||
if (params.syncpt_id >= MaxSyncPoints) {
|
||||
bool must_unmark_fail = !is_allocation;
|
||||
const u32 event_id = params.value.raw;
|
||||
SCOPE_EXIT({
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
if (must_unmark_fail) {
|
||||
events_interface.fails[event_id] = 0;
|
||||
}
|
||||
});
|
||||
|
||||
const u32 fence_id = static_cast<u32>(params.fence.id);
|
||||
|
||||
if (fence_id >= MaxSyncPoints) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
u32 event_id = params.value & 0x00FF;
|
||||
|
||||
if (event_id >= MaxNvEvents) {
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
if (syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
|
||||
params.value = syncpoint_manager.GetSyncpointMin(params.syncpt_id);
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
events_interface.failed[event_id] = false;
|
||||
if (params.fence.value == 0) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
if (const auto new_value = syncpoint_manager.RefreshSyncpoint(params.syncpt_id);
|
||||
syncpoint_manager.IsSyncpointExpired(params.syncpt_id, params.threshold)) {
|
||||
params.value = new_value;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
events_interface.failed[event_id] = false;
|
||||
if (syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) {
|
||||
params.value.raw = syncpoint_manager.GetSyncpointMin(fence_id);
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
if (const auto new_value = syncpoint_manager.RefreshSyncpoint(fence_id);
|
||||
syncpoint_manager.IsSyncpointExpired(fence_id, params.fence.value)) {
|
||||
params.value.raw = new_value;
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
auto& event = events_interface.events[event_id];
|
||||
auto& gpu = system.GPU();
|
||||
const u32 target_value = params.fence.value;
|
||||
|
||||
// This is mostly to take into account unimplemented features. As synced
|
||||
// gpu is always synced.
|
||||
if (!gpu.IsAsync()) {
|
||||
event.event->GetWritableEvent().Signal();
|
||||
return NvResult::Success;
|
||||
}
|
||||
const u32 current_syncpoint_value = event.fence.value;
|
||||
const s32 diff = current_syncpoint_value - params.threshold;
|
||||
if (diff >= 0) {
|
||||
event.event->GetWritableEvent().Signal();
|
||||
params.value = current_syncpoint_value;
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
events_interface.failed[event_id] = false;
|
||||
return NvResult::Success;
|
||||
}
|
||||
const u32 target_value = current_syncpoint_value - diff;
|
||||
|
||||
if (!is_async) {
|
||||
params.value = 0;
|
||||
}
|
||||
const auto check_failing = [&]() {
|
||||
if (!is_allocation && events_interface.fails[event_id] > 1) {
|
||||
{
|
||||
auto lk = system.StallCPU();
|
||||
gpu.WaitFence(fence_id, target_value);
|
||||
system.UnstallCPU();
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
|
||||
if (params.timeout == 0) {
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
if (check_failing()) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
return NvResult::Timeout;
|
||||
}
|
||||
|
||||
EventState status = events_interface.status[event_id];
|
||||
const bool bad_parameter = status != EventState::Free && status != EventState::Registered;
|
||||
if (bad_parameter) {
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
auto lock = events_interface.Lock();
|
||||
|
||||
u32 slot = [&]() {
|
||||
if (is_allocation) {
|
||||
params.value.raw = 0;
|
||||
return events_interface.FindFreeEvent(fence_id);
|
||||
} else {
|
||||
return params.value.raw;
|
||||
}
|
||||
}();
|
||||
|
||||
if (slot >= MaxNvEvents) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
events_interface.SetEventStatus(event_id, EventState::Waiting);
|
||||
events_interface.assigned_syncpt[event_id] = params.syncpt_id;
|
||||
events_interface.assigned_value[event_id] = target_value;
|
||||
if (is_async) {
|
||||
params.value = params.syncpt_id << 4;
|
||||
} else {
|
||||
params.value = ((params.syncpt_id & 0xfff) << 16) | 0x10000000;
|
||||
|
||||
auto* event = events_interface.events[slot].event;
|
||||
|
||||
if (!event) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
params.value |= event_id;
|
||||
event.event->GetWritableEvent().Clear();
|
||||
if (events_interface.failed[event_id]) {
|
||||
{
|
||||
auto lk = system.StallCPU();
|
||||
gpu.WaitFence(params.syncpt_id, target_value);
|
||||
system.UnstallCPU();
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
events_interface.failed[event_id] = false;
|
||||
|
||||
if (events_interface.IsBeingUsed(slot)) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
if (check_failing()) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
|
||||
std::memcpy(output.data(), ¶ms, sizeof(params));
|
||||
|
||||
params.value.raw = 0;
|
||||
|
||||
events_interface.status[slot].store(EventState::Waiting, std::memory_order_relaxed);
|
||||
events_interface.assigned_syncpt[slot] = fence_id;
|
||||
events_interface.assigned_value[slot] = target_value;
|
||||
if (is_allocation) {
|
||||
params.value.syncpoint_id_for_allocation.Assign(static_cast<u16>(fence_id));
|
||||
params.value.event_allocated.Assign(1);
|
||||
} else {
|
||||
params.value.syncpoint_id.Assign(fence_id);
|
||||
}
|
||||
params.value.raw |= slot;
|
||||
|
||||
gpu.RegisterSyncptInterrupt(fence_id, target_value);
|
||||
return NvResult::Timeout;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::FreeEvent(u32 slot) {
|
||||
if (slot >= MaxNvEvents) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
if (!events_interface.registered[slot]) {
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
if (events_interface.IsBeingUsed(slot)) {
|
||||
return NvResult::Busy;
|
||||
}
|
||||
|
||||
events_interface.Free(slot);
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocCtrlEventRegisterParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
@@ -172,16 +203,16 @@ NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::ve
|
||||
if (event_id >= MaxNvEvents) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
|
||||
auto lock = events_interface.Lock();
|
||||
|
||||
if (events_interface.registered[event_id]) {
|
||||
const auto event_state = events_interface.status[event_id];
|
||||
if (event_state != EventState::Free) {
|
||||
LOG_WARNING(Service_NVDRV, "Event already registered! Unregistering previous event");
|
||||
events_interface.UnregisterEvent(event_id);
|
||||
} else {
|
||||
return NvResult::BadParameter;
|
||||
const auto result = FreeEvent(event_id);
|
||||
if (result != NvResult::Success) {
|
||||
return result;
|
||||
}
|
||||
}
|
||||
events_interface.RegisterEvent(event_id);
|
||||
events_interface.Create(event_id);
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -191,32 +222,33 @@ NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
const u32 event_id = params.user_event_id & 0x00FF;
|
||||
LOG_DEBUG(Service_NVDRV, " called, user_event_id: {:X}", event_id);
|
||||
if (event_id >= MaxNvEvents) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
if (!events_interface.registered[event_id]) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
events_interface.UnregisterEvent(event_id);
|
||||
return NvResult::Success;
|
||||
|
||||
auto lock = events_interface.Lock();
|
||||
return FreeEvent(event_id);
|
||||
}
|
||||
|
||||
NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
|
||||
IocCtrlEventSignalParams params{};
|
||||
IocCtrlEventClearParams params{};
|
||||
std::memcpy(¶ms, input.data(), sizeof(params));
|
||||
|
||||
u32 event_id = params.event_id & 0x00FF;
|
||||
LOG_WARNING(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id);
|
||||
u32 event_id = params.event_id.slot;
|
||||
LOG_DEBUG(Service_NVDRV, "cleared event wait on, event_id: {:X}", event_id);
|
||||
|
||||
if (event_id >= MaxNvEvents) {
|
||||
return NvResult::BadParameter;
|
||||
}
|
||||
if (events_interface.status[event_id] == EventState::Waiting) {
|
||||
events_interface.LiberateEvent(event_id);
|
||||
}
|
||||
events_interface.failed[event_id] = true;
|
||||
|
||||
syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
|
||||
auto lock = events_interface.Lock();
|
||||
|
||||
if (events_interface.status[event_id].exchange(
|
||||
EventState::Cancelling, std::memory_order_acq_rel) == EventState::Waiting) {
|
||||
system.GPU().CancelSyncptInterrupt(events_interface.assigned_syncpt[event_id],
|
||||
events_interface.assigned_value[event_id]);
|
||||
syncpoint_manager.RefreshSyncpoint(events_interface.events[event_id].fence.id);
|
||||
}
|
||||
events_interface.fails[event_id]++;
|
||||
events_interface.status[event_id].store(EventState::Cancelled, std::memory_order_release);
|
||||
events_interface.events[event_id].event->GetWritableEvent().Clear();
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include "common/bit_field.h"
|
||||
#include "common/common_types.h"
|
||||
#include "core/hle/service/nvdrv/devices/nvdevice.h"
|
||||
#include "core/hle/service/nvdrv/nvdrv.h"
|
||||
@@ -28,6 +29,24 @@ public:
|
||||
void OnOpen(DeviceFD fd) override;
|
||||
void OnClose(DeviceFD fd) override;
|
||||
|
||||
union SyncpointEventValue {
|
||||
u32 raw;
|
||||
|
||||
union {
|
||||
BitField<0, 4, u32> partial_slot;
|
||||
BitField<4, 28, u32> syncpoint_id;
|
||||
};
|
||||
|
||||
struct {
|
||||
u16 slot;
|
||||
union {
|
||||
BitField<0, 12, u16> syncpoint_id_for_allocation;
|
||||
BitField<12, 1, u16> event_allocated;
|
||||
};
|
||||
};
|
||||
};
|
||||
static_assert(sizeof(SyncpointEventValue) == sizeof(u32));
|
||||
|
||||
private:
|
||||
struct IocSyncptReadParams {
|
||||
u32_le id{};
|
||||
@@ -84,27 +103,18 @@ private:
|
||||
};
|
||||
static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventSignalParams {
|
||||
u32_le event_id{};
|
||||
struct IocCtrlEventClearParams {
|
||||
SyncpointEventValue event_id{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventSignalParams) == 4,
|
||||
"IocCtrlEventSignalParams is incorrect size");
|
||||
static_assert(sizeof(IocCtrlEventClearParams) == 4,
|
||||
"IocCtrlEventClearParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventWaitParams {
|
||||
u32_le syncpt_id{};
|
||||
u32_le threshold{};
|
||||
s32_le timeout{};
|
||||
u32_le value{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventWaitAsyncParams {
|
||||
u32_le syncpt_id{};
|
||||
u32_le threshold{};
|
||||
Fence fence{};
|
||||
u32_le timeout{};
|
||||
u32_le value{};
|
||||
SyncpointEventValue value{};
|
||||
};
|
||||
static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
|
||||
static_assert(sizeof(IocCtrlEventWaitParams) == 16,
|
||||
"IocCtrlEventWaitAsyncParams is incorrect size");
|
||||
|
||||
struct IocCtrlEventRegisterParams {
|
||||
@@ -125,11 +135,14 @@ private:
|
||||
static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
|
||||
|
||||
NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
|
||||
NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
|
||||
bool is_allocation);
|
||||
NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
|
||||
|
||||
NvResult FreeEvent(u32 slot);
|
||||
|
||||
EventInterface& events_interface;
|
||||
SyncpointManager& syncpoint_manager;
|
||||
};
|
||||
|
||||
@@ -69,8 +69,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
|
||||
std::vector<Reloc> relocs(params.relocation_count);
|
||||
std::vector<u32> reloc_shifts(params.relocation_count);
|
||||
std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count);
|
||||
std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
|
||||
std::vector<Fence> fences(params.fence_count);
|
||||
std::vector<u32> fence_thresholds(params.fence_count);
|
||||
|
||||
// Slice input into their respective buffers
|
||||
std::size_t offset = sizeof(IoctlSubmit);
|
||||
@@ -78,15 +77,13 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
|
||||
offset += SliceVectors(input, relocs, params.relocation_count, offset);
|
||||
offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset);
|
||||
offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
|
||||
offset += SliceVectors(input, wait_checks, params.syncpoint_count, offset);
|
||||
offset += SliceVectors(input, fences, params.fence_count, offset);
|
||||
offset += SliceVectors(input, fence_thresholds, params.fence_count, offset);
|
||||
|
||||
auto& gpu = system.GPU();
|
||||
if (gpu.UseNvdec()) {
|
||||
for (std::size_t i = 0; i < syncpt_increments.size(); i++) {
|
||||
const SyncptIncr& syncpt_incr = syncpt_increments[i];
|
||||
fences[i].id = syncpt_incr.id;
|
||||
fences[i].value =
|
||||
fence_thresholds[i] =
|
||||
syncpoint_manager.IncreaseSyncpoint(syncpt_incr.id, syncpt_incr.increments);
|
||||
}
|
||||
}
|
||||
@@ -98,11 +95,6 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
|
||||
cmdlist.size() * sizeof(u32));
|
||||
gpu.PushCommandBuffer(cmdlist);
|
||||
}
|
||||
if (gpu.UseNvdec()) {
|
||||
fences[0].value = syncpoint_manager.IncreaseSyncpoint(fences[0].id, 1);
|
||||
Tegra::ChCommandHeaderList cmdlist{{(4 << 28) | fences[0].id}};
|
||||
gpu.PushCommandBuffer(cmdlist);
|
||||
}
|
||||
std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit));
|
||||
// Some games expect command_buffers to be written back
|
||||
offset = sizeof(IoctlSubmit);
|
||||
@@ -110,8 +102,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u
|
||||
offset += WriteVectors(output, relocs, offset);
|
||||
offset += WriteVectors(output, reloc_shifts, offset);
|
||||
offset += WriteVectors(output, syncpt_increments, offset);
|
||||
offset += WriteVectors(output, wait_checks, offset);
|
||||
offset += WriteVectors(output, fences, offset);
|
||||
offset += WriteVectors(output, fence_thresholds, offset);
|
||||
|
||||
return NvResult::Success;
|
||||
}
|
||||
|
||||
@@ -56,19 +56,16 @@ protected:
|
||||
s32 target{};
|
||||
s32 target_offset{};
|
||||
};
|
||||
static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
|
||||
static_assert(sizeof(Reloc) == 0x10, "Reloc has incorrect size");
|
||||
|
||||
struct SyncptIncr {
|
||||
u32 id{};
|
||||
u32 increments{};
|
||||
u32 unk0{};
|
||||
u32 unk1{};
|
||||
u32 unk2{};
|
||||
};
|
||||
static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
|
||||
|
||||
struct Fence {
|
||||
u32 id{};
|
||||
u32 value{};
|
||||
};
|
||||
static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
|
||||
static_assert(sizeof(SyncptIncr) == 0x14, "SyncptIncr has incorrect size");
|
||||
|
||||
struct IoctlGetSyncpoint {
|
||||
// Input
|
||||
|
||||
@@ -1,3 +1,8 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
@@ -81,11 +86,15 @@ enum class NvResult : u32 {
|
||||
ModuleNotPresent = 0xA000E,
|
||||
};
|
||||
|
||||
// obtained from
|
||||
// https://github.com/skyline-emu/skyline/blob/nvdec-dev/app/src/main/cpp/skyline/services/nvdrv/devices/nvhost/ctrl.h#L47
|
||||
enum class EventState {
|
||||
Free = 0,
|
||||
Registered = 1,
|
||||
Waiting = 2,
|
||||
Busy = 3,
|
||||
Available = 0,
|
||||
Waiting = 1,
|
||||
Cancelling = 2,
|
||||
Signalling = 3,
|
||||
Signalled = 4,
|
||||
Cancelled = 5,
|
||||
};
|
||||
|
||||
union Ioctl {
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <bit>
|
||||
#include <utility>
|
||||
|
||||
#include <fmt/format.h>
|
||||
@@ -28,6 +30,64 @@
|
||||
|
||||
namespace Service::Nvidia {
|
||||
|
||||
std::unique_lock<std::mutex> EventInterface::Lock() {
|
||||
return std::unique_lock<std::mutex>(events_mutex);
|
||||
}
|
||||
|
||||
void EventInterface::Signal(u32 event_id) {
|
||||
if (status[event_id].exchange(EventState::Signalling, std::memory_order_acq_rel) ==
|
||||
EventState::Waiting) {
|
||||
events[event_id].event->GetWritableEvent().Signal();
|
||||
}
|
||||
status[event_id].store(EventState::Signalled, std::memory_order_release);
|
||||
}
|
||||
|
||||
void EventInterface::Create(u32 event_id) {
|
||||
events[event_id].event =
|
||||
module.service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", event_id));
|
||||
status[event_id] = EventState::Available;
|
||||
registered[event_id] = true;
|
||||
const u64 mask = 1ULL << event_id;
|
||||
events_mask |= mask;
|
||||
}
|
||||
|
||||
void EventInterface::Free(u32 event_id) {
|
||||
module.service_context.CloseEvent(events[event_id].event);
|
||||
events[event_id].event = nullptr;
|
||||
status[event_id] = EventState::Available;
|
||||
registered[event_id] = false;
|
||||
const u64 mask = ~(1ULL << event_id);
|
||||
events_mask &= mask;
|
||||
}
|
||||
|
||||
u32 EventInterface::FindFreeEvent(u32 syncpoint_id) {
|
||||
u32 slot{MaxNvEvents};
|
||||
u32 free_slot{MaxNvEvents};
|
||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||
if (events[i].event) {
|
||||
if (!IsBeingUsed(i)) {
|
||||
slot = i;
|
||||
if (assigned_syncpt[i] == syncpoint_id) {
|
||||
return slot;
|
||||
}
|
||||
}
|
||||
} else if (free_slot == MaxNvEvents) {
|
||||
free_slot = i;
|
||||
}
|
||||
}
|
||||
if (free_slot < MaxNvEvents) {
|
||||
Create(free_slot);
|
||||
return free_slot;
|
||||
}
|
||||
|
||||
if (slot < MaxNvEvents) {
|
||||
return slot;
|
||||
}
|
||||
|
||||
LOG_CRITICAL(Service_NVDRV, "Failed to allocate an event");
|
||||
return 0;
|
||||
}
|
||||
|
||||
void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger,
|
||||
Core::System& system) {
|
||||
auto module_ = std::make_shared<Module>(system);
|
||||
@@ -40,11 +100,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger
|
||||
}
|
||||
|
||||
Module::Module(Core::System& system)
|
||||
: syncpoint_manager{system.GPU()}, service_context{system, "nvdrv"} {
|
||||
: syncpoint_manager{system.GPU()}, events_interface{*this}, service_context{system, "nvdrv"} {
|
||||
events_interface.events_mask = 0;
|
||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||
events_interface.events[i].event =
|
||||
service_context.CreateEvent(fmt::format("NVDRV::NvEvent_{}", i));
|
||||
events_interface.status[i] = EventState::Free;
|
||||
events_interface.status[i] = EventState::Available;
|
||||
events_interface.events[i].event = nullptr;
|
||||
events_interface.registered[i] = false;
|
||||
}
|
||||
auto nvmap_dev = std::make_shared<Devices::nvmap>(system);
|
||||
@@ -64,8 +124,11 @@ Module::Module(Core::System& system)
|
||||
}
|
||||
|
||||
Module::~Module() {
|
||||
auto lock = events_interface.Lock();
|
||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||
service_context.CloseEvent(events_interface.events[i].event);
|
||||
if (events_interface.registered[i]) {
|
||||
service_context.CloseEvent(events_interface.events[i].event);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -171,21 +234,35 @@ NvResult Module::Close(DeviceFD fd) {
|
||||
}
|
||||
|
||||
void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
|
||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||
const u32 max = MaxNvEvents - std::countl_zero(events_interface.events_mask);
|
||||
const u32 min = std::countr_zero(events_interface.events_mask);
|
||||
for (u32 i = min; i < max; i++) {
|
||||
if (events_interface.assigned_syncpt[i] == syncpoint_id &&
|
||||
events_interface.assigned_value[i] == value) {
|
||||
events_interface.LiberateEvent(i);
|
||||
events_interface.events[i].event->GetWritableEvent().Signal();
|
||||
events_interface.Signal(i);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Kernel::KReadableEvent& Module::GetEvent(const u32 event_id) {
|
||||
return events_interface.events[event_id].event->GetReadableEvent();
|
||||
}
|
||||
Kernel::KEvent* Module::GetEvent(u32 event_id) {
|
||||
const auto event = Devices::nvhost_ctrl::SyncpointEventValue{.raw = event_id};
|
||||
|
||||
Kernel::KWritableEvent& Module::GetEventWriteable(const u32 event_id) {
|
||||
return events_interface.events[event_id].event->GetWritableEvent();
|
||||
const bool allocated = event.event_allocated.Value() != 0;
|
||||
const u32 slot{allocated ? event.partial_slot.Value() : static_cast<u32>(event.slot)};
|
||||
if (slot >= MaxNvEvents) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const u32 syncpoint_id{allocated ? event.syncpoint_id_for_allocation.Value()
|
||||
: event.syncpoint_id.Value()};
|
||||
|
||||
auto lock = events_interface.Lock();
|
||||
|
||||
if (events_interface.registered[slot] &&
|
||||
events_interface.assigned_syncpt[slot] == syncpoint_id) {
|
||||
return events_interface.events[slot].event;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace Service::Nvidia
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
// Copyright 2018 yuzu emulator team
|
||||
// Copyright 2021 Skyline Team and Contributors (https://github.com/skyline-emu/)
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
@@ -40,17 +41,22 @@ struct NvEvent {
|
||||
Fence fence{};
|
||||
};
|
||||
|
||||
struct EventInterface {
|
||||
// Mask representing currently busy events
|
||||
class Module;
|
||||
|
||||
class EventInterface {
|
||||
public:
|
||||
EventInterface(Module& module_) : module{module_} {}
|
||||
|
||||
// Mask representing registered events
|
||||
u64 events_mask{};
|
||||
// Each kernel event associated to an NV event
|
||||
std::array<NvEvent, MaxNvEvents> events;
|
||||
std::array<NvEvent, MaxNvEvents> events{};
|
||||
// The status of the current NVEvent
|
||||
std::array<EventState, MaxNvEvents> status{};
|
||||
std::array<std::atomic<EventState>, MaxNvEvents> status{};
|
||||
// Tells if an NVEvent is registered or not
|
||||
std::array<bool, MaxNvEvents> registered{};
|
||||
// Tells the NVEvent that it has failed.
|
||||
std::array<bool, MaxNvEvents> failed{};
|
||||
std::array<u32, MaxNvEvents> fails{};
|
||||
// When an NVEvent is waiting on GPU interrupt, this is the sync_point
|
||||
// associated with it.
|
||||
std::array<u32, MaxNvEvents> assigned_syncpt{};
|
||||
@@ -59,50 +65,26 @@ struct EventInterface {
|
||||
std::array<u32, MaxNvEvents> assigned_value{};
|
||||
// Constant to denote an unasigned syncpoint.
|
||||
static constexpr u32 unassigned_syncpt = 0xFFFFFFFF;
|
||||
std::optional<u32> GetFreeEvent() const {
|
||||
u64 mask = events_mask;
|
||||
for (u32 i = 0; i < MaxNvEvents; i++) {
|
||||
const bool is_free = (mask & 0x1) == 0;
|
||||
if (is_free) {
|
||||
if (status[i] == EventState::Registered || status[i] == EventState::Free) {
|
||||
return {i};
|
||||
}
|
||||
}
|
||||
mask = mask >> 1;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
void SetEventStatus(const u32 event_id, EventState new_status) {
|
||||
EventState old_status = status[event_id];
|
||||
if (old_status == new_status) {
|
||||
return;
|
||||
}
|
||||
status[event_id] = new_status;
|
||||
if (new_status == EventState::Registered) {
|
||||
registered[event_id] = true;
|
||||
}
|
||||
if (new_status == EventState::Waiting || new_status == EventState::Busy) {
|
||||
events_mask |= (1ULL << event_id);
|
||||
}
|
||||
}
|
||||
void RegisterEvent(const u32 event_id) {
|
||||
registered[event_id] = true;
|
||||
if (status[event_id] == EventState::Free) {
|
||||
status[event_id] = EventState::Registered;
|
||||
}
|
||||
}
|
||||
void UnregisterEvent(const u32 event_id) {
|
||||
registered[event_id] = false;
|
||||
if (status[event_id] == EventState::Registered) {
|
||||
status[event_id] = EventState::Free;
|
||||
}
|
||||
}
|
||||
void LiberateEvent(const u32 event_id) {
|
||||
status[event_id] = registered[event_id] ? EventState::Registered : EventState::Free;
|
||||
events_mask &= ~(1ULL << event_id);
|
||||
assigned_syncpt[event_id] = unassigned_syncpt;
|
||||
assigned_value[event_id] = 0;
|
||||
|
||||
bool IsBeingUsed(u32 event_id) {
|
||||
const auto current_status = status[event_id].load(std::memory_order_acquire);
|
||||
return current_status == EventState::Waiting || current_status == EventState::Cancelling ||
|
||||
current_status == EventState::Signalling;
|
||||
}
|
||||
|
||||
std::unique_lock<std::mutex> Lock();
|
||||
|
||||
void Signal(u32 event_id);
|
||||
|
||||
void Create(u32 event_id);
|
||||
|
||||
void Free(u32 event_id);
|
||||
|
||||
u32 FindFreeEvent(u32 syncpoint_id);
|
||||
|
||||
private:
|
||||
std::mutex events_mutex;
|
||||
Module& module;
|
||||
};
|
||||
|
||||
class Module final {
|
||||
@@ -139,11 +121,11 @@ public:
|
||||
|
||||
void SignalSyncpt(const u32 syncpoint_id, const u32 value);
|
||||
|
||||
Kernel::KReadableEvent& GetEvent(u32 event_id);
|
||||
|
||||
Kernel::KWritableEvent& GetEventWriteable(u32 event_id);
|
||||
Kernel::KEvent* GetEvent(u32 event_id);
|
||||
|
||||
private:
|
||||
friend class EventInterface;
|
||||
|
||||
/// Manages syncpoints on the host
|
||||
SyncpointManager syncpoint_manager;
|
||||
|
||||
@@ -159,6 +141,9 @@ private:
|
||||
EventInterface events_interface;
|
||||
|
||||
KernelHelpers::ServiceContext service_context;
|
||||
|
||||
void CreateEvent(u32 event_id);
|
||||
void FreeEvent(u32 event_id);
|
||||
};
|
||||
|
||||
/// Registers all NVDRV services with the specified service manager.
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
#include "common/logging/log.h"
|
||||
#include "core/core.h"
|
||||
#include "core/hle/ipc_helpers.h"
|
||||
#include "core/hle/kernel/k_event.h"
|
||||
#include "core/hle/kernel/k_readable_event.h"
|
||||
#include "core/hle/kernel/k_thread.h"
|
||||
#include "core/hle/kernel/k_writable_event.h"
|
||||
@@ -168,7 +169,7 @@ void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
|
||||
void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto fd = rp.Pop<DeviceFD>();
|
||||
const auto event_id = rp.Pop<u32>() & 0x00FF;
|
||||
const auto event_id = rp.Pop<u32>();
|
||||
LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
|
||||
|
||||
if (!is_initialized) {
|
||||
@@ -184,12 +185,14 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (event_id < MaxNvEvents) {
|
||||
auto* event = nvdrv->GetEvent(event_id);
|
||||
|
||||
if (event) {
|
||||
IPC::ResponseBuilder rb{ctx, 3, 1};
|
||||
rb.Push(ResultSuccess);
|
||||
auto& event = nvdrv->GetEvent(event_id);
|
||||
event.Clear();
|
||||
rb.PushCopyObjects(event);
|
||||
auto& readable_event = event->GetReadableEvent();
|
||||
readable_event.Clear();
|
||||
rb.PushCopyObjects(readable_event);
|
||||
rb.PushEnum(NvResult::Success);
|
||||
} else {
|
||||
IPC::ResponseBuilder rb{ctx, 3};
|
||||
|
||||
@@ -4,6 +4,9 @@
|
||||
|
||||
#include <array>
|
||||
|
||||
#include <mbedtls/ctr_drbg.h>
|
||||
#include <mbedtls/entropy.h>
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/common_types.h"
|
||||
#include "common/fs/file.h"
|
||||
@@ -12,7 +15,6 @@
|
||||
#include "common/logging/log.h"
|
||||
|
||||
#include "common/settings.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#include "core/file_sys/control_metadata.h"
|
||||
#include "core/file_sys/patch_manager.h"
|
||||
#include "core/loader/loader.h"
|
||||
@@ -29,11 +31,22 @@ namespace Telemetry = Common::Telemetry;
|
||||
|
||||
static u64 GenerateTelemetryId() {
|
||||
u64 telemetry_id{};
|
||||
|
||||
mbedtls_entropy_context entropy;
|
||||
mbedtls_entropy_init(&entropy);
|
||||
mbedtls_ctr_drbg_context ctr_drbg;
|
||||
constexpr std::array<char, 18> personalization{{"yuzu Telemetry ID"}};
|
||||
|
||||
GenerateRandomBytesWithSeed((u8*)&telemetry_id, sizeof(u64),
|
||||
reinterpret_cast<const u8*>(personalization.data()),
|
||||
personalization.size());
|
||||
mbedtls_ctr_drbg_init(&ctr_drbg);
|
||||
ASSERT(mbedtls_ctr_drbg_seed(&ctr_drbg, mbedtls_entropy_func, &entropy,
|
||||
reinterpret_cast<const unsigned char*>(personalization.data()),
|
||||
personalization.size()) == 0);
|
||||
ASSERT(mbedtls_ctr_drbg_random(&ctr_drbg, reinterpret_cast<unsigned char*>(&telemetry_id),
|
||||
sizeof(u64)) == 0);
|
||||
|
||||
mbedtls_ctr_drbg_free(&ctr_drbg);
|
||||
mbedtls_entropy_free(&entropy);
|
||||
|
||||
return telemetry_id;
|
||||
}
|
||||
|
||||
|
||||
@@ -492,7 +492,7 @@ void TexturePass(Environment& env, IR::Program& program) {
|
||||
const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)};
|
||||
IR::IREmitter ir{*texture_inst.block, insert_point};
|
||||
const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))};
|
||||
inst->SetArg(0, ir.SMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift),
|
||||
inst->SetArg(0, ir.UMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift),
|
||||
ir.Imm32(DESCRIPTOR_SIZE - 1)));
|
||||
} else {
|
||||
inst->SetArg(0, IR::Value{});
|
||||
|
||||
@@ -7,7 +7,6 @@ add_executable(tests
|
||||
common/ring_buffer.cpp
|
||||
common/unique_function.cpp
|
||||
core/core_timing.cpp
|
||||
core/crypto.cpp
|
||||
core/network/network.cpp
|
||||
tests.cpp
|
||||
video_core/buffer_base.cpp
|
||||
|
||||
@@ -1,237 +0,0 @@
|
||||
// Copyright 2021 yuzu emulator team
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <catch2/catch.hpp>
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
|
||||
#include "common/common_types.h"
|
||||
#include "core/core.h"
|
||||
#include "core/core_timing.h"
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/crypto.h"
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
#include "common/x64/cpu_detect.h"
|
||||
#endif
|
||||
|
||||
constexpr static u8 msg[] = "The quick brown fox jumps over the lazy dog";
|
||||
constexpr static u8 key[] = "key";
|
||||
|
||||
TEST_CASE("MD5", "[core]") {
|
||||
constexpr u8 hash[] = "\x9e\x10\x7d\x9d\x37\x2b\xb6\x82\x6b\xd8\x1d\x35\x42\xa4\x19\xd6";
|
||||
u8 md[16];
|
||||
|
||||
CalculateMD5((const u8*)msg, sizeof(msg) - 1, md);
|
||||
REQUIRE(std::memcmp(md, hash, 16) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("SHA256", "[core]") {
|
||||
constexpr u8 hash[] = "\xd7\xa8\xfb\xb3\x07\xd7\x80\x94\x69\xca\x9a\xbc\xb0\x08\x2e\x4f\x8d"
|
||||
"\x56\x51\xe4\x6d\x3c\xdb\x76\x2d\x02\xd0\xbf\x37\xc9\xe5\x92";
|
||||
u8 md[32];
|
||||
|
||||
CalculateSHA256((const u8*)msg, sizeof(msg) - 1, md);
|
||||
REQUIRE(std::memcmp(md, hash, 32) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("HAMCSHA256", "[core]") {
|
||||
constexpr u8 hash[] = "\xf7\xbc\x83\xf4\x30\x53\x84\x24\xb1\x32\x98\xe6\xaa\x6f\xb1\x43\xef\x4d"
|
||||
"\x59\xa1\x49\x46\x17\x59\x97\x47\x9d\xbc\x2d\x1a\x3c\xd8";
|
||||
u8 md[32];
|
||||
|
||||
CalculateHMACSHA256(md, key, sizeof(key) - 1, msg, sizeof(msg) - 1);
|
||||
REQUIRE(std::memcmp(md, hash, 32) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("CMAC-AES", "[core]") {
|
||||
constexpr u8 cmac_key[] = "\x2b\x7e\x15\x16\x28\xae\xd2\xa6\xab\xf7\x15\x88\x09\xcf\x4f\x3c";
|
||||
constexpr u8 cmac_msg1[] = "\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a";
|
||||
constexpr u8 cmac_msg2[] =
|
||||
"\x6b\xc1\xbe\xe2\x2e\x40\x9f\x96\xe9\x3d\x7e\x11\x73\x93\x17\x2a\xae\x2d\x8a\x57\x1e\x03"
|
||||
"\xac\x9c\x9e\xb7\x6f\xac\x45\xaf\x8e\x51\x30\xc8\x1c\x46\xa3\x5c\xe4\x11\xe5\xfb\xc1\x19"
|
||||
"\x1a\x0a\x52\xef\xf6\x9f\x24\x45\xdf\x4f\x9b\x17\xad\x2b\x41\x7b\xe6\x6c\x37\x10";
|
||||
constexpr u8 cmac_hash1[] = "\x07\x0a\x16\xb4\x6b\x4d\x41\x44\xf7\x9b\xdd\x9d\xd0\x4a\x28\x7c";
|
||||
constexpr u8 cmac_hash2[] = "\x51\xf0\xbe\xbf\x7e\x3b\x9d\x92\xfc\x49\x74\x17\x79\x36\x3c\xfe";
|
||||
u8 cmac_md1[16], cmac_md2[16];
|
||||
|
||||
CalculateCMAC(cmac_msg1, sizeof(cmac_msg1) - 1, cmac_key, cmac_md1);
|
||||
CalculateCMAC(cmac_msg2, sizeof(cmac_msg2) - 1, cmac_key, cmac_md2);
|
||||
REQUIRE(std::memcmp(cmac_md1, cmac_hash1, 16) == 0);
|
||||
REQUIRE(std::memcmp(cmac_md2, cmac_hash2, 16) == 0);
|
||||
}
|
||||
|
||||
constexpr static std::array<u8, 16> aes_key = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
constexpr static std::array<u8, 16> aes_iv = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
|
||||
constexpr static u8 aes_plain[] =
|
||||
"\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x0a\x0b\x0c\x0d\x0e\x0f"
|
||||
"\x0f\x0e\x0d\x0c\x0b\x0a\x09\x08\x07\x06\x05\x04\x03\x02\x01\x00";
|
||||
|
||||
TEST_CASE("AES-128-CTR", "[core]") {
|
||||
constexpr u8 aes_cipher[] = "\x0a\x95\x09\xb6\x45\x6b\xf6\x42\xf9\xca\x9e\x53\xca\x5e\xe4\x55"
|
||||
"\x0d\x6d\xe1\x98\x6d\x12\x7b\x9e\x9d\xdc\xf8\x0b\x48\xa6\x0e\xdc";
|
||||
u8 aes_encrypted[32];
|
||||
|
||||
Core::Crypto::AESCipher cipher(aes_key, Core::Crypto::Mode::CTR);
|
||||
cipher.SetIV(aes_iv);
|
||||
cipher.Transcode(aes_plain, 32, aes_encrypted, Core::Crypto::Op::Encrypt);
|
||||
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
|
||||
}
|
||||
|
||||
TEST_CASE("AES-128-ECB", "[core]") {
|
||||
constexpr u8 aes_cipher[] = "\x0a\x94\x0b\xb5\x41\x6e\xf0\x45\xf1\xc3\x94\x58\xc6\x53\xea\x5a"
|
||||
"\x20\xa9\xf9\x92\xb4\x4c\x5b\xe8\x04\x1f\xfc\xdc\x6c\xae\x99\x6a";
|
||||
u8 aes_encrypted[32];
|
||||
|
||||
Core::Crypto::AESCipher cipher(aes_key, Core::Crypto::Mode::ECB);
|
||||
cipher.Transcode(aes_plain, 32, aes_encrypted, Core::Crypto::Op::Encrypt);
|
||||
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
|
||||
}
|
||||
|
||||
constexpr static std::array<u8, 32> aes_xts_key = {
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
|
||||
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0};
|
||||
|
||||
TEST_CASE("AES-128-XTS", "[core]") {
|
||||
constexpr u8 aes_cipher[] = "\x25\x06\xfe\xf2\x0b\x39\xfa\xec\x5a\x69\x93\x41\x60\x95\xb5\xef"
|
||||
"\x00\x75\xdd\x61\xb9\x9e\x5f\xeb\xbe\xdf\xb3\x2e\x04\xb5\x0c\xa7";
|
||||
u8 aes_encrypted[32];
|
||||
|
||||
Core::Crypto::AESCipher cipher(aes_xts_key, Core::Crypto::Mode::XTS);
|
||||
cipher.XTSTranscode(aes_plain, 32, aes_encrypted, 0, 16, Core::Crypto::Op::Encrypt);
|
||||
REQUIRE(std::memcmp(aes_encrypted, aes_cipher, 32) == 0);
|
||||
}
|
||||
|
||||
double RunFunctionAndReturnTime(void (*f)(), const Core::Timing::CoreTiming& timing) {
|
||||
const u64 start = timing.GetGlobalTimeNs().count();
|
||||
f();
|
||||
const u64 end = timing.GetGlobalTimeNs().count();
|
||||
return static_cast<double>(end - start);
|
||||
}
|
||||
|
||||
void MD5SpeedTest() {
|
||||
std::array<u8, 16> hash;
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
std::memset(msg.get(), 0, 1024 * 1024);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
CalculateMD5(msg.get(), 1024 * 1024, hash.data());
|
||||
}
|
||||
}
|
||||
|
||||
void SHA256SpeedTest() {
|
||||
std::array<u8, 32> hash;
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
std::memset(msg.get(), 0, 1024 * 1024);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
CalculateSHA256(msg.get(), 1024 * 1024, hash.data());
|
||||
}
|
||||
}
|
||||
|
||||
void HMACSHA256SpeedTest() {
|
||||
constexpr static u8 key[] = "0123456789abcdef";
|
||||
std::array<u8, 32> hash;
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
std::memset(msg.get(), 0, 1024 * 1024);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
CalculateHMACSHA256(hash.data(), key, sizeof(key) - 1, msg.get(), 1024 * 1024);
|
||||
}
|
||||
}
|
||||
|
||||
void CMACAESSpeedTest() {
|
||||
constexpr static u8 key[] = "0123456789abcdef";
|
||||
std::array<u8, 32> hash;
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
std::memset(msg.get(), 0, 1024 * 1024);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
CalculateCMAC(msg.get(), 1024 * 1024, key, hash.data());
|
||||
}
|
||||
}
|
||||
|
||||
void AES128CTRSpeedTest() {
|
||||
constexpr static std::array<u8, 16> key = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
constexpr static std::array<u8, 16> iv = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
const std::unique_ptr<u8[]> encrypted(new u8[1024 * 1024]);
|
||||
Core::Crypto::AESCipher cipher(key, Core::Crypto::Mode::CTR);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
cipher.SetIV(iv);
|
||||
cipher.Transcode(msg.get(), 1024 * 1024, encrypted.get(), Core::Crypto::Op::Encrypt);
|
||||
}
|
||||
}
|
||||
|
||||
void AES128ECBSpeedTest() {
|
||||
constexpr static std::array<u8, 16> key = {0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7,
|
||||
0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf};
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
const std::unique_ptr<u8[]> encrypted(new u8[1024 * 1024]);
|
||||
Core::Crypto::AESCipher cipher(key, Core::Crypto::Mode::ECB);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
cipher.Transcode(msg.get(), 1024 * 1024, encrypted.get(), Core::Crypto::Op::Encrypt);
|
||||
}
|
||||
}
|
||||
|
||||
void AES128XTSSpeedTest() {
|
||||
constexpr static std::array<u8, 32> xts_key = {
|
||||
0x0, 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7, 0x8, 0x9, 0xa, 0xb, 0xc, 0xd, 0xe, 0xf,
|
||||
0xf, 0xe, 0xd, 0xc, 0xb, 0xa, 0x9, 0x8, 0x7, 0x6, 0x5, 0x4, 0x3, 0x2, 0x1, 0x0};
|
||||
const std::unique_ptr<u8[]> msg(new u8[1024 * 1024]);
|
||||
const std::unique_ptr<u8[]> encrypted(new u8[1024 * 1024]);
|
||||
Core::Crypto::AESCipher cipher(xts_key, Core::Crypto::Mode::XTS);
|
||||
for (int i = 0; i < 1024; i++) {
|
||||
cipher.XTSTranscode(msg.get(), 1024 * 1024, encrypted.get(), 0, 16,
|
||||
Core::Crypto::Op::Encrypt);
|
||||
}
|
||||
}
|
||||
|
||||
struct ScopeInit final {
|
||||
ScopeInit() {
|
||||
core_timing.SetMulticore(true);
|
||||
core_timing.Initialize([]() {});
|
||||
}
|
||||
~ScopeInit() {
|
||||
core_timing.Shutdown();
|
||||
}
|
||||
|
||||
Core::Timing::CoreTiming core_timing;
|
||||
};
|
||||
|
||||
TEST_CASE("SPEED", "[core]") {
|
||||
#ifdef ARCHITECTURE_x86_64
|
||||
const auto& caps = Common::GetCPUCaps();
|
||||
std::string cpu_string = caps.cpu_string;
|
||||
if (caps.avx || caps.avx2 || caps.avx512) {
|
||||
cpu_string += " | AVX";
|
||||
if (caps.avx512) {
|
||||
cpu_string += "512";
|
||||
} else if (caps.avx2) {
|
||||
cpu_string += '2';
|
||||
}
|
||||
if (caps.fma || caps.fma4) {
|
||||
cpu_string += " | FMA";
|
||||
}
|
||||
}
|
||||
printf("Host CPU: %s\n", cpu_string.c_str());
|
||||
#endif
|
||||
ScopeInit guard;
|
||||
double time;
|
||||
time = RunFunctionAndReturnTime(MD5SpeedTest, guard.core_timing);
|
||||
printf("MD5 speed: %fMB/s\n", 1024e9 / time);
|
||||
time = RunFunctionAndReturnTime(SHA256SpeedTest, guard.core_timing);
|
||||
printf("SHA256 speed: %fMB/s\n", 1024e9 / time);
|
||||
time = RunFunctionAndReturnTime(HMACSHA256SpeedTest, guard.core_timing);
|
||||
printf("HMACSHA256 speed: %fMB/s\n", 1024e9 / time);
|
||||
time = RunFunctionAndReturnTime(CMACAESSpeedTest, guard.core_timing);
|
||||
printf("CMAC-AES speed: %fMB/s\n", 1024e9 / time);
|
||||
time = RunFunctionAndReturnTime(AES128CTRSpeedTest, guard.core_timing);
|
||||
printf("AES-128-CTR speed: %fMB/s\n", 1024e9 / time);
|
||||
time = RunFunctionAndReturnTime(AES128ECBSpeedTest, guard.core_timing);
|
||||
printf("AES-128-ECB speed: %fMB/s\n", 1024e9 / time);
|
||||
time = RunFunctionAndReturnTime(AES128XTSSpeedTest, guard.core_timing);
|
||||
printf("AES-128-XTS speed: %fMB/s\n", 1024e9 / time);
|
||||
}
|
||||
@@ -38,6 +38,9 @@ enum : u8 {
|
||||
|
||||
Shaders,
|
||||
|
||||
// Special entries
|
||||
DepthBiasGlobal,
|
||||
|
||||
LastCommonEntry,
|
||||
};
|
||||
|
||||
|
||||
@@ -216,7 +216,7 @@ public:
|
||||
|
||||
void RegisterSyncptInterrupt(u32 syncpoint_id, u32 value);
|
||||
|
||||
[[nodiscard]] bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
|
||||
bool CancelSyncptInterrupt(u32 syncpoint_id, u32 value);
|
||||
|
||||
[[nodiscard]] u64 GetTicks() const;
|
||||
|
||||
|
||||
@@ -627,9 +627,21 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) {
|
||||
if (!state_tracker.TouchDepthBias()) {
|
||||
return;
|
||||
}
|
||||
scheduler.Record([constant = regs.polygon_offset_units, clamp = regs.polygon_offset_clamp,
|
||||
float units = regs.polygon_offset_units / 2.0f;
|
||||
const bool is_d24 = regs.zeta.format == Tegra::DepthFormat::S8_UINT_Z24_UNORM ||
|
||||
regs.zeta.format == Tegra::DepthFormat::D24X8_UNORM ||
|
||||
regs.zeta.format == Tegra::DepthFormat::D24S8_UNORM ||
|
||||
regs.zeta.format == Tegra::DepthFormat::D24C8_UNORM;
|
||||
if (is_d24 && !device.SupportsD24DepthBuffer()) {
|
||||
// the base formulas can be obtained from here:
|
||||
// https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias
|
||||
const double rescale_factor =
|
||||
static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127));
|
||||
units = static_cast<float>(static_cast<double>(units) * rescale_factor);
|
||||
}
|
||||
scheduler.Record([constant = units, clamp = regs.polygon_offset_clamp,
|
||||
factor = regs.polygon_offset_factor](vk::CommandBuffer cmdbuf) {
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor / 2.0f);
|
||||
cmdbuf.SetDepthBias(constant, clamp, factor);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -54,6 +54,7 @@ void SetupDirtyViewports(Tables& tables) {
|
||||
FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports);
|
||||
FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports);
|
||||
tables[0][OFF(viewport_transform_enabled)] = Viewports;
|
||||
tables[1][OFF(screen_y_control)] = Viewports;
|
||||
}
|
||||
|
||||
void SetupDirtyScissors(Tables& tables) {
|
||||
|
||||
@@ -79,7 +79,8 @@ public:
|
||||
}
|
||||
|
||||
bool TouchDepthBias() {
|
||||
return Exchange(Dirty::DepthBias, false);
|
||||
return Exchange(Dirty::DepthBias, false) ||
|
||||
Exchange(VideoCommon::Dirty::DepthBiasGlobal, false);
|
||||
}
|
||||
|
||||
bool TouchBlendConstants() {
|
||||
|
||||
@@ -221,6 +221,7 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) {
|
||||
BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear));
|
||||
}
|
||||
const ImageViewId depth_buffer_id = render_targets.depth_buffer_id;
|
||||
|
||||
PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id));
|
||||
|
||||
for (size_t index = 0; index < NUM_RT; ++index) {
|
||||
@@ -230,6 +231,8 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) {
|
||||
maxwell3d.regs.render_area.width,
|
||||
maxwell3d.regs.render_area.height,
|
||||
};
|
||||
|
||||
flags[Dirty::DepthBiasGlobal] = true;
|
||||
}
|
||||
|
||||
template <class P>
|
||||
|
||||
@@ -623,6 +623,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR
|
||||
is_float16_supported = false;
|
||||
}
|
||||
|
||||
supports_d24_depth =
|
||||
IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT,
|
||||
VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal);
|
||||
|
||||
graphics_queue = logical.GetQueue(graphics_family);
|
||||
present_queue = logical.GetQueue(present_family);
|
||||
}
|
||||
|
||||
@@ -332,6 +332,10 @@ public:
|
||||
return sets_per_pool;
|
||||
}
|
||||
|
||||
bool SupportsD24DepthBuffer() const {
|
||||
return supports_d24_depth;
|
||||
}
|
||||
|
||||
private:
|
||||
/// Checks if the physical device is suitable.
|
||||
void CheckSuitability(bool requires_swapchain) const;
|
||||
@@ -425,6 +429,7 @@ private:
|
||||
bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit
|
||||
bool has_renderdoc{}; ///< Has RenderDoc attached
|
||||
bool has_nsight_graphics{}; ///< Has Nsight Graphics attached
|
||||
bool supports_d24_depth{}; ///< Supports D24 depth buffers.
|
||||
|
||||
// Telemetry parameters
|
||||
std::string vendor_name; ///< Device's driver name.
|
||||
|
||||
Reference in New Issue
Block a user