Compare commits

...

5 Commits
2.0.0 ... 2.0.1

Author SHA1 Message Date
Such Meme, Many Skill
00a58f12ec Bump version 2020-05-04 20:49:23 +02:00
Such Meme, Many Skill
74ba5bb776 Fix broken menus 2020-05-04 20:48:23 +02:00
Such Meme, Many Skill
a9ea9725d4 Speed up copy & formats 2020-05-04 20:30:51 +02:00
Such Meme, Many Skill
9799e2b47e Small optimizations 2020-05-04 13:55:26 +02:00
Such Meme, Many Skill
6681a35b2c Revert some changes 2020-05-03 13:22:37 +02:00
47 changed files with 652 additions and 4347 deletions

View File

@@ -11,7 +11,7 @@ include $(DEVKITARM)/base_rules
IPL_LOAD_ADDR := 0x40008000 IPL_LOAD_ADDR := 0x40008000
LPVERSION_MAJOR := 3 LPVERSION_MAJOR := 3
LPVERSION_MINOR := 0 LPVERSION_MINOR := 0
LPVERSION_BUGFX := 0 LPVERSION_BUGFX := 1
################################################################################ ################################################################################

View File

@@ -45,7 +45,6 @@ void set_default_configuration()
h_cfg.brand = NULL; h_cfg.brand = NULL;
h_cfg.tagline = NULL; h_cfg.tagline = NULL;
h_cfg.errors = 0; h_cfg.errors = 0;
h_cfg.eks = NULL;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN; h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = true; h_cfg.rcm_patched = true;
h_cfg.emummc_force_disable = false; h_cfg.emummc_force_disable = false;

View File

@@ -17,7 +17,6 @@
#ifndef _CONFIG_H_ #ifndef _CONFIG_H_
#define _CONFIG_H_ #define _CONFIG_H_
#include "../hos/hos.h"
#include "../utils/types.h" #include "../utils/types.h"
typedef struct _hekate_config typedef struct _hekate_config
@@ -39,7 +38,6 @@ typedef struct _hekate_config
bool rcm_patched; bool rcm_patched;
u32 sbar_time_keeping; u32 sbar_time_keeping;
u32 errors; u32 errors;
hos_eks_mbr_t *eks;
} hekate_config; } hekate_config;
void set_default_configuration(); void set_default_configuration();

View File

@@ -1,7 +1,7 @@
#pragma once #pragma once
#include "../utils/types.h" #include "../utils/types.h"
#define BIT(n) (1 << n) #define BIT(n) (1U << n)
#define KEY_A BIT(3) #define KEY_A BIT(3)
#define KEY_B BIT(2) #define KEY_B BIT(2)
#define KEY_Y BIT(0) #define KEY_Y BIT(0)

View File

@@ -1,247 +0,0 @@
/*
* Atmosphère Fusée Secondary Storage parser.
*
* Copyright (c) 2019-2020 CTCaer
*
* 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/>.
*/
#include <string.h>
#include "fss.h"
#include "hos.h"
#include "../config/config.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../storage/emummc.h"
#include "../storage/nx_sd.h"
#include "../gfx/gfx.h"
#define DPRINTF(...)
extern hekate_config h_cfg;
extern bool is_ipl_updated(void *buf, char *path, bool force);
// FSS0 Magic and Meta header offset.
#define FSS0_MAGIC 0x30535346
#define FSS0_META_OFFSET 0x4
// FSS0 Content Types.
#define CNT_TYPE_FSP 0
#define CNT_TYPE_EXO 1 // Exosphere (Secure Monitor).
#define CNT_TYPE_WBT 2 // Warmboot (SC7Exit fw).
#define CNT_TYPE_RBT 3 // Rebootstub (Warmboot based reboot fw).
#define CNT_TYPE_SP1 4 // Sept Primary (TSEC and Sept Secondary loader).
#define CNT_TYPE_SP2 5 // Sept Secondary (Acts as pkg11 and derives keys).
#define CNT_TYPE_KIP 6 // KIP1 (Used for replacement or addition).
#define CNT_TYPE_BMP 7
#define CNT_TYPE_EMC 8
#define CNT_TYPE_KLD 9 // Kernel Loader.
#define CNT_TYPE_KRN 10 // Kernel.
// FSS0 Content Flags.
#define CNT_FLAG0_EXPERIMENTAL (1 << 0)
// FSS0 Meta Header.
typedef struct _fss_meta_t
{
u32 magic;
u32 size;
u32 crt0_off;
u32 cnt_off;
u32 cnt_count;
u32 hos_ver;
u32 version;
u32 git_rev;
} fss_meta_t;
// FSS0 Content Header.
typedef struct _fss_content_t
{
u32 offset;
u32 size;
u8 type;
u8 flags0;
u8 flags1;
u8 flags2;
u32 rsvd1;
char name[0x10];
} fss_content_t;
static void _update_r2p(const char *path)
{
char *r2p_path = malloc(256);
u32 path_len = strlen(path);
strcpy(r2p_path, path);
while(path_len)
{
if ((r2p_path[path_len - 1] == '/') || (r2p_path[path_len - 1] == 0x5C))
{
r2p_path[path_len] = 0;
strcat(r2p_path, "reboot_payload.bin");
u8 *r2p_payload = sd_file_read(r2p_path, NULL);
is_ipl_updated(r2p_payload, r2p_path, h_cfg.updater2p ? true : false);
free(r2p_payload);
break;
}
path_len--;
}
free(r2p_path);
}
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt)
{
FIL fp;
bool stock = false;
int sept_used = 0;
if (!sept_ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
if (!strcmp("stock", kv->key))
if (kv->val[0] == '1')
stock = true;
}
if (stock && ctxt->pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && (!emu_cfg.enabled || h_cfg.emummc_force_disable))
return 1;
}
if (f_open(&fp, path, FA_READ) != FR_OK)
return 0;
void *fss = malloc(f_size(&fp));
// Read first 1024 bytes of the fss file.
f_read(&fp, fss, 1024, NULL);
// Get FSS0 Meta header offset.
u32 fss_meta_addr = *(u32 *)(fss + FSS0_META_OFFSET);
fss_meta_t *fss_meta = (fss_meta_t *)(fss + fss_meta_addr);
// Check if valid FSS0 and parse it.
if (fss_meta->magic == FSS0_MAGIC)
{
gfx_printf("Found FSS0, Atmosphere %d.%d.%d-%08x\n"
"Max HOS supported: %d.%d.%d\n"
"Unpacking and loading components.. ",
fss_meta->version >> 24, (fss_meta->version >> 16) & 0xFF, (fss_meta->version >> 8) & 0xFF, fss_meta->git_rev,
fss_meta->hos_ver >> 24, (fss_meta->hos_ver >> 16) & 0xFF, (fss_meta->hos_ver >> 8) & 0xFF);
if (!sept_ctxt)
{
ctxt->atmosphere = true;
ctxt->fss0_hosver = fss_meta->hos_ver;
}
// Parse FSS0 contents.
fss_content_t *curr_fss_cnt = (fss_content_t *)(fss + fss_meta->cnt_off);
void *content;
for (u32 i = 0; i < fss_meta->cnt_count; i++)
{
content = (void *)(fss + curr_fss_cnt[i].offset);
// Check if offset is inside limits.
if ((curr_fss_cnt[i].offset + curr_fss_cnt[i].size) > fss_meta->size)
continue;
// If content is experimental and experimental flag is not enabled, skip it.
if ((curr_fss_cnt[i].flags0 & CNT_FLAG0_EXPERIMENTAL) && !ctxt->fss0_enable_experimental)
continue;
// Parse content.
if (!sept_ctxt)
{
// Prepare content context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_KIP:
if (stock)
continue;
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = content;
list_append(&ctxt->kip1_list, &mkip1->link);
DPRINTF("Loaded %s.kip1 from FSS0 (size %08X)\n", curr_fss_cnt[i].name, curr_fss_cnt[i].size);
break;
case CNT_TYPE_EXO:
ctxt->secmon_size = curr_fss_cnt[i].size;
ctxt->secmon = content;
break;
case CNT_TYPE_WBT:
ctxt->warmboot_size = curr_fss_cnt[i].size;
ctxt->warmboot = content;
break;
default:
continue;
}
// Load content to launch context.
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, content, curr_fss_cnt[i].size, NULL);
}
else
{
// Load sept content directly to launch context.
switch (curr_fss_cnt[i].type)
{
case CNT_TYPE_SP1:
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, sept_ctxt->sept_primary, curr_fss_cnt[i].size, NULL);
break;
case CNT_TYPE_SP2:
if (!memcmp(curr_fss_cnt[i].name, (sept_ctxt->kb < KB_FIRMWARE_VERSION_810) ? "septsecondary00" : "septsecondary01", 15))
{
f_lseek(&fp, curr_fss_cnt[i].offset);
f_read(&fp, sept_ctxt->sept_secondary, curr_fss_cnt[i].size, NULL);
sept_used = 1;
goto out;
}
break;
default:
break;
}
}
}
out:
gfx_printf("Done!\n");
f_close(&fp);
_update_r2p(path);
return (!sept_ctxt ? 1 : sept_used);
}
f_close(&fp);
free(fss);
return 0;
}
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &sept_ctxt->cfg_sec->kvs, link)
{
if (!strcmp("fss0", kv->key))
return parse_fss(NULL, kv->val, sept_ctxt);
}
return 0;
}

View File

@@ -1,34 +0,0 @@
/*
* Copyright (c) 2019 CTCaer
*
* 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/>.
*/
#ifndef _FSS_H_
#define _FSS_H_
#include "hos.h"
typedef struct _fss0_sept_t
{
u32 kb;
ini_sec_t *cfg_sec;
void *sept_primary;
void *sept_secondary;
} fss0_sept_t;
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt);
int load_sept_from_ffs0(fss0_sept_t *sept_ctxt);
#endif

View File

