Compare commits

..

39 Commits
2.0.0 ... 2.0.5

Author SHA1 Message Date
suchmememanyskill
acef46781d hotfix for 11.0.0. Bump version to 2.0.5 2020-12-03 21:58:38 +01:00
aspargas2
024ef7cd6e fix github workflows CI (#28)
* switch github CI to docker

* empty commit to trigger CI
2020-10-29 02:21:34 +01:00
huhenU
4b445d6c9c Add check for unmounted SD card in emmc (#26)
* Add check for unmounted SD card

* Implement it the better way and remove message Meme doesn't like

* Remove comma and remove dump option if no sd is inserted

Hopefully the last commit to this PR. Hopefully.
2020-08-11 17:12:20 +02:00
suchmememanyskill
0991c73c60 (hopefully) fix workflow file 2020-08-03 13:19:50 +02:00
suchmememanyskill
3527b6ac4d Merge branch 'dev' 2020-08-03 13:10:42 +02:00
suchmememanyskill
0146f0ddb0 Bump version 2020-08-03 13:10:02 +02:00
SuchMemeManySkill
b42b52eb43 Include a (bad) method to dump with .cnmt.nca 2020-07-14 17:38:56 +02:00
Such Meme, Many Skill
81cf8c201c Fix a few bugs in the arg parser 2020-05-29 00:07:19 +02:00
Such Meme, Many Skill
34abed91a9 Bump version 2020-05-28 23:26:01 +02:00
suchmememanyskill
0382a17f87 Add fancy badges to readme 2020-05-28 23:14:16 +02:00
suchmememanyskill
d44178a863 Update README.md 2020-05-23 22:43:35 +02:00
Such Meme, Many Skill
abf814686d Change menu around a bit 2020-05-20 02:28:43 +02:00
Such Meme, Many Skill
f8394ae323 Merge branch 'Script_Fuckery' 2020-05-20 00:20:02 +02:00
Such Meme, Many Skill
fc69dc36ee Merge lockpickrcm changes 2020-05-19 18:20:19 +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
f61fcfea32 Empty strings should be valid 2020-05-17 01:04:33 +02:00
Such Meme, Many Skill
a872b90597 Change arg parser, add some commands, may break shit 2020-05-17 00:46: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
84 changed files with 1572 additions and 4302 deletions

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

@@ -0,0 +1,23 @@
name: TegraExplorer builder
on:
push:
branches: [ master ]
pull_request:
branches: [ master ]
jobs:
build:
runs-on: ubuntu-latest
container: devkitpro/devkita64_devkitarm
steps:
- uses: actions/checkout@v1
- name: Build TegraExplorer
run: make -j$(nproc)
- uses: actions/upload-artifact@master
with:
name: TegraExplorer
path: output/TegraExplorer.bin

View File

@@ -8,10 +8,10 @@ include $(DEVKITARM)/base_rules
################################################################################
IPL_LOAD_ADDR := 0x40008000
IPL_LOAD_ADDR := 0x40003000
LPVERSION_MAJOR := 3
LPVERSION_MINOR := 0
LPVERSION_BUGFX := 0
LPVERSION_BUGFX := 5
################################################################################

View File

@@ -1,33 +1,67 @@
# TegraExplorer
[![TegraExplorer builder](https://github.com/suchmememanyskill/TegraExplorer/workflows/TegraExplorer%20builder/badge.svg)](https://github.com/suchmememanyskill/TegraExplorer/actions)
[![Downloads](https://img.shields.io/github/downloads/suchmememanyskill/TegraExplorer/total)](https://github.com/suchmememanyskill/TegraExplorer/releases)
[![Version](https://img.shields.io/github/v/release/suchmememanyskill/tegraexplorer)](https://github.com/suchmememanyskill/TegraExplorer/releases)
[![Donations](https://img.shields.io/badge/Support%20on-Ko--Fi-red)](https://ko-fi.com/suchmememanyskill)
A payload-based file explorer for your switch!
## Usage
1. Get your favorite payload injector
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
- Navigate the SD card
- Navigate the System partition of your sysnand/sysmmc
- Navigate the System partition of your sysmmc and emummc
- Interact with files
- Deleting, copying or moving files
- Deleting, copying, renaming and moving files
- Launching payloads files
- Viewing the hex data of a file
- Launching special [TegraScript](https://github.com/suchmememanyskill/TegraScript) files
- Renaming files
- Interacting with folders
- Deleting or copying folders
- Deleting, copying or renaming folders
- Creating folders
- Dumping your current firmware to sd
- Formatting the sd card
*and more*
## Support
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)
# Credits
## Credits
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
- Denn
- Dennthecafebabe
Other awesome people:
- PhazonicRidley
- Dax
- Huhen
- Bleck9999
- Exelix
- Emmo
## Screenshots
![Preview](/preview.png)

View File

@@ -1,8 +1,8 @@
/*
* Common Gfx Header
* Copyright (c) 2018 naehrwert
* Copyright (c) 2018 CTCaer
* Copyright (c) 2018 M4xw
* Copyright (C) 2018 CTCaer
* Copyright (C) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,

View File

@@ -1,6 +1,6 @@
/*
* Common Module Header
* Copyright (c) 2018 M4xw
* Copyright (C) 2018 M4xw
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,

View File

@@ -19,8 +19,8 @@
//#define IPL_STACK_TOP 0x4003FF00
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
/* --- IPL: 0x40008000 - 0x40028000 --- */
#define IPL_LOAD_ADDR 0x40008000
/* --- IPL: 0x40003000 - 0x40028000 --- */
#define IPL_LOAD_ADDR 0x40003000
#define IPL_SZ_MAX 0x20000 // 128KB.
//#define IRAM_LIB_ADDR 0x4002B000
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.

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.tagline = NULL;
h_cfg.errors = 0;
h_cfg.eks = NULL;
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
h_cfg.rcm_patched = true;
h_cfg.emummc_force_disable = false;

View File

@@ -17,7 +17,6 @@
#ifndef _CONFIG_H_
#define _CONFIG_H_
#include "../hos/hos.h"
#include "../utils/types.h"
typedef struct _hekate_config
@@ -39,7 +38,6 @@ typedef struct _hekate_config
bool rcm_patched;
u32 sbar_time_keeping;
u32 errors;
hos_eks_mbr_t *eks;
} hekate_config;
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;
}
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 pathlen = strlen(ini_path);
@@ -73,6 +73,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
char *filelist = NULL;
FIL fp;
ini_sec_t *csec = NULL;
bool firstIniRun = true;
char *filename = (char *)malloc(256);
@@ -116,10 +117,17 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
do
{
if (firstIniRun){
firstIniRun = false;
strcpy(lbuf, "[Unknown]");
lblen = 9;
}
else {
// 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')

View File

@@ -43,7 +43,7 @@ typedef struct _ini_sec_t
u32 color;
} 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);
#endif

View File

@@ -20,6 +20,9 @@
#include <string.h>
#include "gfx.h"
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
static const u8 _gfx_font[] = {
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
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.
gfx_ctxt_t gfx_ctxt;
gfx_con_t gfx_con;
extern gfx_ctxt_t gfx_ctxt;
extern gfx_con_t gfx_con;
#endif

View File

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

View File

@@ -19,7 +19,7 @@
#include <string.h>
#include "fss.h"
#include "hos.h"
// #include "hos.h"
#include "../config/config.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
@@ -79,31 +79,6 @@ typedef struct _fss_content_t
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;
@@ -224,8 +199,6 @@ out:
gfx_printf("Done!\n");
f_close(&fp);
_update_r2p(path);
return (!sept_ctxt ? 1 : sept_used);
}

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

@@ -68,7 +68,7 @@ typedef struct _hos_eks_mbr_t
u32 rsvd2[3];
} hos_eks_mbr_t;
static_assert(sizeof(hos_eks_mbr_t) < 424, "HOS EKS storage bigger than MBR!");
static_assert(sizeof(hos_eks_mbr_t) == 416, "HOS EKS storage bigger than MBR!");
typedef struct _launch_ctxt_t
{

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 st4rk
* Copyright (c) 2018-2020 CTCaer
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2018 balika011
*
* This program is free software; you can redistribute it and/or modify it
@@ -20,135 +20,30 @@
#include <string.h>
#include "pkg1.h"
#include "../gfx/gfx.h"
#include "../mem/heap.h"
#include "../sec/se.h"
#include "../utils/aarch64_util.h"
#define _NOPv7() 0xE320F000
#define SM_100_ADR 0x4002B020
PATCHSET_DEF(_secmon_1_patchset,
// 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 }
*/
#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 HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
#define HASH_ORDER_700_10x {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
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)
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //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
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //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
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //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
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0
{ "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1
{ "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0
{ "20200303104606", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //10.0.0
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
{ "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0
{ "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0
{ "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2
{ "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.1.0
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.0
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.1
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.1.0
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
{ "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.1.0
{ "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0
{ "20201030110885", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //11.0.0
{ NULL } //End.
};
@@ -159,31 +54,3 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1)
return &_pkg1_ids[i];
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"
typedef struct _patch_t
typedef struct _key_info_t
{
u32 off;
u32 val;
} patch_t;
#define PATCHSET_DEF(name, ...) \
patch_t name[] = { \
__VA_ARGS__, \
{ 0xFFFFFFFF, 0xFFFFFFFF } \
}
u32 start_offset;
u32 hks_offset;
bool hks_offset_is_from_end;
u32 alignment;
u32 hash_max;
u8 hash_order[13];
u32 es_offset;
u32 ssl_offset;
} key_info_t;
typedef struct _pkg1_id_t
{
const char *id;
u32 kb;
u32 tsec_off;
u32 pkg11_off;
u32 sec_map[3];
u32 secmon_base;
u32 warmboot_base;
bool set_warmboot;
patch_t *secmon_patchset;
patch_t *warmboot_patchset;
key_info_t key_info;
} 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);
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

File diff suppressed because it is too large Load Diff

View File

@@ -26,13 +26,11 @@
#define PKG2_SEC_KERNEL 0
#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_START 0x800
u32 pkg2_newkern_ini1_val;
u32 pkg2_newkern_ini1_start;
u32 pkg2_newkern_ini1_end;
extern u32 pkg2_newkern_ini1_val;
extern u32 pkg2_newkern_ini1_start;
extern u32 pkg2_newkern_ini1_end;
typedef struct _kernel_patch_t
{
@@ -42,25 +40,6 @@ typedef struct _kernel_patch_t
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
{
u8 ctr[0x10];
@@ -122,38 +101,8 @@ typedef struct _pkg2_kernel_id_t
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);
int pkg2_has_kip(link_t *info, u64 tid);
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
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);
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
pkg2_hdr_t *pkg2_decrypt(void *data);
#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,25 @@
#include <string.h>
#include "hos.h"
#include "fss.h"
#include "sept.h"
#include "../config/config.h"
#include "../config/ini.h"
#include "../gfx/di.h"
#include "../ianos/ianos.h"
#include "../hos/fss.h"
#include "../hos/hos.h"
#include "../libs/fatfs/ff.h"
#include "../mem/heap.h"
#include "../soc/hw_init.h"
#include "../soc/pmc.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/btn.h"
#include "../utils/list.h"
#include "../utils/types.h"
#include "../gfx/gfx.h"
#define RELOC_META_OFF 0x7C
#define PATCHED_RELOC_SZ 0x94
#define WB_RST_ADDR 0x40010ED0
@@ -57,108 +55,60 @@ u8 warmboot_reboot[] = {
#define SEPT_PRI_ADDR 0x4003F000
#define SEPT_PK1T_ADDR 0xC0400000
#define SEPT_PK1T_STACK 0x40008000
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
extern u32 color_idx;
extern boot_cfg_t b_cfg;
extern hekate_config h_cfg;
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);
void check_sept(ini_sec_t *cfg_sec)
{
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)
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
{
FIL fp;
bool fss0_sept_used = false;
// 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((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size);
*(vu32 *)SEPT_TCSZ_ADDR = tsec_size;
if (cfg_sec)
LIST_INIT(ini_sections);
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
{
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;
bool found = false;
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
{
// Only parse non config sections.
if (ini_sec->type == INI_CHOICE && strcmp(ini_sec->name, "config"))
{
LIST_FOREACH_ENTRY(ini_kv_t, kv, &ini_sec->kvs, link)
{
if (!strcmp("fss0", kv->key))
{
fss0_sept_t sept_ctxt;
sept_ctxt.kb = kb;
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
fss0_sept_used = parse_fss(NULL, kv->val, &sept_ctxt);
fss0_sept_used = load_sept_from_ffs0(&sept_ctxt);
found = true;
break;
}
}
}
if (found)
break;
}
}
if (!fss0_sept_used)
{
// 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;
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
@@ -171,13 +121,13 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
// Copy sept-secondary.
if (kb < KB_FIRMWARE_VERSION_810)
{
if (f_open(&fp, "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_00.enc", FA_READ))
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
goto error;
}
else
{
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
goto error;
}
@@ -189,46 +139,25 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
f_close(&fp);
}
b_cfg.boot_cfg |= (BOOT_CFG_AUTOBOOT_EN | BOOT_CFG_SEPT_RUN);
// Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
bool update_sept_payload = true;
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE))
{
ipl_ver_meta_t tmp_ver;
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
if (tmp_ver.magic == ipl_ver.magic)
{
if (tmp_ver.version == ipl_ver.version)
{
// Save auto boot config to sept payload, if any.
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
update_sept_payload = false;
}
f_close(&fp);
}
else
{
f_close(&fp);
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
}
free(tmp_cfg);
goto error;
}
if (update_sept_payload)
{
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
f_mkdir("sept");
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
f_close(&fp);
}
f_lseek(&fp, PATCHED_RELOC_SZ);
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
f_close(&fp);
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);
@@ -248,8 +177,8 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
(*sept)();
error:
gfx_con.mute = false;
EPRINTF("Failed to run sept\n");
EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again.");
display_backlight_brightness(100, 1000);
btn_wait();

View File

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

View File

@@ -81,8 +81,10 @@ static inline void _gf256_mul_x_le(void *block) {
static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_tweak, u32 tweak_exp, u64 sec, void *dst, void *src, u32 secsize) {
int res = 0;
u8 *pdst = (u8 *)dst;
u8 *psrc = (u8 *)src;
u8 *temptweak = (u8 *)malloc(0x10);
u32 *pdst = (u32 *)dst;
u32 *psrc = (u32 *)src;
u32 *ptweak = (u32 *)tweak;
if (regen_tweak) {
for (int i = 0xF; i >= 0; i--) {
@@ -96,34 +98,33 @@ static inline int _emmc_xts(u32 ks1, u32 ks2, u32 enc, u8 *tweak, bool regen_twe
for (u32 i = 0; i < tweak_exp * 0x20; i++)
_gf256_mul_x_le(tweak);
u8 temptweak[0x10];
memcpy(temptweak, tweak, 0x10);
//We are assuming a 0x10-aligned sector size in this implementation.
for (u32 i = 0; i < secsize / 0x10; i++) {
for (u32 j = 0; j < 0x10; j++)
pdst[j] = psrc[j] ^ tweak[j];
for (u32 j = 0; j < 4; j++)
pdst[j] = psrc[j] ^ ptweak[j];
_gf256_mul_x_le(tweak);
psrc += 0x10;
pdst += 0x10;
psrc += 4;
pdst += 4;
}
se_aes_crypt_ecb(ks2, enc, dst, secsize, src, secsize);
se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
pdst = (u8 *)dst;
pdst = (u32 *)dst;
memcpy(tweak, temptweak, 0x10);
for (u32 i = 0; i < secsize / 0x10; i++) {
for (u32 j = 0; j < 0x10; j++)
pdst[j] = pdst[j] ^ tweak[j];
for (u32 j = 0; j < 4; j++)
pdst[j] = pdst[j] ^ ptweak[j];
_gf256_mul_x_le(tweak);
pdst += 0x10;
pdst += 4;
}
res = 1;
out:;
free(temptweak);
return res;
}

View File

@@ -42,8 +42,8 @@
#include "../../storage/sdmmc.h"
extern sdmmc_storage_t sd_storage;
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
//#define EFSPRINTF(...)
//#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
#define EFSPRINTF(...)
/*--------------------------------------------------------------------------
@@ -5629,7 +5629,8 @@ FRESULT f_forward (
}
#endif /* FF_USE_FORWARD */
#pragma GCC push_options
#pragma GCC optimize ("Os")
#if FF_USE_MKFS && !FF_FS_READONLY
/*-----------------------------------------------------------------------*/
@@ -6094,7 +6095,7 @@ FRESULT f_mkfs (
LEAVE_MKFS(FR_OK);
}
#pragma GCC pop_options
#if FF_MULTI_PARTITION
/*-----------------------------------------------------------------------*/
@@ -6113,9 +6114,6 @@ FRESULT f_fdisk (
DWORD sz_disk, p_sect, b_cyl, b_sect;
FRESULT res;
BYTE *empty_buff;
empty_buff = ff_memcalloc(sizeof(BYTE), 16384);
stat = disk_initialize(pdrv);
if (stat & STA_NOINIT) return FR_NOT_READY;
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
@@ -6168,14 +6166,14 @@ FRESULT f_fdisk (
st_dword(p + 8, b_sect); /* Start sector in LBA */
st_dword(p + 12, p_sect); /* Number of sectors */
/* Next partition */
b_sect += p_sect;
for (int cursect = 0; cursect < 1024; cursect++){
disk_write(pdrv, empty_buff, b_sect + (32 * cursect), 32);
for (u32 cursect = 0; cursect < 512; cursect++){
disk_write(pdrv, buf + 0x4000, b_sect + (64 * cursect), 64);
}
b_sect += p_sect;
}
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
ff_memfree(empty_buff);
/* 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;

View File

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

View File

@@ -136,7 +136,7 @@ void *malloc(u32 size)
void *calloc(u32 num, u32 size)
{
void *res = (void *)_heap_alloc(&_heap, num * size);
memset(res, 0, num * size);
memset(res, 0, ALIGN(num * size, sizeof(hnode_t))); // Clear the aligned size.
return res;
}

View File

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

View File

@@ -57,7 +57,7 @@ typedef enum
FREQ_1600 = 1600000
} 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();
void minerva_change_freq(minerva_freq_t freq);
void minerva_periodic_training();

View File

@@ -2,7 +2,7 @@
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
*
* Copyright (c) 2018-2019 CTCaer
* Copyright (c) 2019 shchmue
* Copyright (c) 2019-2020 shchmue
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -35,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time)
// Get time.
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
time->min = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_MIN_REG) & 0x7F;
u8 hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG);
time->hour = hour & 0x1F;
if (!(val & MAX77620_RTC_24H) && (hour & MAX77620_RTC_HOUR_PM_MASK))
time->hour = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_HOUR_REG) & 0x1F;
if (!(val & MAX77620_RTC_24H) && time->hour & MAX77620_RTC_HOUR_PM_MASK)
time->hour = (time->hour & 0xF) + 12;
// Get day of week. 1: Monday to 7: Sunday.

View File

@@ -1,6 +1,8 @@
/*
* Copyright (c) 2018 naehrwert
* 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
* under the terms and conditions of the GNU General Public License,
@@ -17,6 +19,7 @@
#include <string.h>
#include "../../common/memory_map.h"
#include "../sec/se.h"
#include "../mem/heap.h"
#include "../soc/bpmp.h"
@@ -31,6 +34,9 @@ typedef struct _se_ll_t
vu32 size;
} 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)
{
u8 *pdata = (u8 *)block;
@@ -47,6 +53,22 @@ static void _gf256_mul_x(void *block)
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)
{
ll->num = 0;
@@ -73,17 +95,20 @@ static int _se_wait()
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;
static se_ll_t *ll_dst = NULL, *ll_src = NULL;
if (!ll_dst)
{
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
}
if (dst)
{
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_dst, (u32)dst, dst_size);
}
if (src)
{
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
_se_ll_init(ll_src, (u32)src, src_size);
}
@@ -99,11 +124,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);
if (src)
free(ll_src);
if (dst)
free(ll_dst);
return res;
}
@@ -142,6 +162,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
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)
{
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
@@ -150,7 +230,7 @@ void se_key_acc_ctrl(u32 ks, u32 flags)
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;
for (u32 i = 0; i < size / 4; i++)
@@ -160,6 +240,26 @@ void se_aes_key_set(u32 ks, void *key, u32 size)
}
}
void se_aes_iv_set(u32 ks, const void *iv, u32 size)
{
u32 *data = (u32 *)iv;
for (u32 i = 0; i < size / 4; i++)
{
SE(SE_KEYTABLE_REG_OFFSET) = SE_KEYTABLE_SLOT(ks) | 8 | i;
SE(SE_KEYTABLE_DATA0_REG_OFFSET) = data[i];
}
}
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)
{
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
@@ -169,6 +269,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)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
@@ -195,24 +304,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);
}
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)
{
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
@@ -223,7 +314,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_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_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);
u32 src_size_aligned = src_size & 0xFFFFFFF0;
@@ -244,12 +336,90 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
return 1;
}
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize)
// random calls were derived from Atmosphère's
int se_initialize_rng(u32 ks)
{
u8 *output_buf = (u8 *)malloc(0x10);
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_INSTANTION) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY);
SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 70001;
SE(SE_RNG_SRC_CONFIG_REG_OFFSET) = SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE);
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
int res =_se_execute(OP_START, output_buf, 0x10, NULL, 0);
free(output_buf);
return res;
}
int se_generate_random(u32 ks, void *dst, u32 size)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY);
u32 num_blocks = size >> 4;
u32 aligned_size = num_blocks << 4;
if (num_blocks)
{
SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 1;
if (!_se_execute(OP_START, dst, aligned_size, NULL, 0))
return 0;
}
if (size > aligned_size)
return _se_execute_one_block(OP_START, dst + aligned_size, size - aligned_size, NULL, 0);
return 1;
}
int se_generate_random_key(u32 ks_dst, u32 ks_src)
{
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks_src) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_MODE(RNG_MODE_NORMAL) | SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY);
SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst);
if (!_se_execute(OP_START, NULL, 0, NULL, 0))
return 0;
SE(SE_CRYPTO_KEYTABLE_DST_REG_OFFSET) = SE_CRYPTO_KEYTABLE_DST_KEY_INDEX(ks_dst) | 1;
if (!_se_execute(OP_START, NULL, 0, NULL, 0))
return 0;
return 1;
}
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_AESOUT) |
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) |
SE_CRYPTO_IV_SEL(IV_ORIGINAL);
}
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_CRYPTO_INPUT_SEL(INPUT_AHB) |
SE_CRYPTO_IV_SEL(IV_ORIGINAL);
}
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
return _se_execute(OP_START, dst, dst_size, src, src_size);
}
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize)
{
int res = 0;
u8 *tweak = (u8 *)malloc(0x10);
u8 *pdst = (u8 *)dst;
u8 *psrc = (u8 *)src;
u8 *temptweak = (u8 *)malloc(0x10);
u32 *pdst = (u32 *)dst;
u32 *psrc = (u32 *)src;
u32 *ptweak = (u32 *)tweak;
//Generate tweak.
for (int i = 0xF; i >= 0; i--)
@@ -260,28 +430,40 @@ int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *sr
if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak))
goto out;
memcpy(temptweak, tweak, 0x10);
//We are assuming a 0x10-aligned sector size in this implementation.
for (u32 i = 0; i < secsize / 0x10; i++)
{
for (u32 j = 0; j < 0x10; j++)
pdst[j] = psrc[j] ^ tweak[j];
if (!se_aes_crypt_block_ecb(ks2, enc, pdst, pdst))
goto out;
for (u32 j = 0; j < 0x10; j++)
pdst[j] = pdst[j] ^ tweak[j];
_gf256_mul_x(tweak);
psrc += 0x10;
pdst += 0x10;
for (u32 j = 0; j < 4; j++)
pdst[j] = psrc[j] ^ ptweak[j];
_gf256_mul_x_le(tweak);
psrc += 4;
pdst += 4;
}
se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
pdst = (u32 *)dst;
memcpy(tweak, temptweak, 0x10);
for (u32 i = 0; i < secsize / 0x10; i++)
{
for (u32 j = 0; j < 4; j++)
pdst[j] = pdst[j] ^ ptweak[j];
_gf256_mul_x_le(tweak);
pdst += 4;
}
res = 1;
out:;
free(temptweak);
free(tweak);
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 *psrc = (u8 *)src;
@@ -293,6 +475,62 @@ int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u
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 res;
@@ -319,76 +557,46 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
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)
{
// Setup config for X931 PRNG.
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
int res = 0;
u8 *secret = (u8 *)malloc(0x40);
u8 *ipad = (u8 *)malloc(0x40 + src_size);
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);
//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++)
if (key_size > 0x40)
{
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3);
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);
}
if (!se_calc_sha256(secret, key, key_size))
goto out;
memset(secret + 0x20, 0, 0x20);
}
else
{
memcpy(secret, key, key_size);
memset(secret + key_size, 0, 0x40 - key_size);
}
// Save SRK to PMC secure scratches.
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK);
SE(0x80) = 0; // SE_CRYPTO_LAST_BLOCK
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
u32 *secret32 = (u32 *)secret;
u32 *ipad32 = (u32 *)ipad;
u32 *opad32 = (u32 *)opad;
for (u32 i = 0; i < 0x10; i++)
{
ipad32[i] = secret32[i] ^ 0x36363636;
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
}
// End context save.
SE(SE_CONFIG_REG_OFFSET) = 0;
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
memcpy(ipad + 0x40, src, src_size);
if (!se_calc_sha256(dst, ipad, 0x40 + src_size))
goto out;
memcpy(opad + 0x40, dst, 0x20);
if (!se_calc_sha256(dst, opad, 0x60))
goto out;
// Get SRK.
u32 srk[4];
srk[0] = PMC(0xC0);
srk[1] = PMC(0xC4);
srk[2] = PMC(0x224);
srk[3] = PMC(0x228);
res = 1;
// Decrypt context.
se_aes_key_clear(3);
se_aes_key_set(3, srk, 0x10);
se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize);
se_aes_key_clear(3);
out:;
free(secret);
free(ipad);
free(opad);
return res;
}

View File

@@ -20,15 +20,26 @@
#include "../utils/types.h"
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_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
void se_aes_key_set(u32 ks, void *key, u32 size);
void se_aes_key_set(u32 ks, const void *key, u32 size);
void se_aes_iv_set(u32 ks, const void *iv, u32 size);
void se_aes_key_read(u32 ks, void *key, u32 size);
void se_aes_key_clear(u32 ks);
int se_initialize_rng(u32 ks);
int se_generate_random(u32 ks, void *dst, u32 size);
int se_generate_random_key(u32 ks_dst, u32 ks_src);
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_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_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
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_gen_prng128(void *dst);
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
#endif

View File

@@ -18,6 +18,7 @@
#include <string.h>
#include "../hos/hos.h"
#include "../sec/tsec.h"
#include "../sec/tsec_t210.h"
#include "../sec/se_t210.h"
@@ -29,7 +30,6 @@
#include "../mem/heap.h"
#include "../mem/mc.h"
#include "../utils/util.h"
#include "../hos/hos.h"
// #include "../gfx/gfx.h"
@@ -81,7 +81,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
kfuse_wait_ready();
// Configure Falcon.
//Configure Falcon.
TSEC(TSEC_DMACTL) = 0;
TSEC(TSEC_IRQMSET) =
TSEC_IRQMSET_EXT(0xFF) |
@@ -103,7 +103,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out;
}
// Load firmware or emulate memio environment for newer TSEC fw.
//Load firmware or emulate memio environment for newer TSEC fw.
if (kb == KB_FIRMWARE_VERSION_620)
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
else
@@ -127,7 +127,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
{
// Init SMMU translation for TSEC.
pdir = smmu_init_for_tsec();
smmu_init(tsec_ctxt->secmon_base);
smmu_init(0x4002B000);
// Enable SMMU
if (!smmu_is_used())
smmu_enable();
@@ -170,7 +170,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
iram = page_alloc(0x30);
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
// PKG1.1 magic offset.
pkg11_magic_off = (u32 *)(iram + ((tsec_ctxt->pkg11_off + 0x20) / 4));
pkg11_magic_off = (u32 *)(iram + (0x7000 / 4));
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
// Exception vectors
@@ -178,7 +178,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
}
// Execute firmware.
//Execute firmware.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
TSEC(TSEC_STATUS) = 0;
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
@@ -255,7 +255,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
goto out_free;
}
// Fetch result.
//Fetch result.
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
u32 buf[4];
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
@@ -275,7 +275,7 @@ out_free:;
out:;
// Disable clocks.
//Disable clocks.
clock_disable_kfuse();
clock_disable_sor1();
clock_disable_sor0();

View File

@@ -27,8 +27,6 @@ typedef struct _tsec_ctxt_t
void *fw;
u32 size;
void *pkg1;
u32 pkg11_off;
u32 secmon_base;
} tsec_ctxt_t;
typedef struct _tsec_key_data_t

View File

@@ -26,7 +26,6 @@
#include "pinmux.h"
#include "pmc.h"
#include "t210.h"
#include "uart.h"
#include "../gfx/di.h"
#include "../mem/mc.h"
#include "../mem/minerva.h"
@@ -102,7 +101,7 @@ void _config_gpios()
pinmux_config_i2c(I2C_1);
pinmux_config_i2c(I2C_5);
pinmux_config_uart(UART_A);
pinmux_config_uart(0);
// Configure volume up/down as inputs.
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
@@ -295,11 +294,6 @@ void config_hw()
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
_config_gpios();
#ifdef DEBUG_UART_PORT
clock_enable_uart(DEBUG_UART_PORT);
uart_init(DEBUG_UART_PORT, 115200);
#endif
clock_enable_cl_dvfs();
clock_enable_i2c(I2C_1);
@@ -319,6 +313,7 @@ void config_hw()
sdram_init();
bpmp_mmu_enable();
mc_enable_ahb_redirect();
// Clear flags from PMC_SCRATCH0
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD;
@@ -334,7 +329,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
// Re-enable clocks to Audio Processing Engine as a workaround to hanging.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_V) |= (1 << 10); // Enable AHUB clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_Y) |= (1 << 6); // Enable APE clock.
if (extra_reconfig)
{
@@ -357,7 +352,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
if (magic == 0xBAADF00D)
{
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, SDHCI_TIMING_SD_ID, 0);
sdmmc_init(&sd_sdmmc, SDMMC_1, SDMMC_POWER_3_3, SDMMC_BUS_WIDTH_1, 5, 0);
clock_disable_cl_dvfs();
msleep(200);

View File

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

View File

@@ -47,7 +47,7 @@ typedef struct _emummc_cfg_t
int fs_ver;
} emummc_cfg_t;
emummc_cfg_t emu_cfg;
extern emummc_cfg_t emu_cfg;
bool emummc_load_cfg();
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;
static u32 sd_mode = SD_UHS_SDR82;
sdmmc_t sd_sdmmc;
sdmmc_storage_t sd_storage;
FATFS sd_fs;
u32 sd_get_mode()
{
return sd_mode;

View File

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

View File

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

View File

@@ -29,6 +29,11 @@
#include "../soc/t210.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(...)
@@ -1158,6 +1163,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a
return 0;
}
#pragma GCC pop_options
void sdmmc_end(sdmmc_t *sdmmc)
{
if (!sdmmc->clock_stopped)

View File

@@ -21,9 +21,11 @@ enum utils_err_codes_te_call {
ERR_EMMC_WRITE_FAILED,
ERR_FILE_TOO_BIG_FOR_DEST,
ERR_SD_EJECTED,
ERR_PARSE_FAIL,
ERR_SCRIPT_LOOKUP_FAIL,
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[];
@@ -58,8 +60,7 @@ extern menu_entry mainmenu_shutdown[];
enum mainmenu_tools_return {
TOOLS_DISPLAY_INFO = 1,
TOOLS_DISPLAY_GPIO,
TOOLS_DUMPFIRMWARE,
TOOLS_DUMPUSERSAVE
TOOLS_DUMPFIRMWARE
};
extern menu_entry mainmenu_tools[];
@@ -86,7 +87,8 @@ enum fs_menu_file_return {
FILE_PAYLOAD,
FILE_SCRIPT,
FILE_HEXVIEW,
FILE_DUMPBIS
FILE_DUMPBIS,
FILE_SIGN
};
extern menu_entry fs_menu_file[];
@@ -114,3 +116,5 @@ extern gpt_entry_rule gpt_fs_rules[];
extern menu_entry mmcmenu_start[];
extern menu_entry mmcmenu_filemenu[];
extern menu_entry fwDump_typeMenu[];

View File

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

View File

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

View File

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

View File

@@ -218,8 +218,6 @@ int dump_biskeys(){
//sdmmc_storage_set_mmc_partition(&storage, 0);
//nx_emmc_gpt_parse(&sys_gpt, &storage);
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
pkg1inf.ver = pkg1_id->kb;
strcpy(pkg1inf.id, pkg1_id->id);

View File

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

View File

@@ -16,35 +16,33 @@
#include "../../utils/list.h"
#include "../../mem/heap.h"
#include "emmcmenu.h"
#include "../fs/fsreader.h"
#include "../utils/utils.h"
#include "../gfx/menu.h"
#include "../fs/fsmenu.h"
#include "emmcoperations.h"
#include "../fs/fsutils.h"
#include "../utils/menuUtils.h"
menu_entry *mmcMenuEntries = NULL;
extern sdmmc_storage_t storage;
extern emmc_part_t *system_part;
extern char *clipboard;
extern u8 clipboardhelper;
extern bool sd_mounted;
void addEntry(emmc_part_t *part, u8 property, int spot){
if (mmcMenuEntries[spot].name != NULL){
free(mmcMenuEntries[spot].name);
}
void addEntry(emmc_part_t *part, u8 property_GPT, int spot){
u32 storage = 0;
u8 property = 0;
utils_copystring(part->name, &mmcMenuEntries[spot].name);
if (property & isFS){
mmcMenuEntries[spot].storage = (u32)(property & 0x7F);
mmcMenuEntries[spot].property = ISDIR;
if (property_GPT & isFS){
storage = (u32)(property_GPT & 0x7F);
property = ISDIR;
}
else {
u64 size = 0;
int sizes = 0;
mmcMenuEntries[spot].property = 0;
u32 sizes = 0;
size = (u64)(part->lba_end + 1 - part->lba_start);
size *= (u64)NX_EMMC_BLOCKSIZE;
@@ -54,31 +52,36 @@ void addEntry(emmc_part_t *part, u8 property, int spot){
}
if (sizes > 3)
sizes = 0;
sizes = 3;
mmcMenuEntries[spot].property |= (1 << (4 + sizes));
mmcMenuEntries[spot].storage = (u32)size;
property |= SETSIZE(sizes);
storage = (u32)size;
}
mu_copySingle(part->name, storage, property, &mmcMenuEntries[spot]);
}
int fillMmcMenu(short mmcType){
int count = 4, i;
if (mmcMenuEntries != NULL)
clearfileobjects(&mmcMenuEntries);
mu_clearObjects(&mmcMenuEntries);
link_t *gpt = selectGpt(mmcType);
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
count++;
createfileobjects(count, &mmcMenuEntries);
mu_createObjects(count, &mmcMenuEntries);
for (i = 0; i < 4; i++){
utils_copystring(mmcmenu_start[i].name, &mmcMenuEntries[i].name);
mmcMenuEntries[i].property = mmcmenu_start[i].property;
mmcMenuEntries[i].storage = mmcmenu_start[i].storage;
}
if (!sd_mounted)
sd_mount();
SETBIT(mmcmenu_filemenu[3].property, ISHIDE, !sd_mounted);
SETBIT(mmcmenu_start[1].property, ISHIDE, !sd_mounted);
for (i = 0; i < 4; i++)
mu_copySingle(mmcmenu_start[i].name, mmcmenu_start[i].storage, mmcmenu_start[i].property, &mmcMenuEntries[i]);
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){
addEntry(part, checkGptRules(part->name), i++);
@@ -99,10 +102,14 @@ int handleEntries(short mmcType, menu_entry part){
fileexplorer("emmc:/", 1);
}
else {
/*
if (mmcmenu_filemenu[1].name != NULL)
free(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)
return 0;
@@ -112,7 +119,7 @@ int handleEntries(short mmcType, menu_entry part){
gfx_clearscreen();
if (part.property & isBOOT){
if (part.isNull){
res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps");
}
else {
@@ -146,7 +153,7 @@ int makeMmcMenu(short mmcType){
f_mkdir("sd:/tegraexplorer/partition_dumps");
for (int i = 0; i < count; i++){
if (mmcMenuEntries[i].property & ISMENU || mmcMenuEntries[i].property & ISDIR)
if (mmcMenuEntries[i].property & (ISMENU | ISDIR))
continue;
//gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name);
@@ -159,7 +166,7 @@ int makeMmcMenu(short mmcType){
case 2:
if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){
gfx_clearscreen();
if (!mmcFlashFile(clipboard, mmcType)){
if (!mmcFlashFile(clipboard, mmcType, true)){
gfx_printf("\nDone!");
hidWait();
}

View File

@@ -4,7 +4,7 @@
int emmcDumpSpecific(char *part, char *path);
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 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 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;
FILINFO fno;
u8 *buf;
@@ -32,7 +32,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
gfx_printf("Initializing\r");
buf = calloc(16384, sizeof(u8));
buf = calloc(BUFSIZE, sizeof(u8));
if (!buf){
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);
if (totalSize < totalSizeDest){
if (totalSize < totalSizeDest && warnings){
SWAPCOLOR(COLOR_ORANGE);
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",
3
);
@@ -78,7 +78,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
}
while (totalSectors > 0){
num = MIN(totalSectors, 32);
num = MIN(totalSectors, 128);
if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
gfx_errDisplay("restore_emmc_part", res, 5);
@@ -214,13 +214,13 @@ emmc_part_t *mmcFindPart(char *path, short mmcType){
return NULL;
}
int mmcFlashFile(char *path, short mmcType){
int mmcFlashFile(char *path, short mmcType, bool warnings){
emmc_part_t *part;
int res;
part = mmcFindPart(path, mmcType);
if (part != NULL){
res = emmcRestorePart(path, &storage, part);
res = emmcRestorePart(path, &storage, part, warnings);
emummc_storage_set_mmc_partition(&storage, 0);
return res;
}

View File

@@ -15,6 +15,8 @@
#include "../script/parser.h"
#include "../emmc/emmcoperations.h"
#include "../../hid/hid.h"
#include "../utils/menuUtils.h"
#include "savesign.h"
extern char *currentpath;
extern char *clipboard;
@@ -120,40 +122,45 @@ void copyfile(const char *src_in, const char *outfolder){
int filemenu(menu_entry file){
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)
free(fs_menu_file[i].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[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 ((file.property & (1 << temp)))
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);
if ((tempchar = fsutil_formatFileAttribs(fsutil_getnextloc(currentpath, file.name))) == NULL)
fs_menu_file[2].isHide = 1;
else {
SETBIT(fs_menu_file[2].property, ISHIDE, 0);
sprintf(fs_menu_file[2].name, "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' : '-');
fs_menu_file[2].isHide = 0;
mu_copySingle(tempchar, fs_menu_file[2].storage, fs_menu_file[2].property, &fs_menu_file[2]);
}
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[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[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){
case FILE_COPY:
fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY);
@@ -208,6 +215,17 @@ int filemenu(menu_entry file){
extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath);
fsreader_readfolder(currentpath);
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;
case -1:
return -1;

View File

@@ -11,6 +11,7 @@
#include "../../utils/sprintf.h"
#include "../utils/utils.h"
#include "../../hid/hid.h"
#include "../utils/menuUtils.h"
extern char *currentpath;
extern char *clipboard;
@@ -42,16 +43,18 @@ void copyfolder(char *in, char *out){
int foldermenu(){
int res, hidConn;
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();
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[4].property, ISHIDE, (*(currentpath + res - 1) == '/'));
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_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);

View File

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

View File

@@ -13,25 +13,15 @@
#include "../utils/utils.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){
u8* buff;
buff = calloc(16384, sizeof(u8));
buff = calloc(BUFSIZE, sizeof(u8));
int size = size_src;
int copysize;
while (size > 0){
copysize = MIN(16834, size);
copysize = MIN(BUFSIZE, size);
f_read(in_src, buff, copysize, NULL);
f_write(out_src, buff, copysize, NULL);
size -= copysize;
@@ -48,56 +38,50 @@ void gen_part(int size, FIL* in, char *path){
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){
FIL in;
int res;
u8 version[0x10];
u8 args;
u8 temp[0x4];
u32 filesizes[4];
char *tempPath;
BisFile header;
if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){
gfx_errDisplay("extract_bis_file", res, 0);
return -1;
}
f_read(&in, version, 0x10, NULL);
f_read(&in, &args, 1, NULL);
f_read(&in, &header, sizeof(BisFile), 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++){
f_read(&in, temp, 4, NULL);
filesizes[i] = DecodeInt(temp);
if (!(header.args & (BIT((7 - i)))))
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){
gfx_printf("\nExtracting BOOT0\n");
gen_part(filesizes[0], &in, fsutil_getnextloc(outfolder, "BOOT0.bin"));
}
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);
utils_copystring(fsutil_getnextloc(outfolder, filenames[i - 2]), &tempPath);
gfx_printf("Copying %s\n", filenames[i]);
fsact_copy(tempPath, fsutil_getnextloc(outfolder, filenames[i]), COPY_MODE_PRINT);
RESETCOLOR;
free(tempPath);
}

View File

@@ -7,6 +7,7 @@
#include "../common/common.h"
#include "../../libs/fatfs/ff.h"
#include "entrymenu.h"
#include "../utils/menuUtils.h"
extern char *currentpath;
extern char *clipboard;
@@ -35,7 +36,7 @@ void fileexplorer(const char *startpath, int type){
*/
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){
case FILEMENU_RETURN:
if (!strcmp(startpath, currentpath))

View File

@@ -7,6 +7,7 @@
#include "../gfx/gfxutils.h"
#include "../utils/utils.h"
#include "../../mem/heap.h"
#include "../utils/menuUtils.h"
menu_entry *fsreader_files = NULL;
char *currentpath = NULL;
@@ -29,59 +30,16 @@ void fsreader_writeclipboard(const char *in, u8 args){
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){
/*
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));
u8 property = 0;
if (attribs & AM_DIR)
fsreader_files[spot].property |= (ISDIR);
else {
/*
size = fsutil_getfilesize(fsutil_getnextloc(currentpath, name));
property |= ISDIR;
else
property |= ISNULL;
while (size > 1024){
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);
mu_copySingle(name, 0, property, &fsreader_files[spot]);
}
int fsreader_readfolder(const char *path){
@@ -89,14 +47,13 @@ int fsreader_readfolder(const char *path){
FILINFO fno;
int folderamount, res;
clearfileobjects(&fsreader_files);
createfileobjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files);
mu_clearObjects(&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;
fsreader_files[folderamount].property = fs_menu_startdir[folderamount].property;
}
for (folderamount = 0; folderamount < 3; folderamount++)
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))){
gfx_errDisplay("readfolder", res, 0);

View File

@@ -47,15 +47,6 @@ char *fsutil_getprevloc(char *current){
return ret;
}
int fsutil_getfileobjamount(menu_entry *entries){
int amount = 0;
while (entries[amount].name != NULL)
amount++;
return amount;
}
bool fsutil_checkfile(char* path){
FRESULT fr;
FILINFO fno;
@@ -88,3 +79,20 @@ int fsutil_getfolderentryamount(const char *path){
f_closedir(&dir);
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 "../../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_getprevloc(char *current);
int fsutil_getfileobjamount(menu_entry *entries);
bool fsutil_checkfile(char* path);
u64 fsutil_getfilesize(char *path);
int fsutil_getfolderentryamount(const char *path);
int extract_bis_file(char *path, char *outfolder);
char *fsutil_formatFileAttribs(char *path);

View File

@@ -0,0 +1,62 @@
#include "keys.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>
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;
}
u8 *GetKey(const char *keypath, const char *keyName){
LIST_INIT(inilist);
char *key;
u8 *hex = NULL;
if (!ini_parse(&inilist, keypath, false)){
gfx_errDisplay("GetKey", ERR_INI_PARSE_FAIL, 1);
goto out_free;
}
if ((key = getKey(keyName, &inilist)) == NULL){
gfx_errDisplay("GetKey", ERR_INI_PARSE_FAIL, 2);
goto out_free;
}
hex = getHex(key);
out_free:;
list_empty(&inilist);
return hex;
}

View File

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

View File

@@ -0,0 +1,46 @@
#include "nca.h"
#include "keys.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>
int SetHeaderKey(){
u8 *header_key = GetKey("sd:/switch/prod.keys", "header_key");
if (header_key == NULL)
return -1;
se_aes_key_set(4, header_key + 0x00, 0x10);
se_aes_key_set(5, header_key + 0x10, 0x10);
return 0;
}
int GetNcaType(char *ncaPath){
FIL fp;
u32 read_bytes = 0;
if (f_open(&fp, ncaPath, FA_READ | FA_OPEN_EXISTING))
return -1;
u8 *dec_header = (u8*)malloc(0x600);
if (f_lseek(&fp, 0x200) || f_read(&fp, dec_header, 32, &read_bytes) || read_bytes != 32){
f_close(&fp);
free(dec_header);
return -1;
}
se_aes_xts_crypt(5,4,0,1,dec_header + 0x200, dec_header, 32, 1);
u8 ContentType = dec_header[0x205];
f_close(&fp);
free(dec_header);
return ContentType;
}

View File

@@ -0,0 +1,4 @@
#pragma once
int GetNcaType(char *ncaPath);
int SetHeaderKey();

View File

@@ -0,0 +1,77 @@
#include "savesign.h"
#include "keys.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;
}
bool save_sign(const char *keypath, const char *savepath){
u8 *key = GetKey(keypath, "save_mac_key");
if (key == NULL){
return false;
}
if (!save_commit(savepath, key))
return false;
return true;
}

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, 0, 1279, 15, 0xFF);
gfx_con_setpos(0, 0);
gfx_printf("Tegraexplorer v2.0.0 | Battery: %3d%%\n", battery >> 8);
gfx_printf("Tegraexplorer v2.0.5 | Battery: %3d%%\n", battery >> 8);
RESETCOLOR;
}
@@ -41,7 +41,7 @@ u32 gfx_message(u32 color, const char* message, ...){
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)
return 0;
@@ -52,20 +52,20 @@ u32 gfx_errDisplay(char *src_func, int err, int loc){
if (err < 15)
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]);
if (loc)
gfx_printf("Loc: %d\n", loc);
gfx_printf("\nPress any button to return");
gfx_printf("\nPress any button to return\n");
RESETCOLOR;
return hidWait()->buttons;
}
int gfx_makewaitmenu(char *hiddenmessage, int timer){
int gfx_makewaitmenu(const char *hiddenmessage, int timer){
u32 start = get_tmr_s();
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;
temp = (char*) malloc (size + 1);
@@ -102,7 +102,7 @@ void gfx_printlength(int size, char *toprint){
free(temp);
}
void gfx_printandclear(char *in, int length, int endX){
void gfx_printandclear(const char *in, int length, int endX){
u32 x, y;
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;
void _gfx_sideSetYAuto(){
u32 getX, getY;
@@ -147,7 +141,7 @@ u32 gfx_sideGetY(){
return sideY;
}
void gfx_sideprintf(char* message, ...){
void gfx_sideprintf(const char* message, ...){
va_list ap;
va_start(ap, message);
@@ -158,7 +152,7 @@ void gfx_sideprintf(char* message, ...){
va_end(ap);
}
void gfx_sideprintandclear(char* message, int length){
void gfx_sideprintandclear(const char* message, int length){
gfx_con_setpos(800, sideY);
gfx_printandclear(message, length, 1279);
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);
}
int gfx_defaultWaitMenu(char *message, int time){
int gfx_defaultWaitMenu(const char *message, int time){
gfx_clearscreen();
SWAPCOLOR(COLOR_ORANGE);
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 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)
void gfx_clearscreen();
u32 gfx_message(u32 color, const char* message, ...);
u32 gfx_errDisplay(char *src_func, int err, int loc);
int gfx_makewaitmenu(char *hiddenmessage, int timer);
void gfx_printlength(int size, char *toprint);
void gfx_printandclear(char *in, int length, int endX);
void gfx_printfilesize(int size, char *type);
u32 gfx_errDisplay(const char *src_func, int err, int loc);
int gfx_makewaitmenu(const char *hiddenmessage, int timer);
void gfx_printlength(int size, const char *toprint);
void gfx_printandclear(const char *in, int length, int endX);
void gfx_sideSetY(u32 setY);
u32 gfx_sideGetY();
void gfx_sideprintf(char* message, ...);
void gfx_sideprintandclear(char* message, int length);
void gfx_sideprintf(const char* message, ...);
void gfx_sideprintandclear(const char* message, int length);
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;

View File

@@ -9,82 +9,63 @@
#include "../../soc/gpio.h"
#include "../../hid/hid.h"
#include "../fs/fsutils.h"
#include "../utils/menuUtils.h"
extern void sd_unmount();
extern bool sd_inited;
void _printentry(menu_entry *entry, bool highlighted, bool refresh, char *path){
u64 size;
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);
}
*/
#pragma GCC push_options
#pragma GCC optimize ("O2")
if (!(entry->property & ISMENU && entry->property & ISDIR)){
if (entry->property & ISNULL){
size = fsutil_getfilesize(fsutil_getnextloc(path, entry->name));
void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *path){
if (entry->isHide)
return;
while (size > 1024){
size /= 1024;
sizes++;
}
u32 color = (entry->isMenu) ? entry->storage : ((entry->isDir) ? COLOR_WHITE : COLOR_VIOLET);
if (sizes > 3)
sizes = 0;
SWAPALLCOLOR((highlighted) ? COLOR_DEFAULT : color, (highlighted) ? color : COLOR_DEFAULT);
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 (!(entry->isMenu))
gfx_printf("%c ", (entry->isDir) ? 30 : 31);
if (refresh)
gfx_printandclear(entry->name, 37, 720);
else
gfx_printlength(37, entry->name);
if (entry->property & ISDIR || entry->property & ISMENU)
if (entry->property & (ISMENU | ISDIR))
gfx_printf("\n");
else {
SWAPCOLOR(COLOR_BLUE);
SWAPBGCOLOR(COLOR_DEFAULT);
if (entry->isNull){
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_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;
}
}
bool disableB = false;
int menu_make(menu_entry *entries, int amount, char *toptext){
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 39, calculatedamount = 0;
int menu_make(menu_entry *entries, int amount, const char *toptext){
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, calculatedamount = 0, cursub = 0, temp;
u32 scrolltimer, timer, sideY;
bool refresh = true;
Inputs *input = hidRead();
@@ -92,23 +73,9 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
gfx_clearscreen();
for (int i = 0; i < amount; i++)
if (!(entries[i].property & ISMENU))
calculatedamount++;
calculatedamount = mu_countObjects(entries, amount, ISMENU);
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);
gfx_printlength(42, toptext);
@@ -131,80 +98,79 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
gfx_sideprintf("\n\n\n");
}
gfx_drawScrollBar(minscreen, maxscreen, amount);
while (!(input->a)){
for (;;){
gfx_con_setpos(0, 48);
timer = get_tmr_ms();
if (!currentpos){
while (currentpos < amount && entries[currentpos].property & (ISSKIP | ISHIDE))
currentpos++;
}
if (currentpos == amount - 1){
while (currentpos >= 1 && entries[currentpos].property & (ISSKIP | ISHIDE))
currentpos--;
}
if (!currentpos)
cursub = 1;
else if (currentpos == amount - 1)
cursub = -1;
else
cursub = 0;
if (currentpos > maxscreen){
offset += currentpos - maxscreen;
minscreen += currentpos - maxscreen;
maxscreen += currentpos - maxscreen;
while (entries[currentpos].property & (ISSKIP | ISHIDE))
currentpos += cursub;
if (currentpos > (minscreen + SCREENMAXOFFSET)){
offset += currentpos - (minscreen + SCREENMAXOFFSET);
minscreen += currentpos - (minscreen + SCREENMAXOFFSET);
refresh = true;
}
if (currentpos < minscreen){
else if (currentpos < minscreen){
offset -= minscreen - currentpos;
maxscreen -= minscreen - currentpos;
minscreen -= minscreen - currentpos;
refresh = true;
}
if (refresh || currentfolder == NULL || !calculatedamount){
for (int i = 0 + offset; i < amount && i < 40 + offset; i++)
if (!(entries[i].property & ISHIDE))
_printentry(&entries[i], (i == currentpos), refresh, toptext);
for (int i = 0 + offset; i < amount && i < SCREENMAXOFFSET + 1 + offset; i++)
_printentry(&entries[i], (i == currentpos), refresh, toptext);
}
else {
if (currentpos - minscreen > 0){
gfx_con_setpos(0, 32 + (currentpos - minscreen) * 16);
temp = (currentpos - minscreen > 0) ? 0 : 16;
gfx_con_setpos(0, 32 + temp + (currentpos - minscreen) * 16);
if (!temp)
_printentry(&entries[currentpos - 1], false, false, toptext);
}
else
gfx_con_setpos(0, 48 + (currentpos - minscreen) * 16);
_printentry(&entries[currentpos], true, false, toptext);
if (currentpos < amount - 1 && currentpos < maxscreen)
if (currentpos < MIN(amount - 1, minscreen + SCREENMAXOFFSET))
_printentry(&entries[currentpos + 1], false, false, toptext);
}
RESETCOLOR;
sideY = gfx_sideGetY();
if (!(entries[currentpos].property & ISMENU)){
if (!(entries[currentpos].isMenu)){
gfx_sideprintf("Current selection:\n");
SWAPCOLOR(COLOR_YELLOW);
gfx_sideprintandclear(entries[currentpos].name, 28);
RESETCOLOR;
gfx_sideprintf("Type: %s", (entries[currentpos].property & ISDIR) ? "Dir " : "File");
gfx_sideprintf("Type: %s", (entries[currentpos].isDir) ? "Dir " : "File");
gfx_sideSetY(sideY);
}
else
gfx_boxGrey(800, sideY, 1279, sideY + 48, 0x1B);
gfx_con_setpos(0, 703);
SWAPCOLOR(COLOR_DEFAULT);
SWAPBGCOLOR(COLOR_WHITE);
SWAPALLCOLOR(COLOR_DEFAULT, COLOR_WHITE);
gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - timer);
if (refresh)
gfx_drawScrollBar(minscreen, maxscreen, amount);
gfx_drawScrollBar(minscreen, minscreen + SCREENMAXOFFSET, amount);
refresh = false;
while (hidRead()->buttons & (KEY_B | KEY_A));
input->buttons = 0;
while (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){
scrolltimer = get_tmr_ms();
while (1){
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){
gfx_errDisplay("menu", ERR_SD_EJECTED, 0);
sd_unmount();
@@ -213,47 +179,58 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
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;
if (delay < 300){
scrolltimer = get_tmr_ms();
while (input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)){
if (scrolltimer + delay <= get_tmr_ms())
break;
input = hidRead();
}
continue;
}
if (delay > 46 && input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))
delay -= 45;
if (input->buttons & (KEY_RUP | KEY_RDOWN))
if (input->buttons & (KEY_RDOWN | KEY_RUP)){
delay = 1;
input->Lup = input->Rup;
input->Ldown = input->Rdown;
}
if (delay < 300){
if (scrolltimer + delay < get_tmr_ms()){
break;
}
}
else {
break;
}
}
if (input->buttons & (KEY_LUP | KEY_RUP) && currentpos >= 1){
currentpos--;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos >= 1)
currentpos--;
}
else if (input->buttons & (KEY_LDOWN | KEY_RDOWN) && currentpos < amount - 1){
currentpos++;
while(entries[currentpos].property & (ISSKIP | ISHIDE) && currentpos < amount - 1)
currentpos++;
if (input->a){
break;
}
else if (input->b && !disableB){
if (input->b && !disableB){
currentpos = 0;
break;
}
refresh = false;
if (delay > 46)
delay -= 45;
if (input->Lup && currentpos > 0)
cursub = -1;
else if (input->Ldown && currentpos < amount - 1)
cursub = 1;
else
cursub = 0;
if (cursub){
do {
currentpos += cursub;
} while (currentpos < amount - 1 && currentpos > 0 && entries[currentpos].property & (ISSKIP | ISHIDE));
}
}
minerva_periodic_training();
//return (mode) ? currentpos : entries[currentpos].property;
return currentpos;
}
#pragma GCC pop_options

View File

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

View File

@@ -37,24 +37,12 @@ void MainMenu_SDCard(){
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)){
/*
connect_mmc(SYSMMC);
if (!mount_mmc(emmc_fs_entries[res - 2], res - 1))
fileexplorer("emmc:/", 1);
*/
makeMmcMenu(SYSMMC);
}
}
void MainMenu_EMUMMC(){
/*
connect_mmc(EMUMMC);
if (!mount_mmc(emmc_fs_entries[res - 5], res - 4))
fileexplorer("emmc:/", 1);
*/
makeMmcMenu(EMUMMC);
makeMmcMenu(EMUMMC);
}
void MainMenu_MountSD(){
@@ -62,8 +50,7 @@ void MainMenu_MountSD(){
}
void MainMenu_Tools(){
//res = makemenu(toolsmenu, 8);
res = menu_make(mainmenu_tools, 5, "-- Tools Menu --");
res = menu_make(mainmenu_tools, 4, "-- Tools Menu --");
switch(res){
case TOOLS_DISPLAY_INFO:
@@ -71,21 +58,17 @@ void MainMenu_Tools(){
break;
case TOOLS_DISPLAY_GPIO:
displaygpio();
//makeMmcMenu(SYSMMC);
break;
case TOOLS_DUMPFIRMWARE:
dumpfirmware(SYSMMC);
break;
case TOOLS_DUMPUSERSAVE:
if ((res = utils_mmcMenu()) > 0)
dumpusersaves(res);
res = menu_make(fwDump_typeMenu, 4, "-- Fw Type --");
if (res >= 2)
dumpfirmware(SYSMMC, (res == 2));
break;
}
}
void MainMenu_SDFormat(){
//res = makemenu(formatmenu, 4);
res = menu_make(mainmenu_format, 3, "-- Format Menu --");
if (res > 0){
@@ -131,6 +114,7 @@ void MainMenu_Exit(){
case SHUTDOWN_AMS:
launch_payload("/atmosphere/reboot_payload.bin");
} //todo declock bpmp
}
func_void_ptr mainmenu_functions[] = {
@@ -153,27 +137,31 @@ void RunMenuOption(int option){
void te_main(){
int setter;
//gfx_printf("Initing controller\n");
hidInit();
//gfx_printf("Getting biskeys\n");
if (dump_biskeys() == -1){
gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0);
//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();
//gfx_printf("Loading possible EMU\n");
if (emummc_load_cfg()){
mainmenu_main[2].property |= ISHIDE;
}
//gfx_printf("Dumping gpt\n");
dumpGpt();
//gfx_printf("Disconnecting EMMC\n");
disconnect_mmc();
hidInit();
//gfx_printf("Entering main menu\n");
while (1){
//fillmainmenu();
setter = sd_mounted;
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;
int part_printf(){
SWAPCOLOR(currentcolor);
@@ -71,14 +74,14 @@ int part_printf(){
if (argv[i][0] == '@'){
int toprintint;
if (parseIntInput(argv[i], &toprintint))
return -1;
return INFUNC_FAIL;
gfx_printf("%d", toprintint);
}
else {
char *toprintstring;
if (parseStringInput(argv[i], &toprintstring))
return -1;
return INFUNC_FAIL;
gfx_printf(toprintstring);
}
@@ -91,7 +94,7 @@ int part_printf(){
int part_print_int(){
int toprint;
if (parseIntInput(argv[0], &toprint))
return -1;
return INFUNC_FAIL;
SWAPCOLOR(currentcolor);
gfx_printf("%s: %d\n", argv[0], toprint);
@@ -104,7 +107,7 @@ int part_Wait(){
SWAPCOLOR(currentcolor);
if (parseIntInput(argv[0], &arg))
return -1;
return INFUNC_FAIL;
begintime = get_tmr_s();
@@ -119,9 +122,9 @@ int part_Wait(){
int part_Check(){
int left, right;
if (parseIntInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseIntInput(argv[2], &right))
return -1;
return INFUNC_FAIL;
if (!strcmp(argv[1], "=="))
return (left == right);
@@ -136,13 +139,13 @@ int part_Check(){
else if (!strcmp(argv[1], "<"))
return (left < right);
else
return -1;
return INFUNC_FAIL;
}
int part_if(){
int condition;
if (parseIntInput(argv[0], &condition))
return -1;
return INFUNC_FAIL;
getfollowingchar('{');
@@ -164,7 +167,7 @@ int part_if(){
int part_if_args(){
int condition;
if ((condition = part_Check()) < 0)
return -1;
return INFUNC_FAIL;
getfollowingchar('{');
@@ -177,9 +180,9 @@ int part_if_args(){
int part_Math(){
int left, right;
if (parseIntInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseIntInput(argv[2], &right))
return -1;
return INFUNC_FAIL;
switch (argv[1][0]){
case '+':
@@ -191,7 +194,7 @@ int part_Math(){
case '/':
return left / right;
}
return -1;
return INFUNC_FAIL;
}
int part_SetInt(){
@@ -203,9 +206,9 @@ int part_SetInt(){
int part_SetString(){
char *arg0;
if (parseStringInput(argv[0], &arg0))
return -1;
return INFUNC_FAIL;
if (argv[1][0] != '$')
return -1;
return INFUNC_FAIL;
str_str_add(argv[1], arg0);
return 0;
@@ -215,11 +218,11 @@ int part_SetStringIndex(){
int index;
char *out;
if (parseIntInput(argv[0], &index))
return -1;
return INFUNC_FAIL;
if (argv[1][0] != '$')
return -1;
return INFUNC_FAIL;
if (str_str_index(index, &out))
return -1;
return INFUNC_FAIL;
str_str_add(argv[1], out);
return 0;
@@ -228,7 +231,10 @@ int part_SetStringIndex(){
int part_goto(){
int target = 0;
if (parseIntInput(argv[0], &target))
return -1;
return INFUNC_FAIL;
str_int_add("@RETURN", (int)f_tell(&scriptin));
f_lseek(&scriptin, target);
return 0;
}
@@ -236,14 +242,14 @@ int part_goto(){
int part_invert(){
int arg;
if (parseIntInput(argv[0], &arg))
return -1;
return INFUNC_FAIL;
return (arg) ? 0 : 1;
}
int part_fs_exists(){
char *path;
if (parseStringInput(argv[0], &path))
return -1;
return INFUNC_FAIL;
return fsutil_checkfile(path);
}
@@ -257,7 +263,7 @@ int part_ConnectMMC(){
else if (!strcmp(arg, "EMUMMC"))
connect_mmc(EMUMMC);
else
return -1;
return INFUNC_FAIL;
return 0;
}
@@ -282,6 +288,7 @@ int part_Pause(){
str_int_add("@BTN_DOWN", input->Ldown);
str_int_add("@BTN_LEFT", input->Lleft);
str_int_add("@BTN_RIGHT", input->Lright);
str_int_add("@JOYCONN", hidConnected());
return input->buttons;
}
@@ -289,11 +296,11 @@ int part_Pause(){
int part_addstrings(){
char *combined, *left, *middle;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &middle))
return -1;
return INFUNC_FAIL;
if (argv[2][0] != '$')
return -1;
return INFUNC_FAIL;
combined = calloc(strlen(left) + strlen(middle) + 1, sizeof(char));
sprintf(combined, "%s%s", left, middle);
@@ -306,7 +313,7 @@ int part_addstrings(){
int part_setColor(){
char *arg;
if (parseStringInput(argv[0], &arg))
return -1;
return INFUNC_FAIL;
if (!strcmp(arg, "RED"))
currentcolor = COLOR_RED;
@@ -323,7 +330,7 @@ int part_setColor(){
else if (!strcmp(arg, "WHITE"))
currentcolor = COLOR_WHITE;
else
return -1;
return INFUNC_FAIL;
return 0;
}
@@ -337,9 +344,9 @@ int part_fs_Move(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return -1;
return INFUNC_FAIL;
int res;
res = f_rename(left, right);
@@ -353,7 +360,7 @@ int part_fs_Delete(){
char *arg;
if (parseStringInput(argv[0], &arg))
return -1;
return INFUNC_FAIL;
int res;
res = f_unlink(arg);
@@ -367,7 +374,7 @@ int part_fs_DeleteRecursive(){
char *arg;
if (parseStringInput(argv[0], &arg))
return -1;
return INFUNC_FAIL;
return fsact_del_recursive(arg);
}
@@ -376,9 +383,9 @@ int part_fs_Copy(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return -1;
return INFUNC_FAIL;
return fsact_copy(left, right, COPY_MODE_PRINT);
}
@@ -387,9 +394,9 @@ int part_fs_CopyRecursive(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return -1;
return INFUNC_FAIL;
return fsact_copy_recursive(left, right);
}
@@ -398,7 +405,7 @@ int part_fs_MakeDir(){
char *arg;
if (parseStringInput(argv[0], &arg))
return -1;
return INFUNC_FAIL;
int res;
res = f_mkdir(arg);
@@ -415,10 +422,10 @@ int part_fs_OpenDir(){
char *path;
if (parseStringInput(argv[0], &path))
return -1;
return INFUNC_FAIL;
if (f_opendir(&dir, path))
return -1;
return INFUNC_FAIL;
isdirvalid = true;
str_int_add("@ISDIRVALID", isdirvalid);
@@ -437,7 +444,7 @@ int part_fs_CloseDir(){
int part_fs_ReadDir(){
if (!isdirvalid)
return -1;
return INFUNC_FAIL;
if (!f_readdir(&dir, &fno) && fno.fname[0]){
str_str_add("$FILENAME", fno.fname);
@@ -454,16 +461,16 @@ int part_setPrintPos(){
int left, right;
if (parseIntInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseIntInput(argv[1], &right))
return -1;
return INFUNC_FAIL;
if (left > 78)
return -1;
return INFUNC_FAIL;
if (right > 42)
return -1;
return INFUNC_FAIL;
gfx_con_setpos(left * 16, right * 16);
return 0;
@@ -473,9 +480,9 @@ int part_stringcompare(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return -1;
return INFUNC_FAIL;
return (strcmp(left, right)) ? 0 : 1;
}
@@ -483,11 +490,11 @@ int part_stringcompare(){
int part_fs_combinePath(){
char *combined, *left, *middle;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &middle))
return -1;
return INFUNC_FAIL;
if (argv[2][0] != '$')
return -1;
return INFUNC_FAIL;
combined = fsutil_getnextloc(left, middle);
@@ -500,9 +507,9 @@ int part_mmc_dumpPart(){
char *left, *right;
if (parseStringInput(argv[0], &left))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &right))
return -1;
return INFUNC_FAIL;
if (!strcmp(left, "BOOT")){
return emmcDumpBoot(right);
@@ -516,21 +523,21 @@ int part_mmc_restorePart(){
char *path;
if (parseStringInput(argv[0], &path))
return -1;
return INFUNC_FAIL;
if (currentlyMounted < 0)
return -1;
return INFUNC_FAIL;
return mmcFlashFile(path, currentlyMounted);
return mmcFlashFile(path, currentlyMounted, false);
}
int part_fs_extractBisFile(){
char *path, *outfolder;
if (parseStringInput(argv[0], &path))
return -1;
return INFUNC_FAIL;
if (parseStringInput(argv[1], &outfolder))
return -1;
return INFUNC_FAIL;
return extract_bis_file(path, outfolder);
}
@@ -544,6 +551,60 @@ int part_getPos(){
return (int)f_tell(&scriptin);
}
int part_subString(){
char *str, *sub;
int start, size;
if (parseStringInput(argv[0], &str))
return INFUNC_FAIL;
if (parseIntInput(argv[1], &start))
return INFUNC_FAIL;
if (parseIntInput(argv[2], &size))
return INFUNC_FAIL;
if (argv[3][0] != '$')
return INFUNC_FAIL;
if (start >= strlen(str))
return INFUNC_FAIL;
sub = utils_copyStringSize(str + start, size);
str_str_add(argv[3], sub);
free(sub);
return 0;
}
int part_inputString(){
char *start, *out;
int len;
if (parseStringInput(argv[0], &start))
return INFUNC_FAIL;
if (parseIntInput(argv[1], &len))
return INFUNC_FAIL;
if (argv[2][0] != '$')
return INFUNC_FAIL;
if (len > 39)
return INFUNC_FAIL;
out = utils_InputText(start, len);
if (out == NULL)
return 1;
str_str_add(argv[2], out);
free(out);
return 0;
}
int part_strLen(){
char *in;
if (parseStringInput(argv[0], &in))
return INFUNC_FAIL;
return strlen(in);
}
str_fnc_struct functions[] = {
{"printf", part_printf, 255},
{"printInt", part_print_int, 1},
@@ -560,6 +621,9 @@ str_fnc_struct functions[] = {
{"setColor", part_setColor, 1},
{"combineStrings", part_addstrings, 3},
{"compareStrings", part_stringcompare, 2},
{"subString", part_subString, 4},
{"inputString", part_inputString, 3},
{"stringLength", part_strLen, 1},
{"invert", part_invert, 1},
{"fs_exists", part_fs_exists, 1},
{"fs_move", part_fs_Move, 2},
@@ -584,6 +648,8 @@ str_fnc_struct functions[] = {
{NULL, NULL, 0}
};
#pragma GCC pop_options
int run_function(char *func_name, int *out){
for (u32 i = 0; functions[i].key != NULL; i++){
if (!strcmp(functions[i].key, func_name)){
@@ -591,8 +657,8 @@ int run_function(char *func_name, int *out){
continue;
*out = functions[i].value();
return (*out < 0) ? -1 : 0;
return (*out == INFUNC_FAIL) ? -1 : 0;
}
}
return -1;
return -2;
}

View File

@@ -16,15 +16,15 @@
#include "variables.h"
#include "../fs/fsreader.h"
#include "../utils/utils.h"
#include "../../hid/hid.h"
u32 countchars(char* in, char target) {
int countchars(const char* in, char target) {
u32 len = strlen(in);
u32 count = 0;
for (u32 i = 0; i < len; i++) {
if (in[i] == '"'){
i++;
while (in[i] != '"'){
i++;
while (in[++i] != '"'){
if (i >= len)
return -1;
}
@@ -32,54 +32,55 @@ u32 countchars(char* in, char target) {
if (in[i] == target)
count++;
}
return count;
}
char **argv = NULL;
u32 argc;
u32 splitargs(char* in) {
u32 splitargs(const char* in) {
// arg like '5, "6", @arg7'
u32 i, current = 0, count = 1, len = strlen(in), curcount = 0;
u32 i = 0, count = 1, len = strlen(in), curcount = 0, begin, end;
if ((count += countchars(in, ',')) < 0){
count += countchars(in, ',');
if (!count)
return 0;
}
/*
if (argv != NULL) {
for (i = 0; argv[i] != NULL; i++)
free(argv[i]);
free(argv);
}
*/
argv = calloc(count + 1, sizeof(char*));
for (i = 0; i < count; i++)
argv[i] = calloc(96, sizeof(char));
for (i = 0; i < len && curcount < count; i++) {
if (in[i] == ',') {
curcount++;
current = 0;
}
else if (in[i] == '@' || in[i] == '$' || in[i] == '?') {
while (in[i] != ',' && in[i] != ' ' && in[i] != ')' && i < len) {
argv[curcount][current++] = in[i++];
}
i--;
}
else if ((in[i] >= '0' && in[i] <= '9') || (in[i] >= '<' && in[i] <= '>') || in[i] == '+' || in[i] == '-' || in[i] == '*' || in[i] == '/')
argv[curcount][current++] = in[i];
else if (in[i] == '"') {
while (i < len && curcount < count) {
if (in[i] == ' ' || in[i] == ','){
i++;
while (in[i] != '"') {
argv[curcount][current++] = in[i++];
}
continue;
}
begin = i;
while (strrchr(" ,)", in[i]) == NULL){
if (in[i] == '"'){
begin = i + 1;
while (in[++i] != '"'){
if (in[i] == '\0')
return 0;
}
}
if (in[i] == '\0')
return 0;
i++;
}
end = i;
if (in[i - 1] == '"'){
end--;
}
argv[curcount++] = utils_copyStringSize(in + begin, (u32)(end - begin));
}
return count;
return curcount;
}
FIL scriptin;
@@ -201,17 +202,6 @@ void mainparser(){
getnextvalidchar();
}
/*
if (currentchar == '?'){
char *jumpname;
jumpname = readtilchar(';', ' ');
getnextchar();
str_jmp_add(jumpname, f_tell(&scriptin));
getfollowingchar('\n');
return;
}
*/
functionparser();
res = run_function(funcbuff, &out);
@@ -219,7 +209,16 @@ void mainparser(){
printerrors = true;
//gfx_printf("%s|%s|%d", funcbuff, argv[0], argc);
//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;
//gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]);
}
@@ -287,6 +286,7 @@ void runScript(char *path){
//add builtin vars
str_int_add("@EMUMMC", emu_cfg.enabled);
str_int_add("@RESULT", 0);
str_int_add("@JOYCONN", hidConnected());
str_str_add("$CURRENTPATH", currentpath);
//str_int_printall();

View File

@@ -1,5 +1,7 @@
#pragma once
#define INFUNC_FAIL (int)0xC0000000
void runScript(char *path);
void skipbrackets();
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

@@ -17,6 +17,7 @@
#include "../fs/fsutils.h"
#include "../../mem/heap.h"
#include "../utils/utils.h"
#include "../fs/nca.h"
extern bool sd_mount();
extern void sd_unmount();
@@ -93,7 +94,9 @@ void displaygpio(){
}
}
int dumpfirmware(int mmc){
// bad code ahead aaaa
int dumpfirmware(int mmc, bool daybreak){
DIR dir;
FILINFO fno;
bool fail = false;
@@ -107,6 +110,22 @@ int dumpfirmware(int mmc){
connect_mmc(mmc);
mount_mmc("SYSTEM", 2);
if (daybreak){
if (!fsutil_checkfile("sd:/switch/prod.keys")){
SWAPCOLOR(COLOR_RED);
gfx_printf("prod.keys not found.\nPress any button to exit");
hidWait();
return true;
}
if (SetHeaderKey()){
SWAPCOLOR(COLOR_RED);
gfx_printf("Failed to find header key.\nPress any button to exit");
hidWait();
return true;
}
}
gfx_printf("PKG1 version: %d\n", pkg1.ver);
gfx_printf("Creating folders...\n");
@@ -115,7 +134,24 @@ int dumpfirmware(int mmc){
sdbase = calloc(32 + strlen(pkg1.id), sizeof(char));
sprintf(sdbase, "sd:/tegraexplorer/Firmware/%d (%s)", pkg1.ver, pkg1.id);
gfx_printf("Out: %s\n", sdbase);
if (fsutil_checkfile(sdbase)){
SWAPCOLOR(COLOR_RED);
gfx_printf("Destination folder already exists.\nPress X to delete this folder, any other button to cancel\nPath: %s", sdbase);
Inputs *input = hidWait();
if (!input->x){
free(sdbase);
return true;
}
else {
SWAPCOLOR(COLOR_WHITE);
gfx_printf("\nDeleting folder..\n");
fsact_del_recursive(sdbase);
}
}
gfx_printf("\rOut: %s\n", sdbase);
f_mkdir(sdbase);
if ((ret = f_opendir(&dir, sysbase)))
@@ -127,16 +163,39 @@ int dumpfirmware(int mmc){
printerrors = 0;
while(!f_readdir(&dir, &fno) && fno.fname[0] && !fail){
utils_copystring(fsutil_getnextloc(sdbase, fno.fname), &sdpath);
utils_copystring(fsutil_getnextloc(sysbase, fno.fname), &syspathtemp);
if (fno.fattrib & AM_DIR){
utils_copystring(fsutil_getnextloc(syspathtemp, "00"), &syspath);
free(syspathtemp);
}
else
syspath = syspathtemp;
if (daybreak){
u8 ContentType = GetNcaType(syspath);
if (ContentType < 0){
fail = true;
continue;
}
char *temp;
utils_copystring(fsutil_getnextloc(sdbase, fno.fname), &temp);
if (ContentType == 0x01){
sdpath = calloc(strlen(temp) + 6, 1);
strcpy(sdpath, temp);
memcpy(sdpath + strlen(temp) - 4, ".cnmt.nca", 10);
free(temp);
}
else {
sdpath = temp;
}
}
else
utils_copystring(fsutil_getnextloc(sdbase, fno.fname), &sdpath);
ret = fsact_copy(syspath, sdpath, 0);
gfx_printf("%d %s\r", ++amount, fno.fname);
@@ -145,7 +204,9 @@ int dumpfirmware(int mmc){
fail = true;
free(sdpath);
free(syspath);
free(syspathtemp);
if (syspath != syspathtemp)
free(syspath);
}
printerrors = 1;
@@ -159,7 +220,7 @@ int dumpfirmware(int mmc){
return fail;
}
/*
void dumpusersaves(int mmc){
connect_mmc(mmc);
mount_mmc("USER", 2);
@@ -180,14 +241,15 @@ void dumpusersaves(int mmc){
gfx_printf("Press any key to continue");
hidWait();
}
*/
int format(int mode){
gfx_clearscreen();
int res;
bool fatalerror = false;
DWORD plist[] = {666, 61145088};
DWORD plist[] = {666, 61145088, 0, 0};
u32 timer, totalsectors, alignedsectors, extrasectors;
BYTE work[FF_MAX_SS];
u8 *work;
DWORD clustsize = 32768;
BYTE formatoptions = 0;
formatoptions |= (FM_FAT32);
@@ -198,6 +260,15 @@ int format(int mode){
timer = get_tmr_s();
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 (totalsectors < 83886080){
gfx_printf("%kYou seem to be running this on a <=32GB SD\nNot enough free space for emummc!", COLOR_RED);
@@ -219,7 +290,7 @@ int format(int mode){
if (!fatalerror){
gfx_printf("\nPartitioning SD...\n");
res = f_fdisk(0, plist, &work);
res = f_fdisk(0, plist, work);
if (res){
gfx_printf("%kf_fdisk returned %d!\n", COLOR_RED, res);
@@ -231,7 +302,7 @@ int format(int mode){
if (!fatalerror){
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){
gfx_printf("%kf_mkfs returned %d!\n", COLOR_RED, res);
@@ -241,6 +312,8 @@ int format(int mode){
gfx_printf("Smells like a formatted SD\n\n");
}
free(work);
sd_unmount();
if (!fatalerror){

View File

@@ -1,7 +1,7 @@
#pragma once
#include "../../utils/types.h"
void displayinfo();
void displaygpio();
int format(int mode);
int dumpfirmware(int mmc);
void dumpusersaves(int mmc);
int dumpfirmware(int mmc, bool daybreak);

View File

@@ -193,3 +193,13 @@ char *utils_InputText(char *start, int maxLen){
return buff;
}
char *utils_copyStringSize(const char *in, int size){
if (size > strlen(in) || size < 0)
size = strlen(in);
char *out = calloc(size + 1, 1);
//strncpy(out, in, size);
memcpy(out, in, size);
return out;
}

View File

@@ -24,3 +24,4 @@ int utils_mmcMenu();
void utils_copystring(const char *in, char **out);
char *utils_InputText(char *start, int maxLen);
void utils_takeScreenshot();
char *utils_copyStringSize(const char *in, int size);