Compare commits
15 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
84c776fa6b | ||
|
|
a21b5d453a | ||
|
|
0ef3368893 | ||
|
|
4827fd71b4 | ||
|
|
00aa283a54 | ||
|
|
ef373d954f | ||
|
|
d452d6f89d | ||
|
|
a51d355707 | ||
|
|
a79f4cf6f6 | ||
|
|
903789cf6e | ||
|
|
49ba3a86e2 | ||
|
|
021d84ff04 | ||
|
|
8ecf68cb65 | ||
|
|
bbed78149c | ||
|
|
3fa973f430 |
4
Makefile
4
Makefile
@@ -42,8 +42,8 @@ dist: all
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000034
|
||||
mkdir -p atmosphere-$(AMSVER)/atmosphere/titles/0100000000000032
|
||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/fusee-secondary.bin
|
||||
cp common/defaults/BCT.ini atmosphere-$(AMSVER)/BCT.ini
|
||||
cp fusee/fusee-secondary/fusee-secondary.bin atmosphere-$(AMSVER)/atmosphere/fusee-secondary.bin
|
||||
cp common/defaults/BCT.ini atmosphere-$(AMSVER)/atmosphere/BCT.ini
|
||||
cp common/defaults/loader.ini atmosphere-$(AMSVER)/atmosphere/loader.ini
|
||||
cp -r common/defaults/kip_patches atmosphere-$(AMSVER)/atmosphere/kip_patches
|
||||
cp stratosphere/creport/creport.nsp atmosphere-$(AMSVER)/atmosphere/titles/0100000000000036/exefs.nsp
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
BCT0
|
||||
[stage1]
|
||||
stage2_path = fusee-secondary.bin
|
||||
stage2_path = atmosphere/fusee-secondary.bin
|
||||
stage2_addr = 0xF0000000
|
||||
stage2_entrypoint = 0xF0000000
|
||||
|
||||
[exosphere]
|
||||
debugmode = 0
|
||||
; Note: Disabling debugmode will cause parts of ams.tma to not work, in the future.
|
||||
debugmode = 1
|
||||
debugmode_user = 0
|
||||
|
||||
[stratosphere]
|
||||
|
||||
@@ -19,6 +19,6 @@
|
||||
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MAJOR 0
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MINOR 8
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 1
|
||||
#define ATMOSPHERE_RELEASE_VERSION_MICRO 2
|
||||
|
||||
#endif
|
||||
@@ -1,4 +1,13 @@
|
||||
# Changelog
|
||||
## 0.8.2
|
||||
+ A number of bugs were fixed causing users to sometimes see `Key Derivation Failed!`.
|
||||
+ KFUSE clock enable timings have been adjusted to allow time to stabilize before TSEC is granted access.
|
||||
+ A race condition was fixed that could cause wrong key data to be used on 6.2.0
|
||||
+ The TSEC firmware is now retried on failure, fixing a failure affecting ~1/50 boots on 6.2.0.
|
||||
+ A bug was fixed causing some modules to not work on firmware 1.0.0.
|
||||
+ A bug was fixed causing sleep mode to not work with debugmode enabled.
|
||||
+ As a result, debugmode is now enabled in the default BCT.ini.
|
||||
+ General system stability improvements to enhance the user's experience.
|
||||
## 0.8.1
|
||||
+ A bug was fixed causing users to see `Failed to enable SMMU!` if fusee had previously rebooted.
|
||||
+ This message will still occur sporadically if fusee is not launched from coldboot, but it can never happen twice in a row.
|
||||
|
||||
@@ -31,6 +31,7 @@
|
||||
#include "configitem.h"
|
||||
#include "timers.h"
|
||||
#include "misc.h"
|
||||
#include "uart.h"
|
||||
#include "bpmp.h"
|
||||
#include "sysreg.h"
|
||||
#include "interrupt.h"
|
||||
@@ -213,6 +214,11 @@ void bootup_misc_mmio(void) {
|
||||
}
|
||||
|
||||
if (!g_has_booted_up) {
|
||||
/* N doesn't do this, but we should for compatibility. */
|
||||
uart_select(UART_A);
|
||||
clkrst_reboot(CARDEVICE_UARTA);
|
||||
uart_init(UART_A, 115200);
|
||||
|
||||
intr_register_handler(INTERRUPT_ID_SECURITY_ENGINE, se_operation_completed);
|
||||
if (exosphere_get_target_firmware() >= EXOSPHERE_TARGET_FIRMWARE_400) {
|
||||
intr_register_handler(INTERRUPT_ID_ACTIVITY_MONITOR_4X, actmon_interrupt_handler);
|
||||
|
||||
@@ -72,6 +72,15 @@ bool configitem_should_profile_battery(void) {
|
||||
return g_battery_profile;
|
||||
}
|
||||
|
||||
bool configitem_is_debugmode_priv(void) {
|
||||
uint64_t debugmode = 0;
|
||||
if (configitem_get(true, CONFIGITEM_ISDEBUGMODE, &debugmode) != 0) {
|
||||
generic_panic();
|
||||
}
|
||||
|
||||
return debugmode != 0;
|
||||
}
|
||||
|
||||
uint64_t configitem_get_hardware_type(void) {
|
||||
uint64_t hardware_type;
|
||||
if (configitem_get(true, CONFIGITEM_HARDWARETYPE, &hardware_type) != 0) {
|
||||
|
||||
@@ -50,6 +50,7 @@ uint32_t configitem_get(bool privileged, ConfigItem item, uint64_t *p_outvalue);
|
||||
bool configitem_is_recovery_boot(void);
|
||||
bool configitem_is_retail(void);
|
||||
bool configitem_should_profile_battery(void);
|
||||
bool configitem_is_debugmode_priv(void);
|
||||
|
||||
void configitem_set_debugmode_override(bool user, bool priv);
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "smc_api.h"
|
||||
#include "timers.h"
|
||||
#include "misc.h"
|
||||
#include "uart.h"
|
||||
#include "exocfg.h"
|
||||
|
||||
#define u8 uint8_t
|
||||
@@ -241,7 +242,7 @@ void save_se_and_power_down_cpu(void) {
|
||||
save_se_state();
|
||||
|
||||
if (!configitem_is_retail()) {
|
||||
/* TODO: uart_log("OYASUMI"); */
|
||||
uart_send(UART_A, "OYASUMI", 8);
|
||||
}
|
||||
|
||||
finalize_powerdown();
|
||||
|
||||
@@ -33,7 +33,7 @@ static const uint8_t g_seal_key_sources[CRYPTOUSECASE_MAX_5X][0x10] = {
|
||||
{0x0E, 0xE0, 0xC4, 0x33, 0x82, 0x66, 0xE8, 0x08, 0x39, 0x13, 0x41, 0x7D, 0x04, 0x64, 0x2B, 0x6D},
|
||||
{0xE1, 0xA8, 0xAA, 0x6A, 0x2D, 0x9C, 0xDE, 0x43, 0x0C, 0xDE, 0xC6, 0x17, 0xF6, 0xC7, 0xF1, 0xDE},
|
||||
{0x74, 0x20, 0xF6, 0x46, 0x77, 0xB0, 0x59, 0x2C, 0xE8, 0x1B, 0x58, 0x64, 0x47, 0x41, 0x37, 0xD9},
|
||||
{0xAA, 0x19, 0x0F, 0xFA, 0x4C, 0x30, 0x3B, 0x2E, 0xE8, 0x1B, 0x58, 0x64, 0x47, 0x41, 0x37, 0xD9}
|
||||
{0xAA, 0x19, 0x0F, 0xFA, 0x4C, 0x30, 0x3B, 0x2E, 0xE6, 0xD8, 0x9A, 0xCF, 0xE5, 0x3F, 0xB3, 0x4B}
|
||||
};
|
||||
|
||||
bool usecase_is_invalid(unsigned int usecase) {
|
||||
|
||||
@@ -30,6 +30,7 @@
|
||||
#include "car.h"
|
||||
#include "i2c.h"
|
||||
#include "misc.h"
|
||||
#include "uart.h"
|
||||
#include "interrupt.h"
|
||||
|
||||
#include "pmc.h"
|
||||
@@ -55,8 +56,16 @@ void __attribute__((noreturn)) warmboot_main(void) {
|
||||
|
||||
/* On warmboot (not cpu_on) only */
|
||||
if (VIRT_MC_SECURITY_CFG3 == 0) {
|
||||
/* N only does this on dev units, but we will do it unconditionally. */
|
||||
{
|
||||
uart_select(UART_A);
|
||||
clkrst_reboot(CARDEVICE_UARTA);
|
||||
uart_init(UART_A, 115200);
|
||||
}
|
||||
|
||||
if (!configitem_is_retail()) {
|
||||
/* TODO: uart_log("OHAYO"); */
|
||||
uart_send(UART_A, "OHAYO", 6);
|
||||
uart_wait_idle(UART_A, UART_VENDOR_STATE_TX_IDLE);
|
||||
}
|
||||
|
||||
/* Sanity check the Security Engine. */
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "car.h"
|
||||
#include "timers.h"
|
||||
#include "utils.h"
|
||||
|
||||
static inline uint32_t get_clk_source_reg(CarDevice dev) {
|
||||
@@ -121,7 +122,15 @@ void clkrst_disable(CarDevice dev) {
|
||||
|
||||
void clkrst_reboot(CarDevice dev) {
|
||||
clkrst_disable(dev);
|
||||
clkrst_enable(dev);
|
||||
if (dev == CARDEVICE_KFUSE) {
|
||||
/* Workaround for KFUSE clock. */
|
||||
clk_enable(dev);
|
||||
udelay(100);
|
||||
rst_disable(dev);
|
||||
udelay(200);
|
||||
} else {
|
||||
clkrst_enable(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void clkrst_enable_fuse_regs(bool enable) {
|
||||
|
||||
@@ -40,12 +40,12 @@ static char g_bct0_buffer[BCTO_MAX_SIZE];
|
||||
#define DEFAULT_BCT0_FOR_DEBUG \
|
||||
"BCT0\n"\
|
||||
"[stage1]\n"\
|
||||
"stage2_path = fusee-secondary.bin\n"\
|
||||
"stage2_path = atmosphere/fusee-secondary.bin\n"\
|
||||
"stage2_addr = 0xF0000000\n"\
|
||||
"stage2_entrypoint = 0xF0000000\n"
|
||||
|
||||
static const char *load_config(void) {
|
||||
if (!read_from_file(g_bct0_buffer, BCTO_MAX_SIZE, "BCT.ini")) {
|
||||
if (!read_from_file(g_bct0_buffer, BCTO_MAX_SIZE, "atmosphere/BCT.ini")) {
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Failed to read BCT0 from SD!\n");
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Using default BCT0!\n");
|
||||
memcpy(g_bct0_buffer, DEFAULT_BCT0_FOR_DEBUG, sizeof(DEFAULT_BCT0_FOR_DEBUG));
|
||||
@@ -108,7 +108,7 @@ static void setup_env(void) {
|
||||
|
||||
/* Set up the exception handlers. */
|
||||
setup_exception_handlers();
|
||||
|
||||
|
||||
/* Mount the SD card. */
|
||||
mount_sd();
|
||||
}
|
||||
@@ -133,6 +133,9 @@ int main(void) {
|
||||
uint32_t stage2_version = 0;
|
||||
ScreenLogLevel log_level = SCREEN_LOG_LEVEL_MANDATORY;
|
||||
|
||||
/* Override the global logging level. */
|
||||
log_set_log_level(log_level);
|
||||
|
||||
/* Initialize the display, console, etc. */
|
||||
setup_env();
|
||||
|
||||
@@ -144,9 +147,6 @@ int main(void) {
|
||||
fatal_error("Failed to parse BCT.ini!\n");
|
||||
}
|
||||
|
||||
/* Override the global logging level. */
|
||||
log_set_log_level(log_level);
|
||||
|
||||
/* Say hello. */
|
||||
print(SCREEN_LOG_LEVEL_MANDATORY, "Welcome to Atmosph\xe8re Fus\xe9" "e!\n");
|
||||
print(SCREEN_LOG_LEVEL_DEBUG, "Using color linear framebuffer at 0x%p!\n", g_framebuffer);
|
||||
@@ -159,7 +159,7 @@ int main(void) {
|
||||
strcpy(g_chainloader_arg_data, stage2_path);
|
||||
stage2_args = (stage2_args_t *)(g_chainloader_arg_data + strlen(stage2_path) + 1); /* May be unaligned. */
|
||||
memcpy(&stage2_args->version, &stage2_version, 4);
|
||||
stage2_args->log_level = log_level;
|
||||
memcpy(&stage2_args->log_level, &log_level, sizeof(log_level));
|
||||
stage2_args->display_initialized = false;
|
||||
strcpy(stage2_args->bct0, bct0);
|
||||
g_chainloader_argc = 2;
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
*/
|
||||
|
||||
#include "car.h"
|
||||
#include "timers.h"
|
||||
#include "utils.h"
|
||||
|
||||
static inline uint32_t get_clk_source_reg(CarDevice dev) {
|
||||
@@ -121,7 +122,15 @@ void clkrst_disable(CarDevice dev) {
|
||||
|
||||
void clkrst_reboot(CarDevice dev) {
|
||||
clkrst_disable(dev);
|
||||
clkrst_enable(dev);
|
||||
if (dev == CARDEVICE_KFUSE) {
|
||||
/* Workaround for KFUSE clock. */
|
||||
clk_enable(dev);
|
||||
udelay(100);
|
||||
rst_disable(dev);
|
||||
udelay(200);
|
||||
} else {
|
||||
clkrst_enable(dev);
|
||||
}
|
||||
}
|
||||
|
||||
void clkrst_enable_fuse_regs(bool enable) {
|
||||
|
||||
@@ -442,6 +442,11 @@ static const kernel_hook_t g_kernel_hooks_600[] = {
|
||||
|
||||
/* Kernel Infos. */
|
||||
static const kernel_info_t g_kernel_infos[] = {
|
||||
{ /* 1.0.0-7. */
|
||||
.hash = {0x64, 0x44, 0x07, 0x2F, 0x56, 0x44, 0x73, 0xDD, 0xD5, 0x46, 0x1B, 0x8C, 0xDC, 0xEF, 0x54, 0x98, 0x16, 0xDA, 0x81, 0xDE, 0x5B, 0x1C, 0x9D, 0xD7, 0x5A, 0x13, 0x91, 0xD9, 0x53, 0xAB, 0x8D, 0x8D},
|
||||
.free_code_space_offset = 0x4797C,
|
||||
KERNEL_HOOKS(100)
|
||||
},
|
||||
{ /* 1.0.0. */
|
||||
.hash = {0xB8, 0xC5, 0x0C, 0x68, 0x25, 0xA9, 0xB9, 0x5B, 0xD2, 0x4D, 0x2C, 0x7C, 0x81, 0x7F, 0xE6, 0x96, 0xF2, 0x42, 0x4E, 0x1D, 0x78, 0xDF, 0x3B, 0xCA, 0x3D, 0x6B, 0x68, 0x12, 0xDD, 0xA9, 0xCB, 0x9C},
|
||||
.free_code_space_offset = 0x4797C,
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include "timers.h"
|
||||
#include "tsec.h"
|
||||
|
||||
#define TSEC_KEYGEN_MAX_RETRIES 25
|
||||
|
||||
void *smmu_heap = (void *)SMMU_HEAP_BASE_ADDR;
|
||||
|
||||
static void safe_memcpy(void *dst, void *src, uint32_t sz) {
|
||||
@@ -168,14 +170,6 @@ void smmu_emulate_tsec(void *tsec_keys, const void *package1, size_t package1_si
|
||||
/* Copy package1 into IRAM. */
|
||||
memcpy((void *)0x40010000, package1, package1_size);
|
||||
|
||||
/* Load the TSEC firmware from IRAM. */
|
||||
if (tsec_load_fw((void *)(0x40010000 + 0xE00), 0x2900) < 0) {
|
||||
fatal_error("[SMMU]: Failed to load TSEC firmware!\n");
|
||||
}
|
||||
|
||||
/* Disable the aperture since it has precedence over the SMMU. */
|
||||
mc_disable_ahb_redirect();
|
||||
|
||||
/* Setup TSEC's address space. */
|
||||
uint32_t *pdir = smmu_setup_tsec_as(1);
|
||||
|
||||
@@ -189,21 +183,6 @@ void smmu_emulate_tsec(void *tsec_keys, const void *package1, size_t package1_si
|
||||
volatile uint32_t *iram_pages = smmu_alloc_page(48);
|
||||
volatile uint32_t *expv_page = smmu_alloc_page(1);
|
||||
|
||||
/* Copy CAR, MC and FUSE. */
|
||||
safe_memcpy((void *)car_page, (void *)0x60006000, 0x1000);
|
||||
safe_memcpy((void *)mc_page, (void *)0x70019000, 0x1000);
|
||||
safe_memcpy((void *)&fuse_page[0x800/4], (void *)0x7000F800, 0x400);
|
||||
|
||||
/* Copy IRAM. */
|
||||
memcpy((void *)iram_pages, (void *)0x40010000, 0x30000);
|
||||
|
||||
/* TSEC wants CLK_RST_CONTROLLER_CLK_SOURCE_TSEC_0 to be equal to 2. */
|
||||
car_page[0x1F4/4] = 2;
|
||||
|
||||
/* TSEC wants the aperture fully open. */
|
||||
mc_page[0x65C/4] = 0;
|
||||
mc_page[0x660/4] = 0x80000000;
|
||||
|
||||
/* Map all necessary pages. */
|
||||
smmu_map(pdir, 0x60006000, (uint32_t)car_page, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||
smmu_map(pdir, 0x7000F000, (uint32_t)fuse_page, 1, _READABLE | _NONSECURE);
|
||||
@@ -217,19 +196,69 @@ void smmu_emulate_tsec(void *tsec_keys, const void *package1, size_t package1_si
|
||||
/* Enable the SMMU. */
|
||||
smmu_enable();
|
||||
|
||||
/* Run the TSEC firmware. */
|
||||
tsec_run_fw();
|
||||
|
||||
/* Extract the keys from SE. */
|
||||
/* Loop retrying TSEC firmware execution, in case we lose the SE keydata race. */
|
||||
uint32_t key_buf[0x20/4] = {0};
|
||||
volatile uint32_t *key_data = (volatile uint32_t *)((void *)se_page + 0x320);
|
||||
uint32_t old_key_data = *key_data;
|
||||
uint32_t buf_counter = 0;
|
||||
while (!(tsec->FALCON_CPUCTL & 0x10)) {
|
||||
if (*key_data != old_key_data) {
|
||||
old_key_data = *key_data;
|
||||
key_buf[buf_counter] = *key_data;
|
||||
buf_counter++;
|
||||
unsigned int retries = 0;
|
||||
while (true) {
|
||||
if (retries++ > TSEC_KEYGEN_MAX_RETRIES) {
|
||||
fatal_error("[SMMU] TSEC key generation race was lost too many times!");
|
||||
}
|
||||
|
||||
/* Load the TSEC firmware from IRAM. */
|
||||
if (tsec_load_fw((void *)(0x40010000 + 0xE00), 0x2900) < 0) {
|
||||
fatal_error("[SMMU]: Failed to load TSEC firmware!\n");
|
||||
}
|
||||
|
||||
/* Disable the aperture since it has precedence over the SMMU. */
|
||||
mc_disable_ahb_redirect();
|
||||
|
||||
/* Clear all pages. */
|
||||
memset((void *)car_page, 0, SMMU_PAGE_SIZE);
|
||||
memset((void *)fuse_page, 0, SMMU_PAGE_SIZE);
|
||||
memset((void *)pmc_page, 0, SMMU_PAGE_SIZE);
|
||||
memset((void *)flow_page, 0, SMMU_PAGE_SIZE);
|
||||
memset((void *)se_page, 0, SMMU_PAGE_SIZE);
|
||||
memset((void *)mc_page, 0, SMMU_PAGE_SIZE);
|
||||
memset((void *)iram_pages, 0, 48 * SMMU_PAGE_SIZE);
|
||||
memset((void *)expv_page, 0, SMMU_PAGE_SIZE);
|
||||
|
||||
/* Copy CAR, MC and FUSE. */
|
||||
safe_memcpy((void *)car_page, (void *)0x60006000, 0x1000);
|
||||
safe_memcpy((void *)mc_page, (void *)0x70019000, 0x1000);
|
||||
safe_memcpy((void *)&fuse_page[0x800/4], (void *)0x7000F800, 0x400);
|
||||
|
||||
/* Copy IRAM. */
|
||||
memcpy((void *)iram_pages, (void *)0x40010000, 0x30000);
|
||||
|
||||
/* TSEC wants CLK_RST_CONTROLLER_CLK_SOURCE_TSEC_0 to be equal to 2. */
|
||||
car_page[0x1F4/4] = 2;
|
||||
|
||||
/* TSEC wants the aperture fully open. */
|
||||
mc_page[0x65C/4] = 0;
|
||||
mc_page[0x660/4] = 0x80000000;
|
||||
|
||||
|
||||
/* Run the TSEC firmware. */
|
||||
tsec_run_fw();
|
||||
|
||||
/* Extract the keys from SE. */
|
||||
volatile uint32_t *key_data = (volatile uint32_t *)((void *)se_page + 0x320);
|
||||
uint32_t old_key_data = *key_data;
|
||||
uint32_t buf_counter = 0;
|
||||
while (!(tsec->FALCON_CPUCTL & 0x10)) {
|
||||
const uint32_t new_key_data = *key_data;
|
||||
if (new_key_data != old_key_data) {
|
||||
old_key_data = new_key_data;
|
||||
key_buf[buf_counter] = new_key_data;
|
||||
buf_counter++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Enable back the aperture. */
|
||||
mc_enable_ahb_redirect();
|
||||
|
||||
if (buf_counter == 8) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -248,9 +277,6 @@ void smmu_emulate_tsec(void *tsec_keys, const void *package1, size_t package1_si
|
||||
/* Clear TSEC's address space. */
|
||||
smmu_clear_tsec_as(1);
|
||||
|
||||
/* Enable back the aperture. */
|
||||
mc_enable_ahb_redirect();
|
||||
|
||||
/* Return the decrypted package1 from emulated IRAM. */
|
||||
memcpy(package1_dec, (void *)iram_pages, package1_size);
|
||||
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
"title_id_range_min": "0x0100000000000034",
|
||||
"title_id_range_max": "0x0100000000000034",
|
||||
"main_thread_stack_size": "0x00010000",
|
||||
"main_thread_priority": 37,
|
||||
"main_thread_priority": 15,
|
||||
"default_cpu_id": 3,
|
||||
"process_category": 0,
|
||||
"is_retail": true,
|
||||
"pool_partition": 2,
|
||||
"is_64_bit": true,
|
||||
"address_space_type": 3,
|
||||
"address_space_type": 1,
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
@@ -88,7 +88,7 @@
|
||||
}
|
||||
}, {
|
||||
"type": "min_kernel_version",
|
||||
"value": "0x0060"
|
||||
"value": "0x0030"
|
||||
}, {
|
||||
"type": "handle_table_size",
|
||||
"value": 128
|
||||
|
||||
@@ -69,7 +69,7 @@ void Utils::InitializeSdThreadFunc(void *args) {
|
||||
|
||||
/* Mount SD. */
|
||||
while (R_FAILED(fsMountSdcard(&g_sd_filesystem))) {
|
||||
svcSleepThread(1000ULL);
|
||||
svcSleepThread(1000000ULL);
|
||||
}
|
||||
|
||||
/* Back up CAL0, if it's not backed up already. */
|
||||
|
||||
@@ -10,7 +10,7 @@
|
||||
"is_retail": true,
|
||||
"pool_partition": 2,
|
||||
"is_64_bit": true,
|
||||
"address_space_type": 3,
|
||||
"address_space_type": 1,
|
||||
"filesystem_access": {
|
||||
"permissions": "0xFFFFFFFFFFFFFFFF"
|
||||
},
|
||||
@@ -99,7 +99,7 @@
|
||||
},
|
||||
{
|
||||
"type": "min_kernel_version",
|
||||
"value": "0x0060"
|
||||
"value": "0x0030"
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user