mirror of
https://github.com/Atmosphere-NX/Atmosphere.git
synced 2024-11-27 17:11:00 +01:00
Implement working prodinfo blanking.
This commit is contained in:
parent
3bba035b84
commit
967f14fc7e
@ -282,7 +282,11 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue)
|
||||
break;
|
||||
case CONFIGITEM_HAS_RCM_BUG_PATCH:
|
||||
/* UNOFFICIAL: Gets whether this unit has the RCM bug patched. */
|
||||
*p_outvalue = (int)(fuse_has_rcm_bug_patch());;
|
||||
*p_outvalue = (int)(fuse_has_rcm_bug_patch());
|
||||
break;
|
||||
case CONFIGITEM_SHOULD_BLANK_PROD_INFO:
|
||||
/* UNOFFICIAL: Gets whether we should blank out certain parts of PRODINFO. */
|
||||
*p_outvalue = (int)(exosphere_should_blank_prod_info() != 0);
|
||||
break;
|
||||
default:
|
||||
result = 2;
|
||||
|
@ -45,6 +45,7 @@ typedef enum {
|
||||
CONFIGITEM_NEEDS_SHUTDOWN = 65002,
|
||||
CONFIGITEM_EXOSPHERE_VERHASH = 65003,
|
||||
CONFIGITEM_HAS_RCM_BUG_PATCH = 65004,
|
||||
CONFIGITEM_SHOULD_BLANK_PROD_INFO = 65005,
|
||||
} ConfigItem;
|
||||
|
||||
#define REBOOT_KIND_NO_REBOOT 0
|
||||
|
@ -83,3 +83,11 @@ unsigned int exosphere_should_disable_usermode_exception_handlers(void) {
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS);
|
||||
}
|
||||
|
||||
unsigned int exosphere_should_blank_prod_info(void) {
|
||||
if (!g_has_loaded_config) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return EXOSPHERE_CHECK_FLAG(EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO);
|
||||
}
|
||||
|
@ -39,6 +39,7 @@
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
#define EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO (1 << 4u)
|
||||
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
|
||||
|
||||
typedef struct {
|
||||
@ -54,6 +55,7 @@ unsigned int exosphere_should_perform_620_keygen(void);
|
||||
unsigned int exosphere_should_override_debugmode_priv(void);
|
||||
unsigned int exosphere_should_override_debugmode_user(void);
|
||||
unsigned int exosphere_should_disable_usermode_exception_handlers(void);
|
||||
unsigned int exosphere_should_blank_prod_info(void);
|
||||
|
||||
static inline unsigned int exosphere_get_target_firmware_for_init(void) {
|
||||
const unsigned int magic = MAILBOX_EXOSPHERE_CONFIG_PHYS.magic;
|
||||
|
@ -28,6 +28,7 @@
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV (1 << 1u)
|
||||
#define EXOSPHERE_FLAG_IS_DEBUGMODE_USER (1 << 2u)
|
||||
#define EXOSPHERE_FLAG_DISABLE_USERMODE_EXCEPTION_HANDLERS (1 << 3u)
|
||||
#define EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO (1 << 4u)
|
||||
#define EXOSPHERE_FLAGS_DEFAULT (EXOSPHERE_FLAG_IS_DEBUGMODE_PRIV)
|
||||
|
||||
typedef struct {
|
||||
|
@ -199,6 +199,14 @@ static void nxboot_configure_exosphere(uint32_t target_firmware, unsigned int ke
|
||||
fatal_error("[NXBOOT]: Failed to parse BCT.ini!\n");
|
||||
}
|
||||
|
||||
{
|
||||
FILE *flag = fopen("atmosphere/flags/blank_prodinfo.flag", "rb");
|
||||
if (flag != NULL) {
|
||||
exo_cfg.flags |= EXOSPHERE_FLAG_SHOULD_BLANK_PRODINFO;
|
||||
fclose(flag);
|
||||
}
|
||||
}
|
||||
|
||||
if ((exo_cfg.target_firmware < ATMOSPHERE_TARGET_FIRMWARE_MIN) || (exo_cfg.target_firmware > ATMOSPHERE_TARGET_FIRMWARE_MAX)) {
|
||||
fatal_error("[NXBOOT]: Invalid Exosphere target firmware!\n");
|
||||
}
|
||||
|
@ -112,7 +112,6 @@ class IROStorage : public IStorage {
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) = 0;
|
||||
};
|
||||
|
||||
|
||||
class ProxyStorage : public IStorage {
|
||||
private:
|
||||
FsStorage *base_storage;
|
||||
@ -172,4 +171,4 @@ class ROProxyStorage : public IROStorage {
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
return fsStorageOperateRange(this->base_storage, operation_type, offset, size, out_range_info);
|
||||
};
|
||||
};
|
||||
};
|
||||
|
113
stratosphere/ams_mitm/source/fs_mitm/fs_memory_storage.hpp
Normal file
113
stratosphere/ams_mitm/source/fs_mitm/fs_memory_storage.hpp
Normal file
@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
#include <stratosphere.hpp>
|
||||
#include "fs_shim.h"
|
||||
|
||||
#include "../debug.hpp"
|
||||
#include "fs_istorage.hpp"
|
||||
|
||||
class MemoryStorage : public IStorage {
|
||||
private:
|
||||
u8 * const buffer;
|
||||
const u64 size;
|
||||
public:
|
||||
MemoryStorage(void *b, u64 sz) : buffer(static_cast<u8 *>(b)), size(sz) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~MemoryStorage() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
if (size == 0) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||
return ResultFsOutOfRange;
|
||||
}
|
||||
|
||||
std::memcpy(buffer, this->buffer + offset, size);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
if (size == 0) {
|
||||
return ResultSuccess;
|
||||
}
|
||||
if (buffer == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
if (!IStorage::IsRangeValid(offset, size, this->size)) {
|
||||
return ResultFsOutOfRange;
|
||||
}
|
||||
|
||||
std::memcpy(this->buffer + offset, buffer, size);
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result GetSize(u64 *out_size) override {
|
||||
*out_size = this->size;
|
||||
return ResultSuccess;
|
||||
}
|
||||
|
||||
virtual Result SetSize(u64 size) override {
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
switch (operation_type) {
|
||||
case 2: /* TODO: OperationType_Invalidate */
|
||||
return ResultSuccess;
|
||||
case 3: /* TODO: OperationType_Query */
|
||||
if (out_range_info == nullptr) {
|
||||
return ResultFsNullptrArgument;
|
||||
}
|
||||
/* N checks for size == sizeof(*out_range_info) here, but that's because their wrapper api is bad. */
|
||||
std::memset(out_range_info, 0, sizeof(*out_range_info));
|
||||
return ResultSuccess;
|
||||
default:
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
class ReadOnlyMemoryStorage : public MemoryStorage {
|
||||
public:
|
||||
ReadOnlyMemoryStorage(const void *b, u64 sz) : MemoryStorage(const_cast<void *>(b), sz) {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
virtual ~ReadOnlyMemoryStorage() {
|
||||
/* ... */
|
||||
}
|
||||
|
||||
public:
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
return ResultFsUnsupportedOperation;
|
||||
}
|
||||
};
|
@ -27,12 +27,14 @@
|
||||
#include "fsmitm_boot0storage.hpp"
|
||||
#include "fsmitm_romstorage.hpp"
|
||||
#include "fsmitm_layeredrom.hpp"
|
||||
#include "fsmitm_utils.hpp"
|
||||
|
||||
#include "fs_dir_utils.hpp"
|
||||
#include "fs_save_utils.hpp"
|
||||
#include "fs_subdirectory_filesystem.hpp"
|
||||
#include "fs_directory_savedata_filesystem.hpp"
|
||||
#include "fs_file_storage.hpp"
|
||||
#include "fs_memory_storage.hpp"
|
||||
|
||||
#include "../debug.hpp"
|
||||
|
||||
@ -262,23 +264,13 @@ Result FsMitmService::OpenBisStorage(Out<std::shared_ptr<IStorageInterface>> out
|
||||
const bool is_sysmodule = TitleIdIsSystem(this->title_id);
|
||||
const bool has_bis_write_flag = Utils::HasFlag(this->title_id, "bis_write");
|
||||
const bool has_cal0_read_flag = Utils::HasFlag(this->title_id, "cal_read");
|
||||
const bool has_blank_cal0_flag = Utils::HasGlobalFlag("blank_prodinfo");
|
||||
const bool has_blank_cal0_flag = ShouldBlankProdInfo();
|
||||
if (bis_partition_id == BisStorageId_Boot0) {
|
||||
storage = std::make_shared<IStorageInterface>(new Boot0Storage(bis_storage, this->title_id));
|
||||
} else if (bis_partition_id == BisStorageId_Prodinfo) {
|
||||
/* PRODINFO should *never* be writable. */
|
||||
if (has_blank_cal0_flag) {
|
||||
FsFile file;
|
||||
|
||||
if (R_FAILED((rc = Utils::OpenBlankProdInfoFile(&file)))) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
storage = std::make_shared<IStorageInterface>(new FileStorage(new ProxyFile(&file)));
|
||||
if (out_storage.IsDomain()) {
|
||||
out_domain_id = file.s.object_id;
|
||||
}
|
||||
return rc;
|
||||
storage = std::make_shared<IStorageInterface>(new MitmProxyStorage(std::make_unique<ReadOnlyMemoryStorage>(Utils::GetBlankProdInfoBuffer(), ProdInfoSize), bis_storage.s));
|
||||
} else if (is_sysmodule || has_cal0_read_flag) {
|
||||
storage = std::make_shared<IStorageInterface>(new ROProxyStorage(bis_storage));
|
||||
} else {
|
||||
|
59
stratosphere/ams_mitm/source/fs_mitm/fsmitm_utils.hpp
Normal file
59
stratosphere/ams_mitm/source/fs_mitm/fsmitm_utils.hpp
Normal file
@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2019 Atmosphère-NX
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify it
|
||||
* under the terms and conditions of the GNU General Public License,
|
||||
* version 2, as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
|
||||
* more details.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include <switch.h>
|
||||
|
||||
#include "fs_istorage.hpp"
|
||||
|
||||
class MitmProxyStorage : public IStorage {
|
||||
private:
|
||||
Service srv_holder;
|
||||
std::unique_ptr<IStorage> fwd_storage;
|
||||
public:
|
||||
MitmProxyStorage(std::unique_ptr<IStorage> st, Service sr = {}) : srv_holder(sr), fwd_storage(std::move(st)) {
|
||||
/* ... */
|
||||
}
|
||||
virtual ~MitmProxyStorage() {
|
||||
if (serviceIsActive(&srv_holder)) {
|
||||
serviceClose(&srv_holder);
|
||||
}
|
||||
}
|
||||
public:
|
||||
virtual Result Read(void *buffer, size_t size, u64 offset) override {
|
||||
return this->fwd_storage->Read(buffer, size, offset);
|
||||
}
|
||||
|
||||
virtual Result Write(void *buffer, size_t size, u64 offset) override {
|
||||
return this->fwd_storage->Write(buffer, size, offset);
|
||||
}
|
||||
|
||||
virtual Result Flush() override {
|
||||
return this->fwd_storage->Flush();
|
||||
}
|
||||
|
||||
virtual Result GetSize(u64 *out_size) override {
|
||||
return this->fwd_storage->GetSize(out_size);
|
||||
}
|
||||
|
||||
virtual Result SetSize(u64 size) override {
|
||||
return this->fwd_storage->SetSize(size);
|
||||
}
|
||||
|
||||
virtual Result OperateRange(u32 operation_type, u64 offset, u64 size, FsRangeInfo *out_range_info) override {
|
||||
return this->fwd_storage->OperateRange(operation_type, offset, size, out_range_info);
|
||||
}
|
||||
};
|
@ -60,13 +60,13 @@ static HblOverrideConfig g_hbl_override_config = {
|
||||
static char g_config_ini_data[0x800];
|
||||
|
||||
/* Backup file for CAL0 partition. */
|
||||
static constexpr size_t ProdInfoSize = 0x8000;
|
||||
static constexpr const char *BlankProdInfoPath = "/atmosphere/automatic_backups/BLANK_PRODINFO.bin";
|
||||
static FsFile g_cal0_file = {0};
|
||||
static u8 g_cal0_storage_backup[ProdInfoSize];
|
||||
static u8 g_cal0_backup[ProdInfoSize];
|
||||
|
||||
static FsFile g_blank_prodinfo_file = {0};
|
||||
static HosMutex g_blank_cal0_lock;
|
||||
static bool g_initialized_blank_cal0 = false;
|
||||
static u8 g_blank_cal0[ProdInfoSize];
|
||||
|
||||
static bool IsHexadecimal(const char *str) {
|
||||
while (*str) {
|
||||
@ -142,9 +142,6 @@ void Utils::InitializeThreadFunc(void *args) {
|
||||
fsFileFlush(&g_cal0_file);
|
||||
}
|
||||
|
||||
/* Use one of the storages to make a blank prodinfo file. */
|
||||
Utils::CreateBlankProdInfo();
|
||||
|
||||
/* NOTE: g_cal0_file is intentionally not closed here. This prevents any other process from opening it. */
|
||||
std::memset(g_cal0_storage_backup, 0, sizeof(g_cal0_storage_backup));
|
||||
std::memset(g_cal0_backup, 0, sizeof(g_cal0_backup));
|
||||
@ -672,81 +669,60 @@ void Utils::RebootToFatalError(AtmosphereFatalErrorContext *ctx) {
|
||||
BpcRebootManager::RebootForFatalError(ctx);
|
||||
}
|
||||
|
||||
void Utils::CreateBlankProdInfo() {
|
||||
Result rc;
|
||||
void Utils::EnsureBlankProdInfo() {
|
||||
std::scoped_lock<HosMutex> lk(g_blank_cal0_lock);
|
||||
if (g_initialized_blank_cal0) {
|
||||
return;
|
||||
}
|
||||
|
||||
u8 *cal0;
|
||||
if (IsCal0Valid(g_cal0_backup)) {
|
||||
cal0 = g_cal0_backup;
|
||||
} else if (IsCal0Valid(g_cal0_storage_backup)) {
|
||||
cal0 = g_cal0_storage_backup;
|
||||
} else {
|
||||
/* Read CAL0 in from NAND. */
|
||||
{
|
||||
FsStorage cal0_storage;
|
||||
if (R_FAILED(fsOpenBisStorage(&cal0_storage, BisStorageId_Prodinfo)) || R_FAILED(fsStorageRead(&cal0_storage, 0, g_blank_cal0, ProdInfoSize))) {
|
||||
std::abort();
|
||||
}
|
||||
fsStorageClose(&cal0_storage);
|
||||
}
|
||||
|
||||
if (!IsCal0Valid(g_blank_cal0)) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
const char blank_serial[] = "XAW00000000000";
|
||||
std::memcpy(&cal0[0x250], blank_serial, sizeof(blank_serial) - 1);
|
||||
std::memcpy(&g_blank_cal0[0x250], blank_serial, sizeof(blank_serial) - 1);
|
||||
|
||||
static constexpr size_t NumErase = 7;
|
||||
|
||||
for (size_t i = 0; i < NumErase; i++) {
|
||||
static constexpr size_t s_erase_offsets[NumErase] = {0xAE0, 0x3AE0, 0x35E1, 0x36E1, 0x2B0, 0x3D70, 0x3FC0};
|
||||
static constexpr size_t s_erase_sizes[NumErase] = {0x800, 0x130, 0x6, 0x6, 0x180, 0x240, 0x240};
|
||||
std::memset(&cal0[s_erase_offsets[i]], 0, s_erase_sizes[i]);
|
||||
std::memset(&g_blank_cal0[s_erase_offsets[i]], 0, s_erase_sizes[i]);
|
||||
}
|
||||
|
||||
static constexpr size_t NumHashes = 2;
|
||||
{
|
||||
static constexpr size_t s_hash_offsets[NumHashes] = {0x12E0, 0x20};
|
||||
static constexpr size_t s_data_offsets[NumHashes] = {0xAE0, 0x40};
|
||||
const size_t data_sizes[NumHashes] = {*reinterpret_cast<u32 *>(&cal0[0xAD0]), *reinterpret_cast<u32 *>(&cal0[0x8])};
|
||||
const size_t data_sizes[NumHashes] = {*reinterpret_cast<u32 *>(&g_blank_cal0[0xAD0]), *reinterpret_cast<u32 *>(&g_blank_cal0[0x8])};
|
||||
for (size_t i = 0; i < NumHashes; i++) {
|
||||
u8 hash[SHA256_HASH_SIZE];
|
||||
sha256CalculateHash(hash, &cal0[s_data_offsets[i]], data_sizes[i]);
|
||||
std::memcpy(&cal0[s_hash_offsets[i]], hash, sizeof(hash));
|
||||
sha256CalculateHash(hash, &g_blank_cal0[s_data_offsets[i]], data_sizes[i]);
|
||||
std::memcpy(&g_blank_cal0[s_hash_offsets[i]], hash, sizeof(hash));
|
||||
}
|
||||
}
|
||||
|
||||
/* File creation is allowed to fail, because it may already exist. */
|
||||
fsFsCreateFile(&g_sd_filesystem, BlankProdInfoPath, ProdInfoSize, 0);
|
||||
|
||||
FsFile f;
|
||||
if (R_FAILED((rc = fsFsOpenFile(&g_sd_filesystem, BlankProdInfoPath, FS_OPEN_READ | FS_OPEN_WRITE, &f)))) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = fsFileSetSize(&f, ProdInfoSize)))) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = fsFileWrite(&f, 0, cal0, ProdInfoSize)))) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
if (R_FAILED((rc = fsFileFlush(&f)))) {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
fsFileClose(&f);
|
||||
|
||||
if (R_FAILED((rc = fsFsOpenFile(&g_sd_filesystem, BlankProdInfoPath, FS_OPEN_READ, &g_blank_prodinfo_file)))) {
|
||||
std::abort();
|
||||
}
|
||||
g_initialized_blank_cal0 = true;
|
||||
}
|
||||
|
||||
bool Utils::IsCal0Valid(const u8 *cal0) {
|
||||
char serial_number[0x40] = {0};
|
||||
std::memcpy(serial_number, cal0 + 0x250, 0x18);
|
||||
|
||||
bool is_cal0_valid = true;
|
||||
is_cal0_valid &= std::memcmp(g_cal0_backup, "CAL0", 4) == 0;
|
||||
is_cal0_valid &= std::memcmp(g_cal0_backup + 0x250, serial_number, 0x18) == 0;
|
||||
u32 cal0_size = ((u32 *)g_cal0_backup)[2];
|
||||
is_cal0_valid &= std::memcmp(cal0, "CAL0", 4) == 0;
|
||||
u32 cal0_size = ((u32 *)cal0)[2];
|
||||
is_cal0_valid &= cal0_size + 0x40 <= ProdInfoSize;
|
||||
if (is_cal0_valid) {
|
||||
u8 calc_hash[0x20];
|
||||
sha256CalculateHash(calc_hash, g_cal0_backup + 0x40, cal0_size);
|
||||
is_cal0_valid &= std::memcmp(calc_hash, g_cal0_backup + 0x20, sizeof(calc_hash)) == 0;
|
||||
sha256CalculateHash(calc_hash, cal0 + 0x40, cal0_size);
|
||||
is_cal0_valid &= std::memcmp(calc_hash, cal0 + 0x20, sizeof(calc_hash)) == 0;
|
||||
}
|
||||
|
||||
return is_cal0_valid;
|
||||
@ -771,15 +747,7 @@ u16 Utils::GetCrc16(const void *data, size_t size) {
|
||||
return crc16;
|
||||
}
|
||||
|
||||
Result Utils::OpenBlankProdInfoFile(FsFile *out) {
|
||||
if (!IsSdInitialized()) {
|
||||
std::abort();
|
||||
return ResultFsSdCardNotPresent;
|
||||
}
|
||||
|
||||
Result rc = OpenSdFile(BlankProdInfoPath, FS_OPEN_READ, out);
|
||||
if (R_FAILED((rc))) {
|
||||
std::abort();
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
const void *Utils::GetBlankProdInfoBuffer() {
|
||||
EnsureBlankProdInfo();
|
||||
return g_blank_cal0;
|
||||
}
|
||||
|
@ -37,6 +37,8 @@ enum BisStorageId : u32 {
|
||||
BisStorageId_SystemProperPartition = 33,
|
||||
};
|
||||
|
||||
static constexpr size_t ProdInfoSize = 0x8000;
|
||||
|
||||
struct OverrideKey {
|
||||
u64 key_combination;
|
||||
bool override_by_default;
|
||||
@ -61,7 +63,7 @@ class Utils {
|
||||
|
||||
static bool HasSdRomfsContent(u64 title_id);
|
||||
|
||||
static Result OpenBlankProdInfoFile(FsFile *out);
|
||||
static const void *GetBlankProdInfoBuffer();
|
||||
|
||||
/* Delayed Initialization + MitM detection. */
|
||||
static void InitializeThreadFunc(void *args);
|
||||
@ -98,6 +100,6 @@ class Utils {
|
||||
private:
|
||||
static void RefreshConfiguration();
|
||||
|
||||
static void CreateBlankProdInfo();
|
||||
static void EnsureBlankProdInfo();
|
||||
static bool IsCal0Valid(const u8 *cal0);
|
||||
};
|
@ -1 +1 @@
|
||||
Subproject commit 8ec43f0d69463784c00ddb19c5f3b043e713548e
|
||||
Subproject commit 5fe1dacee28265af5ed8272a3c9921904d6f50fe
|
Loading…
Reference in New Issue
Block a user