@@ -1,953 +0,0 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk
* Copyright (c) 2018 Ced2911
* Copyright (c) 2018-2020 CTCaer
* Copyright (c) 2018 balika011
*
* 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/>.
*/
#include <string.h>
#include "hos.h"
#include "hos_config.h"
#include "sept.h"
#include "secmon_exo.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../mem/minerva.h"
#include "../sec/se.h"
#include "../sec/se_t210.h"
#include "../sec/tsec.h"
#include "../soc/bpmp.h"
#include "../soc/cluster.h"
#include "../soc/fuse.h"
#include "../soc/pmc.h"
#include "../soc/smmu.h"
#include "../soc/t210.h"
#include "../storage/emummc.h"
#include "../storage/nx_emmc.h"
#include "../storage/nx_sd.h"
#include "../storage/sdmmc.h"
#include "../utils/util.h"
#include "../gfx/gfx.h"
extern hekate_config h_cfg;
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
#define EHPRINTFARGS(text, args...) \
({ display_backlight_brightness(h_cfg.backlight, 1000); \
gfx_con.mute = false; \
gfx_printf("%k"text"%k\n", 0xFFFF0000, args, 0xFFCCCCCC); })
#define PKG2_LOAD_ADDR 0xA9800000
// Secmon mailbox.
#define SECMON_MB_ADDR 0x40002EF8
#define SECMON7_MB_ADDR 0x400000F8
typedef struct _secmon_mailbox_t
{
// < 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM and pkg2 ready, 3: Continue boot.
// >= 4.0.0 Signals - 0: Not ready, 1: BCT ready, 2: DRAM ready, 4: pkg2 ready and continue boot.
u32 in;
// Non-zero: Secmon ready.
u32 out;
} secmon_mailbox_t;
static const u8 keyblob_keyseeds[][0x10] = {
{ 0xDF, 0x20, 0x6F, 0x59, 0x44, 0x54, 0xEF, 0xDC, 0x70, 0x74, 0x48, 0x3B, 0x0D, 0xED, 0x9F, 0xD3 }, //1.0.0
{ 0x0C, 0x25, 0x61, 0x5D, 0x68, 0x4C, 0xEB, 0x42, 0x1C, 0x23, 0x79, 0xEA, 0x82, 0x25, 0x12, 0xAC }, //3.0.0
{ 0x33, 0x76, 0x85, 0xEE, 0x88, 0x4A, 0xAE, 0x0A, 0xC2, 0x8A, 0xFD, 0x7D, 0x63, 0xC0, 0x43, 0x3B }, //3.0.1
{ 0x2D, 0x1F, 0x48, 0x80, 0xED, 0xEC, 0xED, 0x3E, 0x3C, 0xF2, 0x48, 0xB5, 0x65, 0x7D, 0xF7, 0xBE }, //4.0.0
{ 0xBB, 0x5A, 0x01, 0xF9, 0x88, 0xAF, 0xF5, 0xFC, 0x6C, 0xFF, 0x07, 0x9E, 0x13, 0x3C, 0x39, 0x80 }, //5.0.0
{ 0xD8, 0xCC, 0xE1, 0x26, 0x6A, 0x35, 0x3F, 0xCC, 0x20, 0xF3, 0x2D, 0x3B, 0x51, 0x7D, 0xE9, 0xC0 } //6.0.0
};
static const u8 cmac_keyseed[0x10] =
{ 0x59, 0xC7, 0xFB, 0x6F, 0xBE, 0x9B, 0xBE, 0x87, 0x65, 0x6B, 0x15, 0xC0, 0x53, 0x73, 0x36, 0xA5 };
static const u8 master_keyseed_retail[0x10] =
{ 0xD8, 0xA2, 0x41, 0x0A, 0xC6, 0xC5, 0x90, 0x01, 0xC6, 0x1D, 0x6A, 0x26, 0x7C, 0x51, 0x3F, 0x3C };
static const u8 console_keyseed[0x10] =
{ 0x4F, 0x02, 0x5F, 0x0E, 0xB6, 0x6D, 0x11, 0x0E, 0xDC, 0x32, 0x7D, 0x41, 0x86, 0xC2, 0xF4, 0x78 };
const u8 package2_keyseed[] =
{ 0xFB, 0x8B, 0x6A, 0x9C, 0x79, 0x00, 0xC8, 0x49, 0xEF, 0xD2, 0x4D, 0x85, 0x4D, 0x30, 0xA0, 0xC7 };
static const u8 master_keyseed_4xx_5xx_610[0x10] =
{ 0x2D, 0xC1, 0xF4, 0x8D, 0xF3, 0x5B, 0x69, 0x33, 0x42, 0x10, 0xAC, 0x65, 0xDA, 0x90, 0x46, 0x66 };
static const u8 master_keyseed_620[0x10] =
{ 0x37, 0x4B, 0x77, 0x29, 0x59, 0xB4, 0x04, 0x30, 0x81, 0xF6, 0xE5, 0x8C, 0x6D, 0x36, 0x17, 0x9A };
static const u8 console_keyseed_4xx_5xx[0x10] =
{ 0x0C, 0x91, 0x09, 0xDB, 0x93, 0x93, 0x07, 0x81, 0x07, 0x3C, 0xC4, 0x16, 0x22, 0x7C, 0x6C, 0x28 };
static void _hos_crit_error(const char *text)
{
gfx_con.mute = false;
gfx_printf("%k%s%k\n", 0xFFFF0000, text, 0xFFCCCCCC);
display_backlight_brightness(h_cfg.backlight, 1000);
}
static void _se_lock(bool lock_se)
{
if (lock_se)
{
for (u32 i = 0; i < 16; i++)
se_key_acc_ctrl(i, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
for (u32 i = 0; i < 2; i++)
se_rsa_acc_ctrl(i, SE_RSA_KEY_TBL_DIS_KEYREAD_FLAG);
SE(SE_TZRAM_SECURITY_0) = 0; // Make SE TZRAM secure only.
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = 0; // Make all key access regs secure only.
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = 0; // Make all RSA access regs secure only.
SE(SE_SECURITY_0) &= 0xFFFFFFFB; // Make access lock regs secure only.
}
memset((void *)IPATCH_BASE, 0, 14 * sizeof(u32));
SB(SB_CSR) = SB_CSR_PIROM_DISABLE;
// This is useful for documenting the bits in the SE config registers, so we can keep it around.
/*gfx_printf("SE(SE_SECURITY_0) = %08X\n", SE(SE_SECURITY_0));
gfx_printf("SE(0x4) = %08X\n", SE(0x4));
gfx_printf("SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET));
gfx_printf("SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) = %08X\n", SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET));
for(u32 i = 0; i < 16; i++)
gfx_printf("%02X ", SE(SE_KEY_TABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc('\n');
for(u32 i = 0; i < 2; i++)
gfx_printf("%02X ", SE(SE_RSA_KEYTABLE_ACCESS_REG_OFFSET + i * 4) & 0xFF);
gfx_putc('\n');
gfx_hexdump(SE_BASE, (void *)SE_BASE, 0x400);*/
}
void _pmc_scratch_lock(u32 kb)
{
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
PMC(APBDEV_PMC_SEC_DISABLE) = 0x7FFFF3;
PMC(APBDEV_PMC_SEC_DISABLE2) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE3) = 0xFFAFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE6) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE7) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE8) = 0xFFAAFFFF;
break;
default:
PMC(APBDEV_PMC_SEC_DISABLE2) |= 0x3FCFFFF;
PMC(APBDEV_PMC_SEC_DISABLE4) |= 0x3F3FFFFF;
PMC(APBDEV_PMC_SEC_DISABLE5) = 0xFFFFFFFF;
PMC(APBDEV_PMC_SEC_DISABLE6) |= 0xF3FFC00F;
PMC(APBDEV_PMC_SEC_DISABLE7) |= 0x3FFFFF;
PMC(APBDEV_PMC_SEC_DISABLE8) |= 0xFF;
break;
}
}
void _sysctr0_reset()
{
SYSCTR0(SYSCTR0_CNTCR) = 0;
SYSCTR0(SYSCTR0_COUNTERID0) = 0;
SYSCTR0(SYSCTR0_COUNTERID1) = 0;
SYSCTR0(SYSCTR0_COUNTERID2) = 0;
SYSCTR0(SYSCTR0_COUNTERID3) = 0;
SYSCTR0(SYSCTR0_COUNTERID4) = 0;
SYSCTR0(SYSCTR0_COUNTERID5) = 0;
SYSCTR0(SYSCTR0_COUNTERID6) = 0;
SYSCTR0(SYSCTR0_COUNTERID7) = 0;
SYSCTR0(SYSCTR0_COUNTERID8) = 0;
SYSCTR0(SYSCTR0_COUNTERID9) = 0;
SYSCTR0(SYSCTR0_COUNTERID10) = 0;
SYSCTR0(SYSCTR0_COUNTERID11) = 0;
}
void hos_eks_get()
{
// Check if EKS already found and parsed.
if (!h_cfg.eks)
{
u8 *mbr = calloc(512 , 1);
// Read EKS blob.
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
// Decrypt EKS blob.
hos_eks_mbr_t *eks = (hos_eks_mbr_t *)(mbr + 0x10);
se_aes_crypt_ecb(14, 0, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
// Check if valid and for this unit.
if (eks->enabled &&
eks->magic == HOS_EKS_MAGIC &&
eks->magic2 == HOS_EKS_MAGIC &&
eks->sbk_low[0] == FUSE(FUSE_PRIVATE_KEY0) &&
eks->sbk_low[1] == FUSE(FUSE_PRIVATE_KEY1))
{
h_cfg.eks = eks;
return;
}
free(mbr);
}
}
void hos_eks_save(u32 kb)
{
if (kb >= KB_FIRMWARE_VERSION_700)
{
// Only 6 Master keys for now.
u8 key_idx = kb - KB_FIRMWARE_VERSION_700;
if (key_idx > 5)
return;
if (!h_cfg.eks)
h_cfg.eks = calloc(512 , 1);
// If matching blob doesn't exist, create it.
if (!(h_cfg.eks->enabled & (1 << key_idx)))
{
// Get keys.
u8 *keys = (u8 *)calloc(0x1000, 1);
se_get_aes_keys(keys + 0x800, keys, 0x10);
// Set magic and personalized info.
h_cfg.eks->magic = HOS_EKS_MAGIC;
h_cfg.eks->magic2 = HOS_EKS_MAGIC;
h_cfg.eks->enabled |= 1 << key_idx;
h_cfg.eks->sbk_low[0] = FUSE(FUSE_PRIVATE_KEY0);
h_cfg.eks->sbk_low[1] = FUSE(FUSE_PRIVATE_KEY1);
// Copy new keys.
memcpy(h_cfg.eks->keys[key_idx].dkg, keys + 10 * 0x10, 0x10);
memcpy(h_cfg.eks->keys[key_idx].mkk, keys + 12 * 0x10, 0x10);
memcpy(h_cfg.eks->keys[key_idx].fdk, keys + 13 * 0x10, 0x10);
memcpy(h_cfg.eks->keys[key_idx].dkk, keys + 15 * 0x10, 0x10);
// Encrypt EKS.
u8 *eks = calloc(512 , 1);
memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
// Write EKS to SD.
u8 *mbr = calloc(512 , 1);
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t));
sdmmc_storage_write(&sd_storage, 0, 1, mbr);
free(eks);
free(mbr);
free(keys);
}
}
}
void hos_eks_clear(u32 kb)
{
if (h_cfg.eks && kb >= KB_FIRMWARE_VERSION_700)
{
// Check if Current Master key is enabled.
u8 key_idx = kb - KB_FIRMWARE_VERSION_700;
if (h_cfg.eks->enabled & (1 << key_idx))
{
// Disable current Master key version.
h_cfg.eks->enabled &= ~(1 << key_idx);
// Encrypt EKS.
u8 *eks = calloc(512 , 1);
memcpy(eks, h_cfg.eks, sizeof(hos_eks_mbr_t));
se_aes_crypt_ecb(14, 1, eks, sizeof(hos_eks_mbr_t), eks, sizeof(hos_eks_mbr_t));
// Write EKS to SD.
u8 *mbr = calloc(512 , 1);
sdmmc_storage_read(&sd_storage, 0, 1, mbr);
memcpy(mbr + 0x10, eks, sizeof(hos_eks_mbr_t));
sdmmc_storage_write(&sd_storage, 0, 1, mbr);
free(eks);
free(mbr);
}
}
}
int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt)
{
u8 tmp[0x20];
u32 retries = 0;
if (kb > KB_FIRMWARE_VERSION_MAX)
return 0;
if (kb <= KB_FIRMWARE_VERSION_600)
tsec_ctxt->size = 0xF00;
else if (kb == KB_FIRMWARE_VERSION_620)
tsec_ctxt->size = 0x2900;
else if (kb == KB_FIRMWARE_VERSION_700)
tsec_ctxt->size = 0x3000;
else
tsec_ctxt->size = 0x3300;
// Prepare smmu tsec page for 6.2.0.
if (kb == KB_FIRMWARE_VERSION_620)
{
u8 *tsec_paged = (u8 *)page_alloc(3);
memcpy(tsec_paged, (void *)tsec_ctxt->fw, tsec_ctxt->size);
tsec_ctxt->fw = tsec_paged;
}
// Get TSEC key.
if (kb <= KB_FIRMWARE_VERSION_620)
{
while (tsec_query(tmp, kb, tsec_ctxt) < 0)
{
memset(tmp, 0x00, 0x20);
retries++;
// We rely on racing conditions, make sure we cover even the unluckiest cases.
if (retries > 15)
{
_hos_crit_error("\nFailed to get TSEC keys. Please try again.");
return 0;
}
}
}
if (kb >= KB_FIRMWARE_VERSION_700)
{
// Use HOS EKS if it exists.
u8 key_idx = kb - KB_FIRMWARE_VERSION_700;
if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx)))
{
// Set Device keygen key to slot 10.
se_aes_key_set(10, h_cfg.eks->keys[key_idx].dkg, 0x10);
// Set Master key to slot 12.
se_aes_key_set(12, h_cfg.eks->keys[key_idx].mkk, 0x10);
// Set FW Device key key to slot 13.
se_aes_key_set(13, h_cfg.eks->keys[key_idx].fdk, 0x10);
// Set Device key to slot 15.
se_aes_key_set(15, h_cfg.eks->keys[key_idx].dkk, 0x10);
// Lock FDK.
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
}
se_aes_key_clear(8);
se_aes_unwrap_key(8, 12, package2_keyseed);
}
else if (kb == KB_FIRMWARE_VERSION_620)
{
// Set TSEC key.
se_aes_key_set(12, tmp, 0x10);
// Set TSEC root key.
se_aes_key_set(13, tmp + 0x10, 0x10);
if (!(emu_cfg.enabled && !h_cfg.emummc_force_disable) && hos_ctxt->stock)
{
// Package2 key.
se_aes_key_set(8, tmp + 0x10, 0x10);
se_aes_unwrap_key(8, 8, master_keyseed_620);
se_aes_unwrap_key(8, 8, master_keyseed_retail);
se_aes_unwrap_key(8, 8, package2_keyseed);
}
else
{
// Decrypt keyblob and set keyslots
se_aes_crypt_block_ecb(12, 0, tmp + 0x20, keyblob_keyseeds[0]);
se_aes_unwrap_key(15, 14, tmp + 0x20);
se_aes_unwrap_key(14, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(13, 13, master_keyseed_620);
se_aes_unwrap_key(12, 13, master_keyseed_retail);
se_aes_unwrap_key(10, 13, master_keyseed_4xx_5xx_610);
// Package2 key.
se_aes_unwrap_key(8, 12, package2_keyseed);
h_cfg.se_keygen_done = 1;
}
}
else
{
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
se_key_acc_ctrl(14, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
// Set TSEC key.
se_aes_key_set(13, tmp, 0x10);
// Derive keyblob keys from TSEC+SBK.
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[0]);
se_aes_unwrap_key(15, 14, tmp);
se_aes_crypt_block_ecb(13, 0, tmp, keyblob_keyseeds[kb]);
se_aes_unwrap_key(13, 14, tmp);
// Clear SBK.
se_aes_key_clear(14);
//TODO: verify keyblob CMAC.
//se_aes_unwrap_key(11, 13, cmac_keyseed);
//se_aes_cmac(tmp, 0x10, 11, keyblob + 0x10, 0xA0);
//if (!memcmp(keyblob, tmp, 0x10))
// return 0;
se_aes_crypt_block_ecb(13, 0, tmp, cmac_keyseed);
se_aes_unwrap_key(11, 13, cmac_keyseed);
// Decrypt keyblob and set keyslots.
se_aes_crypt_ctr(13, keyblob + 0x20, 0x90, keyblob + 0x20, 0x90, keyblob + 0x10);
se_aes_key_set(11, keyblob + 0x20 + 0x80, 0x10); // Package1 key.
se_aes_key_set(12, keyblob + 0x20, 0x10);
se_aes_key_set(13, keyblob + 0x20, 0x10);
se_aes_crypt_block_ecb(12, 0, tmp, master_keyseed_retail);
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
se_aes_unwrap_key(13, 15, console_keyseed);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_400:
se_aes_unwrap_key(13, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_aes_unwrap_key(10, 15, console_keyseed_4xx_5xx);
se_aes_unwrap_key(15, 15, console_keyseed);
se_aes_unwrap_key(14, 12, master_keyseed_4xx_5xx_610);
se_aes_unwrap_key(12, 12, master_keyseed_retail);
break;
}
// Package2 key.
se_key_acc_ctrl(8, SE_KEY_TBL_DIS_KEYREAD_FLAG | SE_KEY_TBL_DIS_OIVREAD_FLAG | SE_KEY_TBL_DIS_UIVREAD_FLAG);
se_aes_unwrap_key(8, 12, package2_keyseed);
}
return 1;
}
static int _read_emmc_pkg1(launch_ctxt_t *ctxt)
{
sdmmc_storage_t storage;
sdmmc_t sdmmc;
int res = emummc_storage_init_mmc(&storage, &sdmmc);
if (res)
{
if (res == 2)
_hos_crit_error("Failed to init eMMC");
else
_hos_crit_error("Failed to init emuMMC");
return 0;
}
// Read package1.
ctxt->pkg1 = (void *)malloc(0x40000);
emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, ctxt->pkg1);
ctxt->pkg1_id = pkg1_identify(ctxt->pkg1);
if (!ctxt->pkg1_id)
{
_hos_crit_error("Unknown pkg1 version.");
EHPRINTFARGS("%sNot yet supported HOS version!",
(emu_cfg.enabled && !h_cfg.emummc_force_disable) ? "Is emuMMC corrupt?\nOr " : "");
goto out;
}
gfx_printf("Identified pkg1 and Keyblob %d\n\n", ctxt->pkg1_id->kb);
// Read the correct keyblob.
ctxt->keyblob = (u8 *)calloc(NX_EMMC_BLOCKSIZE, 1);
emummc_storage_read(&storage, 0x180000 / NX_EMMC_BLOCKSIZE + ctxt->pkg1_id->kb, 1, ctxt->keyblob);
res = 1;
out:;
sdmmc_storage_end(&storage);
return res;
}
static u8 *_read_emmc_pkg2(launch_ctxt_t *ctxt)
{
u8 *bctBuf = NULL;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
int res = emummc_storage_init_mmc(&storage, &sdmmc);
if (res)
{
if (res == 2)
_hos_crit_error("Failed to init eMMC");
else
_hos_crit_error("Failed to init emuMMC");
return NULL;
}
emummc_storage_set_mmc_partition(&storage, EMMC_GPP);
// Parse eMMC GPT.
LIST_INIT(gpt);
nx_emmc_gpt_parse(&gpt, &storage);
DPRINTF("Parsed GPT\n");
// Find package2 partition.
emmc_part_t *pkg2_part = nx_emmc_part_find(&gpt, "BCPKG2-1-Normal-Main");
if (!pkg2_part)
goto out;
// Read in package2 header and get package2 real size.
//TODO: implement memalign for DMA buffers.
static const u32 BCT_SIZE = 0x4000;
bctBuf = (u8 *)malloc(BCT_SIZE);
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE, 1, bctBuf);
u32 *hdr = (u32 *)(bctBuf + 0x100);
u32 pkg2_size = hdr[0] ^ hdr[2] ^ hdr[3];
DPRINTF("pkg2 size on emmc is %08X\n", pkg2_size);
// Read in Boot Config.
memset(bctBuf, 0, BCT_SIZE);
nx_emmc_part_read(&storage, pkg2_part, 0, BCT_SIZE / NX_EMMC_BLOCKSIZE, bctBuf);
// Read in package2.
u32 pkg2_size_aligned = ALIGN(pkg2_size, NX_EMMC_BLOCKSIZE);
DPRINTF("pkg2 size aligned is %08X\n", pkg2_size_aligned);
ctxt->pkg2 = malloc(pkg2_size_aligned);
ctxt->pkg2_size = pkg2_size;
nx_emmc_part_read(&storage, pkg2_part, BCT_SIZE / NX_EMMC_BLOCKSIZE,
pkg2_size_aligned / NX_EMMC_BLOCKSIZE, ctxt->pkg2);
out:;
nx_emmc_gpt_free(&gpt);
sdmmc_storage_end(&storage);
return bctBuf;
}
static void _free_launch_components(launch_ctxt_t *ctxt)
{
free(ctxt->keyblob);
free(ctxt->pkg1);
free(ctxt->pkg2);
free(ctxt->warmboot);
free(ctxt->secmon);
free(ctxt->kernel);
free(ctxt->kip1_patches);
}
static bool _get_fs_exfat_compatible(link_t *info)
{
u32 fs_idx;
u32 fs_ids_cnt;
u32 sha_buf[32 / sizeof(u32)];
kip1_id_t *kip_ids;
LIST_FOREACH_ENTRY(pkg2_kip1_info_t, ki, info, link)
{
if (strncmp((const char*)ki->kip1->name, "FS", 2))
continue;
if (!se_calc_sha256(sha_buf, ki->kip1, ki->size))
break;
pkg2_get_ids(&kip_ids, &fs_ids_cnt);
for (fs_idx = 0; fs_idx < fs_ids_cnt; fs_idx++)
if (!memcmp(sha_buf, kip_ids[fs_idx].hash, 8))
break;
// Return false if FAT32 only.
if (fs_ids_cnt <= fs_idx && !(fs_idx & 1))
return false;
break;
}
return true;
}
int hos_launch(ini_sec_t *cfg)
{
minerva_change_freq(FREQ_1600);
launch_ctxt_t ctxt;
tsec_ctxt_t tsec_ctxt;
volatile secmon_mailbox_t *secmon_mb;
memset(&ctxt, 0, sizeof(launch_ctxt_t));
memset(&tsec_ctxt, 0, sizeof(tsec_ctxt_t));
list_init(&ctxt.kip1_list);
ctxt.cfg = cfg;
if (!gfx_con.mute)
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
gfx_printf("Initializing...\n\n");
// Read package1 and the correct keyblob.
if (!_read_emmc_pkg1(&ctxt))
return 0;
// Try to parse config if present.
if (ctxt.cfg && !parse_boot_config(&ctxt))
{
_hos_crit_error("Wrong ini cfg or missing files!");
return 0;
}
// Enable emummc patching.
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
{
if (ctxt.stock)
{
_hos_crit_error("Stock emuMMC is not supported yet!");
return 0;
}
ctxt.atmosphere = true; // Set atmosphere patching in case of Stock emuMMC and no fss0.
config_kip1patch(&ctxt, "emummc");
}
else if (!emu_cfg.enabled && ctxt.emummc_forced)
{
_hos_crit_error("emuMMC is forced but not enabled!");
return 0;
}
// Check if fuses lower than 4.0.0 or 9.0.0 and if yes apply NO Gamecard patch.
// Additionally check if running emuMMC and disable GC if v3 fuses are burnt and HOS is <= 8.1.0.
if (!ctxt.stock)
{
u32 fuses = fuse_read_odm(7);
if ((h_cfg.autonogc &&
((!(fuses & ~0xF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_400)) || // LAFW v2.
(!(fuses & ~0x3FF) && (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_900)))) // LAFW v3.
|| ((emu_cfg.enabled && !h_cfg.emummc_force_disable) &&
((fuses & 0x400) && (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_810))))
config_kip1patch(&ctxt, "nogc");
}
gfx_printf("Loaded config, pkg1 and keyblob\n");
// Generate keys.
if (!h_cfg.se_keygen_done)
{
tsec_ctxt.fw = (u8 *)ctxt.pkg1 + ctxt.pkg1_id->tsec_off;
tsec_ctxt.pkg1 = ctxt.pkg1;
tsec_ctxt.pkg11_off = ctxt.pkg1_id->pkg11_off;
tsec_ctxt.secmon_base = ctxt.pkg1_id->secmon_base;
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
_hos_crit_error("Failed to run sept");
return 0;
}
if (!hos_keygen(ctxt.keyblob, ctxt.pkg1_id->kb, &tsec_ctxt, &ctxt))
return 0;
gfx_printf("Generated keys\n");
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
h_cfg.se_keygen_done = 1;
}
// Decrypt and unpack package1 if we require parts of it.
if (!ctxt.warmboot || !ctxt.secmon)
{
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600)
pkg1_decrypt(ctxt.pkg1_id, ctxt.pkg1);
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_620 && !(emu_cfg.enabled && !h_cfg.emummc_force_disable))
{
pkg1_unpack((void *)ctxt.pkg1_id->warmboot_base, (void *)ctxt.pkg1_id->secmon_base, NULL, ctxt.pkg1_id, ctxt.pkg1);
gfx_printf("Decrypted & unpacked pkg1\n");
}
else
{
_hos_crit_error("No mandatory secmon or warmboot provided!");
return 0;
}
}
// Replace 'warmboot.bin' if requested.
if (ctxt.warmboot)
memcpy((void *)ctxt.pkg1_id->warmboot_base, ctxt.warmboot, ctxt.warmboot_size);
else
{
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
{
_hos_crit_error("No warmboot provided!");
return 0;
}
// Else we patch it to allow downgrading.
patch_t *warmboot_patchset = ctxt.pkg1_id->warmboot_patchset;
gfx_printf("%kPatching Warmboot%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; warmboot_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->warmboot_base + warmboot_patchset[i].off) = warmboot_patchset[i].val;
}
// Set warmboot address in PMC if required.
if (ctxt.pkg1_id->set_warmboot)
PMC(APBDEV_PMC_SCRATCH1) = ctxt.pkg1_id->warmboot_base;
// Replace 'SecureMonitor' if requested.
if (ctxt.secmon)
memcpy((void *)ctxt.pkg1_id->secmon_base, ctxt.secmon, ctxt.secmon_size);
else if (ctxt.pkg1_id->secmon_patchset)
{
// Else we patch it to allow for an unsigned package2 and patched kernel.
patch_t *secmon_patchset = ctxt.pkg1_id->secmon_patchset;
gfx_printf("%kPatching Secure Monitor%k\n", 0xFFFFBA00, 0xFFCCCCCC);
for (u32 i = 0; secmon_patchset[i].off != 0xFFFFFFFF; i++)
*(vu32 *)(ctxt.pkg1_id->secmon_base + secmon_patchset[i].off) = secmon_patchset[i].val;
}
gfx_printf("Loaded warmboot and secmon\n");
// Read package2.
u8 *bootConfigBuf = _read_emmc_pkg2(&ctxt);
if (!bootConfigBuf)
return 0;
gfx_printf("Read pkg2\n");
// Decrypt package2 and parse KIP1 blobs in INI1 section.
pkg2_hdr_t *pkg2_hdr = pkg2_decrypt(ctxt.pkg2, ctxt.pkg1_id->kb);
if (!pkg2_hdr)
{
_hos_crit_error("Pkg2 decryption failed!");
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
{
EPRINTF("Is Sept updated?");
// Clear EKS slot, in case something went wrong with sept keygen.
hos_eks_clear(ctxt.pkg1_id->kb);
}
return 0;
}
else if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
hos_eks_save(ctxt.pkg1_id->kb); // Save EKS slot if it doesn't exist.
LIST_INIT(kip1_info);
if (!pkg2_parse_kips(&kip1_info, pkg2_hdr, &ctxt.new_pkg2))
{
_hos_crit_error("INI1 parsing failed!");
return 0;
}
gfx_printf("Parsed ini1\n");
// Use the kernel included in package2 in case we didn't load one already.
if (!ctxt.kernel)
{
ctxt.kernel = pkg2_hdr->data;
ctxt.kernel_size = pkg2_hdr->sec_size[PKG2_SEC_KERNEL];
if (!ctxt.stock && (ctxt.svcperm || ctxt.debugmode || ctxt.atmosphere))
{
u8 kernel_hash[0x20];
// Hash only Kernel when it embeds INI1.
if (!ctxt.new_pkg2)
se_calc_sha256(kernel_hash, ctxt.kernel, ctxt.kernel_size);
else
se_calc_sha256(kernel_hash, ctxt.kernel + PKG2_NEWKERN_START,
pkg2_newkern_ini1_start - PKG2_NEWKERN_START);
ctxt.pkg2_kernel_id = pkg2_identify(kernel_hash);
if (!ctxt.pkg2_kernel_id)
{
_hos_crit_error("Failed to identify kernel!");
return 0;
}
// In case a kernel patch option is set; allows to disable SVC verification or/and enable debug mode.
kernel_patch_t *kernel_patchset = ctxt.pkg2_kernel_id->kernel_patchset;
if (kernel_patchset != NULL)
{
gfx_printf("%kPatching kernel%k\n", 0xFFFFBA00, 0xFFCCCCCC);
u32 *temp;
for (u32 i = 0; kernel_patchset[i].id != 0xFFFFFFFF; i++)
{
if ((ctxt.svcperm && kernel_patchset[i].id == SVC_VERIFY_DS)
|| (ctxt.debugmode && kernel_patchset[i].id == DEBUG_MODE_EN && !(ctxt.atmosphere && ctxt.secmon))
|| (ctxt.atmosphere && kernel_patchset[i].id == ATM_GEN_PATCH))
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
else if (ctxt.atmosphere && kernel_patchset[i].id == ATM_ARR_PATCH)
{
temp = (u32 *)kernel_patchset[i].ptr;
for (u32 j = 0; j < kernel_patchset[i].val; j++)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off + (j << 2)) = temp[j];
}
else if (kernel_patchset[i].id < SVC_VERIFY_DS)
*(vu32 *)(ctxt.kernel + kernel_patchset[i].off) = kernel_patchset[i].val;
}
}
}
}
// Merge extra KIP1s into loaded ones.
gfx_printf("%kPatching kips%k\n", 0xFFFFBA00, 0xFFCCCCCC);
LIST_FOREACH_ENTRY(merge_kip_t, mki, &ctxt.kip1_list, link)
pkg2_merge_kip(&kip1_info, (pkg2_kip1_t *)mki->kip1);
// Check if FS is compatible with exFAT.
if (!ctxt.stock && sd_fs.fs_type == FS_EXFAT && !_get_fs_exfat_compatible(&kip1_info))
{
_hos_crit_error("SD Card is exFAT and the installed\nFS only supports FAT32!");
_free_launch_components(&ctxt);
return 0;
}
// Patch kip1s in memory if needed.
const char* unappliedPatch = pkg2_patch_kips(&kip1_info, ctxt.kip1_patches);
if (unappliedPatch != NULL)
{
EHPRINTFARGS("Failed to apply '%s'!", unappliedPatch);
_free_launch_components(&ctxt);
return 0; // MUST stop here, because if user requests 'nogc' but it's not applied, their GC controller gets updated!
}
// Rebuild and encrypt package2.
pkg2_build_encrypt((void *)PKG2_LOAD_ADDR, ctxt.kernel, ctxt.kernel_size, &kip1_info, ctxt.new_pkg2);
gfx_printf("Rebuilt & loaded pkg2\n");
// Unmount SD card.
sd_unmount();
gfx_printf("\n%kBooting...%k\n", 0xFF96FF00, 0xFFCCCCCC);
// Clear pkg1/pkg2 keys.
se_aes_key_clear(8);
se_aes_key_clear(11);
// Finalize per firmware keys.
int bootStateDramPkg2 = 0;
int bootStatePkg2Continue = 0;
switch (ctxt.pkg1_id->kb)
{
case KB_FIRMWARE_VERSION_100_200:
case KB_FIRMWARE_VERSION_300:
case KB_FIRMWARE_VERSION_301:
if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_300)
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0xE3; // Warmboot 3.0.0 PA address id.
else if (ctxt.pkg1_id->kb == KB_FIRMWARE_VERSION_301)
PMC(APBDEV_PMC_SECURE_SCRATCH32) = 0x104; // Warmboot 3.0.1/.2 PA address id.
se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
se_key_acc_ctrl(13, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 3;
break;
case KB_FIRMWARE_VERSION_400:
case KB_FIRMWARE_VERSION_500:
case KB_FIRMWARE_VERSION_600:
se_key_acc_ctrl(12, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
se_key_acc_ctrl(15, SE_KEY_TBL_DIS_KEY_ACCESS_FLAG | SE_KEY_TBL_DIS_KEY_LOCK_FLAG);
default:
bootStateDramPkg2 = 2;
bootStatePkg2Continue = 4;
break;
}
// Clear BCT area for retail units and copy it over if dev unit.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_500)
{
memset((void *)0x4003D000, 0, 0x3000);
if ((fuse_read_odm(4) & 3) == 3)
memcpy((void *)0x4003D000, bootConfigBuf, 0x1000);
}
else
{
memset((void *)0x4003F000, 0, 0x1000);
if ((fuse_read_odm(4) & 3) == 3)
memcpy((void *)0x4003F800, bootConfigBuf, 0x800);
}
free(bootConfigBuf);
// Config Exosphère if booting full Atmosphère.
if (ctxt.atmosphere && ctxt.secmon)
config_exosphere(&ctxt);
// Finalize MC carveout.
if (ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_301)
mc_config_carveout();
// Lock SE before starting 'SecureMonitor' if < 6.2.0, otherwise lock bootrom and ipatches.
_se_lock(ctxt.pkg1_id->kb <= KB_FIRMWARE_VERSION_600);
// Reset sysctr0 counters.
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_620)
_sysctr0_reset();
// < 4.0.0 pkg1.1 locks PMC scratches.
//_pmc_scratch_lock(ctxt.pkg1_id->kb);
// Set secmon mailbox address.
if (ctxt.pkg1_id->kb >= KB_FIRMWARE_VERSION_700)
secmon_mb = (secmon_mailbox_t *)SECMON7_MB_ADDR;
else
secmon_mb = (secmon_mailbox_t *)SECMON_MB_ADDR;
// Start from DRAM ready signal and reset outgoing value.
secmon_mb->in = bootStateDramPkg2;
secmon_mb->out = 0;
// Disable display. This must be executed before secmon to provide support for all fw versions.
display_end();
// Clear EMC_SCRATCH0.
EMC(EMC_SCRATCH0) = 0;
// Flush cache and disable MMU.
bpmp_mmu_disable();
bpmp_clk_rate_set(BPMP_CLK_NORMAL);
minerva_change_freq(FREQ_1600);
// emuMMC: Some cards (Sandisk U1), do not like a fast power cycle. Wait min 100ms.
sdmmc_storage_init_wait_sd();
// Wait for secmon to get ready.
if (smmu_is_used())
smmu_exit();
else
cluster_boot_cpu0(ctxt.pkg1_id->secmon_base);
while (!secmon_mb->out)
; // A usleep(1) only works when in IRAM or with a trained DRAM.
// Signal pkg2 ready and continue boot.
secmon_mb->in = bootStatePkg2Continue;
// Halt ourselves in waitevent state and resume if there's JTAG activity.
while (true)
bpmp_halt();
return 0;
}

