Compare commits

...

24 Commits

Author SHA1 Message Date
Such Meme, Many Skill
b91c36d3fa Fastfs testing 2020-05-19 17:54:21 +02:00
Such Meme, Many Skill
a8e86c2de3 Don't forget to take results 2020-05-17 23:42:53 +02:00
Such Meme, Many Skill
6934e1422f Various improvements to scripting lang
- Errors will now be more precise, there are now 2 separate errors for a function lookup failure and a failure inside a function
- Errors will now show which line number they failed at, instead of the character offset
- Minus values are not considered errors anymore, however, printing them does not work well
- Gotos now make a @RETURN variable to make making functions easier
2020-05-15 20:17:31 +02:00
Such Meme, Many Skill
f49245e4ab Fix hidden copies messing with screen positions 2020-05-15 16:20:52 +02:00
Such Meme, Many Skill
9075f20854 Clean up bisfile extraction 2020-05-15 16:07:23 +02:00
Such Meme, Many Skill
6bc474a981 Bump version 2020-05-10 21:56:11 +02:00
Such Meme, Many Skill
91536268ad Fix compiling issues (hopefully) 2020-05-10 21:51:30 +02:00
Such Meme, Many Skill
b484dc11d8 Hopefully fix partitioning issues & clean up menu control code 2020-05-10 11:41:16 +02:00
Such Meme, Many Skill
14a3a39c01 Remove dumping user saves from tools
This has been replaced by a script: https://github.com/suchmememanyskill/TegraScript/blob/master/scripts/savedumper.te
2020-05-09 13:52:46 +02:00
Such Meme, Many Skill
6868ef3536 Reset print pos after copying a file 2020-05-09 12:21:34 +02:00
Such Meme, Many Skill
97810335ed fix a bug that basically has no effect
thanks shchmue for pointing that out :smug:
2020-05-09 00:26:02 +02:00
Such Meme, Many Skill
43617ef511 Add save signing 2020-05-09 00:22:35 +02:00
Such Meme, Many Skill
19fe7f15a9 Fix (not) asking to make sure to flash in scripts 2020-05-08 20:57:26 +02:00
Such Meme, Many Skill
73ca98c6a8 Merge remote-tracking branch 'origin/master' 2020-05-04 22:36:13 +02:00
Such Meme, Many Skill
12eecd2466 Update readme 2020-05-04 22:36:07 +02:00
suchmememanyskill
40cb293db3 Try no.4 2020-05-04 21:54:39 +02:00
suchmememanyskill
f09a098c77 Try no.3 2020-05-04 21:35:29 +02:00
suchmememanyskill
30f0e88d0a Attempt no.2 2020-05-04 21:32:05 +02:00
suchmememanyskill
c4c5d57af3 Test github actions 2020-05-04 21:24:49 +02:00
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
74 changed files with 1330 additions and 4568 deletions

36
.github/workflows/builder.yml vendored Normal file
View File

@@ -0,0 +1,36 @@
name: TegraExplorer builder
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Install devkitpro
run: |
wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb
sudo dpkg -i devkitpro-pacman.deb
sudo dkp-pacman -S switch-dev --noconfirm
sudo dkp-pacman -S devkitARM --noconfirm
- name: Build TegraExplorer
run: |
echo # SETTING PATH #
export DEVKITPRO=/opt/devkitpro
export DEVKITARM=${DEVKITPRO}/devkitARM
export DEVKITPPC=${DEVKITPRO}/devkitPPC
export PATH=${DEVKITPRO}/tools/bin:$PATH
echo # MAKE #
make -j$(nproc)
- uses: actions/upload-artifact@master
with:
name: TegraExplorer
path: output/TegraExplorer.bin

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 := 2
################################################################################ ################################################################################

View File

@@ -1,33 +1,62 @@
# TegraExplorer # TegraExplorer
A payload-based file explorer for your switch! A payload-based file explorer for your switch!
![TegraExplorer builder](https://github.com/suchmememanyskill/TegraExplorer/workflows/TegraExplorer%20builder/badge.svg)
## Usage ## Usage
1. Get your favorite payload injector 1. Get your favorite payload injector
2. Inject TegraExplorer as a payload 2. Inject TegraExplorer as a payload
Navigate around the menus using the vol+, vol- and power buttons Navigate around the menus using the joycons.
A: Select
B: Back
Left Joystick up/down (Dpad or joystick): navigate menus up/down
Right Joystick up/down: fast menu navigation up/down
Capture (Minerva only): Take a screenshot
L3/R3 (Press joysticks in): Recalibrate centerpoint
If you do not have your joycons connected:
Power -> A
Vol+ -> Left Joystick up
Vol- -> Left Joystick down
## Functions ## Functions
- Navigate the SD card - Navigate the SD card
- Navigate the System partition of your sysnand/sysmmc - Navigate the System partition of your sysmmc and emummc
- Interact with files - Interact with files
- Deleting, copying or moving files - Deleting, copying, renaming and moving files
- Launching payloads files - Launching payloads files
- Viewing the hex data of a file - Viewing the hex data of a file
- Launching special [TegraScript](https://github.com/suchmememanyskill/TegraScript) files
- Renaming files
- Interacting with folders - Interacting with folders
- Deleting or copying folders - Deleting, copying or renaming folders
- Creating folders
- Dumping your current firmware to sd - Dumping your current firmware to sd
- Formatting the sd card - Formatting the sd card
*and more*
## Support ## Support
For general CFW support, go to the [Nintendo Homebrew](https://discord.gg/C29hYvh) discord For general CFW support, go to the [Nintendo Homebrew](https://discord.gg/C29hYvh) discord
For question specifically for TegraExplorer, go to [my discord](https://discord.gg/aH9rsuP) For question specifically for TegraExplorer, go to [my discord](https://discord.gg/aH9rsuP)
# Credits ## Credits
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate) Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate)
Lots of help from: Awesome people who helped with this project:
- shchmue - shchmue
- Denn - Dennthecafebabe
Other awesome people:
- PhazonicRidley
- Dax
- Huhen
- Bleck9999
- Exelix
## Screenshots
![Preview](/preview.png)

BIN
preview.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

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

@@ -64,7 +64,7 @@ ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type
return csec; return csec;
} }
int ini_parse(link_t *dst, char *ini_path, bool is_dir) int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
{ {
u32 lblen; u32 lblen;
u32 pathlen = strlen(ini_path); u32 pathlen = strlen(ini_path);
@@ -73,6 +73,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
char *filelist = NULL; char *filelist = NULL;
FIL fp; FIL fp;
ini_sec_t *csec = NULL; ini_sec_t *csec = NULL;
bool firstIniRun = true;
char *filename = (char *)malloc(256); char *filename = (char *)malloc(256);
@@ -116,10 +117,17 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
do do
{ {
if (firstIniRun){
firstIniRun = false;
strcpy(lbuf, "[Unknown]");
lblen = 9;
}
else {
// Fetch one line. // Fetch one line.
lbuf[0] = 0; lbuf[0] = 0;
f_gets(lbuf, 512, &fp); f_gets(lbuf, 512, &fp);
lblen = strlen(lbuf); lblen = strlen(lbuf);
}
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r. // Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
if (lblen && lbuf[lblen - 1] == '\n') if (lblen && lbuf[lblen - 1] == '\n')

View File

@@ -43,7 +43,7 @@ typedef struct _ini_sec_t
u32 color; u32 color;
} ini_sec_t; } ini_sec_t;
int ini_parse(link_t *dst, char *ini_path, bool is_dir); int ini_parse(link_t *dst, const char *ini_path, bool is_dir);
char *ini_check_payload_section(ini_sec_t *cfg); char *ini_check_payload_section(ini_sec_t *cfg);
#endif #endif

View File

@@ -20,6 +20,9 @@
#include <string.h> #include <string.h>
#include "gfx.h" #include "gfx.h"
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
static const u8 _gfx_font[] = { static const u8 _gfx_font[] = {
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder) 0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file) 0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file)

View File

@@ -61,7 +61,7 @@ void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade);
*/ */
// Global gfx console and context. // Global gfx console and context.
gfx_ctxt_t gfx_ctxt; extern gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con; extern gfx_con_t gfx_con;
#endif #endif

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,40 +26,11 @@
#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; extern u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start; extern u32 pkg2_newkern_ini1_start;
u32 pkg2_newkern_ini1_end; extern 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
{ {
@@ -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,108 +50,28 @@ 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)
{
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. // Copy sept-primary.
if (f_open(&fp, "sept/sept-primary.bin", FA_READ)) if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ))
goto error; goto error;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL)) if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
@@ -171,13 +84,13 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
// 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; goto error;
} }
else else
{ {
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ)) if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
goto error; goto error;
} }
@@ -187,48 +100,25 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
goto error; goto error;
} }
f_close(&fp); f_close(&fp);
}
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
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. // Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t)); boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, &b_cfg, 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_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL); f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
update_sept_payload = false;
}
f_close(&fp); 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);
}
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

