Compare commits

..

20 Commits

Author SHA1 Message Date
Fernando Sahmkow
ee47642488 NvHost: Remake Ctrl Implementation. 2021-11-01 00:51:29 +01:00
Fernando Sahmkow
8688c59239 NvHost: Try a different approach to blocking. 2021-10-30 16:32:51 +02:00
Fernando Sahmkow
63e7957bce NvHost: Fix some regressions and correct signaling on timeout. 2021-10-30 11:16:49 +02:00
Morph
63ed7d9af7 Merge pull request #7193 from FernandoS27/idle
SVC: Implement svcInfo:IdleTickCount
2021-10-25 09:17:49 -04:00
Ameer J
3c8c17be4d Merge pull request #7218 from bylaws/aswdqdsam
Fixup channel submit IOCTL syncpoint parameters
2021-10-24 19:35:00 -04:00
Ameer J
aed5878dd3 Merge pull request #7222 from FernandoS27/fix-indixed-textures-again
TexturePass: Fix clamping  of images as this allowed negative indices.
2021-10-24 15:16:31 -04:00
Fernando Sahmkow
e5291e2031 TexturePass: Fix clamping of images as this allowed negative indices. 2021-10-24 20:46:36 +02:00
Mai M
3be87bed8d Merge pull request #7221 from astrelsky/stepfix
Fixed ARM_Dynamic_64 Step
2021-10-24 14:43:40 -04:00
Andrew Strelsky
31b9797296 Fixed ARM_Dynamic_64 Step 2021-10-24 11:16:32 -04:00
Fernando S
5299554bb0 Merge pull request #7206 from vonchenplus/fix_vulkan_viewport_issue
Vulkan Rasterizer: Fix viewport issue
2021-10-24 01:53:04 +02:00
Billy Laws
2dbef58eeb Fixup channel submit IOCTL syncpoint parameters
The current arguments worked by happenstance as games only ever submit
one syncpoint and request one fence back, if a game were to do something
other than this then the arguments would've been parsed entirely wrong.
2021-10-24 00:01:35 +01:00
Ameer J
494e34af6a Merge pull request #7070 from FernandoS27/want-you-bad
Vulkan Rasterizer: Correct DepthBias/PolygonOffset on Vulkan.
2021-10-23 18:02:23 -04:00
Fernando Sahmkow
ad8afaf1ef Vulran Rasterizer: address feedback. 2021-10-23 23:46:29 +02:00
Narr the Reg
2686bf6734 Merge pull request #7217 from yuzu-emu/revert-6515-gc_thread_safe
Revert "input_common: Fix data race on GC implementation"
2021-10-23 16:41:09 -05:00
Fernando S
33e92c15eb Revert "input_common: Fix data race on GC implementation" 2021-10-23 23:32:16 +02:00
Fernando S
7461196839 Merge pull request #6515 from german77/gc_thread_safe
input_common: Fix data race on GC implementation
2021-10-23 23:28:22 +02:00
Feng Chen
b769bea61b Fix vulkan viewport issue 2021-10-22 22:56:31 +08:00
Fernando Sahmkow
da6673e79a SVC: Implement svcInfo:IdleTickCount
Used by the Witcher 3
2021-10-16 20:33:44 +02:00
Fernando Sahmkow
60a3980561 Vulkan Rasterizer: Correct DepthBias/PolygonOffset on Vulkan. 2021-09-23 03:49:10 +02:00
Rodrigo Locatti
d4cab35533 input_common: Fix data race on GC implementation 2021-08-07 16:46:26 -05:00
37 changed files with 450 additions and 791 deletions

View File

@@ -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)

View File

@@ -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)

View File

@@ -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)

View File

@@ -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_,

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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

View File

@@ -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

View File

@@ -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;
}

View File

@@ -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]) {

View File

@@ -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);
}

View File

@@ -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)));
}

View File

@@ -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;

View File

@@ -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;

View File

@@ -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;
}

View File

@@ -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) {

View File

@@ -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(&params, 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(), &params, 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(), &params, 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(), &params, 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(), &params, 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(), &params, 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(), &params, 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(), &params, 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(), &params, 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(), &params, 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(&params, 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(&params, 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(&params, 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;
}

View File

@@ -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;
};

View File

@@ -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(), &params, 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;
}

View File

@@ -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

View File

@@ -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 {

View File

@@ -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

View File

@@ -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.

View File

@@ -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};

View File

@@ -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;
}

View File

@@ -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{});

View File

@@ -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

View File

@@ -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);
}

View File

@@ -38,6 +38,9 @@ enum : u8 {
Shaders,
// Special entries
DepthBiasGlobal,
LastCommonEntry,
};

View File

@@ -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;

View File

@@ -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);
});
}

View File

@@ -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) {

View File

@@ -79,7 +79,8 @@ public:
}
bool TouchDepthBias() {
return Exchange(Dirty::DepthBias, false);
return Exchange(Dirty::DepthBias, false) ||
Exchange(VideoCommon::Dirty::DepthBiasGlobal, false);
}
bool TouchBlendConstants() {

View File

@@ -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>

View File

@@ -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);
}

View File

@@ -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.