View File

@@ -1,120 +0,0 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
*
* 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/>.
*/
#ifndef _HOS_H_
#define _HOS_H_
#include "pkg1.h"
#include "pkg2.h"
#include "../utils/types.h"
#include "../config/ini.h"
#include "../sec/tsec.h"
#include <assert.h>
#define KB_FIRMWARE_VERSION_100_200 0
#define KB_FIRMWARE_VERSION_300 1
#define KB_FIRMWARE_VERSION_301 2
#define KB_FIRMWARE_VERSION_400 3
#define KB_FIRMWARE_VERSION_500 4
#define KB_FIRMWARE_VERSION_600 5
#define KB_FIRMWARE_VERSION_620 6
#define KB_FIRMWARE_VERSION_700 7
#define KB_FIRMWARE_VERSION_810 8
#define KB_FIRMWARE_VERSION_900 9
#define KB_FIRMWARE_VERSION_910 10
#define KB_FIRMWARE_VERSION_MAX KB_FIRMWARE_VERSION_910
#define HOS_PKG11_MAGIC 0x31314B50
#define HOS_EKS_MAGIC 0x30534B45
typedef struct _exo_ctxt_t
{
bool no_user_exceptions;
bool user_pmu;
bool *cal0_blank;
bool *cal0_allow_writes_sys;
} exo_ctxt_t;
typedef struct _hos_eks_keys_t
{
u8 dkg[0x10];
u8 mkk[0x10];
u8 fdk[0x10];
u8 dkk[0x10];
} hos_eks_keys_t;
typedef struct _hos_eks_mbr_t
{
u32 magic;
u32 enabled;
u32 sbk_low[2];
hos_eks_keys_t keys[6];
u32 magic2;
u32 rsvd2[3];
} hos_eks_mbr_t;
static_assert(sizeof(hos_eks_mbr_t) < 424, "HOS EKS storage bigger than MBR!");
typedef struct _launch_ctxt_t
{
void *keyblob;
void *pkg1;
const pkg1_id_t *pkg1_id;
const pkg2_kernel_id_t *pkg2_kernel_id;
void *warmboot;
u32 warmboot_size;
void *secmon;
u32 secmon_size;
void *pkg2;
u32 pkg2_size;
bool new_pkg2;
void *kernel;
u32 kernel_size;
link_t kip1_list;
char* kip1_patches;
u32 fss0_hosver;
bool svcperm;
bool debugmode;
bool stock;
bool atmosphere;
bool fss0_enable_experimental;
bool emummc_forced;
exo_ctxt_t exo_cfg;
ini_sec_t *cfg;
} launch_ctxt_t;
typedef struct _merge_kip_t
{
void *kip1;
link_t link;
} merge_kip_t;
void hos_eks_get();
void hos_eks_save(u32 kb);
void hos_eks_clear(u32 kb);
int hos_launch(ini_sec_t *cfg);
int hos_keygen(u8 *keyblob, u32 kb, tsec_ctxt_t *tsec_ctxt, launch_ctxt_t *hos_ctxt);
#endif

View File

@@ -1,309 +0,0 @@
/*
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer
*
* 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/>.
*/
#include <string.h>
#include "hos.h"
#include "hos_config.h"
#include "fss.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../storage/nx_sd.h"
#include "../utils/dirlist.h"
#include "../gfx/gfx.h"
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...)
static int _config_warmboot(launch_ctxt_t *ctxt, const char *value)
{
ctxt->warmboot = sd_file_read(value, &ctxt->warmboot_size);
if (!ctxt->warmboot)
return 0;
return 1;
}
static int _config_secmon(launch_ctxt_t *ctxt, const char *value)
{
ctxt->secmon = sd_file_read(value, &ctxt->secmon_size);
if (!ctxt->secmon)
return 0;
return 1;
}
static int _config_kernel(launch_ctxt_t *ctxt, const char *value)
{
ctxt->kernel = sd_file_read(value, &ctxt->kernel_size);
if (!ctxt->kernel)
return 0;
return 1;
}
static int _config_kip1(launch_ctxt_t *ctxt, const char *value)
{
u32 size;
if (!memcmp(value + strlen(value) - 1, "*", 1))
{
char *dir = (char *)malloc(256);
strcpy(dir, value);
u32 dirlen = 0;
dir[strlen(dir) - 2] = 0;
char *filelist = dirlist(dir, "*.kip*", false);
strcat(dir, "/");
dirlen = strlen(dir);
u32 i = 0;
if (filelist)
{
while (true)
{
if (!filelist[i * 256])
break;
strcpy(dir + dirlen, &filelist[i * 256]);
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = sd_file_read(dir, &size);
if (!mkip1->kip1)
{
free(mkip1);
free(dir);
free(filelist);
return 0;
}
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
list_append(&ctxt->kip1_list, &mkip1->link);
i++;
}
}
free(dir);
free(filelist);
}
else
{
merge_kip_t *mkip1 = (merge_kip_t *)malloc(sizeof(merge_kip_t));
mkip1->kip1 = sd_file_read(value, &size);
if (!mkip1->kip1)
{
free(mkip1);
return 0;
}
DPRINTF("Loaded kip1 from SD (size %08X)\n", size);
list_append(&ctxt->kip1_list, &mkip1->link);
}
return 1;
}
int config_kip1patch(launch_ctxt_t *ctxt, const char *value)
{
if (value == NULL)
return 0;
int valueLen = strlen(value);
if (!valueLen)
return 0;
if (ctxt->kip1_patches == NULL)
{
ctxt->kip1_patches = malloc(valueLen + 1);
memcpy(ctxt->kip1_patches, value, valueLen);
ctxt->kip1_patches[valueLen] = 0;
}
else
{
char *oldAlloc = ctxt->kip1_patches;
int oldSize = strlen(oldAlloc);
ctxt->kip1_patches = malloc(oldSize + 1 + valueLen + 1);
memcpy(ctxt->kip1_patches, oldAlloc, oldSize);
free(oldAlloc);
oldAlloc = NULL;
ctxt->kip1_patches[oldSize++] = ',';
memcpy(&ctxt->kip1_patches[oldSize], value, valueLen);
ctxt->kip1_patches[oldSize + valueLen] = 0;
}
return 1;
}
static int _config_svcperm(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled SVC verification\n");
ctxt->svcperm = true;
}
return 1;
}
static int _config_debugmode(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled Debug mode\n");
ctxt->debugmode = true;
}
return 1;
}
static int _config_stock(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled all patching\n");
ctxt->stock = true;
}
return 1;
}
static int _config_emummc_forced(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Forced emuMMC\n");
ctxt->emummc_forced = true;
}
return 1;
}
static int _config_atmosphere(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled atmosphere patching\n");
ctxt->atmosphere = true;
}
return 1;
}
static int _config_dis_exo_user_exceptions(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Disabled exosphere user exception handlers\n");
ctxt->exo_cfg.no_user_exceptions = true;
}
return 1;
}
static int _config_exo_user_pmu_access(launch_ctxt_t *ctxt, const char *value)
{
if (*value == '1')
{
DPRINTF("Enabled user access to PMU\n");
ctxt->exo_cfg.user_pmu = true;
}
return 1;
}
static int _config_exo_cal0_blanking(launch_ctxt_t *ctxt, const char *value)
{
// Override key found.
ctxt->exo_cfg.cal0_blank = calloc(1, 1);
if (*value == '1')
{
DPRINTF("Enabled prodinfo blanking\n");
*ctxt->exo_cfg.cal0_blank = true;
}
return 1;
}
static int _config_exo_cal0_writes_enable(launch_ctxt_t *ctxt, const char *value)
{
// Override key found.
ctxt->exo_cfg.cal0_allow_writes_sys = calloc(1, 1);
if (*value == '1')
{
DPRINTF("Enabled prodinfo writes\n");
*ctxt->exo_cfg.cal0_allow_writes_sys = true;
}
return 1;
}
static int _config_fss(launch_ctxt_t *ctxt, const char *value)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
if (!strcmp("fss0experimental", kv->key))
{
ctxt->fss0_enable_experimental = *kv->val == '1';
break;
}
}
return parse_fss(ctxt, value, NULL);
}
typedef struct _cfg_handler_t
{
const char *key;
int (*handler)(launch_ctxt_t *ctxt, const char *value);
} cfg_handler_t;
static const cfg_handler_t _config_handlers[] = {
{ "warmboot", _config_warmboot },
{ "secmon", _config_secmon },
{ "kernel", _config_kernel },
{ "kip1", _config_kip1 },
{ "kip1patch", config_kip1patch },
{ "fullsvcperm", _config_svcperm },
{ "debugmode", _config_debugmode },
{ "stock", _config_stock },
{ "atmosphere", _config_atmosphere },
{ "fss0", _config_fss },
{ "emummcforce", _config_emummc_forced },
{ "nouserexceptions", _config_dis_exo_user_exceptions },
{ "userpmu", _config_exo_user_pmu_access },
{ "cal0blank", _config_exo_cal0_blanking },
{ "cal0writesys", _config_exo_cal0_writes_enable },
{ NULL, NULL },
};
int parse_boot_config(launch_ctxt_t *ctxt)
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ctxt->cfg->kvs, link)
{
for(u32 i = 0; _config_handlers[i].key; i++)
{
if (!strcmp(_config_handlers[i].key, kv->key))
{
if (!_config_handlers[i].handler(ctxt, kv->val))
{
gfx_con.mute = false;
EPRINTFARGS("Error while loading %s:\n%s", kv->key, kv->val);
return 0;
}
}
}
}
return 1;
}

View File

@@ -1,26 +0,0 @@
/*
* Copyright (c) 2018 naehrwert
*
* 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/>.
*/
#ifndef _HOS_CONFIG_H_
#define _HOS_CONFIG_H_
#include "hos.h"
int parse_boot_config(launch_ctxt_t *ctxt);
int config_kip1patch(launch_ctxt_t *ctxt, const char *value);
#endif

View File