@@ -108,7 +108,7 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
pdst += 0x10; pdst += 0x10;
} }
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize); se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
pdst = (u8 *)dst; pdst = (u8 *)dst;

View File

@@ -42,8 +42,8 @@
#include "../../storage/sdmmc.h" #include "../../storage/sdmmc.h"
extern sdmmc_storage_t sd_storage; extern sdmmc_storage_t sd_storage;
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF); //#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
//#define EFSPRINTF(...) #define EFSPRINTF(...)
/*-------------------------------------------------------------------------- /*--------------------------------------------------------------------------
@@ -4056,7 +4056,216 @@ FRESULT f_write (
LEAVE_FF(fs, FR_OK); LEAVE_FF(fs, FR_OK);
} }
#ifdef FF_FASTFS
/*-----------------------------------------------------------------------*/
/* Fast Read Aligned Sized File Without a Cache */
/*-----------------------------------------------------------------------*/
#if FF_USE_FASTSEEK
FRESULT f_read_fast (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btr /* Number of bytes to read */
)
{
if (btr % 65536 != 0)
return f_read(fp, buff, btr, NULL);
FRESULT res;
FATFS *fs;
UINT csize_bytes;
DWORD clst;
UINT count = 0;
FSIZE_t work_sector = 0;
FSIZE_t sector_base = 0;
BYTE *wbuff = (BYTE*)buff;
// TODO support sector reading inside a cluster
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
FSIZE_t remain = fp->obj.objsize - fp->fptr;
if (btr > remain) btr = (UINT)remain; /* Truncate btr by remaining bytes */
csize_bytes = fs->csize * SS(fs);
if (!fp->fptr) { /* On the top of the file? */
clst = fp->obj.sclust; /* Follow from the origin */
} else {
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
}
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst; /* Set working cluster */
sector_base = clst2sect(fs, fp->clust);
count += fs->csize;
btr -= csize_bytes;
fp->fptr += csize_bytes;
while (btr) {
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DSKC"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst;
work_sector = clst2sect(fs, fp->clust);
if ((work_sector - sector_base) == count) count += fs->csize;
else {
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
wbuff += count * SS(fs);
sector_base = work_sector;
count = fs->csize;
}
fp->fptr += MIN(btr, csize_bytes);
btr -= MIN(btr, csize_bytes);
// TODO: what about if data is smaller than cluster?
// Must read-write back that cluster.
if (!btr) { /* Final cluster/sectors read. */
if (disk_read(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
}
}
LEAVE_FF(fs, FR_OK);
}
#endif
#endif
#ifdef FF_FASTFS
/*-----------------------------------------------------------------------*/
/* Fast Write Aligned Sized File Without a Cache */
/*-----------------------------------------------------------------------*/
#if FF_USE_FASTSEEK
FRESULT f_write_fast (
FIL* fp, /* Pointer to the file object */
const void* buff, /* Pointer to the data to be written */
UINT btw /* Number of bytes to write */
)
{
if (btw % 65536 != 0)
return f_write(fp, buff, btw, NULL);
FRESULT res;
FATFS *fs;
UINT csize_bytes;
DWORD clst;
UINT count = 0;
FSIZE_t work_sector = 0;
FSIZE_t sector_base = 0;
const BYTE *wbuff = (const BYTE*)buff;
// TODO support sector writing inside a cluster
res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) {
EFSPRINTF("FOV");
LEAVE_FF(fs, res); /* Check validity */
}
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
/* Check fptr wrap-around (file size cannot reach 4 GiB at FAT volume) */
if ((!FF_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
}
csize_bytes = fs->csize * SS(fs);
if (!fp->fptr) { /* On the top of the file? */
clst = fp->obj.sclust; /* Follow from the origin */
} else {
if (fp->cltbl) clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
else { EFSPRINTF("CLTBL"); ABORT(fs, FR_CLTBL_NO_INIT); }
}
if (clst < 2) { EFSPRINTF("CCHK"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst; /* Set working cluster */
sector_base = clst2sect(fs, fp->clust);
count += fs->csize;
btw -= csize_bytes;
fp->fptr += csize_bytes;
while (btw) {
clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
if (clst < 2) { EFSPRINTF("CCHK2"); ABORT(fs, FR_INT_ERR); }
else if (clst == 0xFFFFFFFF) { EFSPRINTF("DERR"); ABORT(fs, FR_DISK_ERR); }
fp->clust = clst;
work_sector = clst2sect(fs, fp->clust);
if ((work_sector - sector_base) == count) count += fs->csize;
else {
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
wbuff += count * SS(fs);
sector_base = work_sector;
count = fs->csize;
}
fp->fptr += MIN(btw, csize_bytes);
btw -= MIN(btw, csize_bytes);
// what about if data is smaller than cluster?
// Probably must read-write back that cluster.
if (!btw) { /* Final cluster/sectors write. */
if (disk_write(fs->pdrv, wbuff, sector_base, count) != RES_OK) ABORT(fs, FR_DISK_ERR);
fp->flag &= (BYTE)~FA_DIRTY;
}
}
fp->flag |= FA_MODIFIED; /* Set file change flag */
LEAVE_FF(fs, FR_OK);
}
#endif
#endif
#ifdef FF_FASTFS
#if FF_USE_FASTSEEK
/*-----------------------------------------------------------------------*/
/* Seek File Read/Write Pointer */
/*-----------------------------------------------------------------------*/
DWORD *f_expand_cltbl (
FIL* fp, /* Pointer to the file object */
UINT tblsz, /* Size of table */
FSIZE_t ofs /* File pointer from top of file */
)
{
if (fp->flag & FA_WRITE) f_lseek(fp, ofs); /* Expand file if write is enabled */
if (!fp->cltbl) { /* Allocate memory for cluster link table */
fp->cltbl = (DWORD *)ff_memalloc(tblsz);
fp->cltbl[0] = tblsz;
}
if (f_lseek(fp, CREATE_LINKMAP)) { /* Create cluster link table */
ff_memfree(fp->cltbl);
fp->cltbl = NULL;
EFSPRINTF("CLTBLSZ");
return NULL;
}
f_lseek(fp, 0);
return fp->cltbl;
}
#endif
#endif
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -4169,6 +4378,13 @@ FRESULT f_close (
#endif #endif
} }
} }
if (fp->cltbl != NULL){
ff_memfree(fp->cltbl);
fp->cltbl = NULL;
}
return res; return res;
} }
@@ -5629,7 +5845,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 +6311,7 @@ FRESULT f_mkfs (
LEAVE_MKFS(FR_OK); LEAVE_MKFS(FR_OK);
} }
#pragma GCC pop_options
#if FF_MULTI_PARTITION #if FF_MULTI_PARTITION
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
@@ -6113,9 +6330,6 @@ FRESULT f_fdisk (
DWORD sz_disk, p_sect, b_cyl, b_sect; DWORD sz_disk, p_sect, b_cyl, b_sect;
FRESULT res; FRESULT res;
BYTE *empty_buff;
empty_buff = ff_memcalloc(sizeof(BYTE), 16384);
stat = disk_initialize(pdrv); stat = disk_initialize(pdrv);
if (stat & STA_NOINIT) return FR_NOT_READY; if (stat & STA_NOINIT) return FR_NOT_READY;
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED; if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
@@ -6168,14 +6382,14 @@ FRESULT f_fdisk (
st_dword(p + 8, b_sect); /* Start sector in LBA */ st_dword(p + 8, b_sect); /* Start sector in LBA */
st_dword(p + 12, p_sect); /* Number of sectors */ st_dword(p + 12, p_sect); /* Number of sectors */
/* Next partition */ /* Next partition */
b_sect += p_sect;
for (int cursect = 0; cursect < 1024; cursect++){ for (u32 cursect = 0; cursect < 512; cursect++){
disk_write(pdrv, empty_buff, b_sect + (32 * cursect), 32); disk_write(pdrv, buf + 0x4000, b_sect + (64 * cursect), 64);
} }
b_sect += p_sect;
} }
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */ st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
ff_memfree(empty_buff);
/* Write it to the MBR */ /* Write it to the MBR */
res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR; res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;

