Compare commits
44 Commits
__refs_pul
...
__refs_pul
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7e2e1e3bad | ||
|
|
257b1d2c4b | ||
|
|
85feaf3005 | ||
|
|
d6672501ac | ||
|
|
9c6ae697f5 | ||
|
|
8928aa3008 | ||
|
|
504095cea9 | ||
|
|
ed51c2abda | ||
|
|
acfd771e79 | ||
|
|
664019954a | ||
|
|
f14bb61acd | ||
|
|
929fc849e9 | ||
|
|
5429ea0e69 | ||
|
|
62fa00f586 | ||
|
|
53e94c7be8 | ||
|
|
8e86fa7e60 | ||
|
|
f5d538f118 | ||
|
|
5cc2f99fab | ||
|
|
df96a214ae | ||
|
|
4f2acc54f5 | ||
|
|
7f0f37fca7 | ||
|
|
1cc0e4b4d8 | ||
|
|
35c1607f23 | ||
|
|
d888ac7d20 | ||
|
|
61678c4e9f | ||
|
|
e8868c2ed1 | ||
|
|
a10d64ea79 | ||
|
|
9893da8e2c | ||
|
|
1a45b15a8c | ||
|
|
4a2d9c6454 | ||
|
|
a77ee63f65 | ||
|
|
0a5456feb9 | ||
|
|
07691f994a | ||
|
|
15660bd857 | ||
|
|
dd2ff23621 | ||
|
|
8725b37a35 | ||
|
|
9b837c6069 | ||
|
|
24bd068a08 | ||
|
|
a5af1161c9 | ||
|
|
6cfff2c3f6 | ||
|
|
0105368cc1 | ||
|
|
e586921c28 | ||
|
|
e3f0c93230 | ||
|
|
dd4a02d15c |
@@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .ci* dis
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-6.0
|
||||
CLANG_FORMAT=clang-format-10.0
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -7,7 +7,7 @@ if grep -nrI '\s$' src *.yml *.txt *.md Doxyfile .gitignore .gitmodules .travis*
|
||||
fi
|
||||
|
||||
# Default clang-format points to default 3.5 version one
|
||||
CLANG_FORMAT=clang-format-6.0
|
||||
CLANG_FORMAT=clang-format-10.0
|
||||
$CLANG_FORMAT --version
|
||||
|
||||
if [ "$TRAVIS_EVENT_TYPE" = "pull_request" ]; then
|
||||
|
||||
@@ -60,9 +60,14 @@ else()
|
||||
-Wmissing-declarations
|
||||
-Wno-attributes
|
||||
-Wno-unused-parameter
|
||||
-fconcepts
|
||||
)
|
||||
|
||||
# TODO: Remove when we update to a GCC compiler that enables this
|
||||
# by default (i.e. GCC 10 or newer).
|
||||
if (CMAKE_CXX_COMPILER_ID STREQUAL GNU)
|
||||
add_compile_options(-fconcepts)
|
||||
endif()
|
||||
|
||||
if (ARCHITECTURE_x86_64)
|
||||
add_compile_options("-mcx16")
|
||||
endif()
|
||||
|
||||
@@ -14,50 +14,55 @@ namespace Common {
|
||||
|
||||
#if _MSC_VER
|
||||
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) {
|
||||
u8 result = _InterlockedCompareExchange8((char*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
const u8 result =
|
||||
_InterlockedCompareExchange8(reinterpret_cast<volatile char*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) {
|
||||
u16 result = _InterlockedCompareExchange16((short*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
const u16 result =
|
||||
_InterlockedCompareExchange16(reinterpret_cast<volatile short*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) {
|
||||
u32 result = _InterlockedCompareExchange((long*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
const u32 result =
|
||||
_InterlockedCompareExchange(reinterpret_cast<volatile long*>(pointer), value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) {
|
||||
u64 result = _InterlockedCompareExchange64((__int64*)pointer, value, expected);
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
const u64 result = _InterlockedCompareExchange64(reinterpret_cast<volatile __int64*>(pointer),
|
||||
value, expected);
|
||||
return result == expected;
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128((__int64*)pointer, value[1], value[0],
|
||||
(__int64*)expected.data()) != 0;
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
return _InterlockedCompareExchange128(reinterpret_cast<volatile __int64*>(pointer), value[1],
|
||||
value[0],
|
||||
reinterpret_cast<__int64*>(expected.data())) != 0;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected) {
|
||||
return __sync_bool_compare_and_swap(pointer, expected, value);
|
||||
}
|
||||
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected) {
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected) {
|
||||
unsigned __int128 value_a;
|
||||
unsigned __int128 expected_a;
|
||||
std::memcpy(&value_a, value.data(), sizeof(u128));
|
||||
|
||||
@@ -8,10 +8,10 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
bool AtomicCompareAndSwap(u8 volatile* pointer, u8 value, u8 expected);
|
||||
bool AtomicCompareAndSwap(u16 volatile* pointer, u16 value, u16 expected);
|
||||
bool AtomicCompareAndSwap(u32 volatile* pointer, u32 value, u32 expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u64 value, u64 expected);
|
||||
bool AtomicCompareAndSwap(u64 volatile* pointer, u128 value, u128 expected);
|
||||
bool AtomicCompareAndSwap(volatile u8* pointer, u8 value, u8 expected);
|
||||
bool AtomicCompareAndSwap(volatile u16* pointer, u16 value, u16 expected);
|
||||
bool AtomicCompareAndSwap(volatile u32* pointer, u32 value, u32 expected);
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u64 value, u64 expected);
|
||||
bool AtomicCompareAndSwap(volatile u64* pointer, u128 value, u128 expected);
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -23,10 +23,12 @@ concept IsSTLContainer = requires(T t) {
|
||||
t.size();
|
||||
};
|
||||
|
||||
// Check if type T is derived from T2
|
||||
template <typename T, typename T2>
|
||||
concept IsBaseOf = requires {
|
||||
std::is_base_of_v<T, T2>;
|
||||
// TODO: Replace with std::derived_from when the <concepts> header
|
||||
// is available on all supported platforms.
|
||||
template <typename Derived, typename Base>
|
||||
concept DerivedFrom = requires {
|
||||
std::is_base_of_v<Base, Derived>;
|
||||
std::is_convertible_v<const volatile Derived*, const volatile Base*>;
|
||||
};
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -3,21 +3,9 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "common/hex_util.h"
|
||||
#include "common/logging/log.h"
|
||||
|
||||
namespace Common {
|
||||
|
||||
u8 ToHexNibble(char c1) {
|
||||
if (c1 >= 65 && c1 <= 70)
|
||||
return c1 - 55;
|
||||
if (c1 >= 97 && c1 <= 102)
|
||||
return c1 - 87;
|
||||
if (c1 >= 48 && c1 <= 57)
|
||||
return c1 - 48;
|
||||
LOG_ERROR(Common, "Invalid hex digit: 0x{:02X}", c1);
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
|
||||
std::vector<u8> out(str.size() / 2);
|
||||
if (little_endian) {
|
||||
@@ -30,26 +18,4 @@ std::vector<u8> HexStringToVector(std::string_view str, bool little_endian) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<u8, 16> operator""_array16(const char* str, std::size_t len) {
|
||||
if (len != 32) {
|
||||
LOG_ERROR(Common,
|
||||
"Attempting to parse string to array that is not of correct size (expected=32, "
|
||||
"actual={}).",
|
||||
len);
|
||||
return {};
|
||||
}
|
||||
return HexStringToArray<16>(str);
|
||||
}
|
||||
|
||||
std::array<u8, 32> operator""_array32(const char* str, std::size_t len) {
|
||||
if (len != 64) {
|
||||
LOG_ERROR(Common,
|
||||
"Attempting to parse string to array that is not of correct size (expected=64, "
|
||||
"actual={}).",
|
||||
len);
|
||||
return {};
|
||||
}
|
||||
return HexStringToArray<32>(str);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -14,19 +14,31 @@
|
||||
|
||||
namespace Common {
|
||||
|
||||
u8 ToHexNibble(char c1);
|
||||
constexpr u8 ToHexNibble(char c) {
|
||||
if (c >= 65 && c <= 70) {
|
||||
return c - 55;
|
||||
}
|
||||
|
||||
if (c >= 97 && c <= 102) {
|
||||
return c - 87;
|
||||
}
|
||||
|
||||
return c - 48;
|
||||
}
|
||||
|
||||
std::vector<u8> HexStringToVector(std::string_view str, bool little_endian);
|
||||
|
||||
template <std::size_t Size, bool le = false>
|
||||
std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
constexpr std::array<u8, Size> HexStringToArray(std::string_view str) {
|
||||
std::array<u8, Size> out{};
|
||||
if constexpr (le) {
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2)
|
||||
for (std::size_t i = 2 * Size - 2; i <= 2 * Size; i -= 2) {
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
}
|
||||
} else {
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2)
|
||||
for (std::size_t i = 0; i < 2 * Size; i += 2) {
|
||||
out[i / 2] = (ToHexNibble(str[i]) << 4) | ToHexNibble(str[i + 1]);
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
@@ -48,7 +60,12 @@ std::string HexToString(const ContiguousContainer& data, bool upper = true) {
|
||||
return out;
|
||||
}
|
||||
|
||||
std::array<u8, 0x10> operator"" _array16(const char* str, std::size_t len);
|
||||
std::array<u8, 0x20> operator"" _array32(const char* str, std::size_t len);
|
||||
constexpr std::array<u8, 16> AsArray(const char (&data)[17]) {
|
||||
return HexStringToArray<16>(data);
|
||||
}
|
||||
|
||||
constexpr std::array<u8, 32> AsArray(const char (&data)[65]) {
|
||||
return HexStringToArray<32>(data);
|
||||
}
|
||||
|
||||
} // namespace Common
|
||||
|
||||
@@ -113,19 +113,19 @@ private:
|
||||
Entry CreateEntry(Class log_class, Level log_level, const char* filename, unsigned int line_nr,
|
||||
const char* function, std::string message) const {
|
||||
using std::chrono::duration_cast;
|
||||
using std::chrono::microseconds;
|
||||
using std::chrono::steady_clock;
|
||||
|
||||
Entry entry;
|
||||
entry.timestamp =
|
||||
duration_cast<std::chrono::microseconds>(steady_clock::now() - time_origin);
|
||||
entry.log_class = log_class;
|
||||
entry.log_level = log_level;
|
||||
entry.filename = filename;
|
||||
entry.line_num = line_nr;
|
||||
entry.function = function;
|
||||
entry.message = std::move(message);
|
||||
|
||||
return entry;
|
||||
return {
|
||||
.timestamp = duration_cast<microseconds>(steady_clock::now() - time_origin),
|
||||
.log_class = log_class,
|
||||
.log_level = log_level,
|
||||
.filename = filename,
|
||||
.line_num = line_nr,
|
||||
.function = function,
|
||||
.message = std::move(message),
|
||||
.final_entry = false,
|
||||
};
|
||||
}
|
||||
|
||||
std::mutex writing_mutex;
|
||||
|
||||
@@ -21,19 +21,13 @@ class Filter;
|
||||
*/
|
||||
struct Entry {
|
||||
std::chrono::microseconds timestamp;
|
||||
Class log_class;
|
||||
Level log_level;
|
||||
const char* filename;
|
||||
unsigned int line_num;
|
||||
Class log_class{};
|
||||
Level log_level{};
|
||||
const char* filename = nullptr;
|
||||
unsigned int line_num = 0;
|
||||
std::string function;
|
||||
std::string message;
|
||||
bool final_entry = false;
|
||||
|
||||
Entry() = default;
|
||||
Entry(Entry&& o) = default;
|
||||
|
||||
Entry& operator=(Entry&& o) = default;
|
||||
Entry& operator=(const Entry& o) = default;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <array>
|
||||
#include <mbedtls/cipher.h>
|
||||
#include "common/assert.h"
|
||||
#include "common/logging/log.h"
|
||||
@@ -10,8 +11,10 @@
|
||||
|
||||
namespace Core::Crypto {
|
||||
namespace {
|
||||
std::vector<u8> CalculateNintendoTweak(std::size_t sector_id) {
|
||||
std::vector<u8> out(0x10);
|
||||
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;
|
||||
@@ -63,13 +66,6 @@ AESCipher<Key, KeySize>::~AESCipher() {
|
||||
mbedtls_cipher_free(&ctx->decryption_context);
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIV(std::vector<u8> iv) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, iv.data(), iv.size()) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, iv.data(), iv.size())) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::Transcode(const u8* src, std::size_t size, u8* dest, Op op) const {
|
||||
auto* const context = op == Op::Encrypt ? &ctx->encryption_context : &ctx->decryption_context;
|
||||
@@ -124,6 +120,13 @@ void AESCipher<Key, KeySize>::XTSTranscode(const u8* src, std::size_t size, u8*
|
||||
}
|
||||
}
|
||||
|
||||
template <typename Key, std::size_t KeySize>
|
||||
void AESCipher<Key, KeySize>::SetIVImpl(const u8* data, std::size_t size) {
|
||||
ASSERT_MSG((mbedtls_cipher_set_iv(&ctx->encryption_context, data, size) ||
|
||||
mbedtls_cipher_set_iv(&ctx->decryption_context, data, size)) == 0,
|
||||
"Failed to set IV on mbedtls ciphers.");
|
||||
}
|
||||
|
||||
template class AESCipher<Key128>;
|
||||
template class AESCipher<Key256>;
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
|
||||
#include <memory>
|
||||
#include <type_traits>
|
||||
#include <vector>
|
||||
#include "common/common_types.h"
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
@@ -32,10 +31,12 @@ class AESCipher {
|
||||
|
||||
public:
|
||||
AESCipher(Key key, Mode mode);
|
||||
|
||||
~AESCipher();
|
||||
|
||||
void SetIV(std::vector<u8> iv);
|
||||
template <typename ContiguousContainer>
|
||||
void SetIV(const ContiguousContainer& container) {
|
||||
SetIVImpl(std::data(container), std::size(container));
|
||||
}
|
||||
|
||||
template <typename Source, typename Dest>
|
||||
void Transcode(const Source* src, std::size_t size, Dest* dest, Op op) const {
|
||||
@@ -59,6 +60,8 @@ public:
|
||||
std::size_t sector_size, Op op);
|
||||
|
||||
private:
|
||||
void SetIVImpl(const u8* data, std::size_t size);
|
||||
|
||||
std::unique_ptr<CipherContext> ctx;
|
||||
};
|
||||
} // namespace Core::Crypto
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
// Licensed under GPLv2 or any later version
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include "common/assert.h"
|
||||
#include "core/crypto/ctr_encryption_layer.h"
|
||||
@@ -10,8 +11,7 @@ namespace Core::Crypto {
|
||||
|
||||
CTREncryptionLayer::CTREncryptionLayer(FileSys::VirtualFile base_, Key128 key_,
|
||||
std::size_t base_offset)
|
||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR),
|
||||
iv(16, 0) {}
|
||||
: EncryptionLayer(std::move(base_)), base_offset(base_offset), cipher(key_, Mode::CTR) {}
|
||||
|
||||
std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
if (length == 0)
|
||||
@@ -39,9 +39,8 @@ std::size_t CTREncryptionLayer::Read(u8* data, std::size_t length, std::size_t o
|
||||
return read + Read(data + read, length - read, offset + read);
|
||||
}
|
||||
|
||||
void CTREncryptionLayer::SetIV(const std::vector<u8>& iv_) {
|
||||
const auto length = std::min(iv_.size(), iv.size());
|
||||
iv.assign(iv_.cbegin(), iv_.cbegin() + length);
|
||||
void CTREncryptionLayer::SetIV(const IVData& iv_) {
|
||||
iv = iv_;
|
||||
}
|
||||
|
||||
void CTREncryptionLayer::UpdateIV(std::size_t offset) const {
|
||||
|
||||
@@ -4,7 +4,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <array>
|
||||
|
||||
#include "core/crypto/aes_util.h"
|
||||
#include "core/crypto/encryption_layer.h"
|
||||
#include "core/crypto/key_manager.h"
|
||||
@@ -14,18 +15,20 @@ namespace Core::Crypto {
|
||||
// Sits on top of a VirtualFile and provides CTR-mode AES decription.
|
||||
class CTREncryptionLayer : public EncryptionLayer {
|
||||
public:
|
||||
using IVData = std::array<u8, 16>;
|
||||
|
||||
CTREncryptionLayer(FileSys::VirtualFile base, Key128 key, std::size_t base_offset);
|
||||
|
||||
std::size_t Read(u8* data, std::size_t length, std::size_t offset) const override;
|
||||
|
||||
void SetIV(const std::vector<u8>& iv);
|
||||
void SetIV(const IVData& iv);
|
||||
|
||||
private:
|
||||
std::size_t base_offset;
|
||||
|
||||
// Must be mutable as operations modify cipher contexts.
|
||||
mutable AESCipher<Key128> cipher;
|
||||
mutable std::vector<u8> iv;
|
||||
mutable IVData iv{};
|
||||
|
||||
void UpdateIV(std::size_t offset) const;
|
||||
};
|
||||
|
||||
@@ -40,12 +40,14 @@ namespace Core::Crypto {
|
||||
constexpr u64 CURRENT_CRYPTO_REVISION = 0x5;
|
||||
constexpr u64 FULL_TICKET_SIZE = 0x400;
|
||||
|
||||
using namespace Common;
|
||||
using Common::AsArray;
|
||||
|
||||
const std::array<SHA256Hash, 2> eticket_source_hashes{
|
||||
"B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"_array32, // eticket_rsa_kek_source
|
||||
"E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"_array32, // eticket_rsa_kekek_source
|
||||
// clang-format off
|
||||
constexpr std::array eticket_source_hashes{
|
||||
AsArray("B71DB271DC338DF380AA2C4335EF8873B1AFD408E80B3582D8719FC81C5E511C"), // eticket_rsa_kek_source
|
||||
AsArray("E8965A187D30E57869F562D04383C996DE487BBA5761363D2D4D32391866A85C"), // eticket_rsa_kekek_source
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::map<std::pair<S128KeyType, u64>, std::string> KEYS_VARIABLE_LENGTH{
|
||||
{{S128KeyType::Master, 0}, "master_key_"},
|
||||
|
||||
@@ -27,7 +27,7 @@
|
||||
#include "core/file_sys/vfs_offset.h"
|
||||
#include "core/file_sys/vfs_vector.h"
|
||||
|
||||
using namespace Common;
|
||||
using Common::AsArray;
|
||||
|
||||
namespace Core::Crypto {
|
||||
|
||||
@@ -47,105 +47,123 @@ struct Package2Header {
|
||||
};
|
||||
static_assert(sizeof(Package2Header) == 0x200, "Package2Header has incorrect size.");
|
||||
|
||||
const std::array<SHA256Hash, 0x10> source_hashes{
|
||||
"B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"_array32, // keyblob_mac_key_source
|
||||
"7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"_array32, // master_key_source
|
||||
"21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"_array32, // package2_key_source
|
||||
"FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // aes_kek_generation_source
|
||||
"FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"_array32, // aes_key_generation_source
|
||||
"C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"_array32, // titlekek_source
|
||||
"04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"_array32, // key_area_key_application_source
|
||||
"FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"_array32, // key_area_key_ocean_source
|
||||
"1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"_array32, // key_area_key_system_source
|
||||
"6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"_array32, // sd_card_kek_source
|
||||
"D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"_array32, // sd_card_save_key_source
|
||||
"2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"_array32, // sd_card_nca_key_source
|
||||
"1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"_array32, // header_kek_source
|
||||
"8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"_array32, // header_key_source
|
||||
"D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"_array32, // rsa_kek_seed3
|
||||
"FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"_array32, // rsa_kek_mask0
|
||||
// clang-format off
|
||||
constexpr std::array source_hashes{
|
||||
AsArray("B24BD293259DBC7AC5D63F88E60C59792498E6FC5443402C7FFE87EE8B61A3F0"), // keyblob_mac_key_source
|
||||
AsArray("7944862A3A5C31C6720595EFD302245ABD1B54CCDCF33000557681E65C5664A4"), // master_key_source
|
||||
AsArray("21E2DF100FC9E094DB51B47B9B1D6E94ED379DB8B547955BEF8FE08D8DD35603"), // package2_key_source
|
||||
AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // aes_kek_generation_source
|
||||
AsArray("FBD10056999EDC7ACDB96098E47E2C3606230270D23281E671F0F389FC5BC585"), // aes_key_generation_source
|
||||
AsArray("C48B619827986C7F4E3081D59DB2B460C84312650E9A8E6B458E53E8CBCA4E87"), // titlekek_source
|
||||
AsArray("04AD66143C726B2A139FB6B21128B46F56C553B2B3887110304298D8D0092D9E"), // key_area_key_application_source
|
||||
AsArray("FD434000C8FF2B26F8E9A9D2D2C12F6BE5773CBB9DC86300E1BD99F8EA33A417"), // key_area_key_ocean_source
|
||||
AsArray("1F17B1FD51AD1C2379B58F152CA4912EC2106441E51722F38700D5937A1162F7"), // key_area_key_system_source
|
||||
AsArray("6B2ED877C2C52334AC51E59ABFA7EC457F4A7D01E46291E9F2EAA45F011D24B7"), // sd_card_kek_source
|
||||
AsArray("D482743563D3EA5DCDC3B74E97C9AC8A342164FA041A1DC80F17F6D31E4BC01C"), // sd_card_save_key_source
|
||||
AsArray("2E751CECF7D93A2B957BD5FFCB082FD038CC2853219DD3092C6DAB9838F5A7CC"), // sd_card_nca_key_source
|
||||
AsArray("1888CAED5551B3EDE01499E87CE0D86827F80820EFB275921055AA4E2ABDFFC2"), // header_kek_source
|
||||
AsArray("8F783E46852DF6BE0BA4E19273C4ADBAEE16380043E1B8C418C4089A8BD64AA6"), // header_key_source
|
||||
AsArray("D1757E52F1AE55FA882EC690BC6F954AC46A83DC22F277F8806BD55577C6EED7"), // rsa_kek_seed3
|
||||
AsArray("FC02B9D37B42D7A1452E71444F1F700311D1132E301A83B16062E72A78175085"), // rsa_kek_mask0
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::array<SHA256Hash, 0x20> keyblob_source_hashes{
|
||||
"8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"_array32, // keyblob_key_source_00
|
||||
"2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"_array32, // keyblob_key_source_01
|
||||
"61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"_array32, // keyblob_key_source_02
|
||||
"8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"_array32, // keyblob_key_source_03
|
||||
"95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"_array32, // keyblob_key_source_04
|
||||
"3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"_array32, // keyblob_key_source_05
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_06
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_07
|
||||
// clang-format off
|
||||
constexpr std::array keyblob_source_hashes{
|
||||
AsArray("8A06FE274AC491436791FDB388BCDD3AB9943BD4DEF8094418CDAC150FD73786"), // keyblob_key_source_00
|
||||
AsArray("2D5CAEB2521FEF70B47E17D6D0F11F8CE2C1E442A979AD8035832C4E9FBCCC4B"), // keyblob_key_source_01
|
||||
AsArray("61C5005E713BAE780641683AF43E5F5C0E03671117F702F401282847D2FC6064"), // keyblob_key_source_02
|
||||
AsArray("8E9795928E1C4428E1B78F0BE724D7294D6934689C11B190943923B9D5B85903"), // keyblob_key_source_03
|
||||
AsArray("95FA33AF95AFF9D9B61D164655B32710ED8D615D46C7D6CC3CC70481B686B402"), // keyblob_key_source_04
|
||||
AsArray("3F5BE7B3C8B1ABD8C10B4B703D44766BA08730562C172A4FE0D6B866B3E2DB3E"), // keyblob_key_source_05
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_06
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_07
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_08
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_09
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_0F
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_08
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_09
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_0F
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_10
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_11
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_12
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_13
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_14
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_15
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_16
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_17
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_10
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_11
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_12
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_13
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_14
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_15
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_16
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_17
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_18
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_19
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // keyblob_key_source_1F
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_18
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_19
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // keyblob_key_source_1F
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
const std::array<SHA256Hash, 0x20> master_key_hashes{
|
||||
"0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"_array32, // master_key_00
|
||||
"4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"_array32, // master_key_01
|
||||
"79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"_array32, // master_key_02
|
||||
"4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"_array32, // master_key_03
|
||||
"75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"_array32, // master_key_04
|
||||
"EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"_array32, // master_key_05
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_06
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_07
|
||||
// clang-format off
|
||||
constexpr std::array master_key_hashes{
|
||||
AsArray("0EE359BE3C864BB0782E1D70A718A0342C551EED28C369754F9C4F691BECF7CA"), // master_key_00
|
||||
AsArray("4FE707B7E4ABDAF727C894AAF13B1351BFE2AC90D875F73B2E20FA94B9CC661E"), // master_key_01
|
||||
AsArray("79277C0237A2252EC3DFAC1F7C359C2B3D121E9DB15BB9AB4C2B4408D2F3AE09"), // master_key_02
|
||||
AsArray("4F36C565D13325F65EE134073C6A578FFCB0008E02D69400836844EAB7432754"), // master_key_03
|
||||
AsArray("75FF1D95D26113550EE6FCC20ACB58E97EDEB3A2FF52543ED5AEC63BDCC3DA50"), // master_key_04
|
||||
AsArray("EBE2BCD6704673EC0F88A187BB2AD9F1CC82B718C389425941BDC194DC46B0DD"), // master_key_05
|
||||
AsArray("9497E6779F5D840F2BBA1DE4E95BA1D6F21EFC94717D5AE5CA37D7EC5BD37A19"), // master_key_06
|
||||
AsArray("4EC96B8CB01B8DCE382149443430B2B6EBCB2983348AFA04A25E53609DABEDF6"), // master_key_07
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_08
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_09
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_0F
|
||||
AsArray("2998E2E23609BC2675FF062A2D64AF5B1B78DFF463B24119D64A1B64F01B2D51"), // master_key_08
|
||||
AsArray("9D486A98067C44B37CF173D3BF577891EB6081FF6B4A166347D9DBBF7025076B"), // master_key_09
|
||||
AsArray("4EC5A237A75A083A9C5F6CF615601522A7F822D06BD4BA32612C9CEBBB29BD45"), // master_key_0A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_0F
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_10
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_11
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_12
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_13
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_14
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_15
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_16
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_17
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_10
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_11
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_12
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_13
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_14
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_15
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_16
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_17
|
||||
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_18
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_19
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1A
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1B
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1C
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1D
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1E
|
||||
"0000000000000000000000000000000000000000000000000000000000000000"_array32, // master_key_1F
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_18
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_19
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1A
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1B
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1C
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1D
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1E
|
||||
AsArray("0000000000000000000000000000000000000000000000000000000000000000"), // master_key_1F
|
||||
};
|
||||
// clang-format on
|
||||
|
||||
static constexpr u8 CalculateMaxKeyblobSourceHash() {
|
||||
const auto is_zero = [](const auto& data) {
|
||||
// TODO: Replace with std::all_of whenever mingw decides to update their
|
||||
// libraries to include the constexpr variant of it.
|
||||
for (const auto element : data) {
|
||||
if (element != 0) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
static u8 CalculateMaxKeyblobSourceHash() {
|
||||
for (s8 i = 0x1F; i >= 0; --i) {
|
||||
if (keyblob_source_hashes[i] != SHA256Hash{})
|
||||
if (!is_zero(keyblob_source_hashes[i])) {
|
||||
return static_cast<u8>(i + 1);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -346,10 +364,9 @@ FileSys::VirtualFile PartitionDataManager::GetPackage2Raw(Package2Type type) con
|
||||
}
|
||||
|
||||
static bool AttemptDecrypt(const std::array<u8, 16>& key, Package2Header& header) {
|
||||
const std::vector<u8> iv(header.header_ctr.begin(), header.header_ctr.end());
|
||||
Package2Header temp = header;
|
||||
AESCipher<Key128> cipher(key, Mode::CTR);
|
||||
cipher.SetIV(iv);
|
||||
cipher.SetIV(header.header_ctr);
|
||||
cipher.Transcode(&temp.header_ctr, sizeof(Package2Header) - 0x100, &temp.header_ctr,
|
||||
Op::Decrypt);
|
||||
if (temp.magic == Common::MakeMagic('P', 'K', '2', '1')) {
|
||||
@@ -388,7 +405,7 @@ void PartitionDataManager::DecryptPackage2(const std::array<Key128, 0x20>& packa
|
||||
auto c = a->ReadAllBytes();
|
||||
|
||||
AESCipher<Key128> cipher(package2_keys[revision], Mode::CTR);
|
||||
cipher.SetIV({header.section_ctr[1].begin(), header.section_ctr[1].end()});
|
||||
cipher.SetIV(header.section_ctr[1]);
|
||||
cipher.Transcode(c.data(), c.size(), c.data(), Op::Decrypt);
|
||||
|
||||
const auto ini_file = std::make_shared<FileSys::VectorVfsFile>(c);
|
||||
|
||||
@@ -495,9 +495,10 @@ VirtualFile NCA::Decrypt(const NCASectionHeader& s_header, VirtualFile in, u64 s
|
||||
|
||||
auto out = std::make_shared<Core::Crypto::CTREncryptionLayer>(std::move(in), *key,
|
||||
starting_offset);
|
||||
std::vector<u8> iv(16);
|
||||
for (u8 i = 0; i < 8; ++i)
|
||||
iv[i] = s_header.raw.section_ctr[0x8 - i - 1];
|
||||
Core::Crypto::CTREncryptionLayer::IVData iv{};
|
||||
for (std::size_t i = 0; i < 8; ++i) {
|
||||
iv[i] = s_header.raw.section_ctr[8 - i - 1];
|
||||
}
|
||||
out->SetIV(iv);
|
||||
return std::static_pointer_cast<VfsFile>(out);
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstring>
|
||||
|
||||
@@ -66,7 +67,7 @@ std::size_t BKTR::Read(u8* data, std::size_t length, std::size_t offset) const {
|
||||
Core::Crypto::AESCipher<Core::Crypto::Key128> cipher(key, Core::Crypto::Mode::CTR);
|
||||
|
||||
// Calculate AES IV
|
||||
std::vector<u8> iv(16);
|
||||
std::array<u8, 16> iv{};
|
||||
auto subsection_ctr = subsection.ctr;
|
||||
auto offset_iv = section_offset + base_offset;
|
||||
for (std::size_t i = 0; i < section_ctr.size(); ++i)
|
||||
|
||||
@@ -27,18 +27,12 @@ VirtualDir MiiModel() {
|
||||
auto out = std::make_shared<VectorVfsDirectory>(std::vector<VirtualFile>{},
|
||||
std::vector<VirtualDir>{}, "data");
|
||||
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_LINEAR.size()>>(
|
||||
MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_LOW_SRGB.size()>>(
|
||||
MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_LINEAR.size()>>(
|
||||
MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::TEXTURE_MID_SRGB.size()>>(
|
||||
MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_HIGH.size()>>(
|
||||
MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
|
||||
out->AddFile(std::make_shared<ArrayVfsFile<MiiModelData::SHAPE_MID.size()>>(
|
||||
MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_LINEAR, "NXTextureLowLinear.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_LOW_SRGB, "NXTextureLowSRGB.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_LINEAR, "NXTextureMidLinear.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::TEXTURE_MID_SRGB, "NXTextureMidSRGB.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::SHAPE_HIGH, "ShapeHigh.dat"));
|
||||
out->AddFile(MakeArrayFile(MiiModelData::SHAPE_MID, "ShapeMid.dat"));
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -24,19 +24,18 @@ constexpr std::array<u8, 30> WORD_TXT{
|
||||
} // namespace NgWord1Data
|
||||
|
||||
VirtualDir NgWord1() {
|
||||
std::vector<VirtualFile> files(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
std::vector<VirtualFile> files;
|
||||
files.reserve(NgWord1Data::NUMBER_WORD_TXT_FILES);
|
||||
|
||||
for (std::size_t i = 0; i < files.size(); ++i) {
|
||||
files[i] = std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, fmt::format("{}.txt", i));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, fmt::format("{}.txt", i)));
|
||||
}
|
||||
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::WORD_TXT.size()>>(
|
||||
NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord1Data::VERSION_DAT.size()>>(
|
||||
NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::WORD_TXT, "common.txt"));
|
||||
files.push_back(MakeArrayFile(NgWord1Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
|
||||
"data");
|
||||
}
|
||||
|
||||
namespace NgWord2Data {
|
||||
@@ -55,27 +54,22 @@ constexpr std::array<u8, 0x2C> AC_NX_DATA{
|
||||
} // namespace NgWord2Data
|
||||
|
||||
VirtualDir NgWord2() {
|
||||
std::vector<VirtualFile> files(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
std::vector<VirtualFile> files;
|
||||
files.reserve(NgWord2Data::NUMBER_AC_NX_FILES * 3);
|
||||
|
||||
for (std::size_t i = 0; i < NgWord2Data::NUMBER_AC_NX_FILES; ++i) {
|
||||
files[3 * i] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i));
|
||||
files[3 * i + 1] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i));
|
||||
files[3 * i + 2] = std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b1_nx", i)));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_b2_nx", i)));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, fmt::format("ac_{}_not_b_nx", i)));
|
||||
}
|
||||
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::AC_NX_DATA.size()>>(
|
||||
NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(std::make_shared<ArrayVfsFile<NgWord2Data::VERSION_DAT.size()>>(
|
||||
NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b1_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_b2_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::AC_NX_DATA, "ac_common_not_b_nx"));
|
||||
files.push_back(MakeArrayFile(NgWord2Data::VERSION_DAT, "version.dat"));
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(files, std::vector<VirtualDir>{}, "data");
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(files), std::vector<VirtualDir>{},
|
||||
"data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -654,12 +654,13 @@ static VirtualFile GenerateDefaultTimeZoneFile() {
|
||||
}
|
||||
|
||||
VirtualDir TimeZoneBinary() {
|
||||
const std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||
std::vector<VirtualDir> root_dirs{std::make_shared<VectorVfsDirectory>(
|
||||
std::vector<VirtualFile>{GenerateDefaultTimeZoneFile()}, std::vector<VirtualDir>{},
|
||||
"zoneinfo")};
|
||||
const std::vector<VirtualFile> root_files{
|
||||
std::make_shared<ArrayVfsFile<LOCATION_NAMES.size()>>(LOCATION_NAMES, "binaryList.txt")};
|
||||
return std::make_shared<VectorVfsDirectory>(root_files, root_dirs, "data");
|
||||
std::vector<VirtualFile> root_files{MakeArrayFile(LOCATION_NAMES, "binaryList.txt")};
|
||||
|
||||
return std::make_shared<VectorVfsDirectory>(std::move(root_files), std::move(root_dirs),
|
||||
"data");
|
||||
}
|
||||
|
||||
} // namespace FileSys::SystemArchive
|
||||
|
||||
@@ -4,7 +4,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include "core/file_sys/vfs.h"
|
||||
|
||||
namespace FileSys {
|
||||
@@ -13,7 +17,8 @@ namespace FileSys {
|
||||
template <std::size_t size>
|
||||
class ArrayVfsFile : public VfsFile {
|
||||
public:
|
||||
ArrayVfsFile(std::array<u8, size> data, std::string name = "", VirtualDir parent = nullptr)
|
||||
explicit ArrayVfsFile(const std::array<u8, size>& data, std::string name = "",
|
||||
VirtualDir parent = nullptr)
|
||||
: data(data), name(std::move(name)), parent(std::move(parent)) {}
|
||||
|
||||
std::string GetName() const override {
|
||||
@@ -61,6 +66,12 @@ private:
|
||||
VirtualDir parent;
|
||||
};
|
||||
|
||||
template <std::size_t Size, typename... Args>
|
||||
std::shared_ptr<ArrayVfsFile<Size>> MakeArrayFile(const std::array<u8, Size>& data,
|
||||
Args&&... args) {
|
||||
return std::make_shared<ArrayVfsFile<Size>>(data, std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
// An implementation of VfsFile that is backed by a vector optionally supplied upon construction
|
||||
class VectorVfsFile : public VfsFile {
|
||||
public:
|
||||
|
||||
@@ -229,6 +229,8 @@ inline void ResponseBuilder::Push(u32 value) {
|
||||
|
||||
template <typename T>
|
||||
void ResponseBuilder::PushRaw(const T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(cmdbuf + index, &value, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
@@ -384,6 +386,8 @@ inline s32 RequestParser::Pop() {
|
||||
|
||||
template <typename T>
|
||||
void RequestParser::PopRaw(T& value) {
|
||||
static_assert(std::is_trivially_copyable_v<T>,
|
||||
"It's undefined behavior to use memcpy with non-trivially copyable objects");
|
||||
std::memcpy(&value, cmdbuf + index, sizeof(T));
|
||||
index += (sizeof(T) + 3) / 4; // round up to word length
|
||||
}
|
||||
|
||||
@@ -81,7 +81,7 @@ ResultCode AddressArbiter::IncrementAndSignalToAddressIfEqual(VAddr address, s32
|
||||
do {
|
||||
current_value = monitor.ExclusiveRead32(current_core, address);
|
||||
|
||||
if (current_value != value) {
|
||||
if (current_value != static_cast<u32>(value)) {
|
||||
return ERR_INVALID_STATE;
|
||||
}
|
||||
current_value++;
|
||||
|
||||
@@ -604,7 +604,6 @@ ResultCode PageTable::MapPages(VAddr addr, const PageLinkedList& page_linked_lis
|
||||
if (const auto result{
|
||||
Operate(cur_addr, node.GetNumPages(), perm, OperationType::Map, node.GetAddress())};
|
||||
result.IsError()) {
|
||||
const MemoryInfo info{block_manager->FindBlock(cur_addr).GetMemoryInfo()};
|
||||
const std::size_t num_pages{(addr - cur_addr) / PageSize};
|
||||
|
||||
ASSERT(
|
||||
|
||||
@@ -131,7 +131,8 @@ u32 GlobalScheduler::SelectThreads() {
|
||||
u32 cores_needing_context_switch{};
|
||||
for (u32 core = 0; core < Core::Hardware::NUM_CPU_CORES; core++) {
|
||||
Scheduler& sched = kernel.Scheduler(core);
|
||||
ASSERT(top_threads[core] == nullptr || top_threads[core]->GetProcessorID() == core);
|
||||
ASSERT(top_threads[core] == nullptr ||
|
||||
static_cast<u32>(top_threads[core]->GetProcessorID()) == core);
|
||||
if (update_thread(top_threads[core], sched)) {
|
||||
cores_needing_context_switch |= (1ul << core);
|
||||
}
|
||||
@@ -663,32 +664,26 @@ void Scheduler::Reload() {
|
||||
}
|
||||
|
||||
void Scheduler::SwitchContextStep2() {
|
||||
Thread* previous_thread = current_thread_prev.get();
|
||||
Thread* new_thread = selected_thread.get();
|
||||
|
||||
// Load context of new thread
|
||||
Process* const previous_process =
|
||||
previous_thread != nullptr ? previous_thread->GetOwnerProcess() : nullptr;
|
||||
|
||||
if (new_thread) {
|
||||
ASSERT_MSG(new_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
|
||||
if (selected_thread) {
|
||||
ASSERT_MSG(selected_thread->GetSchedulingStatus() == ThreadSchedStatus::Runnable,
|
||||
"Thread must be runnable.");
|
||||
|
||||
// Cancel any outstanding wakeup events for this thread
|
||||
new_thread->SetIsRunning(true);
|
||||
new_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
|
||||
new_thread->SetWasRunning(false);
|
||||
selected_thread->SetIsRunning(true);
|
||||
selected_thread->last_running_ticks = system.CoreTiming().GetCPUTicks();
|
||||
selected_thread->SetWasRunning(false);
|
||||
|
||||
auto* const thread_owner_process = current_thread->GetOwnerProcess();
|
||||
if (thread_owner_process != nullptr) {
|
||||
system.Kernel().MakeCurrentProcess(thread_owner_process);
|
||||
}
|
||||
if (!new_thread->IsHLEThread()) {
|
||||
Core::ARM_Interface& cpu_core = new_thread->ArmInterface();
|
||||
cpu_core.LoadContext(new_thread->GetContext32());
|
||||
cpu_core.LoadContext(new_thread->GetContext64());
|
||||
cpu_core.SetTlsAddress(new_thread->GetTLSAddress());
|
||||
cpu_core.SetTPIDR_EL0(new_thread->GetTPIDR_EL0());
|
||||
if (!selected_thread->IsHLEThread()) {
|
||||
Core::ARM_Interface& cpu_core = selected_thread->ArmInterface();
|
||||
cpu_core.LoadContext(selected_thread->GetContext32());
|
||||
cpu_core.LoadContext(selected_thread->GetContext64());
|
||||
cpu_core.SetTlsAddress(selected_thread->GetTLSAddress());
|
||||
cpu_core.SetTPIDR_EL0(selected_thread->GetTPIDR_EL0());
|
||||
cpu_core.ChangeProcessorID(this->core_id);
|
||||
cpu_core.ClearExclusiveState();
|
||||
}
|
||||
|
||||
@@ -378,7 +378,11 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext&
|
||||
}
|
||||
|
||||
void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) {
|
||||
LOG_WARNING(Service_AM, "(STUBBED) called");
|
||||
IPC::RequestParser rp{ctx};
|
||||
const auto permission = rp.PopEnum<ScreenshotPermission>();
|
||||
LOG_DEBUG(Service_AM, "called, permission={}", permission);
|
||||
|
||||
screenshot_permission = permission;
|
||||
|
||||
IPC::ResponseBuilder rb{ctx, 2};
|
||||
rb.Push(RESULT_SUCCESS);
|
||||
|
||||
@@ -149,6 +149,12 @@ private:
|
||||
void GetAccumulatedSuspendedTickValue(Kernel::HLERequestContext& ctx);
|
||||
void GetAccumulatedSuspendedTickChangedEvent(Kernel::HLERequestContext& ctx);
|
||||
|
||||
enum class ScreenshotPermission : u32 {
|
||||
Inherit = 0,
|
||||
Enable = 1,
|
||||
Disable = 2,
|
||||
};
|
||||
|
||||
Core::System& system;
|
||||
std::shared_ptr<NVFlinger::NVFlinger> nvflinger;
|
||||
Kernel::EventPair launchable_event;
|
||||
@@ -157,6 +163,7 @@ private:
|
||||
u32 idle_time_detection_extension = 0;
|
||||
u64 num_fatal_sections_entered = 0;
|
||||
bool is_auto_sleep_disabled = false;
|
||||
ScreenshotPermission screenshot_permission = ScreenshotPermission::Inherit;
|
||||
};
|
||||
|
||||
class ICommonStateGetter final : public ServiceFramework<ICommonStateGetter> {
|
||||
|
||||
@@ -24,13 +24,13 @@ BufferQueue::~BufferQueue() = default;
|
||||
void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) {
|
||||
LOG_WARNING(Service, "Adding graphics buffer {}", slot);
|
||||
|
||||
Buffer buffer{};
|
||||
buffer.slot = slot;
|
||||
buffer.igbp_buffer = igbp_buffer;
|
||||
buffer.status = Buffer::Status::Free;
|
||||
free_buffers.push_back(slot);
|
||||
queue.push_back({
|
||||
.slot = slot,
|
||||
.status = Buffer::Status::Free,
|
||||
.igbp_buffer = igbp_buffer,
|
||||
});
|
||||
|
||||
queue.emplace_back(buffer);
|
||||
buffer_wait_event.writable->Signal();
|
||||
}
|
||||
|
||||
@@ -38,7 +38,7 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue
|
||||
u32 height) {
|
||||
|
||||
if (free_buffers.empty()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
auto f_itr = free_buffers.begin();
|
||||
@@ -69,7 +69,7 @@ std::optional<std::pair<u32, Service::Nvidia::MultiFence*>> BufferQueue::Dequeue
|
||||
}
|
||||
|
||||
if (itr == queue.end()) {
|
||||
return {};
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
itr->status = Buffer::Status::Dequeued;
|
||||
@@ -103,14 +103,15 @@ std::optional<std::reference_wrapper<const BufferQueue::Buffer>> BufferQueue::Ac
|
||||
auto itr = queue.end();
|
||||
// Iterate to find a queued buffer matching the requested slot.
|
||||
while (itr == queue.end() && !queue_sequence.empty()) {
|
||||
u32 slot = queue_sequence.front();
|
||||
const u32 slot = queue_sequence.front();
|
||||
itr = std::find_if(queue.begin(), queue.end(), [&slot](const Buffer& buffer) {
|
||||
return buffer.status == Buffer::Status::Queued && buffer.slot == slot;
|
||||
});
|
||||
queue_sequence.pop_front();
|
||||
}
|
||||
if (itr == queue.end())
|
||||
return {};
|
||||
if (itr == queue.end()) {
|
||||
return std::nullopt;
|
||||
}
|
||||
itr->status = Buffer::Status::Acquired;
|
||||
return *itr;
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ public:
|
||||
ResultVal<std::shared_ptr<Kernel::ClientPort>> GetServicePort(const std::string& name);
|
||||
ResultVal<std::shared_ptr<Kernel::ClientSession>> ConnectToService(const std::string& name);
|
||||
|
||||
template <Common::IsBaseOf<Kernel::SessionRequestHandler> T>
|
||||
template <Common::DerivedFrom<Kernel::SessionRequestHandler> T>
|
||||
std::shared_ptr<T> GetService(const std::string& service_name) const {
|
||||
auto service = registered_services.find(service_name);
|
||||
if (service == registered_services.end()) {
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <ostream>
|
||||
#include <string>
|
||||
#include "common/concepts.h"
|
||||
#include "common/file_util.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "common/string_util.h"
|
||||
@@ -21,27 +23,41 @@
|
||||
|
||||
namespace Loader {
|
||||
|
||||
namespace {
|
||||
|
||||
template <Common::DerivedFrom<AppLoader> T>
|
||||
std::optional<FileType> IdentifyFileLoader(FileSys::VirtualFile file) {
|
||||
const auto file_type = T::IdentifyType(file);
|
||||
if (file_type != FileType::Error) {
|
||||
return file_type;
|
||||
}
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
FileType IdentifyFile(FileSys::VirtualFile file) {
|
||||
FileType type;
|
||||
|
||||
#define CHECK_TYPE(loader) \
|
||||
type = AppLoader_##loader::IdentifyType(file); \
|
||||
if (FileType::Error != type) \
|
||||
return type;
|
||||
|
||||
CHECK_TYPE(DeconstructedRomDirectory)
|
||||
CHECK_TYPE(ELF)
|
||||
CHECK_TYPE(NSO)
|
||||
CHECK_TYPE(NRO)
|
||||
CHECK_TYPE(NCA)
|
||||
CHECK_TYPE(XCI)
|
||||
CHECK_TYPE(NAX)
|
||||
CHECK_TYPE(NSP)
|
||||
CHECK_TYPE(KIP)
|
||||
|
||||
#undef CHECK_TYPE
|
||||
|
||||
return FileType::Unknown;
|
||||
if (const auto romdir_type = IdentifyFileLoader<AppLoader_DeconstructedRomDirectory>(file)) {
|
||||
return *romdir_type;
|
||||
} else if (const auto elf_type = IdentifyFileLoader<AppLoader_ELF>(file)) {
|
||||
return *elf_type;
|
||||
} else if (const auto nso_type = IdentifyFileLoader<AppLoader_NSO>(file)) {
|
||||
return *nso_type;
|
||||
} else if (const auto nro_type = IdentifyFileLoader<AppLoader_NRO>(file)) {
|
||||
return *nro_type;
|
||||
} else if (const auto nca_type = IdentifyFileLoader<AppLoader_NCA>(file)) {
|
||||
return *nca_type;
|
||||
} else if (const auto xci_type = IdentifyFileLoader<AppLoader_XCI>(file)) {
|
||||
return *xci_type;
|
||||
} else if (const auto nax_type = IdentifyFileLoader<AppLoader_NAX>(file)) {
|
||||
return *nax_type;
|
||||
} else if (const auto nsp_type = IdentifyFileLoader<AppLoader_NSP>(file)) {
|
||||
return *nsp_type;
|
||||
} else if (const auto kip_type = IdentifyFileLoader<AppLoader_KIP>(file)) {
|
||||
return *kip_type;
|
||||
} else {
|
||||
return FileType::Unknown;
|
||||
}
|
||||
}
|
||||
|
||||
FileType GuessFromFilename(const std::string& name) {
|
||||
|
||||
@@ -704,7 +704,7 @@ struct Memory::Impl {
|
||||
u8* page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
if (page_pointer != nullptr) {
|
||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||
T volatile* pointer = reinterpret_cast<T volatile*>(&page_pointer[vaddr]);
|
||||
auto* pointer = reinterpret_cast<volatile T*>(&page_pointer[vaddr]);
|
||||
return Common::AtomicCompareAndSwap(pointer, data, expected);
|
||||
}
|
||||
|
||||
@@ -720,9 +720,8 @@ struct Memory::Impl {
|
||||
case Common::PageType::RasterizerCachedMemory: {
|
||||
u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
|
||||
system.GPU().InvalidateRegion(vaddr, sizeof(T));
|
||||
T volatile* pointer = reinterpret_cast<T volatile*>(&host_ptr);
|
||||
auto* pointer = reinterpret_cast<volatile T*>(&host_ptr);
|
||||
return Common::AtomicCompareAndSwap(pointer, data, expected);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
@@ -734,7 +733,7 @@ struct Memory::Impl {
|
||||
u8* const page_pointer = current_page_table->pointers[vaddr >> PAGE_BITS];
|
||||
if (page_pointer != nullptr) {
|
||||
// NOTE: Avoid adding any extra logic to this fast-path block
|
||||
u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&page_pointer[vaddr]);
|
||||
auto* pointer = reinterpret_cast<volatile u64*>(&page_pointer[vaddr]);
|
||||
return Common::AtomicCompareAndSwap(pointer, data, expected);
|
||||
}
|
||||
|
||||
@@ -750,9 +749,8 @@ struct Memory::Impl {
|
||||
case Common::PageType::RasterizerCachedMemory: {
|
||||
u8* host_ptr{GetPointerFromRasterizerCachedMemory(vaddr)};
|
||||
system.GPU().InvalidateRegion(vaddr, sizeof(u128));
|
||||
u64 volatile* pointer = reinterpret_cast<u64 volatile*>(&host_ptr);
|
||||
auto* pointer = reinterpret_cast<volatile u64*>(&host_ptr);
|
||||
return Common::AtomicCompareAndSwap(pointer, data, expected);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE();
|
||||
|
||||
@@ -199,17 +199,29 @@ void CheatEngine::Initialize() {
|
||||
metadata.title_id = system.CurrentProcess()->GetTitleID();
|
||||
|
||||
const auto& page_table = system.CurrentProcess()->PageTable();
|
||||
metadata.heap_extents = {page_table.GetHeapRegionStart(), page_table.GetHeapRegionSize()};
|
||||
metadata.address_space_extents = {page_table.GetAddressSpaceStart(),
|
||||
page_table.GetAddressSpaceSize()};
|
||||
metadata.alias_extents = {page_table.GetAliasCodeRegionStart(),
|
||||
page_table.GetAliasCodeRegionSize()};
|
||||
metadata.heap_extents = {
|
||||
.base = page_table.GetHeapRegionStart(),
|
||||
.size = page_table.GetHeapRegionSize(),
|
||||
};
|
||||
|
||||
metadata.address_space_extents = {
|
||||
.base = page_table.GetAddressSpaceStart(),
|
||||
.size = page_table.GetAddressSpaceSize(),
|
||||
};
|
||||
|
||||
metadata.alias_extents = {
|
||||
.base = page_table.GetAliasCodeRegionStart(),
|
||||
.size = page_table.GetAliasCodeRegionSize(),
|
||||
};
|
||||
|
||||
is_pending_reload.exchange(true);
|
||||
}
|
||||
|
||||
void CheatEngine::SetMainMemoryParameters(VAddr main_region_begin, u64 main_region_size) {
|
||||
metadata.main_nso_extents = {main_region_begin, main_region_size};
|
||||
metadata.main_nso_extents = {
|
||||
.base = main_region_begin,
|
||||
.size = main_region_size,
|
||||
};
|
||||
}
|
||||
|
||||
void CheatEngine::Reload(std::vector<CheatEntry> cheats) {
|
||||
|
||||
@@ -148,19 +148,17 @@ void GCButtonFactory::EndConfiguration() {
|
||||
|
||||
class GCAnalog final : public Input::AnalogDevice {
|
||||
public:
|
||||
GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter)
|
||||
GCAnalog(int port_, int axis_x_, int axis_y_, float deadzone_, GCAdapter::Adapter* adapter,
|
||||
float range_)
|
||||
: port(port_), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_), gcadapter(adapter),
|
||||
origin_value_x(adapter->GetOriginValue(port_, axis_x_)),
|
||||
origin_value_y(adapter->GetOriginValue(port_, axis_y_)) {}
|
||||
origin_value_y(adapter->GetOriginValue(port_, axis_y_)), range(range_) {}
|
||||
|
||||
float GetAxis(int axis) const {
|
||||
if (gcadapter->DeviceConnected(port)) {
|
||||
std::lock_guard lock{mutex};
|
||||
const auto origin_value = axis % 2 == 0 ? origin_value_x : origin_value_y;
|
||||
// division is not by a perfect 128 to account for some variance in center location
|
||||
// e.g. my device idled at 131 in X, 120 in Y, and full range of motion was in range
|
||||
// [20-230]
|
||||
return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / 95.0f;
|
||||
return (gcadapter->GetPadState()[port].axes.at(axis) - origin_value) / (100.0f * range);
|
||||
}
|
||||
return 0.0f;
|
||||
}
|
||||
@@ -215,6 +213,7 @@ private:
|
||||
GCAdapter::Adapter* gcadapter;
|
||||
const float origin_value_x;
|
||||
const float origin_value_y;
|
||||
const float range;
|
||||
mutable std::mutex mutex;
|
||||
};
|
||||
|
||||
@@ -234,8 +233,9 @@ std::unique_ptr<Input::AnalogDevice> GCAnalogFactory::Create(const Common::Param
|
||||
const int axis_x = params.Get("axis_x", 0);
|
||||
const int axis_y = params.Get("axis_y", 1);
|
||||
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
|
||||
const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
|
||||
|
||||
return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get());
|
||||
return std::make_unique<GCAnalog>(port, axis_x, axis_y, deadzone, adapter.get(), range);
|
||||
}
|
||||
|
||||
void GCAnalogFactory::BeginConfiguration() {
|
||||
|
||||
@@ -66,14 +66,14 @@ public:
|
||||
state.axes.insert_or_assign(axis, value);
|
||||
}
|
||||
|
||||
float GetAxis(int axis) const {
|
||||
float GetAxis(int axis, float range) const {
|
||||
std::lock_guard lock{mutex};
|
||||
return state.axes.at(axis) / 32767.0f;
|
||||
return state.axes.at(axis) / (32767.0f * range);
|
||||
}
|
||||
|
||||
std::tuple<float, float> GetAnalog(int axis_x, int axis_y) const {
|
||||
float x = GetAxis(axis_x);
|
||||
float y = GetAxis(axis_y);
|
||||
std::tuple<float, float> GetAnalog(int axis_x, int axis_y, float range) const {
|
||||
float x = GetAxis(axis_x, range);
|
||||
float y = GetAxis(axis_y, range);
|
||||
y = -y; // 3DS uses an y-axis inverse from SDL
|
||||
|
||||
// Make sure the coordinates are in the unit circle,
|
||||
@@ -313,7 +313,7 @@ public:
|
||||
trigger_if_greater(trigger_if_greater_) {}
|
||||
|
||||
bool GetStatus() const override {
|
||||
const float axis_value = joystick->GetAxis(axis);
|
||||
const float axis_value = joystick->GetAxis(axis, 1.0f);
|
||||
if (trigger_if_greater) {
|
||||
return axis_value > threshold;
|
||||
}
|
||||
@@ -329,11 +329,13 @@ private:
|
||||
|
||||
class SDLAnalog final : public Input::AnalogDevice {
|
||||
public:
|
||||
SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_)
|
||||
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_) {}
|
||||
SDLAnalog(std::shared_ptr<SDLJoystick> joystick_, int axis_x_, int axis_y_, float deadzone_,
|
||||
float range_)
|
||||
: joystick(std::move(joystick_)), axis_x(axis_x_), axis_y(axis_y_), deadzone(deadzone_),
|
||||
range(range_) {}
|
||||
|
||||
std::tuple<float, float> GetStatus() const override {
|
||||
const auto [x, y] = joystick->GetAnalog(axis_x, axis_y);
|
||||
const auto [x, y] = joystick->GetAnalog(axis_x, axis_y, range);
|
||||
const float r = std::sqrt((x * x) + (y * y));
|
||||
if (r > deadzone) {
|
||||
return std::make_tuple(x / r * (r - deadzone) / (1 - deadzone),
|
||||
@@ -363,6 +365,7 @@ private:
|
||||
const int axis_x;
|
||||
const int axis_y;
|
||||
const float deadzone;
|
||||
const float range;
|
||||
};
|
||||
|
||||
/// A button device factory that creates button devices from SDL joystick
|
||||
@@ -458,13 +461,13 @@ public:
|
||||
const int axis_x = params.Get("axis_x", 0);
|
||||
const int axis_y = params.Get("axis_y", 1);
|
||||
const float deadzone = std::clamp(params.Get("deadzone", 0.0f), 0.0f, .99f);
|
||||
|
||||
const float range = std::clamp(params.Get("range", 1.0f), 0.50f, 1.50f);
|
||||
auto joystick = state.GetSDLJoystickByGUID(guid, port);
|
||||
|
||||
// This is necessary so accessing GetAxis with axis_x and axis_y won't crash
|
||||
joystick->SetAxis(axis_x, 0);
|
||||
joystick->SetAxis(axis_y, 0);
|
||||
return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone);
|
||||
return std::make_unique<SDLAnalog>(joystick, axis_x, axis_y, deadzone, range);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -1574,8 +1574,7 @@ std::string ARBDecompiler::Select(Operation operation) {
|
||||
}
|
||||
|
||||
std::string ARBDecompiler::FClamp(Operation operation) {
|
||||
// 1.0f in hex, replace with std::bit_cast on C++20
|
||||
static constexpr u32 POSITIVE_ONE = 0x3f800000;
|
||||
static constexpr u32 POSITIVE_ONE = std::bit_cast<u32>(1.0f);
|
||||
|
||||
std::string temporary = AllocTemporary();
|
||||
const Node& value = operation[0];
|
||||
|
||||
@@ -96,7 +96,6 @@ SurfaceParams SurfaceParams::CreateForTexture(const FormatLookupTable& lookup_ta
|
||||
}
|
||||
params.type = GetFormatType(params.pixel_format);
|
||||
}
|
||||
params.type = GetFormatType(params.pixel_format);
|
||||
// TODO: on 1DBuffer we should use the tic info.
|
||||
if (tic.IsBuffer()) {
|
||||
params.target = SurfaceTarget::TextureBuffer;
|
||||
|
||||
Reference in New Issue
Block a user