@@ -1,7 +1,7 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 st4rk * Copyright (c) 2018 st4rk
* Copyright (c) 2018-2020 CTCaer * Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011 * Copyright (c) 2018 balika011
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
@@ -20,135 +20,29 @@
#include <string.h> #include <string.h>
#include "pkg1.h" #include "pkg1.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../sec/se.h" #include "../sec/se.h"
#include "../utils/aarch64_util.h"
#define _NOPv7() 0xE320F000 #define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
#define SM_100_ADR 0x4002B020 #define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
PATCHSET_DEF(_secmon_1_patchset, #define HASH_ORDER_700_10x {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
// Patch the relocator to be able to run from SM_100_ADR.
{ 0x1E0, _ADRP(0, 0x7C013000 - _PAGEOFF(SM_100_ADR)) },
//Patch package2 decryption and signature/hash checks.
{ 0x9F0 + 0xADC, _NOP() }, //Header signature.
{ 0x9F0 + 0xB8C, _NOP() }, //Version.
{ 0x9F0 + 0xBB0, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_2_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xAC8 + 0xAAC, _NOP() }, //Header signature.
{ 0xAC8 + 0xB3C, _NOP() }, //Version.
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_3_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xAC8 + 0xA30, _NOP() }, //Header signature.
{ 0xAC8 + 0xAB4, _NOP() }, //package2 structure.
{ 0xAC8 + 0xAC0, _NOP() }, //Version.
{ 0xAC8 + 0xADC, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_4_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0x2300 + 0x5D80, _NOP() }, //package2 structure.
{ 0x2300 + 0x5D8C, _NOP() }, //Version.
{ 0x2300 + 0x5EFC, _NOP() }, //Header signature.
{ 0xAC8 + 0xA2C, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_5_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDA8 + 0x9D8, _NOP() }, //package2 structure.
{ 0xDA8 + 0x9E4, _NOP() }, //Version.
{ 0xDA8 + 0xC9C, _NOP() }, //Header signature.
{ 0xDA8 + 0x1038, _NOP() } //Sections SHA2.
);
PATCHSET_DEF(_secmon_6_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
{ 0xDC8 + 0x82C, _NOP() }, //Version.
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
// Fix sleep mode for debug.
// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
// { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
);
PATCHSET_DEF(_secmon_620_patchset,
// Patch package2 decryption and signature/hash checks.
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
{ 0xDC8 + 0x610, _NOP() }, //Version.
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
// Fix sleep mode for debug.
// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
// { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
);
PATCHSET_DEF(_warmboot_1_patchset,
{ 0x4DC, _NOPv7() } // Fuse check.
);
PATCHSET_DEF(_warmboot_2_patchset,
{ 0x4DC, _NOPv7() } // Fuse check.
);
PATCHSET_DEF(_warmboot_3_patchset,
{ 0x4DC, _NOPv7() }, // Fuse check.
{ 0x4F0, _NOPv7() } // Segment id check.
);
PATCHSET_DEF(_warmboot_4_patchset,
{ 0x544, _NOPv7() }, // Fuse check.
{ 0x558, _NOPv7() } // Segment id check.
);
/*
* package1.1 header: <wb, ldr, sm>
* package1.1 layout:
* 1.0: {sm, ldr, wb} { 2, 1, 0 }
* 2.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.0: {wb, ldr, sm} { 0, 1, 2 }
* 3.1: {wb, ldr, sm} { 0, 1, 2 }
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
*/
static const pkg1_id_t _pkg1_ids[] = { static const pkg1_id_t _pkg1_ids[] = {
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator) { "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0 { "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0 { "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2 { "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0 { "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.1.0
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0 { "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0 { "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0 { "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0 { "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1 { "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1 { "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0 { "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.1.0
{ "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1 { "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
{ "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0 { "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.1.0
{ "20200303104606", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //10.0.0 { "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0
{ NULL } //End. { NULL } //End.
}; };
@@ -159,31 +53,3 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1)
return &_pkg1_ids[i]; return &_pkg1_ids[i];
return NULL; return NULL;
} }
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
{
// Decrypt package1.
u8 *pkg11 = pkg1 + id->pkg11_off;
u32 pkg11_size = *(u32 *)pkg11;
se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10);
}
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)
{
pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);
u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };
//u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off };
u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);
for (u32 i = 0; i < 3; i++)
{
if (id->sec_map[i] == 0 && warmboot_dst)
memcpy(warmboot_dst, pdata, sec_size[id->sec_map[i]]);
else if (id->sec_map[i] == 1 && ldr_dst)
memcpy(ldr_dst, pdata, sec_size[id->sec_map[i]]);
else if (id->sec_map[i] == 2 && secmon_dst)
memcpy(secmon_dst, pdata, sec_size[id->sec_map[i]]);
pdata += sec_size[id->sec_map[i]];
}
}

View File

@@ -19,46 +19,25 @@
#include "../utils/types.h" #include "../utils/types.h"
typedef struct _patch_t typedef struct _key_info_t
{ {
u32 off; u32 start_offset;
u32 val; u32 hks_offset;
} patch_t; bool hks_offset_is_from_end;
u32 alignment;
#define PATCHSET_DEF(name, ...) \ u32 hash_max;
patch_t name[] = { \ u8 hash_order[13];
__VA_ARGS__, \ u32 es_offset;
{ 0xFFFFFFFF, 0xFFFFFFFF } \ u32 ssl_offset;
} } key_info_t;
typedef struct _pkg1_id_t typedef struct _pkg1_id_t
{ {
const char *id; const char *id;
u32 kb; u32 kb;
u32 tsec_off; key_info_t key_info;
u32 pkg11_off;
u32 sec_map[3];
u32 secmon_base;
u32 warmboot_base;
bool set_warmboot;
patch_t *secmon_patchset;
patch_t *warmboot_patchset;
} pkg1_id_t; } pkg1_id_t;
typedef struct _pk11_hdr_t
{
u32 magic;
u32 wb_size;
u32 wb_off;
u32 pad;
u32 ldr_size;
u32 ldr_off;
u32 sm_size;
u32 sm_off;
} pk11_hdr_t;
const pkg1_id_t *pkg1_identify(u8 *pkg1); const pkg1_id_t *pkg1_identify(u8 *pkg1);
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);
#endif #endif

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018-2020 CTCaer * Copyright (C) 2018-2020 CTCaer
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -26,41 +26,12 @@
#define PKG2_SEC_KERNEL 0 #define PKG2_SEC_KERNEL 0
#define PKG2_SEC_INI1 1 #define PKG2_SEC_INI1 1
#define INI1_MAGIC 0x31494E49
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset. #define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
#define PKG2_NEWKERN_START 0x800
u32 pkg2_newkern_ini1_val; u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start; u32 pkg2_newkern_ini1_start;
u32 pkg2_newkern_ini1_end; u32 pkg2_newkern_ini1_end;
typedef struct _kernel_patch_t
{
u32 id;
u32 off;
u32 val;
u32 *ptr;
} kernel_patch_t;
#define KERNEL_PATCHSET_DEF(name, ...) \
kernel_patch_t name[] = { \
__VA_ARGS__, \
{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, (u32 *)0xFFFFFFFF} \
}
enum
{
// Always applied.
SVC_GENERIC = 0,
// Generic instruction patches.
SVC_VERIFY_DS = 0x10,
DEBUG_MODE_EN = 0x11,
ATM_GEN_PATCH = 0x12,
ATM_SYSM_INCR = ATM_GEN_PATCH,
// >4 bytes patches. Value is a pointer of a u32 array.
ATM_ARR_PATCH = 0x13,
};
typedef struct _pkg2_hdr_t typedef struct _pkg2_hdr_t
{ {
u8 ctr[0x10]; u8 ctr[0x10];
@@ -116,44 +87,8 @@ typedef struct _pkg2_kip1_info_t
link_t link; link_t link;
} pkg2_kip1_info_t; } pkg2_kip1_info_t;
typedef struct _pkg2_kernel_id_t
{
u8 hash[8];
kernel_patch_t *kernel_patchset;
} pkg2_kernel_id_t;
typedef struct _kip1_patch_t
{
u32 offset; // section+offset of patch to apply.
u32 length; // In bytes, 0 means last patch.
char* srcData; // That must match.
char* dstData; // That it gets replaced by.
} kip1_patch_t;
typedef struct _kip1_patchset_t
{
char* name; // NULL means end.
kip1_patch_t* patches; // NULL means not necessary.
} kip1_patchset_t;
typedef struct _kip1_id_t
{
const char* name;
u8 hash[8];
kip1_patchset_t* patchset;
} kip1_id_t;
void pkg2_get_newkern_info(u8 *kern_data);
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2); bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
int pkg2_has_kip(link_t *info, u64 tid); int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1); pkg2_hdr_t *pkg2_decrypt(void *data);
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
void pkg2_get_ids(kip1_id_t **ids, u32 *entries);
const char* pkg2_patch_kips(link_t *info, char* patchNames);
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb);
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
#endif #endif

View File

@@ -1,156 +0,0 @@
#include <string.h>
#include <stdlib.h>
#include "pkg2_ini_kippatch.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#define KPS(x) ((u32)(x) << 29)
static u8 *_htoa(u8 *result, const char *ptr, u8 byte_len)
{
char ch = *ptr;
u32 ascii_len = byte_len * 2;
if (!result)
result = malloc(byte_len);
u8 *dst = result;
while (ch == ' ' || ch == '\t')
ch = *(++ptr);
bool shift = true;
while (ascii_len)
{
u8 tmp = 0;
if (ch >= '0' && ch <= '9')
tmp = (ch - '0');
else if (ch >= 'A' && ch <= 'F')
tmp = (ch - 'A' + 10);
else if (ch >= 'a' && ch <= 'f')
tmp = (ch - 'a' + 10);
if (shift)
*dst = (tmp << 4) & 0xF0;
else
{
*dst |= (tmp & 0x0F);
dst++;
}
ascii_len--;
ch = *(++ptr);
shift = !shift;
}
return result;
}
static char *_strdup(char *str)
{
if (!str)
return NULL;
if (str[0] == ' ' && (strlen(str) > 1))
str++;
char *res = (char *)malloc(strlen(str) + 1);
strcpy(res, str);
if (res[strlen(res) - 1] == ' ' && (strlen(res) > 1))
res[strlen(res) - 1] = 0;
return res;
}
static u32 _find_patch_section_name(char *lbuf, u32 lblen, char schar)
{
u32 i;
for (i = 0; i < lblen && lbuf[i] != schar && lbuf[i] != '\n' && lbuf[i] != '\r'; i++)
;
lbuf[i] = 0;
return i;
}
static ini_kip_sec_t *_ini_create_kip_section(link_t *dst, ini_kip_sec_t *ksec, char *name)
{
if (ksec)
list_append(dst, &ksec->link);
ksec = (ini_kip_sec_t *)calloc(sizeof(ini_kip_sec_t), 1);
u32 i = _find_patch_section_name(name, strlen(name), ':') + 1;
ksec->name = _strdup(name);
// Get hash section.
_htoa(ksec->hash, &name[i], 8);
return ksec;
}
int ini_patch_parse(link_t *dst, char *ini_path)
{
u32 lblen;
char lbuf[512];
FIL fp;
ini_kip_sec_t *ksec = NULL;
// Open ini.
if (f_open(&fp, ini_path, FA_READ) != FR_OK)
return 0;
do
{
// Fetch one line.
lbuf[0] = 0;
f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf);
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
if (lblen && lbuf[lblen - 1] == '\n')
lbuf[lblen - 1] = 0;
if (lblen > 2 && lbuf[0] == '[') // Create new section.
{
_find_patch_section_name(lbuf, lblen, ']');
ksec = _ini_create_kip_section(dst, ksec, &lbuf[1]);
list_init(&ksec->pts);
}
else if (ksec && lbuf[0] == '.') //Extract key/value.
{
u32 tmp = 0;
u32 i = _find_patch_section_name(lbuf, lblen, '=');
ini_patchset_t *pt = (ini_patchset_t *)calloc(sizeof(ini_patchset_t), 1);
pt->name = _strdup(&lbuf[1]);
u8 kip_sidx = lbuf[i + 1] - '0';
if (kip_sidx < 6)
{
pt->offset = KPS(kip_sidx);
tmp = _find_patch_section_name(&lbuf[i + 3], lblen, ':');
pt->offset |= strtol(&lbuf[i + 3], NULL, 16);
i += tmp + 4;
tmp = _find_patch_section_name(&lbuf[i], lblen, ':');
pt->length = strtol(&lbuf[i], NULL, 16);
i += tmp + 1;
tmp = _find_patch_section_name(&lbuf[i], lblen, ',');
pt->srcData = _htoa(NULL, &lbuf[i], pt->length);
i += tmp + 1;
pt->dstData = _htoa(NULL, &lbuf[i], pt->length);
}
list_append(&ksec->pts, &pt->link);
}
} while (!f_eof(&fp));
f_close(&fp);
if (ksec)
list_append(dst, &ksec->link);
return 1;
}

View File

@@ -1,43 +0,0 @@
/*
* Copyright (c) 2019 CTCaer
*
* 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/>.
*/
#ifndef _INIPATCH_H_
#define _INIPATCH_H_
#include "../utils/types.h"
#include "../utils/list.h"
typedef struct _ini_patchset_t
{
char *name;
u32 offset; // section + offset of patch to apply.
u32 length; // In bytes, 0 means last patch.
u8 *srcData; // That must match.
u8 *dstData; // Gets replaced with.
link_t link;
} ini_patchset_t;
typedef struct _ini_kip_sec_t
{
char *name;
u8 hash[8];
link_t pts;
link_t link;
} ini_kip_sec_t;
int ini_patch_parse(link_t *dst, char *ini_path);
#endif

View File

@@ -1,355 +0,0 @@
/*
* Copyright (c) 2018-2020 CTCaer
* Copyright (c) 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/>.
*/
#include <string.h>
#include <stdlib.h>
#include "hos.h"
#include "../config/config.h"
#include "../gfx/di.h"
#include "../gfx/gfx.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../soc/fuse.h"
#include "../storage/emummc.h"
#include "../storage/nx_sd.h"
#include "../storage/sdmmc.h"
#include "../utils/btn.h"
#include "../utils/util.h"
#include "../utils/types.h"
extern hekate_config h_cfg;
enum emuMMC_Type
{
emuMMC_None = 0,
emuMMC_Partition,
emuMMC_File,
emuMMC_MAX
};
/* "EFS0" */
#define EMUMMC_MAGIC 0x30534645
#define EMUMMC_FILE_PATH_MAX 0x80
typedef struct
{
u32 magic;
u32 type;
u32 id;
u32 fs_ver;
} emummc_base_config_t;
typedef struct
{
u64 start_sector;
} emummc_partition_config_t;
typedef struct
{
char path[EMUMMC_FILE_PATH_MAX];
} emummc_file_config_t;
typedef struct
{
emummc_base_config_t base_cfg;
union
{
emummc_partition_config_t partition_cfg;
emummc_file_config_t file_cfg;
};
char nintendo_path[EMUMMC_FILE_PATH_MAX];
} exo_emummc_config_t;
typedef struct _exo_cfg_t
{
u32 magic;
u32 fwno;
u32 flags;
u32 reserved[5];
exo_emummc_config_t emummc_cfg;
} exo_cfg_t;
typedef struct _atm_meta_t
{
u32 magic;
u32 fwno;
} wb_cfg_t;
// Atmosphère reboot-to-fatal-error.
typedef struct _atm_fatal_error_ctx
{
u32 magic;
u32 error_desc;
u64 title_id;
union
{
u64 gprs[32];
struct
{
u64 _gprs[29];
u64 fp;
u64 lr;
u64 sp;
};
};
u64 pc;
u64 module_base;
u32 pstate;
u32 afsr0;
u32 afsr1;
u32 esr;
u64 far;
u64 report_identifier; // Normally just system tick.
u64 stack_trace_size;
u64 stack_dump_size;
u64 stack_trace[0x20];
u8 stack_dump[0x100];
u8 tls[0x100];
} atm_fatal_error_ctx;
#define ATM_FATAL_ERR_CTX_ADDR 0x4003E000
#define ATM_FATAL_MAGIC 0x30454641 // AFE0
#define ATM_WB_HEADER_OFF 0x244
#define ATM_WB_MAGIC 0x30544257
// Exosphère mailbox defines.
#define EXO_CFG_ADDR 0x8000F000
#define EXO_MAGIC_VAL 0x304F5845
#define EXO_FLAG_DBG_PRIV (1 << 1)
#define EXO_FLAG_DBG_USER (1 << 2)
#define EXO_FLAG_NO_USER_EXC (1 << 3)
#define EXO_FLAG_USER_PMU (1 << 4)
#define EXO_FLAG_CAL0_BLANKING (1 << 5)
#define EXO_FLAG_CAL0_WRITES_SYS (1 << 6)
void config_exosphere(launch_ctxt_t *ctxt)
{
u32 exoFwNo = 0;
u32 exoFlags = 0;
u32 kb = ctxt->pkg1_id->kb;
bool user_debug = false;
bool cal0_blanking = false;
bool cal0_allow_writes_sys = false;
memset((exo_cfg_t *)EXO_CFG_ADDR, 0, sizeof(exo_cfg_t));
volatile exo_cfg_t *exo_cfg = (exo_cfg_t *)EXO_CFG_ADDR;
switch (kb)
{
case KB_FIRMWARE_VERSION_100_200:
if (!strcmp(ctxt->pkg1_id->id, "20161121183008"))
exoFwNo = 1;
else
exoFwNo = 2;
break;
case KB_FIRMWARE_VERSION_300:
exoFwNo = 3;
break;
default:
exoFwNo = kb + 1;
if (!strcmp(ctxt->pkg1_id->id, "20190314172056") || (kb >= KB_FIRMWARE_VERSION_810))
exoFwNo++; // ATM_TARGET_FW_800/810/900/910.
if (!strcmp(ctxt->pkg1_id->id, "20200303104606"))
exoFwNo++; // ATM_TARGET_FW_1000.
break;
}
if (!ctxt->stock)
{
// Parse exosphere.ini.
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "exosphere.ini", false))
{
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Only parse exosphere section.
if (!(ini_sec->type == INI_CHOICE) || strcmp(ini_sec->name, "exosphere"))
continue;
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("debugmode_user", kv->key))
user_debug = atoi(kv->val);
else if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
{
if (!strcmp("blank_prodinfo_emummc", kv->key))
cal0_blanking = atoi(kv->val);
}
else
{
if (!strcmp("blank_prodinfo_sysmmc", kv->key))
cal0_blanking = atoi(kv->val);
else if (!strcmp("allow_writing_to_cal_sysmmc", kv->key))
cal0_allow_writes_sys = atoi(kv->val);
}
}
break;
}
}
}
// To avoid problems, make private debug mode always on if not semi-stock.
if (!ctxt->stock || (emu_cfg.enabled && !h_cfg.emummc_force_disable))
exoFlags |= EXO_FLAG_DBG_PRIV;
// Enable user debug.
if (user_debug)
exoFlags |= EXO_FLAG_DBG_USER;
// Disable proper failure handling.
if (ctxt->exo_cfg.no_user_exceptions)
exoFlags |= EXO_FLAG_NO_USER_EXC;
// Enable user access to PMU.
if (ctxt->exo_cfg.user_pmu)
exoFlags |= EXO_FLAG_USER_PMU;
// Check if exo ini value is overridden and enable prodinfo blanking.
if ((ctxt->exo_cfg.cal0_blank && *ctxt->exo_cfg.cal0_blank)
|| (!ctxt->exo_cfg.cal0_blank && cal0_blanking))
exoFlags |= EXO_FLAG_CAL0_BLANKING;
// Check if exo ini value is overridden and allow prodinfo writes.
if ((ctxt->exo_cfg.cal0_allow_writes_sys && *ctxt->exo_cfg.cal0_allow_writes_sys)
|| (!ctxt->exo_cfg.cal0_allow_writes_sys && cal0_allow_writes_sys))
exoFlags |= EXO_FLAG_CAL0_WRITES_SYS;
// Set mailbox values.
exo_cfg->magic = EXO_MAGIC_VAL;
exo_cfg->fwno = exoFwNo;
exo_cfg->flags = exoFlags;
// If warmboot is lp0fw, add in RSA modulus.
volatile wb_cfg_t *wb_cfg = (wb_cfg_t *)(ctxt->pkg1_id->warmboot_base + ATM_WB_HEADER_OFF);
if (wb_cfg->magic == ATM_WB_MAGIC)
{
wb_cfg->fwno = exoFwNo;
sdmmc_storage_t storage;
sdmmc_t sdmmc;
// Set warmboot binary rsa modulus.
u8 *rsa_mod = (u8 *)malloc(512);
sdmmc_storage_init_mmc(&storage, &sdmmc, SDMMC_BUS_WIDTH_8, SDHCI_TIMING_MMC_HS400);
sdmmc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
sdmmc_storage_read(&storage, 1, 1, rsa_mod);
sdmmc_storage_end(&storage);
// Patch AutoRCM out.
if ((fuse_read_odm(4) & 3) != 3)
rsa_mod[0x10] = 0xF7;
else
rsa_mod[0x10] = 0x37;
memcpy((void *)(ctxt->pkg1_id->warmboot_base + 0x10), rsa_mod + 0x10, 0x100);
}
if (emu_cfg.enabled && !h_cfg.emummc_force_disable)
{
exo_cfg->emummc_cfg.base_cfg.magic = EMUMMC_MAGIC;
exo_cfg->emummc_cfg.base_cfg.type = emu_cfg.sector ? emuMMC_Partition : emuMMC_File;
exo_cfg->emummc_cfg.base_cfg.fs_ver = emu_cfg.fs_ver;
exo_cfg->emummc_cfg.base_cfg.id = emu_cfg.id;
if (emu_cfg.sector)
exo_cfg->emummc_cfg.partition_cfg.start_sector = emu_cfg.sector;
else
strcpy((char *)exo_cfg->emummc_cfg.file_cfg.path, emu_cfg.path);
if (emu_cfg.nintendo_path && !ctxt->stock)
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, emu_cfg.nintendo_path);
else if (ctxt->stock)
strcpy((char *)exo_cfg->emummc_cfg.nintendo_path, "Nintendo");
else
exo_cfg->emummc_cfg.nintendo_path[0] = 0;
}
}
static const char *get_error_desc(u32 error_desc)
{
switch (error_desc)
{
case 0x100:
return "Instruction Abort";
case 0x101:
return "Data Abort";
case 0x102:
return "PC Misalignment";
case 0x103:
return "SP Misalignment";
case 0x104:
return "Trap";
case 0x106:
return "SError";
case 0x301:
return "Bad SVC";
case 0xFFE:
return "std::abort()";
default:
return "Unknown";
}
}
void secmon_exo_check_panic()
{
volatile atm_fatal_error_ctx *rpt = (atm_fatal_error_ctx *)ATM_FATAL_ERR_CTX_ADDR;
// Mask magic to maintain compatibility with any AFE version, thanks to additive struct members.
if ((rpt->magic & 0xF0FFFFFF) != ATM_FATAL_MAGIC)
return;
gfx_clear_grey(0x1B);
gfx_con_setpos(0, 0);
WPRINTF("Panic occurred while running Atmosphere.\n\n");
WPRINTFARGS("Title ID: %08X%08X", (u32)((u64)rpt->title_id >> 32), (u32)rpt->title_id);
WPRINTFARGS("Error Desc: %s (0x%x)\n", get_error_desc(rpt->error_desc), rpt->error_desc);
// Save context to the SD card.
char filepath[0x40];
f_mkdir("atmosphere/fatal_errors");
strcpy(filepath, "/atmosphere/fatal_errors/report_");
itoa((u32)((u64)rpt->report_identifier >> 32), filepath + strlen(filepath), 16);
itoa((u32)(rpt->report_identifier), filepath + strlen(filepath), 16);
strcat(filepath, ".bin");
sd_save_to_file((void *)rpt, sizeof(atm_fatal_error_ctx), filepath);
gfx_con.fntsz = 8;
WPRINTFARGS("Report saved to %s\n", filepath);
// Change magic to invalid, to prevent double-display of error/bootlooping.
rpt->magic = 0x0;
gfx_con.fntsz = 16;
gfx_printf("\n\nPress POWER to continue.\n");
display_backlight_brightness(100, 1000);
msleep(1000);
u32 btn = btn_wait();
while (!(btn & BTN_POWER))
btn = btn_wait();
display_backlight_brightness(0, 1000);
gfx_con_setpos(0, 0);
}