View File

@@ -246,7 +246,10 @@ typedef enum {
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */ FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > FF_FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ FR_INVALID_PARAMETER, /* (19) Given parameter is invalid */
#ifdef FF_FASTFS
FR_CLTBL_NO_INIT /* (20) The cluster table for fast seek/read/write was not created */
#endif
} FRESULT; } FRESULT;
@@ -288,6 +291,11 @@ int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */ int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */ int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */ TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#ifdef FF_FASTFS
FRESULT f_read_fast (FIL* fp, const void* buff, UINT btr); /* Fast read data from the file */
FRESULT f_write_fast (FIL* fp, const void* buff, UINT btw); /* Fast write data to the file */
DWORD *f_expand_cltbl (FIL* fp, UINT tblsz, FSIZE_t ofs); /* Expand file and populate cluster table */
#endif
#define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize)) #define f_eof(fp) ((int)((fp)->fptr == (fp)->obj.objsize))
#define f_error(fp) ((fp)->err) #define f_error(fp) ((fp)->err)

View File

@@ -42,7 +42,13 @@
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */ /* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define FF_FASTFS 1
#ifdef FF_FASTFS
#define FF_USE_FASTSEEK 1
#else
#define FF_USE_FASTSEEK 0 #define FF_USE_FASTSEEK 0
#endif
/* This option switches fast seek function. (0:Disable or 1:Enable) */ /* This option switches fast seek function. (0:Disable or 1:Enable) */
@@ -287,3 +293,5 @@
/*--- End of configuration options ---*/ /*--- End of configuration options ---*/

View File

@@ -44,10 +44,10 @@
//#include "keys/keys.h" //#include "keys/keys.h"
sdmmc_t sd_sdmmc; //sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage; //sdmmc_storage_t sd_storage;
__attribute__ ((aligned (16))) FATFS sd_fs; //__attribute__ ((aligned (16))) FATFS sd_fs;
bool sd_mounted, sd_inited; //bool sd_mounted, sd_inited;
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR; volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
hekate_config h_cfg; hekate_config h_cfg;
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg; boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;

View File

@@ -27,6 +27,7 @@
#include "../soc/t210.h" #include "../soc/t210.h"
extern volatile nyx_storage_t *nyx_str; extern volatile nyx_storage_t *nyx_str;
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
u32 minerva_init() u32 minerva_init()
{ {

View File

@@ -57,7 +57,7 @@ typedef enum
FREQ_1600 = 1600000 FREQ_1600 = 1600000
} minerva_freq_t; } minerva_freq_t;
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *); extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
u32 minerva_init(); u32 minerva_init();
void minerva_change_freq(minerva_freq_t freq); void minerva_change_freq(minerva_freq_t freq);
void minerva_periodic_training(); void minerva_periodic_training();

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);
memcpy(keys + i * keysize, aligned_buf, 0x10);
if (keysize > 0x10)
{
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);
} }
else
{
memcpy(secret, key, key_size);
memset(secret + key_size, 0, 0x40 - key_size);
} }
// 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

@@ -32,6 +32,7 @@ extern sdmmc_storage_t sd_storage;
extern FATFS sd_fs; extern FATFS sd_fs;
extern hekate_config h_cfg; extern hekate_config h_cfg;
emummc_cfg_t emu_cfg;
extern bool sd_mount(); extern bool sd_mount();
extern void sd_unmount(); extern void sd_unmount();

View File

@@ -47,7 +47,7 @@ typedef struct _emummc_cfg_t
int fs_ver; int fs_ver;
} emummc_cfg_t; } emummc_cfg_t;
emummc_cfg_t emu_cfg; extern emummc_cfg_t emu_cfg;
bool emummc_load_cfg(); bool emummc_load_cfg();
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc); int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);

View File

@@ -25,6 +25,10 @@
bool sd_mounted = false, sd_inited = false; bool sd_mounted = false, sd_inited = false;
static u32 sd_mode = SD_UHS_SDR82; static u32 sd_mode = SD_UHS_SDR82;
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
u32 sd_get_mode() u32 sd_get_mode()
{ {
return sd_mode; return sd_mode;

View File

@@ -30,9 +30,9 @@ enum
SD_UHS_SDR82 = 3, SD_UHS_SDR82 = 3,
}; };
sdmmc_t sd_sdmmc; extern sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage; extern sdmmc_storage_t sd_storage;
FATFS sd_fs; extern FATFS sd_fs;
u32 sd_get_mode(); u32 sd_get_mode();
int sd_init_retry(bool power_cycle); int sd_init_retry(bool power_cycle);

View File

@@ -21,7 +21,7 @@
#include "../utils/types.h" #include "../utils/types.h"
#include "sdmmc_driver.h" #include "sdmmc_driver.h"
u32 sd_power_cycle_time_start; extern u32 sd_power_cycle_time_start;
typedef enum _sdmmc_type typedef enum _sdmmc_type
{ {

View File

@@ -29,6 +29,11 @@
#include "../soc/t210.h" #include "../soc/t210.h"
#include "../utils/util.h" #include "../utils/util.h"
#pragma GCC push_options
#pragma GCC optimize ("Os")
u32 sd_power_cycle_time_start;
//#define DPRINTF(...) gfx_printf(__VA_ARGS__) //#define DPRINTF(...) gfx_printf(__VA_ARGS__)
#define DPRINTF(...) #define DPRINTF(...)
@@ -1158,6 +1163,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a
return 0; return 0;
} }
#pragma GCC pop_options
void sdmmc_end(sdmmc_t *sdmmc) void sdmmc_end(sdmmc_t *sdmmc)
{ {
if (!sdmmc->clock_stopped) if (!sdmmc->clock_stopped)

View File

@@ -21,9 +21,11 @@ enum utils_err_codes_te_call {
ERR_EMMC_WRITE_FAILED, ERR_EMMC_WRITE_FAILED,
ERR_FILE_TOO_BIG_FOR_DEST, ERR_FILE_TOO_BIG_FOR_DEST,
ERR_SD_EJECTED, ERR_SD_EJECTED,
ERR_PARSE_FAIL, ERR_SCRIPT_LOOKUP_FAIL,
ERR_CANNOT_COPY_FILE_TO_FS_PART, ERR_CANNOT_COPY_FILE_TO_FS_PART,
ERR_NO_DESTINATION ERR_NO_DESTINATION,
ERR_INI_PARSE_FAIL,
ERR_IN_FUNC
}; };
extern const char *utils_err_codes_te[]; extern const char *utils_err_codes_te[];
@@ -58,8 +60,7 @@ extern menu_entry mainmenu_shutdown[];
enum mainmenu_tools_return { enum mainmenu_tools_return {
TOOLS_DISPLAY_INFO = 1, TOOLS_DISPLAY_INFO = 1,
TOOLS_DISPLAY_GPIO, TOOLS_DISPLAY_GPIO,
TOOLS_DUMPFIRMWARE, TOOLS_DUMPFIRMWARE
TOOLS_DUMPUSERSAVE
}; };
extern menu_entry mainmenu_tools[]; extern menu_entry mainmenu_tools[];
@@ -86,7 +87,8 @@ enum fs_menu_file_return {
FILE_PAYLOAD, FILE_PAYLOAD,
FILE_SCRIPT, FILE_SCRIPT,
FILE_HEXVIEW, FILE_HEXVIEW,
FILE_DUMPBIS FILE_DUMPBIS,
FILE_SIGN
}; };
extern menu_entry fs_menu_file[]; extern menu_entry fs_menu_file[];

View File

@@ -50,9 +50,11 @@ const char *utils_err_codes_te[] = { // these start at 50
"EMMC WRITE FAILED", "EMMC WRITE FAILED",
"FILE TOO BIG FOR DEST", "FILE TOO BIG FOR DEST",
"SD EJECTED", "SD EJECTED",
"PARSING FAILED", "FUNC LOOKUP FAIL",
"CANNOT COPY FILE TO FS PART", "CANNOT COPY FILE TO FS PART",
"NO DESTINATION" "NO DESTINATION",
"INI PARSE FAIL",
"ERR IN FUNC"
}; };
/* /*
const char *pkg2names[] = { const char *pkg2names[] = {

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}
}; };
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}},
{"Sign Save", COLOR_ORANGE, {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);
@@ -159,7 +159,7 @@ int makeMmcMenu(short mmcType){
case 2: case 2:
if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){ if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){
gfx_clearscreen(); gfx_clearscreen();
if (!mmcFlashFile(clipboard, mmcType)){ if (!mmcFlashFile(clipboard, mmcType, true)){
gfx_printf("\nDone!"); gfx_printf("\nDone!");
hidWait(); hidWait();
} }

View File

@@ -4,7 +4,7 @@
int emmcDumpSpecific(char *part, char *path); int emmcDumpSpecific(char *part, char *path);
int emmcDumpBoot(char *basePath); int emmcDumpBoot(char *basePath);
int mmcFlashFile(char *path, short mmcType); int mmcFlashFile(char *path, short mmcType, bool warnings);
int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part); int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part);
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part); int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part, bool warnings);

View File

@@ -17,7 +17,7 @@
extern sdmmc_storage_t storage; extern sdmmc_storage_t storage;
extern emmc_part_t *system_part; extern emmc_part_t *system_part;
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part, bool warnings){
FIL fp; FIL fp;
FILINFO fno; FILINFO fno;
u8 *buf; u8 *buf;
@@ -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);
@@ -54,10 +54,10 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
gfx_printf("Flashing %s\n", part->name); gfx_printf("Flashing %s\n", part->name);
if (totalSize < totalSizeDest){ if (totalSize < totalSizeDest && warnings){
SWAPCOLOR(COLOR_ORANGE); SWAPCOLOR(COLOR_ORANGE);
gfx_printf("File is too small for destination.\nDo you want to flash it anyway?\n\nB to Cancel\n"); gfx_printf("File is too small for destination.\nDo you want to flash it anyway?\n\nB to Cancel\n");
u8 btnres = gfx_makewaitmenu( u32 btnres = gfx_makewaitmenu(
"A to Confirm", "A to Confirm",
3 3
); );
@@ -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);
@@ -214,13 +214,13 @@ emmc_part_t *mmcFindPart(char *path, short mmcType){
return NULL; return NULL;
} }
int mmcFlashFile(char *path, short mmcType){ int mmcFlashFile(char *path, short mmcType, bool warnings){
emmc_part_t *part; emmc_part_t *part;
int res; int res;
part = mmcFindPart(path, mmcType); part = mmcFindPart(path, mmcType);
if (part != NULL){ if (part != NULL){
res = emmcRestorePart(path, &storage, part); res = emmcRestorePart(path, &storage, part, warnings);
emummc_storage_set_mmc_partition(&storage, 0); emummc_storage_set_mmc_partition(&storage, 0);
return res; return res;
} }

View File

@@ -15,6 +15,8 @@
#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"
#include "savesign.h"
extern char *currentpath; extern char *currentpath;
extern char *clipboard; extern char *clipboard;
@@ -120,40 +122,45 @@ 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);
fs_menu_file[12].isHide = (!!strcmp(currentpath, "emmc:/save"));
/*
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, 13, "-- File Menu --");
switch (temp){ switch (temp){
case FILE_COPY: case FILE_COPY:
fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY); fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY);
@@ -184,7 +191,6 @@ int filemenu(menu_entry file){
break; break;
} }
fsreader_readfolder(currentpath);
break; break;
case FILE_PAYLOAD: case FILE_PAYLOAD:
launch_payload(fsutil_getnextloc(currentpath, file.name)); launch_payload(fsutil_getnextloc(currentpath, file.name));
@@ -198,7 +204,6 @@ int filemenu(menu_entry file){
*/ */
runScript(fsutil_getnextloc(currentpath, file.name)); runScript(fsutil_getnextloc(currentpath, file.name));
fsreader_readfolder(currentpath);
break; break;
case FILE_HEXVIEW: case FILE_HEXVIEW:
viewbytes(fsutil_getnextloc(currentpath, file.name)); viewbytes(fsutil_getnextloc(currentpath, file.name));
@@ -206,12 +211,23 @@ int filemenu(menu_entry file){
case FILE_DUMPBIS: case FILE_DUMPBIS:
gfx_clearscreen(); gfx_clearscreen();
extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath); extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath);
fsreader_readfolder(currentpath);
hidWait(); hidWait();
break;
case FILE_SIGN:
if (gfx_defaultWaitMenu("WARNING!\n\nThis should only be used if you know what signing and a save is\nDo not do this if you don't know what this does\n\nRequires you to have a prod.keys located in the switch folder\n", 5)){
gfx_clearscreen();
gfx_printf("Signing save...\n");
if (save_sign("sd:/switch/prod.keys", fsutil_getnextloc(currentpath, file.name))){
gfx_printf("Done!\nPress any key to exit");
hidWait();
}
}
break; break;
case -1: case -1:
return -1; return -1;
} }
fsreader_readfolder(currentpath);
return 0; return 0;
} }

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,15 @@
#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; u8 *buff, toPrint = options & COPY_MODE_PRINT, toCancel = options & COPY_MODE_CANCEL;
u8 *buff; u32 x, y, i = 11, toSpeed;
unsigned int x, y, i = 0;
int res; int res;
gfx_con_getpos(&x, &y); gfx_con_getpos(&x, &y);
@@ -31,64 +31,76 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
return 1; return 1;
} }
if (f_stat(locin, &in_info)){ if ((res = f_stat(locin, &in_info))){
gfx_errDisplay("copy", res, 3); gfx_errDisplay("copy", res, 3);
return 1; return 1;
} }
if (f_open(&out, locout, FA_CREATE_ALWAYS | FA_WRITE)){ if ((res = f_open(&out, locout, FA_CREATE_ALWAYS | FA_WRITE))){
gfx_errDisplay("copy", res, 4); gfx_errDisplay("copy", res, 4);
return 1; return 1;
} }
buff = malloc (BUFSIZE); if (toPrint){
sizeoffile = f_size(&in); SWAPCOLOR(COLOR_GREEN);
totalsize = sizeoffile; gfx_printf("[ ]");
x += 16;
while (sizeoffile > 0){
if ((res = f_read(&in, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp1))){
gfx_errDisplay("copy", res, 5);
return 1;
}
if ((res = f_write(&out, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp2))){
gfx_errDisplay("copy", res, 6);
return 1;
}
if (temp1 != temp2){
gfx_errDisplay("copy", ERR_DISK_WRITE_FAILED, 7);
return 1;
}
sizeoffile -= temp1;
sizecopied += temp1;
if (options & COPY_MODE_PRINT && 10 > i++){
gfx_printf("%k[%d%%]%k", COLOR_GREEN, ((sizecopied * 100) / totalsize) ,COLOR_WHITE);
gfx_con_setpos(x, y); gfx_con_setpos(x, y);
}
i = 0; buff = malloc (BUFSIZE);
sizeRemaining = f_size(&in);
const u64 totalsize = sizeRemaining;
if (options & COPY_MODE_CANCEL) DWORD *clmt_in = f_expand_cltbl(&in, BUFSIZE / 4, 0);
if (hidRead()->buttons & (KEY_VOLP | KEY_VOLM)){ DWORD *clmt_out = f_expand_cltbl(&out, BUFSIZE / 4, totalsize);
while (sizeRemaining > 0){
toCopy = MIN(sizeRemaining, BUFSIZE);
if ((res = f_read_fast(&in, buff, toCopy))){
gfx_errDisplay("copy", res, 5);
break;
}
if ((res = f_write_fast(&out, buff, toCopy))){
gfx_errDisplay("copy", res, 6);
break;
}
sizeRemaining -= toCopy;
if (toPrint && (i > 16 || !sizeRemaining)){
gfx_printf("%3d%%", (u32)(((totalsize - sizeRemaining) * 100) / totalsize));
gfx_con_setpos(x, y);
}
if (toCancel && i > 16){
if (btn_read() & (BTN_VOL_DOWN | BTN_VOL_UP)){
f_unlink(locout); f_unlink(locout);
break; break;
} }
} }
if (options){
if (i++ > 16)
i = 0;
}
}
if (toPrint){
RESETCOLOR;
gfx_con_setpos(x - 16, y);
} }
f_close(&in); f_close(&in);
f_close(&out); f_close(&out);
free(buff); free(buff);
if ((res = f_chmod(locout, in_info.fattrib, 0x3A))){ f_chmod(locout, in_info.fattrib, 0x3A);
gfx_errDisplay("copy", res, 8);
return 1;
}
f_stat(locin, &in_info); //somehow stops fatfs from being weird f_stat(locin, &in_info); //somehow stops fatfs from being weird
return 0; return res;
} }
int fsact_del_recursive(char *path){ int fsact_del_recursive(char *path){

View File

@@ -13,25 +13,15 @@
#include "../utils/utils.h" #include "../utils/utils.h"
#include "fsactions.h" #include "fsactions.h"
u32 DecodeInt(u8* data) {
u32 out = 0;
for (int i = 0; i < 4; i++) {
out |= (data[i] << ((3 - i) * 8));
}
return out;
}
void copy_fil_size(FIL* in_src, FIL* out_src, int size_src){ void copy_fil_size(FIL* in_src, FIL* out_src, int size_src){
u8* buff; u8* buff;
buff = calloc(16384, sizeof(u8)); buff = calloc(BUFSIZE, sizeof(u8));
int size = size_src; int size = size_src;
int copysize; int copysize;
while (size > 0){ while (size > 0){
copysize = MIN(16834, size); copysize = MIN(BUFSIZE, size);
f_read(in_src, buff, copysize, NULL); f_read(in_src, buff, copysize, NULL);
f_write(out_src, buff, copysize, NULL); f_write(out_src, buff, copysize, NULL);
size -= copysize; size -= copysize;
@@ -48,56 +38,50 @@ void gen_part(int size, FIL* in, char *path){
f_close(&out); f_close(&out);
} }
const char *filenames[] = {
"BOOT0.bin",
"BOOT1.bin",
"BCPKG2-1-Normal-Main",
"BCPKG2-3-SafeMode-Main",
"BCPKG2-2-Normal-Sub",
"BCPKG2-4-SafeMode-Sub"
};
int extract_bis_file(char *path, char *outfolder){ int extract_bis_file(char *path, char *outfolder){
FIL in; FIL in;
int res; int res;
u8 version[0x10];
u8 args;
u8 temp[0x4];
u32 filesizes[4];
char *tempPath; char *tempPath;
BisFile header;
if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){ if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){
gfx_errDisplay("extract_bis_file", res, 0); gfx_errDisplay("extract_bis_file", res, 0);
return -1; return -1;
} }
f_read(&in, version, 0x10, NULL); f_read(&in, &header, sizeof(BisFile), NULL);
f_read(&in, &args, 1, NULL);
for (int i = 0; i < 4; i++)
header.sizes[i] = FLIPU32(header.sizes[i]);
gfx_printf("Version: %s\n\n", header.version);
// Loop to actually extract stuff
for (int i = 0; i < 4; i++){ for (int i = 0; i < 4; i++){
f_read(&in, temp, 4, NULL); if (!(header.args & (BIT((7 - i)))))
filesizes[i] = DecodeInt(temp); continue;
gfx_printf("Extracting %s\n", filenames[i]);
gen_part(header.sizes[i], &in, fsutil_getnextloc(outfolder, filenames[i]));
} }
gfx_printf("Version: %s\n\n", version); // Loop to copy pkg2_1->2 and pkg2_3->4
for (int i = 4; i < 6; i++){
if (!(header.args & BIT((9 - i))))
continue;
if (args & BOOT0_ARG){ utils_copystring(fsutil_getnextloc(outfolder, filenames[i - 2]), &tempPath);
gfx_printf("\nExtracting BOOT0\n"); gfx_printf("Copying %s\n", filenames[i]);
gen_part(filesizes[0], &in, fsutil_getnextloc(outfolder, "BOOT0.bin")); fsact_copy(tempPath, fsutil_getnextloc(outfolder, filenames[i]), COPY_MODE_PRINT);
}
if (args & BOOT1_ARG){
gfx_printf("Extracting BOOT1\n");
gen_part(filesizes[1], &in, fsutil_getnextloc(outfolder, "BOOT1.bin"));
}
if (args & BCPKG2_1_ARG){
utils_copystring(fsutil_getnextloc(outfolder, "BCPKG2-1-Normal-Main"), &tempPath);
gfx_printf("Extracting BCPKG2_1/2\n");
gen_part(filesizes[2], &in, tempPath);
fsact_copy(tempPath, fsutil_getnextloc(outfolder, "BCPKG2-2-Normal-Sub"), COPY_MODE_PRINT);
RESETCOLOR;
free(tempPath);
}
if (args & BCPKG2_3_ARG){
utils_copystring(fsutil_getnextloc(outfolder, "BCPKG2-3-SafeMode-Main"), &tempPath);
gfx_printf("Extracting BCPKG2_3/4\n");
gen_part(filesizes[3], &in, tempPath);
fsact_copy(tempPath, fsutil_getnextloc(outfolder, "BCPKG2-4-SafeMode-Sub"), COPY_MODE_PRINT);
RESETCOLOR; RESETCOLOR;
free(tempPath); free(tempPath);
} }

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

@@ -2,10 +2,18 @@
#include "../common/types.h" #include "../common/types.h"
#include "../../utils/types.h" #include "../../utils/types.h"
typedef struct {
u8 version[0x10];
u8 args;
u32 sizes[4];
} __attribute__((__packed__)) BisFile;
#define FLIPU32(in) ((in >> 24) & 0xFF) | ((in >> 8) & 0xFF00) | ((in << 8) & 0xFF0000) | ((in << 24) & 0xFF000000)
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

@@ -0,0 +1,123 @@
#include "savesign.h"
#include "../../utils/types.h"
#include "../../libs/fatfs/ff.h"
#include "../../sec/se.h"
#include "../../mem/heap.h"
#include "../gfx/gfxutils.h"
#include "../../config/ini.h"
#include "../common/common.h"
#include <string.h>
bool save_commit(const char *path, u8 *save_mac_key){
FIL file;
int res;
u8 *buf, hash[0x20], *cmac_data, cmac[0x10];
const u32 hashed_data_size = 0x3D00, cmac_data_size = 0x200;
bool success = false;
buf = malloc(hashed_data_size);
cmac_data = malloc(cmac_data_size);
if ((res = f_open(&file, path, FA_OPEN_EXISTING | FA_READ | FA_WRITE))){
gfx_errDisplay("save_commit", res, 1);
goto out_free;
}
f_lseek(&file, 0x300);
if ((res = f_read(&file, buf, hashed_data_size, NULL))){
gfx_errDisplay("save_commit", res, 2);
goto out_free;
}
se_calc_sha256(hash, buf, hashed_data_size);
f_lseek(&file, 0x108);
if ((res = f_write(&file, hash, sizeof(hash), NULL))){
gfx_errDisplay("save_commit", res, 3);
goto out_free;
}
f_lseek(&file, 0x100);
if ((res = f_read(&file, cmac_data, cmac_data_size, NULL))){
gfx_errDisplay("save_commit", res, 4);
goto out_free;
}
se_aes_key_set(3, save_mac_key, 0x10);
se_aes_cmac(3, cmac, 0x10, cmac_data, cmac_data_size);
f_lseek(&file, 0);
if ((res = f_write(&file, cmac, sizeof(cmac), NULL))){
gfx_errDisplay("save_commit", res, 5);
goto out_free;
}
success = true;
out_free:;
free(buf);
free(cmac_data);
f_close(&file);
return success;
}
char *getKey(const char *search, link_t *inilist){
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, inilist, link){
if (ini_sec->type == INI_CHOICE){
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp(search, kv->key))
return kv->val;
}
}
}
return NULL;
}
u8 getHexSingle(const char c) {
if (c >= '0' && c <= '9')
return c - '0';
if (c >= 'a' && c <= 'f')
return c - 'a' + 10;
}
u8 *getHex(const char *in){
u32 len = strlen(in), count = 0;
u8 *out = calloc(len / 2, sizeof(u8));
for (u32 i = 0; i < len; i += 2){
out[count++] = (u8)(getHexSingle(in[i]) << 4) | (getHexSingle(in[i + 1]));
}
return out;
}
bool save_sign(const char *keypath, const char *savepath){
LIST_INIT(inilist);
char *key;
u8 *hex;
bool success = false;
if (!ini_parse(&inilist, keypath, false)){
gfx_errDisplay("save_sign", ERR_INI_PARSE_FAIL, 1);
goto out_free;
}
if ((key = getKey("save_mac_key", &inilist)) == NULL){
gfx_errDisplay("save_sign", ERR_INI_PARSE_FAIL, 2);
goto out_free;
}
hex = getHex(key);
if (!save_commit(savepath, hex))
goto out_free;
success = true;
out_free:;
list_empty(&inilist);
return success;
}

View File

@@ -0,0 +1,4 @@
#pragma once
#include "../../utils/types.h"
bool save_sign(const char *keypath, const char *savepath);

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.2 | 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;
@@ -52,20 +52,20 @@ u32 gfx_errDisplay(char *src_func, int err, int loc){
if (err < 15) if (err < 15)
gfx_printf("Desc: %s\n", utils_err_codes[err]); gfx_printf("Desc: %s\n", utils_err_codes[err]);
else if (err >= ERR_SAME_LOC && err <= ERR_NO_DESTINATION) else if (err >= ERR_SAME_LOC && err <= ERR_IN_FUNC)
gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]); gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]);
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
@@ -203,8 +167,8 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
while (hidRead()->buttons & (KEY_B | KEY_A)); while (hidRead()->buttons & (KEY_B | KEY_A));
input->buttons = 0; scrolltimer = get_tmr_ms();
while (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){ while (1){
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){ if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){
gfx_errDisplay("menu", ERR_SD_EJECTED, 0); gfx_errDisplay("menu", ERR_SD_EJECTED, 0);
sd_unmount(); sd_unmount();
@@ -213,33 +177,39 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
input = hidRead(); input = hidRead();
if (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))) if (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){
delay = 300; delay = 300;
continue;
}
if (input->buttons & (KEY_RDOWN | KEY_RUP)){
delay = 1;
input->Lup = input->Rup;
input->Ldown = input->Rdown;
}
if (delay < 300){ if (delay < 300){
scrolltimer = get_tmr_ms(); if (scrolltimer + delay < get_tmr_ms()){
while (input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)){ break;
if (scrolltimer + delay <= get_tmr_ms()) }
}
else {
break; break;
input = hidRead();
} }
} }
if (delay > 46 && input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)) if (delay > 46)
delay -= 45; delay -= 45;
if (input->buttons & (KEY_RUP | KEY_RDOWN)) if (input->Lup && currentpos >= 1){
delay = 1;
}
if (input->buttons & (KEY_LUP | KEY_RUP) && currentpos >= 1){
currentpos--; currentpos--;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1) while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1)
currentpos--; currentpos--;
} }
else if (input->buttons & (KEY_LDOWN | KEY_RDOWN) && currentpos < amount - 1){ else if (input->Ldown && currentpos < amount - 1){
currentpos++; currentpos++;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1) while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1)
currentpos++; currentpos++;
@@ -257,3 +227,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