View File

@@ -1,25 +0,0 @@
/*
* Copyright (c) 2018-2019 CTCaer
*
* 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/>.
*/
#ifndef _SECMON_EXO_H_
#define _SECMON_EXO_H_
#include "../utils/types.h"
void config_exosphere(launch_ctxt_t *ctxt);
void secmon_exo_check_panic();
#endif

View File

@@ -16,27 +16,20 @@
#include <string.h> #include <string.h>
#include "hos.h"
#include "fss.h"
#include "sept.h" #include "sept.h"
#include "../config/config.h"
#include "../gfx/di.h" #include "../gfx/di.h"
#include "../ianos/ianos.h"
#include "../libs/fatfs/ff.h" #include "../libs/fatfs/ff.h"
#include "../mem/heap.h" #include "../mem/heap.h"
#include "../soc/hw_init.h" #include "../soc/hw_init.h"
#include "../soc/pmc.h" #include "../soc/pmc.h"
#include "../soc/t210.h" #include "../soc/t210.h"
#include "../storage/emummc.h"
#include "../storage/nx_emmc.h" #include "../storage/nx_emmc.h"
#include "../storage/nx_sd.h"
#include "../storage/sdmmc.h" #include "../storage/sdmmc.h"
#include "../utils/btn.h" #include "../utils/btn.h"
#include "../utils/types.h" #include "../utils/types.h"
#include "../gfx/gfx.h" #include "../gfx/gfx.h"
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94 #define PATCHED_RELOC_SZ 0x94
#define WB_RST_ADDR 0x40010ED0 #define WB_RST_ADDR 0x40010ED0
@@ -57,178 +50,75 @@ u8 warmboot_reboot[] = {
#define SEPT_PRI_ADDR 0x4003F000 #define SEPT_PRI_ADDR 0x4003F000
#define SEPT_PK1T_ADDR 0xC0400000 #define SEPT_PK1T_ADDR 0xC0400000
#define SEPT_PK1T_STACK 0x40008000
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4) #define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100) #define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0) #define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE) #define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
extern u32 color_idx;
extern boot_cfg_t b_cfg; extern boot_cfg_t b_cfg;
extern hekate_config h_cfg; extern void sd_unmount();
extern const volatile ipl_ver_meta_t ipl_ver;
extern bool is_ipl_updated(void *buf);
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size); extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
void check_sept(ini_sec_t *cfg_sec) int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
{
hos_eks_get();
// Check if non-hekate payload is used for sept and restore it.
if (h_cfg.sept_run)
{
if (!f_stat("sept/payload.bak", NULL))
{
f_unlink("sept/payload.bin");
f_rename("sept/payload.bak", "sept/payload.bin");
}
return;
}
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
sdmmc_storage_t storage;
sdmmc_t sdmmc;
int res = emummc_storage_init_mmc(&storage, &sdmmc);
if (res)
{
if (res == 2)
EPRINTF("Failed to init eMMC");
else
EPRINTF("Failed to init emuMMC");
goto out_free;
}
emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
// Read package1.
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
if (!pkg1_id)
{
gfx_con.fntsz = 16;
EPRINTF("Unknown pkg1 version.");
goto out_free;
}
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
{
u8 key_idx = pkg1_id->kb - KB_FIRMWARE_VERSION_700;
if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx)))
{
h_cfg.sept_run = true;
EMC(EMC_SCRATCH0) |= EMC_SEPT_RUN;
goto out_free;
}
sdmmc_storage_end(&storage);
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec);
}
out_free:
free(pkg1);
sdmmc_storage_end(&storage);
}
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
{ {
FIL fp; FIL fp;
bool fss0_sept_used = false;
// Copy warmboot reboot code and TSEC fw. // Copy warmboot reboot code and TSEC fw.
u32 tsec_fw_size = 0x3000;
if (kb > KB_FIRMWARE_VERSION_700)
tsec_fw_size = 0x3300;
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot)); memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size); memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size);
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size; *(vu32 *)SEPT_TCSZ_ADDR = tsec_size;
if (cfg_sec) // Copy sept-primary.
if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ))
goto error;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
{ {
fss0_sept_t sept_ctxt;
sept_ctxt.kb = kb;
sept_ctxt.cfg_sec = cfg_sec;
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
fss0_sept_used = load_sept_from_ffs0(&sept_ctxt);
}
if (!fss0_sept_used)
{
// Copy sept-primary.
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
goto error;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
{
f_close(&fp);
goto error;
}
f_close(&fp); f_close(&fp);
goto error;
}
f_close(&fp);
// Copy sept-secondary. // Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810) if (kb < KB_FIRMWARE_VERSION_810)
{ {
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ)) if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version. if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
goto error;
}
else
{
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
goto error; goto error;
} }
else
if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL)) {
{ if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
f_close(&fp);
goto error; goto error;
}
f_close(&fp);
} }
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN); if (f_read(&fp, (u8 *)SEPT_STG2_ADDR, f_size(&fp), NULL))
bool update_sept_payload = true;
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
{ {
ipl_ver_meta_t tmp_ver;
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
if (tmp_ver.magic == ipl_ver.magic)
{
if (tmp_ver.version == ipl_ver.version)
{
// Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
update_sept_payload = false;
}
f_close(&fp);
}
else
{
f_close(&fp);
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
}
}
if (update_sept_payload)
{
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
f_mkdir("sept");
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
f_close(&fp); f_close(&fp);
goto error;
} }
f_close(&fp);
// Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE)) {
free(tmp_cfg);
goto error;
}
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
f_close(&fp);
sd_unmount(); sd_unmount();
gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]);
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE); u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
@@ -248,8 +138,8 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
(*sept)(); (*sept)();
error: error:
gfx_con.mute = false; EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again.");
EPRINTF("Failed to run sept\n"); display_backlight_brightness(100, 1000);
btn_wait(); btn_wait();

View File

@@ -19,7 +19,6 @@
#include "../utils/types.h" #include "../utils/types.h"
void check_sept(ini_sec_t *cfg_sec); int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb);
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec);
#endif #endif

View File

@@ -5629,7 +5629,8 @@ FRESULT f_forward (
} }
#endif /* FF_USE_FORWARD */ #endif /* FF_USE_FORWARD */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#if FF_USE_MKFS && !FF_FS_READONLY #if FF_USE_MKFS && !FF_FS_READONLY
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -6094,7 +6095,7 @@ FRESULT f_mkfs (
LEAVE_MKFS(FR_OK); LEAVE_MKFS(FR_OK);
} }
#pragma GCC pop_options
#if FF_MULTI_PARTITION #if FF_MULTI_PARTITION
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/

View File

@@ -1,6 +1,8 @@
/* /*
* Copyright (c) 2018 naehrwert * Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer * Copyright (c) 2018 CTCaer
* Copyright (c) 2018 Atmosphère-NX
* Copyright (c) 2019-2020 shchmue
* *
* This program is free software; you can redistribute it and/or modify it * This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License, * under the terms and conditions of the GNU General Public License,
@@ -31,6 +33,9 @@ typedef struct _se_ll_t
vu32 size; vu32 size;
} se_ll_t; } se_ll_t;
static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
static void _gf256_mul_x(void *block) static void _gf256_mul_x(void *block)
{ {
u8 *pdata = (u8 *)block; u8 *pdata = (u8 *)block;
@@ -47,6 +52,22 @@ static void _gf256_mul_x(void *block)
pdata[0xF] ^= 0x87; pdata[0xF] ^= 0x87;
} }
static void _gf256_mul_x_le(void *block)
{
u8 *pdata = (u8 *)block;
u32 carry = 0;
for (u32 i = 0; i < 0x10; i++)
{
u8 b = pdata[i];
pdata[i] = (b << 1) | carry;
carry = b >> 7;
}
if (carry)
pdata[0x0] ^= 0x87;
}
static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size) static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size)
{ {
ll->num = 0; ll->num = 0;
@@ -73,17 +94,15 @@ static int _se_wait()
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size) static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
{ {
se_ll_t *ll_dst = NULL, *ll_src = NULL; se_ll_t *ll_dst = (se_ll_t *)0xECFFFFE0, *ll_src = (se_ll_t *)0xECFFFFF0;
if (dst) if (dst)
{ {
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_dst, (u32)dst, dst_size); _se_ll_init(ll_dst, (u32)dst, dst_size);
} }
if (src) if (src)
{ {
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_src, (u32)src, src_size); _se_ll_init(ll_src, (u32)src, src_size);
} }
@@ -99,11 +118,6 @@ static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false); bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
if (src)
free(ll_src);
if (dst)
free(ll_dst);
return res; return res;
} }
@@ -142,6 +156,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs); SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
} }
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
{
u32 *data = (u32 *)mod;
for (u32 i = 0; i < mod_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]);
}
data = (u32 *)exp;
for (u32 i = 0; i < exp_size / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]);
}
_se_rsa_mod_sizes[ks] = mod_size;
_se_rsa_exp_sizes[ks] = exp_size;
}
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
void se_rsa_key_clear(u32 ks)
{
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
SE(SE_RSA_KEYTABLE_DATA) = 0;
}
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
{
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
SE(SE_RSA_KEYTABLE_DATA) = 0;
}
}
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
{
int res;
u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE];
for (u32 i = 0; i < src_size; i++)
stack_buf[i] = *((u8 *)src + src_size - i - 1);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2;
res = _se_execute(OP_START, NULL, 0, stack_buf, src_size);
// Copy output hash.
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < dst_size / 4; i++)
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2)));
return res;
}
void se_key_acc_ctrl(u32 ks, u32 flags) void se_key_acc_ctrl(u32 ks, u32 flags)
{ {
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG) if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
@@ -150,7 +224,7 @@ void se_key_acc_ctrl(u32 ks, u32 flags)
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks); SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
} }
void se_aes_key_set(u32 ks, void *key, u32 size) void se_aes_key_set(u32 ks, const void *key, u32 size)
{ {
u32 *data = (u32 *)key; u32 *data = (u32 *)key;
for (u32 i = 0; i < size / 4; i++) for (u32 i = 0; i < size / 4; i++)
@@ -160,6 +234,16 @@ void se_aes_key_set(u32 ks, void *key, u32 size)
} }
} }
void se_aes_key_read(u32 ks, void *key, u32 size)
{
u32 *data = (u32 *)key;
for (u32 i = 0; i < size / 4; i++)
{
SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | i;
data[i] = SE(SE_KEYTABLE_DATA0_REG_OFFSET);
}
}
void se_aes_key_clear(u32 ks) void se_aes_key_clear(u32 ks)
{ {
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++) for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
@@ -169,6 +253,15 @@ void se_aes_key_clear(u32 ks)
} }
} }
void se_aes_key_iv_clear(u32 ks)
{
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
{
SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i;
SE(SE_KEYTABLE_DATA0_REG_OFFSET) = 0;
}
}
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input) int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
{ {
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
@@ -195,24 +288,6 @@ int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src,
return _se_execute(OP_START, dst, dst_size, src, src_size); return _se_execute(OP_START, dst, dst_size, src, src_size);
} }
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
{
if (enc)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
}
else
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
}
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
return _se_execute(OP_START, dst, dst_size, src, src_size);
}
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src) int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
{ {
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10); return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
@@ -223,7 +298,8 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
SE(SE_SPARE_0_REG_OFFSET) = 1; SE(SE_SPARE_0_REG_OFFSET) = 1;
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY); SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1); SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1) |
SE_CRYPTO_VCTRAM_SEL(VCTRAM_AHB);
_se_aes_ctr_set(ctr); _se_aes_ctr_set(ctr);
u32 src_size_aligned = src_size & 0xFFFFFFF0; u32 src_size_aligned = src_size & 0xFFFFFFF0;
@@ -244,7 +320,7 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
return 1; return 1;
} }
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize) int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize)
{ {
int res = 0; int res = 0;
u8 *tweak = (u8 *)malloc(0x10); u8 *tweak = (u8 *)malloc(0x10);
@@ -269,7 +345,7 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *sr
goto out; goto out;
for (u32 j = 0; j < 0x10; j++) for (u32 j = 0; j < 0x10; j++)
pdst[j] = pdst[j] ^ tweak[j]; pdst[j] = pdst[j] ^ tweak[j];
_gf256_mul_x(tweak); _gf256_mul_x_le(tweak);
psrc += 0x10; psrc += 0x10;
pdst += 0x10; pdst += 0x10;
} }
@@ -281,7 +357,7 @@ out:;
return res; return res;
} }
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs) int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs)
{ {
u8 *pdst = (u8 *)dst; u8 *pdst = (u8 *)dst;
u8 *psrc = (u8 *)src; u8 *psrc = (u8 *)src;
@@ -293,6 +369,58 @@ int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u
return 1; return 1;
} }
// se_aes_cmac() was derived from Atmosphère's se_compute_aes_cmac
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
{
int res = 0;
u8 *key = (u8 *)calloc(0x10, 1);
u8 *last_block = (u8 *)calloc(0x10, 1);
// generate derived key
if (!se_aes_crypt_block_ecb(ks, 1, key, key))
goto out;
_gf256_mul_x(key);
if (src_size & 0xF)
_gf256_mul_x(key);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) |
SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
se_aes_key_iv_clear(ks);
u32 num_blocks = (src_size + 0xf) >> 4;
if (num_blocks > 1) {
SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2;
if (!_se_execute(OP_START, NULL, 0, src, src_size))
goto out;
SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
}
if (src_size & 0xf) {
memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf);
last_block[src_size & 0xf] = 0x80;
} else if (src_size >= 0x10) {
memcpy(last_block, src + src_size - 0x10, 0x10);
}
for (u32 i = 0; i < 0x10; i++)
last_block[i] ^= key[i];
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
res = _se_execute(OP_START, NULL, 0, last_block, 0x10);
u32 *dst32 = (u32 *)dst;
for (u32 i = 0; i < (dst_size >> 2); i++)
dst32[i] = SE(SE_HASH_RESULT_REG_OFFSET + (i << 2));
out:;
free(key);
free(last_block);
return res;
}
// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256.
int se_calc_sha256(void *dst, const void *src, u32 src_size) int se_calc_sha256(void *dst, const void *src, u32 src_size)
{ {
int res; int res;
@@ -319,76 +447,45 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
return res; return res;
} }
int se_gen_prng128(void *dst) int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size) {
{ int res = 0;
// Setup config for X931 PRNG. u8 *secret = (u8 *)malloc(0x40);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY); u8 *ipad = (u8 *)malloc(0x40 + src_size);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM); u8 *opad = (u8 *)malloc(0x60);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL); if (key_size > 0x40)
//SE(SE_RNG_SRC_CONFIG_REG_OFFSET) =
// SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE);
SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 1;
SE(SE_BLOCK_COUNT_REG_OFFSET) = (16 >> 4) - 1;
// Trigger the operation.
return _se_execute(OP_START, dst, 16, NULL, 0);
}
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
{
u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);
// Set Secure Random Key.
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED);
SE(SE_CRYPTO_LAST_BLOCK) = 0;
_se_execute(OP_START, NULL, 0, NULL, 0);
// Save AES keys.
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++)
{ {
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) | if (!se_calc_sha256(secret, key, key_size))
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3); goto out;
memset(secret + 0x20, 0, 0x20);
SE(SE_CRYPTO_LAST_BLOCK) = 0; }
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0); else
memcpy(keys + i * keysize, aligned_buf, 0x10); {
memcpy(secret, key, key_size);
if (keysize > 0x10) memset(secret + key_size, 0, 0x40 - key_size);
{
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7);
SE(SE_CRYPTO_LAST_BLOCK) = 0;
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10);
}
} }
// Save SRK to PMC secure scratches. u32 *secret32 = (u32 *)secret;
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK); u32 *ipad32 = (u32 *)ipad;
SE(0x80) = 0; // SE_CRYPTO_LAST_BLOCK u32 *opad32 = (u32 *)opad;
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0); for (u32 i = 0; i < 0x10; i++)
{
ipad32[i] = secret32[i] ^ 0x36363636;
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
}
// End context save. memcpy(ipad + 0x40, src, src_size);
SE(SE_CONFIG_REG_OFFSET) = 0; if (!se_calc_sha256(dst, ipad, 0x40 + src_size))
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0); goto out;
memcpy(opad + 0x40, dst, 0x20);
if (!se_calc_sha256(dst, opad, 0x60))
goto out;
// Get SRK. res = 1;
u32 srk[4];
srk[0] = PMC(0xC0);
srk[1] = PMC(0xC4);
srk[2] = PMC(0x224);
srk[3] = PMC(0x228);
// Decrypt context. out:;
se_aes_key_clear(3); free(secret);
se_aes_key_set(3, srk, 0x10); free(ipad);
se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize); free(opad);
se_aes_key_clear(3); return res;
} }

View File

@@ -20,15 +20,21 @@
#include "../utils/types.h" #include "../utils/types.h"
void se_rsa_acc_ctrl(u32 rs, u32 flags); void se_rsa_acc_ctrl(u32 rs, u32 flags);
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size);
void se_rsa_key_clear(u32 ks);
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
void se_key_acc_ctrl(u32 ks, u32 flags); void se_key_acc_ctrl(u32 ks, u32 flags);
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize); void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_key_set(u32 ks, void *key, u32 size); void se_aes_key_read(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks); void se_aes_key_clear(u32 ks);
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input); int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size); int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src); int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr); int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize);
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs);
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
int se_calc_sha256(void *dst, const void *src, u32 src_size); int se_calc_sha256(void *dst, const void *src, u32 src_size);
int se_gen_prng128(void *dst); int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
#endif #endif

View File

@@ -29,7 +29,6 @@
#include "../mem/heap.h" #include "../mem/heap.h"
#include "../mem/mc.h" #include "../mem/mc.h"
#include "../utils/util.h" #include "../utils/util.h"
#include "../hos/hos.h"
// #include "../gfx/gfx.h" // #include "../gfx/gfx.h"

View File

@@ -2,74 +2,74 @@
#include "types.h" #include "types.h"
menu_entry mainmenu_main[] = { menu_entry mainmenu_main[] = {
{"[SD:/] SD CARD", COLOR_GREEN, ISMENU}, {"[SD:/] SD CARD", COLOR_GREEN, {ISMENU}},
{"[EMMC:/] EMMC", COLOR_ORANGE, ISMENU}, {"[EMMC:/] EMMC", COLOR_ORANGE, {ISMENU}},
{"[EMMC:/] EMUMMC", COLOR_BLUE, ISMENU}, {"[EMMC:/] EMUMMC", COLOR_BLUE, {ISMENU}},
{"\nMount/Unmount SD", COLOR_WHITE, ISMENU}, {"\nMount/Unmount SD", COLOR_WHITE, {ISMENU}},
{"Tools", COLOR_VIOLET, ISMENU}, {"Tools", COLOR_VIOLET, {ISMENU}},
{"SD format", COLOR_VIOLET, ISMENU}, {"SD format", COLOR_VIOLET, {ISMENU}},
{"\nCredits", COLOR_WHITE, ISMENU}, {"\nCredits", COLOR_WHITE, {ISMENU}},
{"Exit", COLOR_WHITE, ISMENU} {"Exit", COLOR_WHITE, {ISMENU}}
}; };
menu_entry mainmenu_shutdown[] = { menu_entry mainmenu_shutdown[] = {
{"Back", COLOR_WHITE, ISMENU}, {"Back", COLOR_WHITE, {ISMENU}},
{"\nReboot to RCM", COLOR_VIOLET, ISMENU}, {"\nReboot to RCM", COLOR_VIOLET, {ISMENU}},
{"Reboot normally", COLOR_ORANGE, ISMENU}, {"Reboot normally", COLOR_ORANGE, {ISMENU}},
{"Power off\n", COLOR_BLUE, ISMENU}, {"Power off\n", COLOR_BLUE, {ISMENU}},
{"Reboot to Hekate", COLOR_GREEN, ISMENU}, {"Reboot to Hekate", COLOR_GREEN, {ISMENU}},
{"Reboot to Atmosphere", COLOR_GREEN, ISMENU} {"Reboot to Atmosphere", COLOR_GREEN, {ISMENU}}
}; };
menu_entry mainmenu_tools[] = { menu_entry mainmenu_tools[] = {
{"Back", COLOR_WHITE, ISMENU}, {"Back", COLOR_WHITE, {ISMENU}},
{"\nDisplay Console Info", COLOR_GREEN, ISMENU}, {"\nDisplay Console Info", COLOR_GREEN, {ISMENU}},
{"Display GPIO pins", COLOR_VIOLET, ISMENU}, {"Display GPIO pins", COLOR_VIOLET, {ISMENU}},
{"Dump Firmware", COLOR_BLUE, ISMENU}, {"Dump Firmware", COLOR_BLUE, {ISMENU}},
{"Dump User Saves", COLOR_YELLOW, ISMENU} {"Dump User Saves", COLOR_YELLOW, {ISMENU}}
}; };
menu_entry mainmenu_format[] = { menu_entry mainmenu_format[] = {
{"Back\n", COLOR_WHITE, ISMENU}, {"Back\n", COLOR_WHITE, {ISMENU}},
{"Format entire SD to FAT32", COLOR_RED, ISMENU}, {"Format entire SD to FAT32", COLOR_RED, {ISMENU}},
{"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, ISMENU} {"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, {ISMENU}}
}; };
menu_entry utils_mmcChoice[] = { menu_entry utils_mmcChoice[] = {
{"Back\n", COLOR_WHITE, ISMENU}, {"Back\n", COLOR_WHITE, {ISMENU}},
{"SysMMC", COLOR_ORANGE, ISMENU}, {"SysMMC", COLOR_ORANGE, {ISMENU}},
{"EmuMMC", COLOR_BLUE, ISMENU} {"EmuMMC", COLOR_BLUE, {ISMENU}}
}; };
menu_entry fs_menu_file[] = { menu_entry fs_menu_file[] = {
{NULL, COLOR_GREEN, ISMENU | ISSKIP}, {NULL, COLOR_GREEN, {ISMENU | ISSKIP}},
{NULL, COLOR_VIOLET, ISMENU | ISSKIP}, {NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
{NULL, COLOR_VIOLET, ISMENU | ISSKIP}, {NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
{"\n\n\nBack", COLOR_WHITE, ISMENU}, {"\n\n\nBack", COLOR_WHITE, {ISMENU}},
{"\nCopy to clipboard", COLOR_BLUE, ISMENU}, {"\nCopy to clipboard", COLOR_BLUE, {ISMENU}},
{"Move to clipboard", COLOR_BLUE, ISMENU}, {"Move to clipboard", COLOR_BLUE, {ISMENU}},
{"Rename file", COLOR_BLUE, ISMENU}, {"Rename file", COLOR_BLUE, {ISMENU}},
{"\nDelete file\n", COLOR_RED, ISMENU}, {"\nDelete file\n", COLOR_RED, {ISMENU}},
{"Launch Payload", COLOR_ORANGE, ISMENU}, {"Launch Payload", COLOR_ORANGE, {ISMENU}},
{"Launch Script", COLOR_YELLOW, ISMENU}, {"Launch Script", COLOR_YELLOW, {ISMENU}},
{"View Hex", COLOR_GREEN, ISMENU}, {"View Hex", COLOR_GREEN, {ISMENU}},
{"\nExtract BIS", COLOR_YELLOW, ISMENU} {"\nExtract BIS", COLOR_YELLOW, {ISMENU}}
}; };
menu_entry fs_menu_folder[] = { menu_entry fs_menu_folder[] = {
{NULL, COLOR_VIOLET, ISMENU | ISSKIP}, {NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
{"\nBack", COLOR_WHITE, ISMENU}, {"\nBack", COLOR_WHITE, {ISMENU}},
{"Return to main menu\n", COLOR_BLUE, ISMENU}, {"Return to main menu\n", COLOR_BLUE, {ISMENU}},
{"Copy to clipboard", COLOR_VIOLET, ISMENU}, {"Copy to clipboard", COLOR_VIOLET, {ISMENU}},
{"Delete folder\n", COLOR_RED, ISMENU}, {"Delete folder\n", COLOR_RED, {ISMENU}},
{"Rename folder", COLOR_BLUE, ISMENU}, {"Rename folder", COLOR_BLUE, {ISMENU}},
{"Create folder", COLOR_BLUE, ISMENU} {"Create folder", COLOR_BLUE, {ISMENU}}
}; };
menu_entry fs_menu_startdir[] = { menu_entry fs_menu_startdir[] = {
{"Folder -> previous folder ", COLOR_ORANGE, ISMENU}, {"Folder -> previous folder ", COLOR_ORANGE, {ISMENU}},
{"Clipboard -> Current folder", COLOR_ORANGE, ISMENU}, {"Clipboard -> Current folder", COLOR_ORANGE, {ISMENU}},
{"Current folder menu ", COLOR_ORANGE, ISMENU} {"Current folder menu ", COLOR_ORANGE, {ISMENU}}
}; };
gpt_entry_rule gpt_fs_rules[] = { gpt_entry_rule gpt_fs_rules[] = {
@@ -81,15 +81,15 @@ gpt_entry_rule gpt_fs_rules[] = {
}; };
menu_entry mmcmenu_start[] = { menu_entry mmcmenu_start[] = {
{"Back", COLOR_ORANGE, ISMENU}, {"Back", COLOR_ORANGE, {ISMENU}},
{"Dump File Partitions", COLOR_ORANGE, ISMENU}, {"Dump File Partitions", COLOR_ORANGE, {ISMENU}},
{"Clipboard -> Partition\n", COLOR_ORANGE, ISMENU}, {"Clipboard -> Partition\n", COLOR_ORANGE, {ISMENU}},
{"BOOT0/1", COLOR_BLUE, isBOOT | ISMENU} {"BOOT0/1", COLOR_BLUE, {ISNULL | ISMENU}}
}; };
menu_entry mmcmenu_filemenu[] = { menu_entry mmcmenu_filemenu[] = {
{"Part:", COLOR_ORANGE, ISSKIP | ISMENU}, {"Part:", COLOR_ORANGE, {ISSKIP | ISMENU}},
{NULL, COLOR_VIOLET, ISSKIP | ISMENU}, {NULL, COLOR_VIOLET, {ISSKIP | ISMENU}},
{"\nBack", COLOR_WHITE, ISMENU}, {"\nBack", COLOR_WHITE, {ISMENU}},
{"Dump to SD", COLOR_YELLOW, ISMENU} {"Dump to SD", COLOR_YELLOW, {ISMENU}}
}; };

View File

@@ -1,18 +1,14 @@
#pragma once #pragma once
#include "../../utils/types.h" #include "../../utils/types.h"
#define ISDIR (1 << 0) #define BIT(n) (1U << n)
#define ISARC (1 << 1)
#define ISHIDE (1 << 8) #define ISDIR BIT(0)
#define ISMENU (1 << 9) #define ISMENU BIT(1)
#define ISSKIP (1 << 10) #define SETSIZE(x) (x << 2)
#define ISNULL BIT(4)
#define ISGB (1 << 7) #define ISHIDE BIT(5)
#define ISMB (1 << 6) #define ISSKIP BIT(6)
#define ISKB (1 << 5)
#define ISB (1 << 4)
#define ISNULL (1 << 3)
#define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift)) #define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift))
@@ -27,7 +23,7 @@
#define COPY_MODE_PRINT 0x1 #define COPY_MODE_PRINT 0x1
#define COPY_MODE_CANCEL 0x2 #define COPY_MODE_CANCEL 0x2
#define BUFSIZE 32768 #define BUFSIZE 65536 //32768
#define OPERATIONCOPY 0x2 #define OPERATIONCOPY 0x2
#define OPERATIONMOVE 0x4 #define OPERATIONMOVE 0x4
@@ -43,7 +39,17 @@
typedef struct { typedef struct {
char *name; char *name;
u32 storage; u32 storage;
u16 property; union {
u8 property;
struct {
u8 isDir:1;
u8 isMenu:1;
u8 size:2;
u8 isNull:1;
u8 isHide:1;
u8 isSkip:1;
};
};
} menu_entry; } menu_entry;
typedef struct { typedef struct {

View File

@@ -218,6 +218,7 @@ int dump_biskeys(){
//sdmmc_storage_set_mmc_partition(&storage, 0); //sdmmc_storage_set_mmc_partition(&storage, 0);
//nx_emmc_gpt_parse(&sys_gpt, &storage); //nx_emmc_gpt_parse(&sys_gpt, &storage);
se_aes_key_set(8, bis_key[2] + 0x00, 0x10); se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
se_aes_key_set(9, bis_key[2] + 0x10, 0x10); se_aes_key_set(9, bis_key[2] + 0x10, 0x10);

View File

@@ -45,7 +45,7 @@ int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
f_lseek(&fp, 0); f_lseek(&fp, 0);
while (totalSectors > 0){ while (totalSectors > 0){
num = MIN(totalSectors, 64); num = MIN(totalSectors, 128);
if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){ if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){
gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3); gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3);
return -1; return -1;

View File

@@ -16,12 +16,12 @@
#include "../../utils/list.h" #include "../../utils/list.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "emmcmenu.h" #include "emmcmenu.h"
#include "../fs/fsreader.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../gfx/menu.h" #include "../gfx/menu.h"
#include "../fs/fsmenu.h" #include "../fs/fsmenu.h"
#include "emmcoperations.h" #include "emmcoperations.h"
#include "../fs/fsutils.h" #include "../fs/fsutils.h"
#include "../utils/menuUtils.h"
menu_entry *mmcMenuEntries = NULL; menu_entry *mmcMenuEntries = NULL;
extern sdmmc_storage_t storage; extern sdmmc_storage_t storage;
@@ -30,21 +30,18 @@ extern char *clipboard;
extern u8 clipboardhelper; extern u8 clipboardhelper;
void addEntry(emmc_part_t *part, u8 property, int spot){ void addEntry(emmc_part_t *part, u8 property_GPT, int spot){
if (mmcMenuEntries[spot].name != NULL){ u32 storage = 0;
free(mmcMenuEntries[spot].name); u8 property = 0;
}
utils_copystring(part->name, &mmcMenuEntries[spot].name); if (property_GPT & isFS){
storage = (u32)(property_GPT & 0x7F);
if (property & isFS){ property = ISDIR;
mmcMenuEntries[spot].storage = (u32)(property & 0x7F);
mmcMenuEntries[spot].property = ISDIR;
} }
else { else {
u64 size = 0; u64 size = 0;
int sizes = 0; u32 sizes = 0;
mmcMenuEntries[spot].property = 0;
size = (u64)(part->lba_end + 1 - part->lba_start); size = (u64)(part->lba_end + 1 - part->lba_start);
size *= (u64)NX_EMMC_BLOCKSIZE; size *= (u64)NX_EMMC_BLOCKSIZE;
@@ -54,31 +51,30 @@ void addEntry(emmc_part_t *part, u8 property, int spot){
} }
if (sizes > 3) if (sizes > 3)
sizes = 0; sizes = 3;
mmcMenuEntries[spot].property |= (1 << (4 + sizes)); property |= SETSIZE(sizes);
mmcMenuEntries[spot].storage = (u32)size; storage = (u32)size;
} }
mu_copySingle(part->name, storage, property, &mmcMenuEntries[spot]);
} }
int fillMmcMenu(short mmcType){ int fillMmcMenu(short mmcType){
int count = 4, i; int count = 4, i;
if (mmcMenuEntries != NULL) if (mmcMenuEntries != NULL)
clearfileobjects(&mmcMenuEntries); mu_clearObjects(&mmcMenuEntries);
link_t *gpt = selectGpt(mmcType); link_t *gpt = selectGpt(mmcType);
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link) LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
count++; count++;
createfileobjects(count, &mmcMenuEntries); mu_createObjects(count, &mmcMenuEntries);
for (i = 0; i < 4; i++){ for (i = 0; i < 4; i++)
utils_copystring(mmcmenu_start[i].name, &mmcMenuEntries[i].name); mu_copySingle(mmcmenu_start[i].name, mmcmenu_start[i].storage, mmcmenu_start[i].property, &mmcMenuEntries[i]);
mmcMenuEntries[i].property = mmcmenu_start[i].property;
mmcMenuEntries[i].storage = mmcmenu_start[i].storage;
}
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){ LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){
addEntry(part, checkGptRules(part->name), i++); addEntry(part, checkGptRules(part->name), i++);
@@ -99,10 +95,14 @@ int handleEntries(short mmcType, menu_entry part){
fileexplorer("emmc:/", 1); fileexplorer("emmc:/", 1);
} }
else { else {
/*
if (mmcmenu_filemenu[1].name != NULL) if (mmcmenu_filemenu[1].name != NULL)
free(mmcmenu_filemenu[1].name); free(mmcmenu_filemenu[1].name);
utils_copystring(part.name, &mmcmenu_filemenu[1].name); utils_copystring(part.name, &mmcmenu_filemenu[1].name);
*/
mu_copySingle(part.name, mmcmenu_filemenu[1].storage, mmcmenu_filemenu[1].property, &mmcmenu_filemenu[1]);
if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3) if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3)
return 0; return 0;
@@ -112,7 +112,7 @@ int handleEntries(short mmcType, menu_entry part){
gfx_clearscreen(); gfx_clearscreen();
if (part.property & isBOOT){ if (part.isNull){
res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps"); res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps");
} }
else { else {
@@ -146,7 +146,7 @@ int makeMmcMenu(short mmcType){
f_mkdir("sd:/tegraexplorer/partition_dumps"); f_mkdir("sd:/tegraexplorer/partition_dumps");
for (int i = 0; i < count; i++){ for (int i = 0; i < count; i++){
if (mmcMenuEntries[i].property & ISMENU || mmcMenuEntries[i].property & ISDIR) if (mmcMenuEntries[i].property & (ISMENU | ISDIR))
continue; continue;
//gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name); //gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name);

View File

@@ -32,7 +32,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
gfx_printf("Initializing\r"); gfx_printf("Initializing\r");
buf = calloc(16384, sizeof(u8)); buf = calloc(BUFSIZE, sizeof(u8));
if (!buf){ if (!buf){
gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1); gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1);
@@ -78,7 +78,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
} }
while (totalSectors > 0){ while (totalSectors > 0){
num = MIN(totalSectors, 32); num = MIN(totalSectors, 128);
if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){ if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
gfx_errDisplay("restore_emmc_part", res, 5); gfx_errDisplay("restore_emmc_part", res, 5);

View File

@@ -15,6 +15,7 @@
#include "../script/parser.h" #include "../script/parser.h"
#include "../emmc/emmcoperations.h" #include "../emmc/emmcoperations.h"
#include "../../hid/hid.h" #include "../../hid/hid.h"
#include "../utils/menuUtils.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -120,38 +121,42 @@ void copyfile(const char *src_in, const char *outfolder){
int filemenu(menu_entry file){ int filemenu(menu_entry file){
int temp; int temp;
FILINFO attribs; char *tempchar;
for (int i = 0; i < 3; i++) /*
for (int i = 0; i < 2; i++)
if (fs_menu_file[i].name != NULL) if (fs_menu_file[i].name != NULL)
free(fs_menu_file[i].name); free(fs_menu_file[i].name);
utils_copystring(file.name, &fs_menu_file[0].name); utils_copystring(file.name, &fs_menu_file[0].name);
*/
mu_copySingle(file.name, fs_menu_file[0].storage, fs_menu_file[0].property, &fs_menu_file[0]);
if (fs_menu_file[1].name != NULL)
free(fs_menu_file[1].name);
fs_menu_file[1].name = malloc(16); fs_menu_file[1].name = malloc(16);
fs_menu_file[2].name = malloc(16); sprintf(fs_menu_file[1].name, "\nSize: %d %s", file.storage, gfx_file_size_names[file.size]);
for (temp = 4; temp < 8; temp++) if ((tempchar = fsutil_formatFileAttribs(fsutil_getnextloc(currentpath, file.name))) == NULL)
if ((file.property & (1 << temp))) fs_menu_file[2].isHide = 1;
break;
sprintf(fs_menu_file[1].name, "\nSize: %d %s", file.storage, gfx_file_size_names[temp - 4]);
if (f_stat(fsutil_getnextloc(currentpath, file.name), &attribs))
SETBIT(fs_menu_file[2].property, ISHIDE, 1);
else { else {
SETBIT(fs_menu_file[2].property, ISHIDE, 0); fs_menu_file[2].isHide = 0;
sprintf(fs_menu_file[2].name, "Attribs: %c%c%c%c", mu_copySingle(tempchar, fs_menu_file[2].storage, fs_menu_file[2].property, &fs_menu_file[2]);
(attribs.fattrib & AM_RDO) ? 'R' : '-',
(attribs.fattrib & AM_SYS) ? 'S' : '-',
(attribs.fattrib & AM_HID) ? 'H' : '-',
(attribs.fattrib & AM_ARC) ? 'A' : '-');
} }
fs_menu_file[6].isHide = !hidConnected();
fs_menu_file[8].isHide = (!(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL);
fs_menu_file[9].isHide = (strstr(file.name, ".te") == NULL);
fs_menu_file[11].isHide = (strstr(file.name, ".bis") == NULL);
/*
SETBIT(fs_menu_file[6].property, ISHIDE, !hidConnected()); SETBIT(fs_menu_file[6].property, ISHIDE, !hidConnected());
SETBIT(fs_menu_file[8].property, ISHIDE, !(strstr(file.name, ".bin") != NULL && file.property & ISKB) && strstr(file.name, ".rom") == NULL); SETBIT(fs_menu_file[8].property, ISHIDE, !(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL);
SETBIT(fs_menu_file[9].property, ISHIDE, strstr(file.name, ".te") == NULL); SETBIT(fs_menu_file[9].property, ISHIDE, strstr(file.name, ".te") == NULL);
SETBIT(fs_menu_file[11].property, ISHIDE, strstr(file.name, ".bis") == NULL); SETBIT(fs_menu_file[11].property, ISHIDE, strstr(file.name, ".bis") == NULL);
*/
temp = menu_make(fs_menu_file, 12, "-- File Menu --"); temp = menu_make(fs_menu_file, 12, "-- File Menu --");
switch (temp){ switch (temp){

View File

@@ -11,6 +11,7 @@
#include "../../utils/sprintf.h" #include "../../utils/sprintf.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../../hid/hid.h" #include "../../hid/hid.h"
#include "../utils/menuUtils.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -42,16 +43,18 @@ void copyfolder(char *in, char *out){
int foldermenu(){ int foldermenu(){
int res, hidConn; int res, hidConn;
char *name; char *name;
FILINFO attribs;
if (fs_menu_folder[0].name != NULL)
free(fs_menu_folder[0].name);
fs_menu_folder[0].name = malloc(16);
hidConn = hidConnected(); hidConn = hidConnected();
res = strlen(currentpath); res = strlen(currentpath);
fs_menu_folder[3].isHide = (*(currentpath + res - 1) == '/');
fs_menu_folder[4].isHide = (*(currentpath + res - 1) == '/');
fs_menu_folder[5].isHide = (*(currentpath + res - 1) == '/' || !hidConn);
fs_menu_folder[6].isHide = !hidConn;
/*
SETBIT(fs_menu_folder[3].property, ISHIDE, (*(currentpath + res - 1) == '/')); SETBIT(fs_menu_folder[3].property, ISHIDE, (*(currentpath + res - 1) == '/'));
SETBIT(fs_menu_folder[4].property, ISHIDE, (*(currentpath + res - 1) == '/')); SETBIT(fs_menu_folder[4].property, ISHIDE, (*(currentpath + res - 1) == '/'));
SETBIT(fs_menu_folder[5].property, ISHIDE, (*(currentpath + res - 1) == '/') || !hidConn); SETBIT(fs_menu_folder[5].property, ISHIDE, (*(currentpath + res - 1) == '/') || !hidConn);
@@ -67,6 +70,17 @@ int foldermenu(){
(attribs.fattrib & AM_HID) ? 'H' : '-', (attribs.fattrib & AM_HID) ? 'H' : '-',
(attribs.fattrib & AM_ARC) ? 'A' : '-'); (attribs.fattrib & AM_ARC) ? 'A' : '-');
} }
*/
if ((name = fsutil_formatFileAttribs(currentpath)) == NULL){
fs_menu_folder[0].isHide = 1;
}
else {
fs_menu_folder[0].isHide = 0;
mu_copySingle(name, fs_menu_folder[0].storage, fs_menu_folder[0].property, &fs_menu_folder[0]);
}
res = menu_make(fs_menu_folder, 7, currentpath); res = menu_make(fs_menu_folder, 7, currentpath);

View File

@@ -8,15 +8,16 @@
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../../hid/hid.h" #include "../../hid/hid.h"
#include "../../utils/btn.h"
#include "fsutils.h" #include "fsutils.h"
int fsact_copy(const char *locin, const char *locout, u8 options){ int fsact_copy(const char *locin, const char *locout, u8 options){
FIL in, out; FIL in, out;
FILINFO in_info; FILINFO in_info;
u64 sizeoffile, sizecopied = 0, totalsize; u64 sizeRemaining, toCopy;
UINT temp1, temp2; UINT temp1, temp2;
u8 *buff; u8 *buff, toPrint = options & COPY_MODE_PRINT, toCancel = options & COPY_MODE_CANCEL;
unsigned int x, y, i = 0; u32 x, y, i = 11;
int res; int res;
gfx_con_getpos(&x, &y); gfx_con_getpos(&x, &y);
@@ -41,17 +42,26 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
return 1; return 1;
} }
buff = malloc (BUFSIZE); if (toPrint){
sizeoffile = f_size(&in); SWAPCOLOR(COLOR_GREEN);
totalsize = sizeoffile; gfx_printf("[ ]");
x += 16;
gfx_con_setpos(x, y);
}
while (sizeoffile > 0){ buff = malloc (BUFSIZE);
if ((res = f_read(&in, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp1))){ sizeRemaining = f_size(&in);
const u64 totalsize = sizeRemaining;
while (sizeRemaining > 0){
toCopy = MIN(sizeRemaining, BUFSIZE);
if ((res = f_read(&in, buff, toCopy, &temp1))){
gfx_errDisplay("copy", res, 5); gfx_errDisplay("copy", res, 5);
return 1; return 1;
} }
if ((res = f_write(&out, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp2))){ if ((res = f_write(&out, buff, toCopy, &temp2))){
gfx_errDisplay("copy", res, 6); gfx_errDisplay("copy", res, 6);
return 1; return 1;
} }
@@ -61,23 +71,28 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
return 1; return 1;
} }
sizeoffile -= temp1; sizeRemaining -= toCopy;
sizecopied += temp1;
if (options & COPY_MODE_PRINT && 10 > i++){ if (toPrint && (i > 16 || !sizeRemaining)){
gfx_printf("%k[%d%%]%k", COLOR_GREEN, ((sizecopied * 100) / totalsize) ,COLOR_WHITE); gfx_printf("%3d%%", (u32)(((totalsize - sizeRemaining) * 100) / totalsize));
gfx_con_setpos(x, y); gfx_con_setpos(x, y);
}
i = 0; if (toCancel && i > 16){
if (btn_read() & (BTN_VOL_DOWN | BTN_VOL_UP)){
f_unlink(locout);
break;
}
}
if (options & COPY_MODE_CANCEL) if (options){
if (hidRead()->buttons & (KEY_VOLP | KEY_VOLM)){ if (i++ > 16)
f_unlink(locout); i = 0;
break;
}
} }
} }
RESETCOLOR;
f_close(&in); f_close(&in);
f_close(&out); f_close(&out);
free(buff); free(buff);

View File

@@ -7,6 +7,7 @@
#include "../common/common.h" #include "../common/common.h"
#include "../../libs/fatfs/ff.h" #include "../../libs/fatfs/ff.h"
#include "entrymenu.h" #include "entrymenu.h"
#include "../utils/menuUtils.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -35,7 +36,7 @@ void fileexplorer(const char *startpath, int type){
*/ */
while (1){ while (1){
res = menu_make(fsreader_files, fsutil_getfileobjamount(fsreader_files), currentpath); res = menu_make(fsreader_files, mu_countObjects(fsreader_files, 0, 0), currentpath);
switch (res){ switch (res){
case FILEMENU_RETURN: case FILEMENU_RETURN:
if (!strcmp(startpath, currentpath)) if (!strcmp(startpath, currentpath))

View File

@@ -7,6 +7,7 @@
#include "../gfx/gfxutils.h" #include "../gfx/gfxutils.h"
#include "../utils/utils.h" #include "../utils/utils.h"
#include "../../mem/heap.h" #include "../../mem/heap.h"
#include "../utils/menuUtils.h"
menu_entry *fsreader_files = NULL; menu_entry *fsreader_files = NULL;
char *currentpath = NULL; char *currentpath = NULL;
@@ -29,59 +30,16 @@ void fsreader_writeclipboard(const char *in, u8 args){
utils_copystring(in, &clipboard); utils_copystring(in, &clipboard);
} }
void clearfileobjects(menu_entry **menu){
if ((*menu) != NULL){
for (int i = 0; (*menu)[i].name != NULL; i++){
free((*menu)[i].name);
(*menu)[i].name = NULL;
}
free((*menu));
(*menu) = NULL;
}
}
void createfileobjects(int size, menu_entry **menu){
(*menu) = calloc (size + 1, sizeof(menu_entry));
(*menu)[size].name = NULL;
}
void addobject(char* name, int spot, u8 attribs){ void addobject(char* name, int spot, u8 attribs){
/* u8 property = 0;
u64 size = 0;
int sizes = 0;
*/
fsreader_files[spot].property = 0;
if (fsreader_files[spot].name != NULL){
free(fsreader_files[spot].name);
fsreader_files[spot].name = NULL;
}
utils_copystring(name, &(fsreader_files[spot].name));
if (attribs & AM_DIR) if (attribs & AM_DIR)
fsreader_files[spot].property |= (ISDIR); property |= ISDIR;
else { else
/* property |= ISNULL;
size = fsutil_getfilesize(fsutil_getnextloc(currentpath, name));
while (size > 1024){ mu_copySingle(name, 0, property, &fsreader_files[spot]);
size /= 1024;
sizes++;
}
if (sizes > 3)
sizes = 0;
fsreader_files[spot].property |= (1 << (4 + sizes));
fsreader_files[spot].storage = size;
*/
fsreader_files[spot].storage = 0;
fsreader_files[spot].property = ISNULL;
}
if (attribs & AM_ARC)
fsreader_files[spot].property |= (ISARC);
} }
int fsreader_readfolder(const char *path){ int fsreader_readfolder(const char *path){
@@ -89,14 +47,13 @@ int fsreader_readfolder(const char *path){
FILINFO fno; FILINFO fno;
int folderamount, res; int folderamount, res;
clearfileobjects(&fsreader_files); mu_clearObjects(&fsreader_files);
createfileobjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files); mu_createObjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files);
for (folderamount = 0; folderamount < 3; folderamount++){
utils_copystring(fs_menu_startdir[folderamount].name, &(fsreader_files[folderamount].name));
fsreader_files[folderamount].storage = fs_menu_startdir[folderamount].storage; for (folderamount = 0; folderamount < 3; folderamount++)
fsreader_files[folderamount].property = fs_menu_startdir[folderamount].property; mu_copySingle(fs_menu_startdir[folderamount].name, fs_menu_startdir[folderamount].storage, fs_menu_startdir[folderamount].property, &fsreader_files[folderamount]);
}
if ((res = f_opendir(&dir, path))){ if ((res = f_opendir(&dir, path))){
gfx_errDisplay("readfolder", res, 0); gfx_errDisplay("readfolder", res, 0);

View File

@@ -47,15 +47,6 @@ char *fsutil_getprevloc(char *current){
return ret; return ret;
} }
int fsutil_getfileobjamount(menu_entry *entries){
int amount = 0;
while (entries[amount].name != NULL)
amount++;
return amount;
}
bool fsutil_checkfile(char* path){ bool fsutil_checkfile(char* path){
FRESULT fr; FRESULT fr;
FILINFO fno; FILINFO fno;
@@ -88,3 +79,20 @@ int fsutil_getfolderentryamount(const char *path){
f_closedir(&dir); f_closedir(&dir);
return folderamount; return folderamount;
} }
char *fsutil_formatFileAttribs(char *path){
FILINFO attribs;
char *out;
out = malloc(16);
if (f_stat(path, &attribs))
return NULL;
sprintf(out, "Attribs: %c%c%c%c",
(attribs.fattrib & AM_RDO) ? 'R' : '-',
(attribs.fattrib & AM_SYS) ? 'S' : '-',
(attribs.fattrib & AM_HID) ? 'H' : '-',
(attribs.fattrib & AM_ARC) ? 'A' : '-');
return out;
}

View File

@@ -4,8 +4,8 @@
char *fsutil_getnextloc(const char *current, const char *add); char *fsutil_getnextloc(const char *current, const char *add);
char *fsutil_getprevloc(char *current); char *fsutil_getprevloc(char *current);
int fsutil_getfileobjamount(menu_entry *entries);
bool fsutil_checkfile(char* path); bool fsutil_checkfile(char* path);
u64 fsutil_getfilesize(char *path); u64 fsutil_getfilesize(char *path);
int fsutil_getfolderentryamount(const char *path); int fsutil_getfolderentryamount(const char *path);
int extract_bis_file(char *path, char *outfolder); int extract_bis_file(char *path, char *outfolder);
char *fsutil_formatFileAttribs(char *path);

View File

@@ -23,7 +23,7 @@ void gfx_clearscreen(){
gfx_boxGrey(0, 703, 1279, 719, 0xFF); gfx_boxGrey(0, 703, 1279, 719, 0xFF);
gfx_boxGrey(0, 0, 1279, 15, 0xFF); gfx_boxGrey(0, 0, 1279, 15, 0xFF);
gfx_con_setpos(0, 0); gfx_con_setpos(0, 0);
gfx_printf("Tegraexplorer v2.0.0 | Battery: %3d%%\n", battery >> 8); gfx_printf("Tegraexplorer v2.0.1 | Battery: %3d%%\n", battery >> 8);
RESETCOLOR; RESETCOLOR;
} }
@@ -41,7 +41,7 @@ u32 gfx_message(u32 color, const char* message, ...){
return hidWait()->buttons; return hidWait()->buttons;
} }
u32 gfx_errDisplay(char *src_func, int err, int loc){ u32 gfx_errDisplay(const char *src_func, int err, int loc){
if (!printerrors) if (!printerrors)
return 0; return 0;
@@ -58,14 +58,14 @@ u32 gfx_errDisplay(char *src_func, int err, int loc){
if (loc) if (loc)
gfx_printf("Loc: %d\n", loc); gfx_printf("Loc: %d\n", loc);
gfx_printf("\nPress any button to return"); gfx_printf("\nPress any button to return\n");
RESETCOLOR; RESETCOLOR;
return hidWait()->buttons; return hidWait()->buttons;
} }
int gfx_makewaitmenu(char *hiddenmessage, int timer){ int gfx_makewaitmenu(const char *hiddenmessage, int timer){
u32 start = get_tmr_s(); u32 start = get_tmr_s();
Inputs *input = NULL; Inputs *input = NULL;
@@ -86,7 +86,7 @@ int gfx_makewaitmenu(char *hiddenmessage, int timer){
} }
} }
void gfx_printlength(int size, char *toprint){ void gfx_printlength(int size, const char *toprint){
char *temp; char *temp;
temp = (char*) malloc (size + 1); temp = (char*) malloc (size + 1);
@@ -102,7 +102,7 @@ void gfx_printlength(int size, char *toprint){
free(temp); free(temp);
} }
void gfx_printandclear(char *in, int length, int endX){ void gfx_printandclear(const char *in, int length, int endX){
u32 x, y; u32 x, y;
gfx_printlength(length, in); gfx_printlength(length, in);
@@ -126,12 +126,6 @@ void gfx_printandclear(char *in, int length, int endX){
*/ */
} }
void gfx_printfilesize(int size, char *type){
SWAPCOLOR(COLOR_VIOLET);
gfx_printf("\a%4d\e%s", size, type);
RESETCOLOR;
}
static u32 sideY = 0; static u32 sideY = 0;
void _gfx_sideSetYAuto(){ void _gfx_sideSetYAuto(){
u32 getX, getY; u32 getX, getY;
@@ -147,7 +141,7 @@ u32 gfx_sideGetY(){
return sideY; return sideY;
} }
void gfx_sideprintf(char* message, ...){ void gfx_sideprintf(const char* message, ...){
va_list ap; va_list ap;
va_start(ap, message); va_start(ap, message);
@@ -158,7 +152,7 @@ void gfx_sideprintf(char* message, ...){
va_end(ap); va_end(ap);
} }
void gfx_sideprintandclear(char* message, int length){ void gfx_sideprintandclear(const char* message, int length){
gfx_con_setpos(800, sideY); gfx_con_setpos(800, sideY);
gfx_printandclear(message, length, 1279); gfx_printandclear(message, length, 1279);
gfx_putc('\n'); gfx_putc('\n');
@@ -180,7 +174,7 @@ void gfx_drawScrollBar(int minView, int maxView, int count){
gfx_boxGrey(740, 16 + offsetSize, 755, 16 + barSize + offsetSize, 0x66); gfx_boxGrey(740, 16 + offsetSize, 755, 16 + barSize + offsetSize, 0x66);
} }
int gfx_defaultWaitMenu(char *message, int time){ int gfx_defaultWaitMenu(const char *message, int time){
gfx_clearscreen(); gfx_clearscreen();
SWAPCOLOR(COLOR_ORANGE); SWAPCOLOR(COLOR_ORANGE);
gfx_printf("\n%s\n\nPress B to return\n", message); gfx_printf("\n%s\n\nPress B to return\n", message);

View File

@@ -4,20 +4,20 @@
#define SWAPCOLOR(color) gfx_printf("%k", color) #define SWAPCOLOR(color) gfx_printf("%k", color)
#define SWAPBGCOLOR(color) gfx_printf("%K", color) #define SWAPBGCOLOR(color) gfx_printf("%K", color)
#define SWAPALLCOLOR(fg, bg) gfx_printf("%k%K", fg, bg)
#define RESETCOLOR gfx_printf("%k%K", COLOR_WHITE, COLOR_DEFAULT) #define RESETCOLOR gfx_printf("%k%K", COLOR_WHITE, COLOR_DEFAULT)
void gfx_clearscreen(); void gfx_clearscreen();
u32 gfx_message(u32 color, const char* message, ...); u32 gfx_message(u32 color, const char* message, ...);
u32 gfx_errDisplay(char *src_func, int err, int loc); u32 gfx_errDisplay(const char *src_func, int err, int loc);
int gfx_makewaitmenu(char *hiddenmessage, int timer); int gfx_makewaitmenu(const char *hiddenmessage, int timer);
void gfx_printlength(int size, char *toprint); void gfx_printlength(int size, const char *toprint);
void gfx_printandclear(char *in, int length, int endX); void gfx_printandclear(const char *in, int length, int endX);
void gfx_printfilesize(int size, char *type);
void gfx_sideSetY(u32 setY); void gfx_sideSetY(u32 setY);
u32 gfx_sideGetY(); u32 gfx_sideGetY();
void gfx_sideprintf(char* message, ...); void gfx_sideprintf(const char* message, ...);
void gfx_sideprintandclear(char* message, int length); void gfx_sideprintandclear(const char* message, int length);
void gfx_drawScrollBar(int minView, int maxView, int count); void gfx_drawScrollBar(int minView, int maxView, int count);
int gfx_defaultWaitMenu(char *message, int time); int gfx_defaultWaitMenu(const char *message, int time);
extern int printerrors; extern int printerrors;

View File

@@ -9,81 +9,59 @@
#include "../../soc/gpio.h" #include "../../soc/gpio.h"
#include "../../hid/hid.h" #include "../../hid/hid.h"
#include "../fs/fsutils.h" #include "../fs/fsutils.h"
#include "../utils/menuUtils.h"
extern void sd_unmount(); extern void sd_unmount();
extern bool sd_inited; extern bool sd_inited;
void _printentry(menu_entry *entry, bool highlighted, bool refresh, char *path){ #pragma GCC push_options
u64 size; #pragma GCC optimize ("O2")
u16 sizes = 0;
u32 color = (entry->property & ISMENU) ? entry->storage : ((entry->property & ISDIR) ? COLOR_WHITE : COLOR_VIOLET);
/*
if (entry.property & ISMENU)
SWAPCOLOR(entry.storage);
else if (entry.property & ISDIR)
SWAPCOLOR(COLOR_WHITE);
else {
SWAPCOLOR(COLOR_VIOLET);
}
*/
if (!(entry->property & ISMENU && entry->property & ISDIR)){ void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *path){
if (entry->property & ISNULL){ u32 color = (entry->isMenu) ? entry->storage : ((entry->isDir) ? COLOR_WHITE : COLOR_VIOLET);
size = fsutil_getfilesize(fsutil_getnextloc(path, entry->name));
while (size > 1024){ SWAPALLCOLOR((highlighted) ? COLOR_DEFAULT : color, (highlighted) ? color : COLOR_DEFAULT);
size /= 1024;
sizes++;
}
if (sizes > 3) if (!(entry->isMenu))
sizes = 0; gfx_printf("%c ", (entry->isDir) ? 30 : 31);
entry->property |= (1 << (4 + sizes));
entry->storage = size;
SETBIT(entry->property, ISNULL, 0);
}
for (sizes = 4; sizes < 8; sizes++)
if ((entry->property & (1 << sizes)))
break;
}
/*
if (highlighted){
SWAPBGCOLOR(COLOR_WHITE);
if ((entry.property & ISMENU) ? entry.storage == COLOR_WHITE : entry.property & ISDIR)
SWAPCOLOR(COLOR_DEFAULT);
}
else
SWAPBGCOLOR(COLOR_DEFAULT);
*/
SWAPCOLOR((highlighted) ? COLOR_DEFAULT : color);
SWAPBGCOLOR((highlighted) ? color : COLOR_DEFAULT);
if (!(entry->property & ISMENU))
gfx_printf("%c ", (entry->property & ISDIR) ? 30 : 31);
if (refresh) if (refresh)
gfx_printandclear(entry->name, 37, 720); gfx_printandclear(entry->name, 37, 720);
else else
gfx_printlength(37, entry->name); gfx_printlength(37, entry->name);
if (entry->property & ISDIR || entry->property & ISMENU) if (entry->property & (ISMENU | ISDIR))
gfx_printf("\n"); gfx_printf("\n");
else { else {
SWAPCOLOR(COLOR_BLUE); if (entry->isNull){
SWAPBGCOLOR(COLOR_DEFAULT); u64 totalSize;
u32 sizeType = 0;
totalSize = fsutil_getfilesize(fsutil_getnextloc(path, entry->name));
while (totalSize > 1024){
totalSize /= 1024;
sizeType++;
}
if (sizeType > 3)
sizeType = 3;
entry->size = sizeType;
entry->storage = totalSize;
SETBIT(entry->property, ISNULL, 0);
}
SWAPALLCOLOR(COLOR_BLUE, COLOR_DEFAULT);
gfx_printf("\a%4d", entry->storage); gfx_printf("\a%4d", entry->storage);
gfx_con.fntsz = 8; gfx_con.fntsz = 8;
gfx_printf("\n\e%s\n", gfx_file_size_names[sizes - 4]); gfx_printf("\n\e%s\n", gfx_file_size_names[entry->size]);
gfx_con.fntsz = 16; gfx_con.fntsz = 16;
} }
} }
bool disableB = false; bool disableB = false;
int menu_make(menu_entry *entries, int amount, char *toptext){ int menu_make(menu_entry *entries, int amount, const char *toptext){
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 39, calculatedamount = 0; int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 39, calculatedamount = 0;
u32 scrolltimer, timer, sideY; u32 scrolltimer, timer, sideY;
bool refresh = true; bool refresh = true;
@@ -92,23 +70,9 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
gfx_clearscreen(); gfx_clearscreen();
for (int i = 0; i < amount; i++) calculatedamount = mu_countObjects(entries, amount, ISMENU);
if (!(entries[i].property & ISMENU))
calculatedamount++;
gfx_con_setpos(0, 16); gfx_con_setpos(0, 16);
/*
if (calculatedamount){
SWAPCOLOR(COLOR_DEFAULT);
SWAPBGCOLOR(COLOR_WHITE);
gfx_printf("%3d entries\n", calculatedamount);
RESETCOLOR;
}
else
gfx_printf("\n");
*/
SWAPCOLOR(COLOR_GREEN); SWAPCOLOR(COLOR_GREEN);
gfx_printlength(42, toptext); gfx_printlength(42, toptext);
@@ -162,7 +126,7 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
if (refresh || currentfolder == NULL || !calculatedamount){ if (refresh || currentfolder == NULL || !calculatedamount){
for (int i = 0 + offset; i < amount && i < 40 + offset; i++) for (int i = 0 + offset; i < amount && i < 40 + offset; i++)
if (!(entries[i].property & ISHIDE)) if (!(entries[i].isHide))
_printentry(&entries[i], (i == currentpos), refresh, toptext); _printentry(&entries[i], (i == currentpos), refresh, toptext);
} }
else { else {
@@ -182,12 +146,12 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
RESETCOLOR; RESETCOLOR;
sideY = gfx_sideGetY(); sideY = gfx_sideGetY();
if (!(entries[currentpos].property & ISMENU)){ if (!(entries[currentpos].isMenu)){
gfx_sideprintf("Current selection:\n"); gfx_sideprintf("Current selection:\n");
SWAPCOLOR(COLOR_YELLOW); SWAPCOLOR(COLOR_YELLOW);
gfx_sideprintandclear(entries[currentpos].name, 28); gfx_sideprintandclear(entries[currentpos].name, 28);
RESETCOLOR; RESETCOLOR;
gfx_sideprintf("Type: %s", (entries[currentpos].property & ISDIR) ? "Dir " : "File"); gfx_sideprintf("Type: %s", (entries[currentpos].isDir) ? "Dir " : "File");
gfx_sideSetY(sideY); gfx_sideSetY(sideY);
} }
else else
@@ -257,3 +221,5 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
//return (mode) ? currentpos : entries[currentpos].property; //return (mode) ? currentpos : entries[currentpos].property;
return currentpos; return currentpos;
} }
#pragma GCC pop_options

View File

@@ -1,4 +1,4 @@
#pragma once #pragma once
#include "../common/types.h" #include "../common/types.h"
int menu_make(menu_entry *entries, int amount, char *toptext); int menu_make(menu_entry *entries, int amount, const char *toptext);

View File

@@ -131,6 +131,7 @@ void MainMenu_Exit(){
case SHUTDOWN_AMS: case SHUTDOWN_AMS:
launch_payload("/atmosphere/reboot_payload.bin"); launch_payload("/atmosphere/reboot_payload.bin");
} //todo declock bpmp } //todo declock bpmp
} }
func_void_ptr mainmenu_functions[] = { func_void_ptr mainmenu_functions[] = {
@@ -153,27 +154,31 @@ void RunMenuOption(int option){
void te_main(){ void te_main(){
int setter; int setter;
//gfx_printf("Initing controller\n");
hidInit();
//gfx_printf("Getting biskeys\n");
if (dump_biskeys() == -1){ if (dump_biskeys() == -1){
gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0); gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0);
//mainmenu_main[1].property |= ISHIDE; //mainmenu_main[1].property |= ISHIDE;
} }
//gfx_message(COLOR_ORANGE, "%d %d %d", sd_mount(), sd_mounted, sd_inited); //gfx_printf("Mounting SD\n");
sd_mount(); sd_mount();
//gfx_printf("Loading possible EMU\n");
if (emummc_load_cfg()){ if (emummc_load_cfg()){
mainmenu_main[2].property |= ISHIDE; mainmenu_main[2].property |= ISHIDE;
} }
//gfx_printf("Dumping gpt\n");
dumpGpt(); dumpGpt();
//gfx_printf("Disconnecting EMMC\n");
disconnect_mmc(); disconnect_mmc();
hidInit(); //gfx_printf("Entering main menu\n");
while (1){ while (1){
//fillmainmenu();
setter = sd_mounted; setter = sd_mounted;
if (emu_cfg.enabled){ if (emu_cfg.enabled){

View File

@@ -64,6 +64,9 @@ int parseStringInput(char *in, char **out){
} }
} }
#pragma GCC push_options
#pragma GCC optimize ("Os")
u32 currentcolor = COLOR_WHITE; u32 currentcolor = COLOR_WHITE;
int part_printf(){ int part_printf(){
SWAPCOLOR(currentcolor); SWAPCOLOR(currentcolor);
@@ -584,6 +587,8 @@ str_fnc_struct functions[] = {
{NULL, NULL, 0} {NULL, NULL, 0}
}; };
#pragma GCC pop_options
int run_function(char *func_name, int *out){ int run_function(char *func_name, int *out){
for (u32 i = 0; functions[i].key != NULL; i++){ for (u32 i = 0; functions[i].key != NULL; i++){
if (!strcmp(functions[i].key, func_name)){ if (!strcmp(functions[i].key, func_name)){

View File

@@ -64,13 +64,14 @@ u32 splitargs(char* in) {
curcount++; curcount++;
current = 0; current = 0;
} }
else if (in[i] == '@' || in[i] == '$' || in[i] == '?') { else if (in[i] == '@' || in[i] == '$') {
while (in[i] != ',' && in[i] != ' ' && in[i] != ')' && i < len) { while (strrchr(", )", in[i]) == NULL && i < len) {
argv[curcount][current++] = in[i++]; argv[curcount][current++] = in[i++];
} }
i--; i--;
} }
else if ((in[i] >= '0' && in[i] <= '9') || (in[i] >= '<' && in[i] <= '>') || in[i] == '+' || in[i] == '-' || in[i] == '*' || in[i] == '/') //else if ((in[i] >= '0' && in[i] <= '9') || (in[i] >= '<' && in[i] <= '>') || in[i] == '+' || in[i] == '-' || in[i] == '*' || in[i] == '/')
else if (strrchr("0123456789<=>+-*/", in[i]) != NULL)
argv[curcount][current++] = in[i]; argv[curcount][current++] = in[i];
else if (in[i] == '"') { else if (in[i] == '"') {
i++; i++;

View File

@@ -0,0 +1,41 @@
#include "menuUtils.h"
#include "../../utils/types.h"
#include "../common/types.h"
#include "../../mem/heap.h"
#include "utils.h"
void mu_clearObjects(menu_entry **menu){
if ((*menu) != NULL){
for (int i = 0; (*menu)[i].name != NULL; i++){
free((*menu)[i].name);
(*menu)[i].name = NULL;
}
free((*menu));
(*menu) = NULL;
}
}
void mu_createObjects(int size, menu_entry **menu){
(*menu) = calloc (size + 1, sizeof(menu_entry));
(*menu)[size].name = NULL;
}
int mu_countObjects(menu_entry *entries, u32 count, u8 propertyMask){
int amount = 0;
for (u32 i = 0; (count) ? i < count : entries[i].name != NULL; i++){
if (!(entries[i].property & propertyMask))
amount++;
}
return amount;
}
void mu_copySingle(char *name, u32 storage, u8 property, menu_entry *out){
if (out->name != NULL)
free(out->name);
utils_copystring(name, &out->name);
out->storage = storage;
out->property = property;
}

View File

@@ -0,0 +1,8 @@
#pragma once
#include "../../utils/types.h"
#include "../common/types.h"
void mu_createObjects(int size, menu_entry **menu);
void mu_clearObjects(menu_entry **menu);
int mu_countObjects(menu_entry *entries, u32 count, u8 propertyMask);
void mu_copySingle(char *name, u32 storage, u8 property, menu_entry *out);

View File

@@ -185,9 +185,9 @@ int format(int mode){
gfx_clearscreen(); gfx_clearscreen();
int res; int res;
bool fatalerror = false; bool fatalerror = false;
DWORD plist[] = {666, 61145088}; DWORD plist[] = {666, 61145088, 0, 0};
u32 timer, totalsectors, alignedsectors, extrasectors; u32 timer, totalsectors, alignedsectors, extrasectors;
BYTE work[FF_MAX_SS]; u8 *work;
DWORD clustsize = 32768; DWORD clustsize = 32768;
BYTE formatoptions = 0; BYTE formatoptions = 0;
formatoptions |= (FM_FAT32); formatoptions |= (FM_FAT32);
@@ -198,6 +198,15 @@ int format(int mode){
timer = get_tmr_s(); timer = get_tmr_s();
totalsectors = sd_storage.csd.capacity; totalsectors = sd_storage.csd.capacity;
gfx_printf("Initializing...\n");
work = calloc(BUFSIZE, sizeof(BYTE));
if (work == NULL){
gfx_errDisplay("format", ERR_MEM_ALLOC_FAILED, 0);
return 0;
}
if (mode == FORMAT_EMUMMC){ if (mode == FORMAT_EMUMMC){
if (totalsectors < 83886080){ if (totalsectors < 83886080){
gfx_printf("%kYou seem to be running this on a <=32GB SD\nNot enough free space for emummc!", COLOR_RED); gfx_printf("%kYou seem to be running this on a <=32GB SD\nNot enough free space for emummc!", COLOR_RED);
@@ -219,7 +228,7 @@ int format(int mode){
if (!fatalerror){ if (!fatalerror){
gfx_printf("\nPartitioning SD...\n"); gfx_printf("\nPartitioning SD...\n");
res = f_fdisk(0, plist, &work); res = f_fdisk(0, plist, work);
if (res){ if (res){
gfx_printf("%kf_fdisk returned %d!\n", COLOR_RED, res); gfx_printf("%kf_fdisk returned %d!\n", COLOR_RED, res);
@@ -231,7 +240,7 @@ int format(int mode){
if (!fatalerror){ if (!fatalerror){
gfx_printf("\n\nFormatting Partition1...\n"); gfx_printf("\n\nFormatting Partition1...\n");
res = f_mkfs("0:", formatoptions, clustsize, &work, sizeof work); res = f_mkfs("0:", formatoptions, clustsize, work, BUFSIZE * sizeof(BYTE));
if (res){ if (res){
gfx_printf("%kf_mkfs returned %d!\n", COLOR_RED, res); gfx_printf("%kf_mkfs returned %d!\n", COLOR_RED, res);
@@ -241,6 +250,8 @@ int format(int mode){
gfx_printf("Smells like a formatted SD\n\n"); gfx_printf("Smells like a formatted SD\n\n");
} }
free(work);
sd_unmount(); sd_unmount();
if (!fatalerror){ if (!fatalerror){