@@ -37,23 +37,11 @@ void MainMenu_SDCard(){
void MainMenu_EMMC(){ void MainMenu_EMMC(){
if (gfx_defaultWaitMenu("You're about to enter EMMC\nModifying anything here can result in a BRICK!\n\nPlease only continue if you know what you're doing", 4)){ if (gfx_defaultWaitMenu("You're about to enter EMMC\nModifying anything here can result in a BRICK!\n\nPlease only continue if you know what you're doing", 4)){
/*
connect_mmc(SYSMMC);
if (!mount_mmc(emmc_fs_entries[res - 2], res - 1))
fileexplorer("emmc:/", 1);
*/
makeMmcMenu(SYSMMC); makeMmcMenu(SYSMMC);
} }
} }
void MainMenu_EMUMMC(){ void MainMenu_EMUMMC(){
/*
connect_mmc(EMUMMC);
if (!mount_mmc(emmc_fs_entries[res - 5], res - 4))
fileexplorer("emmc:/", 1);
*/
makeMmcMenu(EMUMMC); makeMmcMenu(EMUMMC);
} }
@@ -62,8 +50,7 @@ void MainMenu_MountSD(){
} }
void MainMenu_Tools(){ void MainMenu_Tools(){
//res = makemenu(toolsmenu, 8); res = menu_make(mainmenu_tools, 4, "-- Tools Menu --");
res = menu_make(mainmenu_tools, 5, "-- Tools Menu --");
switch(res){ switch(res){
case TOOLS_DISPLAY_INFO: case TOOLS_DISPLAY_INFO:
@@ -71,21 +58,14 @@ void MainMenu_Tools(){
break; break;
case TOOLS_DISPLAY_GPIO: case TOOLS_DISPLAY_GPIO:
displaygpio(); displaygpio();
//makeMmcMenu(SYSMMC);
break; break;
case TOOLS_DUMPFIRMWARE: case TOOLS_DUMPFIRMWARE:
dumpfirmware(SYSMMC); dumpfirmware(SYSMMC);
break; break;
case TOOLS_DUMPUSERSAVE:
if ((res = utils_mmcMenu()) > 0)
dumpusersaves(res);
break;
} }
} }
void MainMenu_SDFormat(){ void MainMenu_SDFormat(){
//res = makemenu(formatmenu, 4);
res = menu_make(mainmenu_format, 3, "-- Format Menu --"); res = menu_make(mainmenu_format, 3, "-- Format Menu --");
if (res > 0){ if (res > 0){
@@ -131,6 +111,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 +134,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);
@@ -71,14 +74,14 @@ int part_printf(){
if (argv[i][0] == '@'){ if (argv[i][0] == '@'){
int toprintint; int toprintint;
if (parseIntInput(argv[i], &toprintint)) if (parseIntInput(argv[i], &toprintint))
return -1; return INFUNC_FAIL;
gfx_printf("%d", toprintint); gfx_printf("%d", toprintint);
} }
else { else {
char *toprintstring; char *toprintstring;
if (parseStringInput(argv[i], &toprintstring)) if (parseStringInput(argv[i], &toprintstring))
return -1; return INFUNC_FAIL;
gfx_printf(toprintstring); gfx_printf(toprintstring);
} }
@@ -91,7 +94,7 @@ int part_printf(){
int part_print_int(){ int part_print_int(){
int toprint; int toprint;
if (parseIntInput(argv[0], &toprint)) if (parseIntInput(argv[0], &toprint))
return -1; return INFUNC_FAIL;
SWAPCOLOR(currentcolor); SWAPCOLOR(currentcolor);
gfx_printf("%s: %d\n", argv[0], toprint); gfx_printf("%s: %d\n", argv[0], toprint);
@@ -104,7 +107,7 @@ int part_Wait(){
SWAPCOLOR(currentcolor); SWAPCOLOR(currentcolor);
if (parseIntInput(argv[0], &arg)) if (parseIntInput(argv[0], &arg))
return -1; return INFUNC_FAIL;
begintime = get_tmr_s(); begintime = get_tmr_s();
@@ -119,9 +122,9 @@ int part_Wait(){
int part_Check(){ int part_Check(){
int left, right; int left, right;
if (parseIntInput(argv[0], &left)) if (parseIntInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseIntInput(argv[2], &right)) if (parseIntInput(argv[2], &right))
return -1; return INFUNC_FAIL;
if (!strcmp(argv[1], "==")) if (!strcmp(argv[1], "=="))
return (left == right); return (left == right);
@@ -136,13 +139,13 @@ int part_Check(){
else if (!strcmp(argv[1], "<")) else if (!strcmp(argv[1], "<"))
return (left < right); return (left < right);
else else
return -1; return INFUNC_FAIL;
} }
int part_if(){ int part_if(){
int condition; int condition;
if (parseIntInput(argv[0], &condition)) if (parseIntInput(argv[0], &condition))
return -1; return INFUNC_FAIL;
getfollowingchar('{'); getfollowingchar('{');
@@ -164,7 +167,7 @@ int part_if(){
int part_if_args(){ int part_if_args(){
int condition; int condition;
if ((condition = part_Check()) < 0) if ((condition = part_Check()) < 0)
return -1; return INFUNC_FAIL;
getfollowingchar('{'); getfollowingchar('{');
@@ -177,9 +180,9 @@ int part_if_args(){
int part_Math(){ int part_Math(){
int left, right; int left, right;
if (parseIntInput(argv[0], &left)) if (parseIntInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseIntInput(argv[2], &right)) if (parseIntInput(argv[2], &right))
return -1; return INFUNC_FAIL;
switch (argv[1][0]){ switch (argv[1][0]){
case '+': case '+':
@@ -191,7 +194,7 @@ int part_Math(){
case '/': case '/':
return left / right; return left / right;
} }
return -1; return INFUNC_FAIL;
} }
int part_SetInt(){ int part_SetInt(){
@@ -203,9 +206,9 @@ int part_SetInt(){
int part_SetString(){ int part_SetString(){
char *arg0; char *arg0;
if (parseStringInput(argv[0], &arg0)) if (parseStringInput(argv[0], &arg0))
return -1; return INFUNC_FAIL;
if (argv[1][0] != '$') if (argv[1][0] != '$')
return -1; return INFUNC_FAIL;
str_str_add(argv[1], arg0); str_str_add(argv[1], arg0);
return 0; return 0;
@@ -215,11 +218,11 @@ int part_SetStringIndex(){
int index; int index;
char *out; char *out;
if (parseIntInput(argv[0], &index)) if (parseIntInput(argv[0], &index))
return -1; return INFUNC_FAIL;
if (argv[1][0] != '$') if (argv[1][0] != '$')
return -1; return INFUNC_FAIL;
if (str_str_index(index, &out)) if (str_str_index(index, &out))
return -1; return INFUNC_FAIL;
str_str_add(argv[1], out); str_str_add(argv[1], out);
return 0; return 0;
@@ -228,7 +231,10 @@ int part_SetStringIndex(){
int part_goto(){ int part_goto(){
int target = 0; int target = 0;
if (parseIntInput(argv[0], &target)) if (parseIntInput(argv[0], &target))
return -1; return INFUNC_FAIL;
str_int_add("@RETURN", (int)f_tell(&scriptin));
f_lseek(&scriptin, target); f_lseek(&scriptin, target);
return 0; return 0;
} }
@@ -236,14 +242,14 @@ int part_goto(){
int part_invert(){ int part_invert(){
int arg; int arg;
if (parseIntInput(argv[0], &arg)) if (parseIntInput(argv[0], &arg))
return -1; return INFUNC_FAIL;
return (arg) ? 0 : 1; return (arg) ? 0 : 1;
} }
int part_fs_exists(){ int part_fs_exists(){
char *path; char *path;
if (parseStringInput(argv[0], &path)) if (parseStringInput(argv[0], &path))
return -1; return INFUNC_FAIL;
return fsutil_checkfile(path); return fsutil_checkfile(path);
} }
@@ -257,7 +263,7 @@ int part_ConnectMMC(){
else if (!strcmp(arg, "EMUMMC")) else if (!strcmp(arg, "EMUMMC"))
connect_mmc(EMUMMC); connect_mmc(EMUMMC);
else else
return -1; return INFUNC_FAIL;
return 0; return 0;
} }
@@ -289,11 +295,11 @@ int part_Pause(){
int part_addstrings(){ int part_addstrings(){
char *combined, *left, *middle; char *combined, *left, *middle;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &middle)) if (parseStringInput(argv[1], &middle))
return -1; return INFUNC_FAIL;
if (argv[2][0] != '$') if (argv[2][0] != '$')
return -1; return INFUNC_FAIL;
combined = calloc(strlen(left) + strlen(middle) + 1, sizeof(char)); combined = calloc(strlen(left) + strlen(middle) + 1, sizeof(char));
sprintf(combined, "%s%s", left, middle); sprintf(combined, "%s%s", left, middle);
@@ -306,7 +312,7 @@ int part_addstrings(){
int part_setColor(){ int part_setColor(){
char *arg; char *arg;
if (parseStringInput(argv[0], &arg)) if (parseStringInput(argv[0], &arg))
return -1; return INFUNC_FAIL;
if (!strcmp(arg, "RED")) if (!strcmp(arg, "RED"))
currentcolor = COLOR_RED; currentcolor = COLOR_RED;
@@ -323,7 +329,7 @@ int part_setColor(){
else if (!strcmp(arg, "WHITE")) else if (!strcmp(arg, "WHITE"))
currentcolor = COLOR_WHITE; currentcolor = COLOR_WHITE;
else else
return -1; return INFUNC_FAIL;
return 0; return 0;
} }
@@ -337,9 +343,9 @@ int part_fs_Move(){
char *left, *right; char *left, *right;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &right)) if (parseStringInput(argv[1], &right))
return -1; return INFUNC_FAIL;
int res; int res;
res = f_rename(left, right); res = f_rename(left, right);
@@ -353,7 +359,7 @@ int part_fs_Delete(){
char *arg; char *arg;
if (parseStringInput(argv[0], &arg)) if (parseStringInput(argv[0], &arg))
return -1; return INFUNC_FAIL;
int res; int res;
res = f_unlink(arg); res = f_unlink(arg);
@@ -367,7 +373,7 @@ int part_fs_DeleteRecursive(){
char *arg; char *arg;
if (parseStringInput(argv[0], &arg)) if (parseStringInput(argv[0], &arg))
return -1; return INFUNC_FAIL;
return fsact_del_recursive(arg); return fsact_del_recursive(arg);
} }
@@ -376,9 +382,9 @@ int part_fs_Copy(){
char *left, *right; char *left, *right;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &right)) if (parseStringInput(argv[1], &right))
return -1; return INFUNC_FAIL;
return fsact_copy(left, right, COPY_MODE_PRINT); return fsact_copy(left, right, COPY_MODE_PRINT);
} }
@@ -387,9 +393,9 @@ int part_fs_CopyRecursive(){
char *left, *right; char *left, *right;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &right)) if (parseStringInput(argv[1], &right))
return -1; return INFUNC_FAIL;
return fsact_copy_recursive(left, right); return fsact_copy_recursive(left, right);
} }
@@ -398,7 +404,7 @@ int part_fs_MakeDir(){
char *arg; char *arg;
if (parseStringInput(argv[0], &arg)) if (parseStringInput(argv[0], &arg))
return -1; return INFUNC_FAIL;
int res; int res;
res = f_mkdir(arg); res = f_mkdir(arg);
@@ -415,10 +421,10 @@ int part_fs_OpenDir(){
char *path; char *path;
if (parseStringInput(argv[0], &path)) if (parseStringInput(argv[0], &path))
return -1; return INFUNC_FAIL;
if (f_opendir(&dir, path)) if (f_opendir(&dir, path))
return -1; return INFUNC_FAIL;
isdirvalid = true; isdirvalid = true;
str_int_add("@ISDIRVALID", isdirvalid); str_int_add("@ISDIRVALID", isdirvalid);
@@ -437,7 +443,7 @@ int part_fs_CloseDir(){
int part_fs_ReadDir(){ int part_fs_ReadDir(){
if (!isdirvalid) if (!isdirvalid)
return -1; return INFUNC_FAIL;
if (!f_readdir(&dir, &fno) && fno.fname[0]){ if (!f_readdir(&dir, &fno) && fno.fname[0]){
str_str_add("$FILENAME", fno.fname); str_str_add("$FILENAME", fno.fname);
@@ -454,16 +460,16 @@ int part_setPrintPos(){
int left, right; int left, right;
if (parseIntInput(argv[0], &left)) if (parseIntInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseIntInput(argv[1], &right)) if (parseIntInput(argv[1], &right))
return -1; return INFUNC_FAIL;
if (left > 78) if (left > 78)
return -1; return INFUNC_FAIL;
if (right > 42) if (right > 42)
return -1; return INFUNC_FAIL;
gfx_con_setpos(left * 16, right * 16); gfx_con_setpos(left * 16, right * 16);
return 0; return 0;
@@ -473,9 +479,9 @@ int part_stringcompare(){
char *left, *right; char *left, *right;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &right)) if (parseStringInput(argv[1], &right))
return -1; return INFUNC_FAIL;
return (strcmp(left, right)) ? 0 : 1; return (strcmp(left, right)) ? 0 : 1;
} }
@@ -483,11 +489,11 @@ int part_stringcompare(){
int part_fs_combinePath(){ int part_fs_combinePath(){
char *combined, *left, *middle; char *combined, *left, *middle;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &middle)) if (parseStringInput(argv[1], &middle))
return -1; return INFUNC_FAIL;
if (argv[2][0] != '$') if (argv[2][0] != '$')
return -1; return INFUNC_FAIL;
combined = fsutil_getnextloc(left, middle); combined = fsutil_getnextloc(left, middle);
@@ -500,9 +506,9 @@ int part_mmc_dumpPart(){
char *left, *right; char *left, *right;
if (parseStringInput(argv[0], &left)) if (parseStringInput(argv[0], &left))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &right)) if (parseStringInput(argv[1], &right))
return -1; return INFUNC_FAIL;
if (!strcmp(left, "BOOT")){ if (!strcmp(left, "BOOT")){
return emmcDumpBoot(right); return emmcDumpBoot(right);
@@ -516,21 +522,21 @@ int part_mmc_restorePart(){
char *path; char *path;
if (parseStringInput(argv[0], &path)) if (parseStringInput(argv[0], &path))
return -1; return INFUNC_FAIL;
if (currentlyMounted < 0) if (currentlyMounted < 0)
return -1; return INFUNC_FAIL;
return mmcFlashFile(path, currentlyMounted); return mmcFlashFile(path, currentlyMounted, false);
} }
int part_fs_extractBisFile(){ int part_fs_extractBisFile(){
char *path, *outfolder; char *path, *outfolder;
if (parseStringInput(argv[0], &path)) if (parseStringInput(argv[0], &path))
return -1; return INFUNC_FAIL;
if (parseStringInput(argv[1], &outfolder)) if (parseStringInput(argv[1], &outfolder))
return -1; return INFUNC_FAIL;
return extract_bis_file(path, outfolder); return extract_bis_file(path, outfolder);
} }
@@ -544,6 +550,8 @@ int part_getPos(){
return (int)f_tell(&scriptin); return (int)f_tell(&scriptin);
} }
str_fnc_struct functions[] = { str_fnc_struct functions[] = {
{"printf", part_printf, 255}, {"printf", part_printf, 255},
{"printInt", part_print_int, 1}, {"printInt", part_print_int, 1},
@@ -584,6 +592,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)){
@@ -591,8 +601,8 @@ int run_function(char *func_name, int *out){
continue; continue;
*out = functions[i].value(); *out = functions[i].value();
return (*out < 0) ? -1 : 0; return (*out == INFUNC_FAIL) ? -1 : 0;
} }
} }
return -1; return -2;
} }

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++;
@@ -219,7 +220,16 @@ void mainparser(){
printerrors = true; printerrors = true;
//gfx_printf("%s|%s|%d", funcbuff, argv[0], argc); //gfx_printf("%s|%s|%d", funcbuff, argv[0], argc);
//btn_wait(); //btn_wait();
gfx_errDisplay("mainparser", ERR_PARSE_FAIL, f_tell(&scriptin)); int lineNumber = 1;
u64 end = f_tell(&scriptin);
f_lseek(&scriptin, 0);
while (f_tell(&scriptin) < end && !f_eof(&scriptin)){
if (getnextchar() == '\n')
lineNumber++;
}
gfx_errDisplay((res == -1) ? funcbuff : "run_function", (res == -1) ? ERR_IN_FUNC : ERR_SCRIPT_LOOKUP_FAIL, lineNumber);
forceExit = true; forceExit = true;
//gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]); //gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]);
} }
@@ -276,7 +286,9 @@ void runScript(char *path){
gfx_clearscreen(); gfx_clearscreen();
utils_copystring(path, &path_local); utils_copystring(path, &path_local);
res = f_open(&scriptin, path, FA_READ | FA_OPEN_EXISTING); res = f_open(&scriptin, path, FA_READ | FA_OPEN_EXISTING);
DWORD *clmt_in = f_expand_cltbl(&scriptin, BUFSIZE / 4, 0);
if (res != FR_OK){ if (res != FR_OK){
gfx_errDisplay("ParseScript", res, 1); gfx_errDisplay("ParseScript", res, 1);
return; return;

View File

@@ -1,5 +1,7 @@
#pragma once #pragma once
#define INFUNC_FAIL (int)0xC0000000
void runScript(char *path); void runScript(char *path);
void skipbrackets(); void skipbrackets();
void getfollowingchar(char end); void getfollowingchar(char end);

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

@@ -159,7 +159,7 @@ int dumpfirmware(int mmc){
return fail; return fail;
} }
/*
void dumpusersaves(int mmc){ void dumpusersaves(int mmc){
connect_mmc(mmc); connect_mmc(mmc);
mount_mmc("USER", 2); mount_mmc("USER", 2);
@@ -180,14 +180,15 @@ void dumpusersaves(int mmc){
gfx_printf("Press any key to continue"); gfx_printf("Press any key to continue");
hidWait(); hidWait();
} }
*/
int format(int mode){ 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 +199,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 +229,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 +241,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 +251,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){

View File

@@ -4,4 +4,3 @@ void displayinfo();
void displaygpio(); void displaygpio();
int format(int mode); int format(int mode);
int dumpfirmware(int mmc); int dumpfirmware(int mmc);
void dumpusersaves(int mmc);