Compare commits
39 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
acef46781d | ||
|
|
024ef7cd6e | ||
|
|
4b445d6c9c | ||
|
|
0991c73c60 | ||
|
|
3527b6ac4d | ||
|
|
0146f0ddb0 | ||
|
|
b42b52eb43 | ||
|
|
81cf8c201c | ||
|
|
34abed91a9 | ||
|
|
0382a17f87 | ||
|
|
d44178a863 | ||
|
|
abf814686d | ||
|
|
f8394ae323 | ||
|
|
fc69dc36ee | ||
|
|
a8e86c2de3 | ||
|
|
f61fcfea32 | ||
|
|
a872b90597 | ||
|
|
6934e1422f | ||
|
|
f49245e4ab | ||
|
|
9075f20854 | ||
|
|
6bc474a981 | ||
|
|
91536268ad | ||
|
|
b484dc11d8 | ||
|
|
14a3a39c01 | ||
|
|
6868ef3536 | ||
|
|
97810335ed | ||
|
|
43617ef511 | ||
|
|
19fe7f15a9 | ||
|
|
73ca98c6a8 | ||
|
|
12eecd2466 | ||
|
|
40cb293db3 | ||
|
|
f09a098c77 | ||
|
|
30f0e88d0a | ||
|
|
c4c5d57af3 | ||
|
|
00a58f12ec | ||
|
|
74ba5bb776 | ||
|
|
a9ea9725d4 | ||
|
|
9799e2b47e | ||
|
|
6681a35b2c |
23
.github/workflows/builder.yml
vendored
Normal file
23
.github/workflows/builder.yml
vendored
Normal 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
|
||||||
4
Makefile
4
Makefile
@@ -8,10 +8,10 @@ include $(DEVKITARM)/base_rules
|
|||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
IPL_LOAD_ADDR := 0x40008000
|
IPL_LOAD_ADDR := 0x40003000
|
||||||
LPVERSION_MAJOR := 3
|
LPVERSION_MAJOR := 3
|
||||||
LPVERSION_MINOR := 0
|
LPVERSION_MINOR := 0
|
||||||
LPVERSION_BUGFX := 0
|
LPVERSION_BUGFX := 5
|
||||||
|
|
||||||
################################################################################
|
################################################################################
|
||||||
|
|
||||||
|
|||||||
48
README.md
48
README.md
@@ -1,33 +1,67 @@
|
|||||||
# TegraExplorer
|
# TegraExplorer
|
||||||
|
|
||||||
|
[](https://github.com/suchmememanyskill/TegraExplorer/actions)
|
||||||
|
[](https://github.com/suchmememanyskill/TegraExplorer/releases)
|
||||||
|
[](https://github.com/suchmememanyskill/TegraExplorer/releases)
|
||||||
|
[](https://ko-fi.com/suchmememanyskill)
|
||||||
|
|
||||||
A payload-based file explorer for your switch!
|
A payload-based file explorer for your switch!
|
||||||
|
|
||||||
## Usage
|
## Usage
|
||||||
1. Get your favorite payload injector
|
1. Get your favorite payload injector
|
||||||
2. Inject TegraExplorer as a payload
|
2. Inject TegraExplorer as a payload
|
||||||
|
|
||||||
Navigate around the menus using the vol+, vol- and power buttons
|
Navigate around the menus using the joycons.
|
||||||
|
- A: Select
|
||||||
|
- B: Back
|
||||||
|
- Left Joystick up/down (Dpad or joystick): navigate menus up/down
|
||||||
|
- Right Joystick up/down: fast menu navigation up/down
|
||||||
|
- Capture (Minerva only): Take a screenshot
|
||||||
|
- L3/R3 (Press joysticks in): Recalibrate centerpoint
|
||||||
|
|
||||||
|
If you do not have your joycons connected:
|
||||||
|
- Power -> A
|
||||||
|
- Vol+ -> Left Joystick up
|
||||||
|
- Vol- -> Left Joystick down
|
||||||
|
|
||||||
## Functions
|
## Functions
|
||||||
- Navigate the SD card
|
- Navigate the SD card
|
||||||
- Navigate the System partition of your sysnand/sysmmc
|
- Navigate the System partition of your sysmmc and emummc
|
||||||
- Interact with files
|
- Interact with files
|
||||||
- Deleting, copying or moving files
|
- Deleting, copying, renaming and moving files
|
||||||
- Launching payloads files
|
- Launching payloads files
|
||||||
- Viewing the hex data of a file
|
- Viewing the hex data of a file
|
||||||
|
- Launching special [TegraScript](https://github.com/suchmememanyskill/TegraScript) files
|
||||||
|
- Renaming files
|
||||||
- Interacting with folders
|
- Interacting with folders
|
||||||
- Deleting or copying folders
|
- Deleting, copying or renaming folders
|
||||||
|
- Creating folders
|
||||||
- Dumping your current firmware to sd
|
- Dumping your current firmware to sd
|
||||||
- Formatting the sd card
|
- Formatting the sd card
|
||||||
|
|
||||||
|
*and more*
|
||||||
|
|
||||||
## Support
|
## Support
|
||||||
|
|
||||||
For general CFW support, go to the [Nintendo Homebrew](https://discord.gg/C29hYvh) discord
|
For general CFW support, go to the [Nintendo Homebrew](https://discord.gg/C29hYvh) discord
|
||||||
|
|
||||||
For question specifically for TegraExplorer, go to [my discord](https://discord.gg/aH9rsuP)
|
For question specifically for TegraExplorer, go to [my discord](https://discord.gg/aH9rsuP)
|
||||||
|
|
||||||
# Credits
|
## Credits
|
||||||
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate)
|
Based on [Lockpick_RCM](https://github.com/shchmue/Lockpick_RCM), and thus also based on [Hekate](https://github.com/CTCaer/hekate)
|
||||||
|
|
||||||
Lots of help from:
|
Awesome people who helped with this project:
|
||||||
- shchmue
|
- shchmue
|
||||||
- Denn
|
- Dennthecafebabe
|
||||||
|
|
||||||
|
Other awesome people:
|
||||||
|
- PhazonicRidley
|
||||||
|
- Dax
|
||||||
|
- Huhen
|
||||||
|
- Bleck9999
|
||||||
|
- Exelix
|
||||||
|
- Emmo
|
||||||
|
|
||||||
|
## Screenshots
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
@@ -1,9 +1,9 @@
|
|||||||
/*
|
/*
|
||||||
* Common Gfx Header
|
* Common Gfx Header
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (C) 2018 CTCaer
|
||||||
* Copyright (c) 2018 M4xw
|
* Copyright (C) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
* version 2, as published by the Free Software Foundation.
|
* version 2, as published by the Free Software Foundation.
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
/*
|
/*
|
||||||
* Common Module Header
|
* Common Module Header
|
||||||
* Copyright (c) 2018 M4xw
|
* Copyright (C) 2018 M4xw
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
|
|||||||
@@ -19,8 +19,8 @@
|
|||||||
|
|
||||||
//#define IPL_STACK_TOP 0x4003FF00
|
//#define IPL_STACK_TOP 0x4003FF00
|
||||||
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
|
/* --- BIT/BCT: 0x40000000 - 0x40003000 --- */
|
||||||
/* --- IPL: 0x40008000 - 0x40028000 --- */
|
/* --- IPL: 0x40003000 - 0x40028000 --- */
|
||||||
#define IPL_LOAD_ADDR 0x40008000
|
#define IPL_LOAD_ADDR 0x40003000
|
||||||
#define IPL_SZ_MAX 0x20000 // 128KB.
|
#define IPL_SZ_MAX 0x20000 // 128KB.
|
||||||
//#define IRAM_LIB_ADDR 0x4002B000
|
//#define IRAM_LIB_ADDR 0x4002B000
|
||||||
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
|
#define SDRAM_PARAMS_ADDR 0x40030000 // SDRAM extraction buffer during sdram init.
|
||||||
|
|||||||
BIN
preview.png
Normal file
BIN
preview.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 13 KiB |
@@ -45,7 +45,6 @@ void set_default_configuration()
|
|||||||
h_cfg.brand = NULL;
|
h_cfg.brand = NULL;
|
||||||
h_cfg.tagline = NULL;
|
h_cfg.tagline = NULL;
|
||||||
h_cfg.errors = 0;
|
h_cfg.errors = 0;
|
||||||
h_cfg.eks = NULL;
|
|
||||||
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
h_cfg.sept_run = EMC(EMC_SCRATCH0) & EMC_SEPT_RUN;
|
||||||
h_cfg.rcm_patched = true;
|
h_cfg.rcm_patched = true;
|
||||||
h_cfg.emummc_force_disable = false;
|
h_cfg.emummc_force_disable = false;
|
||||||
|
|||||||
@@ -17,7 +17,6 @@
|
|||||||
#ifndef _CONFIG_H_
|
#ifndef _CONFIG_H_
|
||||||
#define _CONFIG_H_
|
#define _CONFIG_H_
|
||||||
|
|
||||||
#include "../hos/hos.h"
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
typedef struct _hekate_config
|
typedef struct _hekate_config
|
||||||
@@ -39,7 +38,6 @@ typedef struct _hekate_config
|
|||||||
bool rcm_patched;
|
bool rcm_patched;
|
||||||
u32 sbar_time_keeping;
|
u32 sbar_time_keeping;
|
||||||
u32 errors;
|
u32 errors;
|
||||||
hos_eks_mbr_t *eks;
|
|
||||||
} hekate_config;
|
} hekate_config;
|
||||||
|
|
||||||
void set_default_configuration();
|
void set_default_configuration();
|
||||||
|
|||||||
@@ -64,7 +64,7 @@ ini_sec_t *_ini_create_section(link_t *dst, ini_sec_t *csec, char *name, u8 type
|
|||||||
return csec;
|
return csec;
|
||||||
}
|
}
|
||||||
|
|
||||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
int ini_parse(link_t *dst, const char *ini_path, bool is_dir)
|
||||||
{
|
{
|
||||||
u32 lblen;
|
u32 lblen;
|
||||||
u32 pathlen = strlen(ini_path);
|
u32 pathlen = strlen(ini_path);
|
||||||
@@ -73,6 +73,7 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
char *filelist = NULL;
|
char *filelist = NULL;
|
||||||
FIL fp;
|
FIL fp;
|
||||||
ini_sec_t *csec = NULL;
|
ini_sec_t *csec = NULL;
|
||||||
|
bool firstIniRun = true;
|
||||||
|
|
||||||
char *filename = (char *)malloc(256);
|
char *filename = (char *)malloc(256);
|
||||||
|
|
||||||
@@ -116,10 +117,17 @@ int ini_parse(link_t *dst, char *ini_path, bool is_dir)
|
|||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
|
if (firstIniRun){
|
||||||
|
firstIniRun = false;
|
||||||
|
strcpy(lbuf, "[Unknown]");
|
||||||
|
lblen = 9;
|
||||||
|
}
|
||||||
|
else {
|
||||||
// Fetch one line.
|
// Fetch one line.
|
||||||
lbuf[0] = 0;
|
lbuf[0] = 0;
|
||||||
f_gets(lbuf, 512, &fp);
|
f_gets(lbuf, 512, &fp);
|
||||||
lblen = strlen(lbuf);
|
lblen = strlen(lbuf);
|
||||||
|
}
|
||||||
|
|
||||||
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
// Remove trailing newline. Depends on 'FF_USE_STRFUNC 2' that removes \r.
|
||||||
if (lblen && lbuf[lblen - 1] == '\n')
|
if (lblen && lbuf[lblen - 1] == '\n')
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ typedef struct _ini_sec_t
|
|||||||
u32 color;
|
u32 color;
|
||||||
} ini_sec_t;
|
} ini_sec_t;
|
||||||
|
|
||||||
int ini_parse(link_t *dst, char *ini_path, bool is_dir);
|
int ini_parse(link_t *dst, const char *ini_path, bool is_dir);
|
||||||
char *ini_check_payload_section(ini_sec_t *cfg);
|
char *ini_check_payload_section(ini_sec_t *cfg);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -20,6 +20,9 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "gfx.h"
|
#include "gfx.h"
|
||||||
|
|
||||||
|
gfx_ctxt_t gfx_ctxt;
|
||||||
|
gfx_con_t gfx_con;
|
||||||
|
|
||||||
static const u8 _gfx_font[] = {
|
static const u8 _gfx_font[] = {
|
||||||
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
|
0x00, 0x0C, 0x12, 0x7E, 0x42, 0x42, 0x7E, 0x00, // Char 030 (folder)
|
||||||
0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file)
|
0x00, 0x0E, 0x12, 0x22, 0x22, 0x22, 0x3E, 0x00, // Char 031 (file)
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ void gfx_boxGrey(int x0, int y0, int x1, int y1, u8 shade);
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
// Global gfx console and context.
|
// Global gfx console and context.
|
||||||
gfx_ctxt_t gfx_ctxt;
|
extern gfx_ctxt_t gfx_ctxt;
|
||||||
gfx_con_t gfx_con;
|
extern gfx_con_t gfx_con;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#define BIT(n) (1 << n)
|
#define BIT(n) (1U << n)
|
||||||
#define KEY_A BIT(3)
|
#define KEY_A BIT(3)
|
||||||
#define KEY_B BIT(2)
|
#define KEY_B BIT(2)
|
||||||
#define KEY_Y BIT(0)
|
#define KEY_Y BIT(0)
|
||||||
|
|||||||
@@ -19,7 +19,7 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "fss.h"
|
#include "fss.h"
|
||||||
#include "hos.h"
|
// #include "hos.h"
|
||||||
#include "../config/config.h"
|
#include "../config/config.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
@@ -79,31 +79,6 @@ typedef struct _fss_content_t
|
|||||||
char name[0x10];
|
char name[0x10];
|
||||||
} fss_content_t;
|
} 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)
|
int parse_fss(launch_ctxt_t *ctxt, const char *path, fss0_sept_t *sept_ctxt)
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
@@ -224,8 +199,6 @@ out:
|
|||||||
gfx_printf("Done!\n");
|
gfx_printf("Done!\n");
|
||||||
f_close(&fp);
|
f_close(&fp);
|
||||||
|
|
||||||
_update_r2p(path);
|
|
||||||
|
|
||||||
return (!sept_ctxt ? 1 : sept_used);
|
return (!sept_ctxt ? 1 : sept_used);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
953
source/hos/hos.c
953
source/hos/hos.c
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -68,7 +68,7 @@ typedef struct _hos_eks_mbr_t
|
|||||||
u32 rsvd2[3];
|
u32 rsvd2[3];
|
||||||
} hos_eks_mbr_t;
|
} 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
|
typedef struct _launch_ctxt_t
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
|
|
||||||
@@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 st4rk
|
* Copyright (c) 2018 st4rk
|
||||||
* Copyright (c) 2018-2020 CTCaer
|
* Copyright (c) 2018-2019 CTCaer
|
||||||
* Copyright (c) 2018 balika011
|
* Copyright (c) 2018 balika011
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
@@ -20,135 +20,30 @@
|
|||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "pkg1.h"
|
#include "pkg1.h"
|
||||||
#include "../gfx/gfx.h"
|
|
||||||
#include "../mem/heap.h"
|
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../utils/aarch64_util.h"
|
|
||||||
|
|
||||||
#define _NOPv7() 0xE320F000
|
#define HASH_ORDER_100_100 {2, 3, 4, 0, 5, 6, 1}
|
||||||
|
#define HASH_ORDER_200_510 {2, 3, 4, 0, 5, 7, 10, 12, 11, 6, 8, 1}
|
||||||
#define SM_100_ADR 0x4002B020
|
#define HASH_ORDER_600_620 {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 1}
|
||||||
PATCHSET_DEF(_secmon_1_patchset,
|
#define HASH_ORDER_700_10x {6, 5, 10, 7, 8, 2, 3, 4, 0, 12, 11, 9, 1}
|
||||||
// Patch the relocator to be able to run from SM_100_ADR.
|
|
||||||
{ 0x1E0, _ADRP(0, 0x7C013000 - _PAGEOFF(SM_100_ADR)) },
|
|
||||||
//Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0x9F0 + 0xADC, _NOP() }, //Header signature.
|
|
||||||
{ 0x9F0 + 0xB8C, _NOP() }, //Version.
|
|
||||||
{ 0x9F0 + 0xBB0, _NOP() } //Sections SHA2.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_2_patchset,
|
|
||||||
// Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0xAC8 + 0xAAC, _NOP() }, //Header signature.
|
|
||||||
{ 0xAC8 + 0xB3C, _NOP() }, //Version.
|
|
||||||
{ 0xAC8 + 0xB58, _NOP() } //Sections SHA2.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_3_patchset,
|
|
||||||
// Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0xAC8 + 0xA30, _NOP() }, //Header signature.
|
|
||||||
{ 0xAC8 + 0xAB4, _NOP() }, //package2 structure.
|
|
||||||
{ 0xAC8 + 0xAC0, _NOP() }, //Version.
|
|
||||||
{ 0xAC8 + 0xADC, _NOP() } //Sections SHA2.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_4_patchset,
|
|
||||||
// Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0x2300 + 0x5D80, _NOP() }, //package2 structure.
|
|
||||||
{ 0x2300 + 0x5D8C, _NOP() }, //Version.
|
|
||||||
{ 0x2300 + 0x5EFC, _NOP() }, //Header signature.
|
|
||||||
{ 0xAC8 + 0xA2C, _NOP() } //Sections SHA2.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_5_patchset,
|
|
||||||
// Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0xDA8 + 0x9D8, _NOP() }, //package2 structure.
|
|
||||||
{ 0xDA8 + 0x9E4, _NOP() }, //Version.
|
|
||||||
{ 0xDA8 + 0xC9C, _NOP() }, //Header signature.
|
|
||||||
{ 0xDA8 + 0x1038, _NOP() } //Sections SHA2.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_6_patchset,
|
|
||||||
// Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0xDC8 + 0x820, _NOP() }, //package2 structure.
|
|
||||||
{ 0xDC8 + 0x82C, _NOP() }, //Version.
|
|
||||||
{ 0xDC8 + 0xE90, _NOP() }, //Header signature.
|
|
||||||
{ 0xDC8 + 0x112C, _NOP() } //Sections SHA2.
|
|
||||||
// Fix sleep mode for debug.
|
|
||||||
// { 0x1A68 + 0x3854, 0x94000E45 }, //gpio_config_for_uart.
|
|
||||||
// { 0x1A68 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
|
||||||
// { 0x1A68 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
|
||||||
// { 0x1A68 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
|
||||||
// { 0x1A68 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
|
||||||
// { 0x1A68 + 0x3868, 0x94000C8C }, //uart_configure.
|
|
||||||
// { 0x1A68 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_secmon_620_patchset,
|
|
||||||
// Patch package2 decryption and signature/hash checks.
|
|
||||||
{ 0xDC8 + 0x604, _NOP() }, //package2 structure.
|
|
||||||
{ 0xDC8 + 0x610, _NOP() }, //Version.
|
|
||||||
{ 0xDC8 + 0xC74, _NOP() }, //Header signature.
|
|
||||||
{ 0xDC8 + 0xF10, _NOP() } //Sections SHA2.
|
|
||||||
// Fix sleep mode for debug.
|
|
||||||
// { 0x2AC8 + 0x3854, 0x94000F42 }, //gpio_config_for_uart.
|
|
||||||
// { 0x2AC8 + 0x3858, 0x97FFFC0F }, //clkrst_reboot_uarta.
|
|
||||||
// { 0x2AC8 + 0x385C, 0x52A00021 }, //MOV W1, #0x10000 ; baudrate.
|
|
||||||
// { 0x2AC8 + 0x3860, 0x2A1F03E0 }, //MOV W0, WZR ; uart_port -> A.
|
|
||||||
// { 0x2AC8 + 0x3864, 0x72984001 }, //MOVK W1, #0xC200 ; baudrate.
|
|
||||||
// { 0x2AC8 + 0x3868, 0x94000D89 }, //uart_configure.
|
|
||||||
// { 0x2AC8 + 0x3A6C, _NOP() } // warmboot UARTA cfg.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_1_patchset,
|
|
||||||
{ 0x4DC, _NOPv7() } // Fuse check.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_2_patchset,
|
|
||||||
{ 0x4DC, _NOPv7() } // Fuse check.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_3_patchset,
|
|
||||||
{ 0x4DC, _NOPv7() }, // Fuse check.
|
|
||||||
{ 0x4F0, _NOPv7() } // Segment id check.
|
|
||||||
);
|
|
||||||
|
|
||||||
PATCHSET_DEF(_warmboot_4_patchset,
|
|
||||||
{ 0x544, _NOPv7() }, // Fuse check.
|
|
||||||
{ 0x558, _NOPv7() } // Segment id check.
|
|
||||||
);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* package1.1 header: <wb, ldr, sm>
|
|
||||||
* package1.1 layout:
|
|
||||||
* 1.0: {sm, ldr, wb} { 2, 1, 0 }
|
|
||||||
* 2.0: {wb, ldr, sm} { 0, 1, 2 }
|
|
||||||
* 3.0: {wb, ldr, sm} { 0, 1, 2 }
|
|
||||||
* 3.1: {wb, ldr, sm} { 0, 1, 2 }
|
|
||||||
* 4.0: {ldr, sm, wb} { 1, 2, 0 }
|
|
||||||
* 5.0: {ldr, sm, wb} { 1, 2, 0 }
|
|
||||||
* 6.0: {ldr, sm, wb} { 1, 2, 0 }
|
|
||||||
* 6.2: {ldr, sm, wb} { 1, 2, 0 }
|
|
||||||
* 7.0: {ldr, sm, wb} { 1, 2, 0 }
|
|
||||||
*/
|
|
||||||
|
|
||||||
static const pkg1_id_t _pkg1_ids[] = {
|
static const pkg1_id_t _pkg1_ids[] = {
|
||||||
{ "20161121183008", 0, 0x1900, 0x3FE0, { 2, 1, 0 }, SM_100_ADR, 0x8000D000, true, _secmon_1_patchset, _warmboot_1_patchset }, //1.0.0 (Patched relocator)
|
{ "20161121183008", 0, {0x1b517, 0x125bc2, 1, 16, 6, HASH_ORDER_100_100, 0, 0x449dc} }, //1.0.0
|
||||||
{ "20170210155124", 0, 0x1900, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_2_patchset, _warmboot_2_patchset }, //2.0.0 - 2.3.0
|
{ "20170210155124", 0, {0x1d226, 0x26fe, 0, 16, 11, HASH_ORDER_200_510, 0x557b, 0x3d41a} }, //2.0.0 - 2.3.0
|
||||||
{ "20170519101410", 1, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.0
|
{ "20170519101410", 1, {0x1ffa6, 0x298b, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.0
|
||||||
{ "20170710161758", 2, 0x1A00, 0x3FE0, { 0, 1, 2 }, 0x4002D000, 0x8000D000, true, _secmon_3_patchset, _warmboot_3_patchset }, //3.0.1 - 3.0.2
|
{ "20170710161758", 2, {0x20026, 0x29ab, 0, 16, 11, HASH_ORDER_200_510, 0x552d, 0x3cb81} }, //3.0.1 - 3.0.2
|
||||||
{ "20170921172629", 3, 0x1800, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_4_patchset, _warmboot_4_patchset }, //4.0.0 - 4.1.0
|
{ "20170921172629", 3, {0x1c64c, 0x37eb, 0, 16, 11, HASH_ORDER_200_510, 0x5382, 0x3711c} }, //4.0.0 - 4.1.0
|
||||||
{ "20180220163747", 4, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003B000, false, _secmon_5_patchset, _warmboot_4_patchset }, //5.0.0 - 5.1.0
|
{ "20180220163747", 4, {0x1f3b4, 0x465b, 0, 16, 11, HASH_ORDER_200_510, 0x5a63, 0x37901} }, //5.0.0 - 5.1.0
|
||||||
{ "20180802162753", 5, 0x1900, 0x3FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_6_patchset, _warmboot_4_patchset }, //6.0.0 - 6.1.0
|
{ "20180802162753", 5, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.0.0 - 6.1.0
|
||||||
{ "20181107105733", 6, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x4002B000, 0x4003D800, false, _secmon_620_patchset, _warmboot_4_patchset }, //6.2.0
|
{ "20181107105733", 6, {0x27350, 0x17ff5, 1, 8, 11, HASH_ORDER_600_620, 0x5674, 0x1d5be} }, //6.2.0
|
||||||
{ "20181218175730", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.0
|
{ "20181218175730", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.0
|
||||||
{ "20190208150037", 7, 0x0F00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //7.0.1
|
{ "20190208150037", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //7.0.1
|
||||||
{ "20190314172056", 7, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.0.0 - 8.0.1
|
{ "20190314172056", 7, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.0.0 - 8.0.1
|
||||||
{ "20190531152432", 8, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //8.1.0
|
{ "20190531152432", 8, {0x29c50, 0x6a73, 0, 8, 12, HASH_ORDER_700_10x, 0x5563, 0x1d437} }, //8.1.0
|
||||||
{ "20190809135709", 9, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.0.0 - 9.0.1
|
{ "20190809135709", 9, {0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.0.0 - 9.0.1
|
||||||
{ "20191021113848", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //9.1.0
|
{ "20191021113848", 10,{0x2ec10, 0x5573, 0, 1, 12, HASH_ORDER_700_10x, 0x6495, 0x1d807} }, //9.1.0
|
||||||
{ "20200303104606", 10, 0x0E00, 0x6FE0, { 1, 2, 0 }, 0x40030000, 0x4003E000, false, NULL, NULL }, //10.0.0
|
{ "20200303104606", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //10.0.0
|
||||||
|
{ "20201030110885", 10,{0x30ea0, 0x5e4b, 0, 1, 12, HASH_ORDER_700_10x, 0x663c, 0x1d9a4} }, //11.0.0
|
||||||
{ NULL } //End.
|
{ NULL } //End.
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -159,31 +54,3 @@ const pkg1_id_t *pkg1_identify(u8 *pkg1)
|
|||||||
return &_pkg1_ids[i];
|
return &_pkg1_ids[i];
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1)
|
|
||||||
{
|
|
||||||
// Decrypt package1.
|
|
||||||
u8 *pkg11 = pkg1 + id->pkg11_off;
|
|
||||||
u32 pkg11_size = *(u32 *)pkg11;
|
|
||||||
se_aes_crypt_ctr(11, pkg11 + 0x20, pkg11_size, pkg11 + 0x20, pkg11_size, pkg11 + 0x10);
|
|
||||||
}
|
|
||||||
|
|
||||||
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1)
|
|
||||||
{
|
|
||||||
pk11_hdr_t *hdr = (pk11_hdr_t *)(pkg1 + id->pkg11_off + 0x20);
|
|
||||||
|
|
||||||
u32 sec_size[3] = { hdr->wb_size, hdr->ldr_size, hdr->sm_size };
|
|
||||||
//u32 sec_off[3] = { hdr->wb_off, hdr->ldr_off, hdr->sm_off };
|
|
||||||
|
|
||||||
u8 *pdata = (u8 *)hdr + sizeof(pk11_hdr_t);
|
|
||||||
for (u32 i = 0; i < 3; i++)
|
|
||||||
{
|
|
||||||
if (id->sec_map[i] == 0 && warmboot_dst)
|
|
||||||
memcpy(warmboot_dst, pdata, sec_size[id->sec_map[i]]);
|
|
||||||
else if (id->sec_map[i] == 1 && ldr_dst)
|
|
||||||
memcpy(ldr_dst, pdata, sec_size[id->sec_map[i]]);
|
|
||||||
else if (id->sec_map[i] == 2 && secmon_dst)
|
|
||||||
memcpy(secmon_dst, pdata, sec_size[id->sec_map[i]]);
|
|
||||||
pdata += sec_size[id->sec_map[i]];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -19,46 +19,25 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
typedef struct _patch_t
|
typedef struct _key_info_t
|
||||||
{
|
{
|
||||||
u32 off;
|
u32 start_offset;
|
||||||
u32 val;
|
u32 hks_offset;
|
||||||
} patch_t;
|
bool hks_offset_is_from_end;
|
||||||
|
u32 alignment;
|
||||||
#define PATCHSET_DEF(name, ...) \
|
u32 hash_max;
|
||||||
patch_t name[] = { \
|
u8 hash_order[13];
|
||||||
__VA_ARGS__, \
|
u32 es_offset;
|
||||||
{ 0xFFFFFFFF, 0xFFFFFFFF } \
|
u32 ssl_offset;
|
||||||
}
|
} key_info_t;
|
||||||
|
|
||||||
typedef struct _pkg1_id_t
|
typedef struct _pkg1_id_t
|
||||||
{
|
{
|
||||||
const char *id;
|
const char *id;
|
||||||
u32 kb;
|
u32 kb;
|
||||||
u32 tsec_off;
|
key_info_t key_info;
|
||||||
u32 pkg11_off;
|
|
||||||
u32 sec_map[3];
|
|
||||||
u32 secmon_base;
|
|
||||||
u32 warmboot_base;
|
|
||||||
bool set_warmboot;
|
|
||||||
patch_t *secmon_patchset;
|
|
||||||
patch_t *warmboot_patchset;
|
|
||||||
} pkg1_id_t;
|
} pkg1_id_t;
|
||||||
|
|
||||||
typedef struct _pk11_hdr_t
|
|
||||||
{
|
|
||||||
u32 magic;
|
|
||||||
u32 wb_size;
|
|
||||||
u32 wb_off;
|
|
||||||
u32 pad;
|
|
||||||
u32 ldr_size;
|
|
||||||
u32 ldr_off;
|
|
||||||
u32 sm_size;
|
|
||||||
u32 sm_off;
|
|
||||||
} pk11_hdr_t;
|
|
||||||
|
|
||||||
const pkg1_id_t *pkg1_identify(u8 *pkg1);
|
const pkg1_id_t *pkg1_identify(u8 *pkg1);
|
||||||
void pkg1_decrypt(const pkg1_id_t *id, u8 *pkg1);
|
|
||||||
void pkg1_unpack(void *warmboot_dst, void *secmon_dst, void *ldr_dst, const pkg1_id_t *id, u8 *pkg1);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
1260
source/hos/pkg2.c
1260
source/hos/pkg2.c
File diff suppressed because it is too large
Load Diff
@@ -26,13 +26,11 @@
|
|||||||
#define PKG2_SEC_KERNEL 0
|
#define PKG2_SEC_KERNEL 0
|
||||||
#define PKG2_SEC_INI1 1
|
#define PKG2_SEC_INI1 1
|
||||||
|
|
||||||
#define INI1_MAGIC 0x31494E49
|
|
||||||
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
#define PKG2_NEWKERN_GET_INI1_HEURISTIC 0xD2800015 // Offset of OP + 12 is the INI1 offset.
|
||||||
#define PKG2_NEWKERN_START 0x800
|
|
||||||
|
|
||||||
u32 pkg2_newkern_ini1_val;
|
extern u32 pkg2_newkern_ini1_val;
|
||||||
u32 pkg2_newkern_ini1_start;
|
extern u32 pkg2_newkern_ini1_start;
|
||||||
u32 pkg2_newkern_ini1_end;
|
extern u32 pkg2_newkern_ini1_end;
|
||||||
|
|
||||||
typedef struct _kernel_patch_t
|
typedef struct _kernel_patch_t
|
||||||
{
|
{
|
||||||
@@ -42,25 +40,6 @@ typedef struct _kernel_patch_t
|
|||||||
u32 *ptr;
|
u32 *ptr;
|
||||||
} kernel_patch_t;
|
} kernel_patch_t;
|
||||||
|
|
||||||
#define KERNEL_PATCHSET_DEF(name, ...) \
|
|
||||||
kernel_patch_t name[] = { \
|
|
||||||
__VA_ARGS__, \
|
|
||||||
{0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF, (u32 *)0xFFFFFFFF} \
|
|
||||||
}
|
|
||||||
|
|
||||||
enum
|
|
||||||
{
|
|
||||||
// Always applied.
|
|
||||||
SVC_GENERIC = 0,
|
|
||||||
// Generic instruction patches.
|
|
||||||
SVC_VERIFY_DS = 0x10,
|
|
||||||
DEBUG_MODE_EN = 0x11,
|
|
||||||
ATM_GEN_PATCH = 0x12,
|
|
||||||
ATM_SYSM_INCR = ATM_GEN_PATCH,
|
|
||||||
// >4 bytes patches. Value is a pointer of a u32 array.
|
|
||||||
ATM_ARR_PATCH = 0x13,
|
|
||||||
};
|
|
||||||
|
|
||||||
typedef struct _pkg2_hdr_t
|
typedef struct _pkg2_hdr_t
|
||||||
{
|
{
|
||||||
u8 ctr[0x10];
|
u8 ctr[0x10];
|
||||||
@@ -122,38 +101,8 @@ typedef struct _pkg2_kernel_id_t
|
|||||||
kernel_patch_t *kernel_patchset;
|
kernel_patch_t *kernel_patchset;
|
||||||
} pkg2_kernel_id_t;
|
} pkg2_kernel_id_t;
|
||||||
|
|
||||||
typedef struct _kip1_patch_t
|
|
||||||
{
|
|
||||||
u32 offset; // section+offset of patch to apply.
|
|
||||||
u32 length; // In bytes, 0 means last patch.
|
|
||||||
char* srcData; // That must match.
|
|
||||||
char* dstData; // That it gets replaced by.
|
|
||||||
} kip1_patch_t;
|
|
||||||
|
|
||||||
typedef struct _kip1_patchset_t
|
|
||||||
{
|
|
||||||
char* name; // NULL means end.
|
|
||||||
kip1_patch_t* patches; // NULL means not necessary.
|
|
||||||
} kip1_patchset_t;
|
|
||||||
|
|
||||||
typedef struct _kip1_id_t
|
|
||||||
{
|
|
||||||
const char* name;
|
|
||||||
u8 hash[8];
|
|
||||||
kip1_patchset_t* patchset;
|
|
||||||
} kip1_id_t;
|
|
||||||
|
|
||||||
void pkg2_get_newkern_info(u8 *kern_data);
|
|
||||||
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
bool pkg2_parse_kips(link_t *info, pkg2_hdr_t *pkg2, bool *new_pkg2);
|
||||||
int pkg2_has_kip(link_t *info, u64 tid);
|
int pkg2_decompress_kip(pkg2_kip1_info_t* ki, u32 sectsToDecomp);
|
||||||
void pkg2_replace_kip(link_t *info, u64 tid, pkg2_kip1_t *kip1);
|
pkg2_hdr_t *pkg2_decrypt(void *data);
|
||||||
void pkg2_add_kip(link_t *info, pkg2_kip1_t *kip1);
|
|
||||||
void pkg2_merge_kip(link_t *info, pkg2_kip1_t *kip1);
|
|
||||||
void pkg2_get_ids(kip1_id_t **ids, u32 *entries);
|
|
||||||
const char* pkg2_patch_kips(link_t *info, char* patchNames);
|
|
||||||
|
|
||||||
const pkg2_kernel_id_t *pkg2_identify(u8 *hash);
|
|
||||||
pkg2_hdr_t *pkg2_decrypt(void *data, u8 kb);
|
|
||||||
void pkg2_build_encrypt(void *dst, void *kernel, u32 kernel_size, link_t *kips_info, bool new_pkg2);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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;
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -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);
|
|
||||||
}
|
|
||||||
@@ -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
|
|
||||||
@@ -16,27 +16,25 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include "hos.h"
|
|
||||||
#include "fss.h"
|
|
||||||
#include "sept.h"
|
#include "sept.h"
|
||||||
#include "../config/config.h"
|
#include "../config/ini.h"
|
||||||
#include "../gfx/di.h"
|
#include "../gfx/di.h"
|
||||||
#include "../ianos/ianos.h"
|
#include "../hos/fss.h"
|
||||||
|
#include "../hos/hos.h"
|
||||||
#include "../libs/fatfs/ff.h"
|
#include "../libs/fatfs/ff.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../soc/hw_init.h"
|
#include "../soc/hw_init.h"
|
||||||
#include "../soc/pmc.h"
|
#include "../soc/pmc.h"
|
||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../storage/emummc.h"
|
|
||||||
#include "../storage/nx_emmc.h"
|
#include "../storage/nx_emmc.h"
|
||||||
#include "../storage/nx_sd.h"
|
#include "../storage/nx_sd.h"
|
||||||
#include "../storage/sdmmc.h"
|
#include "../storage/sdmmc.h"
|
||||||
#include "../utils/btn.h"
|
#include "../utils/btn.h"
|
||||||
|
#include "../utils/list.h"
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
#include "../gfx/gfx.h"
|
#include "../gfx/gfx.h"
|
||||||
|
|
||||||
#define RELOC_META_OFF 0x7C
|
|
||||||
#define PATCHED_RELOC_SZ 0x94
|
#define PATCHED_RELOC_SZ 0x94
|
||||||
|
|
||||||
#define WB_RST_ADDR 0x40010ED0
|
#define WB_RST_ADDR 0x40010ED0
|
||||||
@@ -57,108 +55,60 @@ u8 warmboot_reboot[] = {
|
|||||||
#define SEPT_PRI_ADDR 0x4003F000
|
#define SEPT_PRI_ADDR 0x4003F000
|
||||||
|
|
||||||
#define SEPT_PK1T_ADDR 0xC0400000
|
#define SEPT_PK1T_ADDR 0xC0400000
|
||||||
|
#define SEPT_PK1T_STACK 0x40008000
|
||||||
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
|
#define SEPT_TCSZ_ADDR (SEPT_PK1T_ADDR - 0x4)
|
||||||
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
|
#define SEPT_STG1_ADDR (SEPT_PK1T_ADDR + 0x2E100)
|
||||||
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
#define SEPT_STG2_ADDR (SEPT_PK1T_ADDR + 0x60E0)
|
||||||
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
#define SEPT_PKG_SZ (0x2F100 + WB_RST_SIZE)
|
||||||
|
|
||||||
|
extern u32 color_idx;
|
||||||
extern boot_cfg_t b_cfg;
|
extern boot_cfg_t b_cfg;
|
||||||
extern hekate_config h_cfg;
|
|
||||||
extern const volatile ipl_ver_meta_t ipl_ver;
|
|
||||||
|
|
||||||
extern bool is_ipl_updated(void *buf);
|
|
||||||
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
extern void reloc_patcher(u32 payload_dst, u32 payload_src, u32 payload_size);
|
||||||
|
|
||||||
void check_sept(ini_sec_t *cfg_sec)
|
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb)
|
||||||
{
|
|
||||||
hos_eks_get();
|
|
||||||
|
|
||||||
// Check if non-hekate payload is used for sept and restore it.
|
|
||||||
if (h_cfg.sept_run)
|
|
||||||
{
|
|
||||||
if (!f_stat("sept/payload.bak", NULL))
|
|
||||||
{
|
|
||||||
f_unlink("sept/payload.bin");
|
|
||||||
f_rename("sept/payload.bak", "sept/payload.bin");
|
|
||||||
}
|
|
||||||
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8 *pkg1 = (u8 *)calloc(1, 0x40000);
|
|
||||||
|
|
||||||
sdmmc_storage_t storage;
|
|
||||||
sdmmc_t sdmmc;
|
|
||||||
int res = emummc_storage_init_mmc(&storage, &sdmmc);
|
|
||||||
if (res)
|
|
||||||
{
|
|
||||||
if (res == 2)
|
|
||||||
EPRINTF("Failed to init eMMC");
|
|
||||||
else
|
|
||||||
EPRINTF("Failed to init emuMMC");
|
|
||||||
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
emummc_storage_set_mmc_partition(&storage, EMMC_BOOT0);
|
|
||||||
|
|
||||||
// Read package1.
|
|
||||||
emummc_storage_read(&storage, 0x100000 / NX_EMMC_BLOCKSIZE, 0x40000 / NX_EMMC_BLOCKSIZE, pkg1);
|
|
||||||
const pkg1_id_t *pkg1_id = pkg1_identify(pkg1);
|
|
||||||
if (!pkg1_id)
|
|
||||||
{
|
|
||||||
gfx_con.fntsz = 16;
|
|
||||||
EPRINTF("Unknown pkg1 version.");
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pkg1_id->kb >= KB_FIRMWARE_VERSION_700 && !h_cfg.sept_run)
|
|
||||||
{
|
|
||||||
u8 key_idx = pkg1_id->kb - KB_FIRMWARE_VERSION_700;
|
|
||||||
if (h_cfg.eks && (h_cfg.eks->enabled & (1 << key_idx)))
|
|
||||||
{
|
|
||||||
h_cfg.sept_run = true;
|
|
||||||
EMC(EMC_SCRATCH0) |= EMC_SEPT_RUN;
|
|
||||||
goto out_free;
|
|
||||||
}
|
|
||||||
|
|
||||||
sdmmc_storage_end(&storage);
|
|
||||||
reboot_to_sept((u8 *)pkg1 + pkg1_id->tsec_off, pkg1_id->kb, cfg_sec);
|
|
||||||
}
|
|
||||||
|
|
||||||
out_free:
|
|
||||||
free(pkg1);
|
|
||||||
sdmmc_storage_end(&storage);
|
|
||||||
}
|
|
||||||
|
|
||||||
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
|
|
||||||
{
|
{
|
||||||
FIL fp;
|
FIL fp;
|
||||||
bool fss0_sept_used = false;
|
bool fss0_sept_used = false;
|
||||||
|
|
||||||
// Copy warmboot reboot code and TSEC fw.
|
// Copy warmboot reboot code and TSEC fw.
|
||||||
u32 tsec_fw_size = 0x3000;
|
|
||||||
if (kb > KB_FIRMWARE_VERSION_700)
|
|
||||||
tsec_fw_size = 0x3300;
|
|
||||||
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
memcpy((u8 *)(SEPT_PK1T_ADDR - WB_RST_SIZE), (u8 *)warmboot_reboot, sizeof(warmboot_reboot));
|
||||||
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_fw_size);
|
memcpy((void *)SEPT_PK1T_ADDR, tsec_fw, tsec_size);
|
||||||
*(vu32 *)SEPT_TCSZ_ADDR = tsec_fw_size;
|
*(vu32 *)SEPT_TCSZ_ADDR = tsec_size;
|
||||||
|
|
||||||
if (cfg_sec)
|
LIST_INIT(ini_sections);
|
||||||
|
if (ini_parse(&ini_sections, "bootloader/hekate_ipl.ini", false))
|
||||||
{
|
{
|
||||||
fss0_sept_t sept_ctxt;
|
bool found = false;
|
||||||
sept_ctxt.kb = kb;
|
LIST_FOREACH_ENTRY(ini_sec_t, ini_sec, &ini_sections, link)
|
||||||
sept_ctxt.cfg_sec = cfg_sec;
|
{
|
||||||
sept_ctxt.sept_primary = (void *)SEPT_STG1_ADDR;
|
// Only parse non config sections.
|
||||||
sept_ctxt.sept_secondary = (void *)SEPT_STG2_ADDR;
|
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)
|
if (!fss0_sept_used)
|
||||||
{
|
{
|
||||||
// Copy sept-primary.
|
// Copy sept-primary.
|
||||||
if (f_open(&fp, "sept/sept-primary.bin", FA_READ))
|
if (f_open(&fp, "sd:/sept/sept-primary.bin", FA_READ))
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
if (f_read(&fp, (u8 *)SEPT_STG1_ADDR, f_size(&fp), NULL))
|
||||||
@@ -171,13 +121,13 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
|
|||||||
// Copy sept-secondary.
|
// Copy sept-secondary.
|
||||||
if (kb < KB_FIRMWARE_VERSION_810)
|
if (kb < KB_FIRMWARE_VERSION_810)
|
||||||
{
|
{
|
||||||
if (f_open(&fp, "sept/sept-secondary_00.enc", FA_READ))
|
if (f_open(&fp, "sd:/sept/sept-secondary_00.enc", FA_READ))
|
||||||
if (f_open(&fp, "sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
|
if (f_open(&fp, "sd:/sept/sept-secondary.enc", FA_READ)) // Try the deprecated version.
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (f_open(&fp, "sept/sept-secondary_01.enc", FA_READ))
|
if (f_open(&fp, "sd:/sept/sept-secondary_01.enc", FA_READ))
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -189,46 +139,25 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
|
|||||||
f_close(&fp);
|
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;
|
tmp_cfg->boot_cfg |= BOOT_CFG_SEPT_RUN;
|
||||||
if (!f_open(&fp, "sept/payload.bin", FA_READ | FA_WRITE))
|
|
||||||
|
if (f_open(&fp, "sd:/sept/payload.bin", FA_READ | FA_WRITE))
|
||||||
{
|
{
|
||||||
ipl_ver_meta_t tmp_ver;
|
free(tmp_cfg);
|
||||||
f_lseek(&fp, PATCHED_RELOC_SZ + sizeof(boot_cfg_t));
|
goto error;
|
||||||
f_read(&fp, &tmp_ver, sizeof(ipl_ver_meta_t), NULL);
|
|
||||||
|
|
||||||
if (tmp_ver.magic == ipl_ver.magic)
|
|
||||||
{
|
|
||||||
if (tmp_ver.version == ipl_ver.version)
|
|
||||||
{
|
|
||||||
// Save auto boot config to sept payload, if any.
|
|
||||||
boot_cfg_t *tmp_cfg = malloc(sizeof(boot_cfg_t));
|
|
||||||
memcpy(tmp_cfg, &b_cfg, sizeof(boot_cfg_t));
|
|
||||||
f_lseek(&fp, PATCHED_RELOC_SZ);
|
|
||||||
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
|
||||||
update_sept_payload = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
f_close(&fp);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
f_close(&fp);
|
|
||||||
f_rename("sept/payload.bin", "sept/payload.bak"); // Backup foreign payload.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (update_sept_payload)
|
f_lseek(&fp, PATCHED_RELOC_SZ);
|
||||||
{
|
f_write(&fp, tmp_cfg, sizeof(boot_cfg_t), NULL);
|
||||||
volatile reloc_meta_t *reloc = (reloc_meta_t *)(IPL_LOAD_ADDR + RELOC_META_OFF);
|
|
||||||
f_mkdir("sept");
|
f_close(&fp);
|
||||||
f_open(&fp, "sept/payload.bin", FA_WRITE | FA_CREATE_ALWAYS);
|
|
||||||
f_write(&fp, (u8 *)reloc->start, reloc->end - reloc->start, NULL);
|
|
||||||
f_close(&fp);
|
|
||||||
}
|
|
||||||
|
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
gfx_printf("\n%kPress Power or Vol +/-\n to Reboot to Sept...", colors[(color_idx++) % 6]);
|
||||||
|
|
||||||
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
u32 pk1t_sept = SEPT_PK1T_ADDR - (ALIGN(PATCHED_RELOC_SZ, 0x10) + WB_RST_SIZE);
|
||||||
|
|
||||||
@@ -248,8 +177,8 @@ int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec)
|
|||||||
(*sept)();
|
(*sept)();
|
||||||
|
|
||||||
error:
|
error:
|
||||||
gfx_con.mute = false;
|
EPRINTF("\nSept files not found in sd:/sept!\nPlace appropriate files and try again.");
|
||||||
EPRINTF("Failed to run sept\n");
|
display_backlight_brightness(100, 1000);
|
||||||
|
|
||||||
btn_wait();
|
btn_wait();
|
||||||
|
|
||||||
|
|||||||
@@ -19,7 +19,6 @@
|
|||||||
|
|
||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
void check_sept(ini_sec_t *cfg_sec);
|
int reboot_to_sept(const u8 *tsec_fw, const u32 tsec_size, const u32 kb);
|
||||||
int reboot_to_sept(const u8 *tsec_fw, u32 kb, ini_sec_t *cfg_sec);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -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) {
|
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;
|
int res = 0;
|
||||||
u8 *pdst = (u8 *)dst;
|
u8 *temptweak = (u8 *)malloc(0x10);
|
||||||
u8 *psrc = (u8 *)src;
|
u32 *pdst = (u32 *)dst;
|
||||||
|
u32 *psrc = (u32 *)src;
|
||||||
|
u32 *ptweak = (u32 *)tweak;
|
||||||
|
|
||||||
if (regen_tweak) {
|
if (regen_tweak) {
|
||||||
for (int i = 0xF; i >= 0; i--) {
|
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++)
|
for (u32 i = 0; i < tweak_exp * 0x20; i++)
|
||||||
_gf256_mul_x_le(tweak);
|
_gf256_mul_x_le(tweak);
|
||||||
|
|
||||||
u8 temptweak[0x10];
|
|
||||||
memcpy(temptweak, tweak, 0x10);
|
memcpy(temptweak, tweak, 0x10);
|
||||||
|
|
||||||
//We are assuming a 0x10-aligned sector size in this implementation.
|
//We are assuming a 0x10-aligned sector size in this implementation.
|
||||||
for (u32 i = 0; i < secsize / 0x10; i++) {
|
for (u32 i = 0; i < secsize / 0x10; i++) {
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
for (u32 j = 0; j < 4; j++)
|
||||||
pdst[j] = psrc[j] ^ tweak[j];
|
pdst[j] = psrc[j] ^ ptweak[j];
|
||||||
_gf256_mul_x_le(tweak);
|
_gf256_mul_x_le(tweak);
|
||||||
psrc += 0x10;
|
psrc += 4;
|
||||||
pdst += 0x10;
|
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);
|
memcpy(tweak, temptweak, 0x10);
|
||||||
for (u32 i = 0; i < secsize / 0x10; i++) {
|
for (u32 i = 0; i < secsize / 0x10; i++) {
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
for (u32 j = 0; j < 4; j++)
|
||||||
pdst[j] = pdst[j] ^ tweak[j];
|
pdst[j] = pdst[j] ^ ptweak[j];
|
||||||
_gf256_mul_x_le(tweak);
|
_gf256_mul_x_le(tweak);
|
||||||
pdst += 0x10;
|
pdst += 4;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
res = 1;
|
res = 1;
|
||||||
|
|
||||||
out:;
|
out:;
|
||||||
|
free(temptweak);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,8 +42,8 @@
|
|||||||
#include "../../storage/sdmmc.h"
|
#include "../../storage/sdmmc.h"
|
||||||
extern sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
|
|
||||||
#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
//#define EFSPRINTF(text, ...) print_error(); gfx_printf("%k"text"%k\n", 0xFFFFFF00, 0xFFFFFFFF);
|
||||||
//#define EFSPRINTF(...)
|
#define EFSPRINTF(...)
|
||||||
|
|
||||||
/*--------------------------------------------------------------------------
|
/*--------------------------------------------------------------------------
|
||||||
|
|
||||||
@@ -5629,7 +5629,8 @@ FRESULT f_forward (
|
|||||||
}
|
}
|
||||||
#endif /* FF_USE_FORWARD */
|
#endif /* FF_USE_FORWARD */
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
#if FF_USE_MKFS && !FF_FS_READONLY
|
#if FF_USE_MKFS && !FF_FS_READONLY
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
@@ -6094,7 +6095,7 @@ FRESULT f_mkfs (
|
|||||||
LEAVE_MKFS(FR_OK);
|
LEAVE_MKFS(FR_OK);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|
||||||
#if FF_MULTI_PARTITION
|
#if FF_MULTI_PARTITION
|
||||||
/*-----------------------------------------------------------------------*/
|
/*-----------------------------------------------------------------------*/
|
||||||
@@ -6113,9 +6114,6 @@ FRESULT f_fdisk (
|
|||||||
DWORD sz_disk, p_sect, b_cyl, b_sect;
|
DWORD sz_disk, p_sect, b_cyl, b_sect;
|
||||||
FRESULT res;
|
FRESULT res;
|
||||||
|
|
||||||
BYTE *empty_buff;
|
|
||||||
empty_buff = ff_memcalloc(sizeof(BYTE), 16384);
|
|
||||||
|
|
||||||
stat = disk_initialize(pdrv);
|
stat = disk_initialize(pdrv);
|
||||||
if (stat & STA_NOINIT) return FR_NOT_READY;
|
if (stat & STA_NOINIT) return FR_NOT_READY;
|
||||||
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
|
if (stat & STA_PROTECT) return FR_WRITE_PROTECTED;
|
||||||
@@ -6168,14 +6166,14 @@ FRESULT f_fdisk (
|
|||||||
st_dword(p + 8, b_sect); /* Start sector in LBA */
|
st_dword(p + 8, b_sect); /* Start sector in LBA */
|
||||||
st_dword(p + 12, p_sect); /* Number of sectors */
|
st_dword(p + 12, p_sect); /* Number of sectors */
|
||||||
/* Next partition */
|
/* Next partition */
|
||||||
b_sect += p_sect;
|
|
||||||
|
|
||||||
for (int cursect = 0; cursect < 1024; cursect++){
|
for (u32 cursect = 0; cursect < 512; cursect++){
|
||||||
disk_write(pdrv, empty_buff, b_sect + (32 * cursect), 32);
|
disk_write(pdrv, buf + 0x4000, b_sect + (64 * cursect), 64);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
b_sect += p_sect;
|
||||||
}
|
}
|
||||||
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
|
st_word(p, 0xAA55); /* MBR signature (always at offset 510) */
|
||||||
ff_memfree(empty_buff);
|
|
||||||
|
|
||||||
/* Write it to the MBR */
|
/* Write it to the MBR */
|
||||||
res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
|
res = (disk_write(pdrv, buf, 0, 1) == RES_OK && disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
|
||||||
|
|||||||
@@ -44,10 +44,10 @@
|
|||||||
|
|
||||||
//#include "keys/keys.h"
|
//#include "keys/keys.h"
|
||||||
|
|
||||||
sdmmc_t sd_sdmmc;
|
//sdmmc_t sd_sdmmc;
|
||||||
sdmmc_storage_t sd_storage;
|
//sdmmc_storage_t sd_storage;
|
||||||
__attribute__ ((aligned (16))) FATFS sd_fs;
|
//__attribute__ ((aligned (16))) FATFS sd_fs;
|
||||||
bool sd_mounted, sd_inited;
|
//bool sd_mounted, sd_inited;
|
||||||
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
volatile nyx_storage_t *nyx_str = (nyx_storage_t *)NYX_STORAGE_ADDR;
|
||||||
hekate_config h_cfg;
|
hekate_config h_cfg;
|
||||||
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
boot_cfg_t __attribute__((section ("._boot_cfg"))) b_cfg;
|
||||||
|
|||||||
@@ -136,7 +136,7 @@ void *malloc(u32 size)
|
|||||||
void *calloc(u32 num, u32 size)
|
void *calloc(u32 num, u32 size)
|
||||||
{
|
{
|
||||||
void *res = (void *)_heap_alloc(&_heap, num * 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;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -164,7 +164,7 @@ void heap_monitor(heap_monitor_t *mon, bool print_node_stats)
|
|||||||
count, node->used, (u32)node + sizeof(hnode_t), node->size);
|
count, node->used, (u32)node + sizeof(hnode_t), node->size);
|
||||||
|
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
if (node->next)
|
if (node->next)
|
||||||
node = node->next;
|
node = node->next;
|
||||||
else
|
else
|
||||||
|
|||||||
@@ -27,6 +27,7 @@
|
|||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
|
|
||||||
extern volatile nyx_storage_t *nyx_str;
|
extern volatile nyx_storage_t *nyx_str;
|
||||||
|
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||||
|
|
||||||
u32 minerva_init()
|
u32 minerva_init()
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ typedef enum
|
|||||||
FREQ_1600 = 1600000
|
FREQ_1600 = 1600000
|
||||||
} minerva_freq_t;
|
} minerva_freq_t;
|
||||||
|
|
||||||
void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
extern void (*minerva_cfg)(mtc_config_t *mtc_cfg, void *);
|
||||||
u32 minerva_init();
|
u32 minerva_init();
|
||||||
void minerva_change_freq(minerva_freq_t freq);
|
void minerva_change_freq(minerva_freq_t freq);
|
||||||
void minerva_periodic_training();
|
void minerva_periodic_training();
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
* PMIC Real Time Clock driver for Nintendo Switch's MAX77620-RTC
|
||||||
*
|
*
|
||||||
* Copyright (c) 2018-2019 CTCaer
|
* 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
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -35,10 +35,10 @@ void max77620_rtc_get_time(rtc_time_t *time)
|
|||||||
// Get time.
|
// Get time.
|
||||||
time->sec = i2c_recv_byte(I2C_5, MAX77620_RTC_I2C_ADDR, MAX77620_RTC_SEC_REG) & 0x7F;
|
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;
|
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;
|
time->hour = (time->hour & 0xF) + 12;
|
||||||
|
|
||||||
// Get day of week. 1: Monday to 7: Sunday.
|
// Get day of week. 1: Monday to 7: Sunday.
|
||||||
|
|||||||
418
source/sec/se.c
418
source/sec/se.c
@@ -1,6 +1,8 @@
|
|||||||
/*
|
/*
|
||||||
* Copyright (c) 2018 naehrwert
|
* Copyright (c) 2018 naehrwert
|
||||||
* Copyright (c) 2018 CTCaer
|
* Copyright (c) 2018 CTCaer
|
||||||
|
* Copyright (c) 2018 Atmosphère-NX
|
||||||
|
* Copyright (c) 2019-2020 shchmue
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms and conditions of the GNU General Public License,
|
* under the terms and conditions of the GNU General Public License,
|
||||||
@@ -17,6 +19,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../../common/memory_map.h"
|
||||||
#include "../sec/se.h"
|
#include "../sec/se.h"
|
||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../soc/bpmp.h"
|
#include "../soc/bpmp.h"
|
||||||
@@ -31,6 +34,9 @@ typedef struct _se_ll_t
|
|||||||
vu32 size;
|
vu32 size;
|
||||||
} se_ll_t;
|
} se_ll_t;
|
||||||
|
|
||||||
|
static u32 _se_rsa_mod_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
|
||||||
|
static u32 _se_rsa_exp_sizes[TEGRA_SE_RSA_KEYSLOT_COUNT];
|
||||||
|
|
||||||
static void _gf256_mul_x(void *block)
|
static void _gf256_mul_x(void *block)
|
||||||
{
|
{
|
||||||
u8 *pdata = (u8 *)block;
|
u8 *pdata = (u8 *)block;
|
||||||
@@ -47,6 +53,22 @@ static void _gf256_mul_x(void *block)
|
|||||||
pdata[0xF] ^= 0x87;
|
pdata[0xF] ^= 0x87;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void _gf256_mul_x_le(void *block)
|
||||||
|
{
|
||||||
|
u8 *pdata = (u8 *)block;
|
||||||
|
u32 carry = 0;
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 0x10; i++)
|
||||||
|
{
|
||||||
|
u8 b = pdata[i];
|
||||||
|
pdata[i] = (b << 1) | carry;
|
||||||
|
carry = b >> 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (carry)
|
||||||
|
pdata[0x0] ^= 0x87;
|
||||||
|
}
|
||||||
|
|
||||||
static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size)
|
static void _se_ll_init(se_ll_t *ll, u32 addr, u32 size)
|
||||||
{
|
{
|
||||||
ll->num = 0;
|
ll->num = 0;
|
||||||
@@ -73,17 +95,20 @@ static int _se_wait()
|
|||||||
|
|
||||||
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
static int _se_execute(u32 op, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||||
{
|
{
|
||||||
se_ll_t *ll_dst = NULL, *ll_src = NULL;
|
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)
|
if (dst)
|
||||||
{
|
{
|
||||||
ll_dst = (se_ll_t *)malloc(sizeof(se_ll_t));
|
|
||||||
_se_ll_init(ll_dst, (u32)dst, dst_size);
|
_se_ll_init(ll_dst, (u32)dst, dst_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (src)
|
if (src)
|
||||||
{
|
{
|
||||||
ll_src = (se_ll_t *)malloc(sizeof(se_ll_t));
|
|
||||||
_se_ll_init(ll_src, (u32)src, src_size);
|
_se_ll_init(ll_src, (u32)src, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,11 +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);
|
bpmp_mmu_maintenance(BPMP_MMU_MAINT_CLN_INV_WAY, false);
|
||||||
|
|
||||||
if (src)
|
|
||||||
free(ll_src);
|
|
||||||
if (dst)
|
|
||||||
free(ll_dst);
|
|
||||||
|
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,6 +162,66 @@ void se_rsa_acc_ctrl(u32 rs, u32 flags)
|
|||||||
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
|
SE(SE_RSA_KEYTABLE_ACCESS_LOCK_OFFSET) &= ~(1 << rs);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// se_rsa_key_set() was derived from Atmosphère's set_rsa_keyslot
|
||||||
|
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size)
|
||||||
|
{
|
||||||
|
u32 *data = (u32 *)mod;
|
||||||
|
for (u32 i = 0; i < mod_size / 4; i++)
|
||||||
|
{
|
||||||
|
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
|
||||||
|
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[mod_size / 4 - i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
data = (u32 *)exp;
|
||||||
|
for (u32 i = 0; i < exp_size / 4; i++)
|
||||||
|
{
|
||||||
|
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
|
||||||
|
SE(SE_RSA_KEYTABLE_DATA) = byte_swap_32(data[exp_size / 4 - i - 1]);
|
||||||
|
}
|
||||||
|
|
||||||
|
_se_rsa_mod_sizes[ks] = mod_size;
|
||||||
|
_se_rsa_exp_sizes[ks] = exp_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
// se_rsa_key_clear() was derived from Atmosphère's clear_rsa_keyslot
|
||||||
|
void se_rsa_key_clear(u32 ks)
|
||||||
|
{
|
||||||
|
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
|
||||||
|
{
|
||||||
|
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_MOD) | i;
|
||||||
|
SE(SE_RSA_KEYTABLE_DATA) = 0;
|
||||||
|
}
|
||||||
|
for (u32 i = 0; i < TEGRA_SE_RSA2048_DIGEST_SIZE / 4; i++)
|
||||||
|
{
|
||||||
|
SE(SE_RSA_KEYTABLE_ADDR) = RSA_KEY_NUM(ks) | RSA_KEY_TYPE(RSA_KEY_TYPE_EXP) | i;
|
||||||
|
SE(SE_RSA_KEYTABLE_DATA) = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// se_rsa_exp_mod() was derived from Atmosphère's se_synchronous_exp_mod and se_get_exp_mod_output
|
||||||
|
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||||
|
{
|
||||||
|
int res;
|
||||||
|
u8 stack_buf[TEGRA_SE_RSA2048_DIGEST_SIZE];
|
||||||
|
|
||||||
|
for (u32 i = 0; i < src_size; i++)
|
||||||
|
stack_buf[i] = *((u8 *)src + src_size - i - 1);
|
||||||
|
|
||||||
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_RSA) | SE_CONFIG_DST(DST_RSAREG);
|
||||||
|
SE(SE_RSA_CONFIG) = RSA_KEY_SLOT(ks);
|
||||||
|
SE(SE_RSA_KEY_SIZE_REG_OFFSET) = (_se_rsa_mod_sizes[ks] >> 6) - 1;
|
||||||
|
SE(SE_RSA_EXP_SIZE_REG_OFFSET) = _se_rsa_exp_sizes[ks] >> 2;
|
||||||
|
|
||||||
|
res = _se_execute(OP_START, NULL, 0, stack_buf, src_size);
|
||||||
|
|
||||||
|
// Copy output hash.
|
||||||
|
u32 *dst32 = (u32 *)dst;
|
||||||
|
for (u32 i = 0; i < dst_size / 4; i++)
|
||||||
|
dst32[dst_size / 4 - i - 1] = byte_swap_32(SE(SE_RSA_OUTPUT + (i << 2)));
|
||||||
|
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
void se_key_acc_ctrl(u32 ks, u32 flags)
|
void se_key_acc_ctrl(u32 ks, u32 flags)
|
||||||
{
|
{
|
||||||
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
|
if (flags & SE_KEY_TBL_DIS_KEY_ACCESS_FLAG)
|
||||||
@@ -150,7 +230,7 @@ void se_key_acc_ctrl(u32 ks, u32 flags)
|
|||||||
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
|
SE(SE_KEY_TABLE_ACCESS_LOCK_OFFSET) &= ~(1 << ks);
|
||||||
}
|
}
|
||||||
|
|
||||||
void se_aes_key_set(u32 ks, void *key, u32 size)
|
void se_aes_key_set(u32 ks, const void *key, u32 size)
|
||||||
{
|
{
|
||||||
u32 *data = (u32 *)key;
|
u32 *data = (u32 *)key;
|
||||||
for (u32 i = 0; i < size / 4; i++)
|
for (u32 i = 0; i < size / 4; i++)
|
||||||
@@ -160,6 +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)
|
void se_aes_key_clear(u32 ks)
|
||||||
{
|
{
|
||||||
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
|
for (u32 i = 0; i < TEGRA_SE_AES_MAX_KEY_SIZE / 4; i++)
|
||||||
@@ -169,6 +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)
|
int se_aes_unwrap_key(u32 ks_dst, u32 ks_src, const void *input)
|
||||||
{
|
{
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_KEYTAB);
|
||||||
@@ -195,24 +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);
|
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_crypt_cbc(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size)
|
|
||||||
{
|
|
||||||
if (enc)
|
|
||||||
{
|
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
|
|
||||||
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_DEC_ALG(ALG_AES_DEC) | SE_CONFIG_DST(DST_MEMORY);
|
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_PREVAHB) |
|
|
||||||
SE_CRYPTO_CORE_SEL(CORE_DECRYPT) | SE_CRYPTO_XOR_POS(XOR_BOTTOM);
|
|
||||||
}
|
|
||||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = (src_size >> 4) - 1;
|
|
||||||
return _se_execute(OP_START, dst, dst_size, src, src_size);
|
|
||||||
}
|
|
||||||
|
|
||||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src)
|
||||||
{
|
{
|
||||||
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
|
return se_aes_crypt_ecb(ks, enc, dst, 0x10, src, 0x10);
|
||||||
@@ -223,7 +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_SPARE_0_REG_OFFSET) = 1;
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
|
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) |
|
||||||
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1);
|
SE_CRYPTO_XOR_POS(XOR_BOTTOM) | SE_CRYPTO_INPUT_SEL(INPUT_LNR_CTR) | SE_CRYPTO_CTR_VAL(1) |
|
||||||
|
SE_CRYPTO_VCTRAM_SEL(VCTRAM_AHB);
|
||||||
_se_aes_ctr_set(ctr);
|
_se_aes_ctr_set(ctr);
|
||||||
|
|
||||||
u32 src_size_aligned = src_size & 0xFFFFFFF0;
|
u32 src_size_aligned = src_size & 0xFFFFFFF0;
|
||||||
@@ -244,12 +336,90 @@ int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_s
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_xts_crypt_sec(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize)
|
// 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;
|
int res = 0;
|
||||||
u8 *tweak = (u8 *)malloc(0x10);
|
u8 *tweak = (u8 *)malloc(0x10);
|
||||||
u8 *pdst = (u8 *)dst;
|
u8 *temptweak = (u8 *)malloc(0x10);
|
||||||
u8 *psrc = (u8 *)src;
|
u32 *pdst = (u32 *)dst;
|
||||||
|
u32 *psrc = (u32 *)src;
|
||||||
|
u32 *ptweak = (u32 *)tweak;
|
||||||
|
|
||||||
//Generate tweak.
|
//Generate tweak.
|
||||||
for (int i = 0xF; i >= 0; i--)
|
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))
|
if (!se_aes_crypt_block_ecb(ks1, 1, tweak, tweak))
|
||||||
goto out;
|
goto out;
|
||||||
|
|
||||||
|
memcpy(temptweak, tweak, 0x10);
|
||||||
|
|
||||||
//We are assuming a 0x10-aligned sector size in this implementation.
|
//We are assuming a 0x10-aligned sector size in this implementation.
|
||||||
for (u32 i = 0; i < secsize / 0x10; i++)
|
for (u32 i = 0; i < secsize / 0x10; i++)
|
||||||
{
|
{
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
for (u32 j = 0; j < 4; j++)
|
||||||
pdst[j] = psrc[j] ^ tweak[j];
|
pdst[j] = psrc[j] ^ ptweak[j];
|
||||||
if (!se_aes_crypt_block_ecb(ks2, enc, pdst, pdst))
|
_gf256_mul_x_le(tweak);
|
||||||
goto out;
|
psrc += 4;
|
||||||
for (u32 j = 0; j < 0x10; j++)
|
pdst += 4;
|
||||||
pdst[j] = pdst[j] ^ tweak[j];
|
}
|
||||||
_gf256_mul_x(tweak);
|
|
||||||
psrc += 0x10;
|
se_aes_crypt_ecb(ks2, enc, dst, secsize, dst, secsize);
|
||||||
pdst += 0x10;
|
|
||||||
|
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;
|
res = 1;
|
||||||
|
|
||||||
out:;
|
out:;
|
||||||
|
free(temptweak);
|
||||||
free(tweak);
|
free(tweak);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u32 secsize, u32 num_secs)
|
int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, const void *src, u32 secsize, u32 num_secs)
|
||||||
{
|
{
|
||||||
u8 *pdst = (u8 *)dst;
|
u8 *pdst = (u8 *)dst;
|
||||||
u8 *psrc = (u8 *)src;
|
u8 *psrc = (u8 *)src;
|
||||||
@@ -293,6 +475,62 @@ int se_aes_xts_crypt(u32 ks1, u32 ks2, u32 enc, u64 sec, void *dst, void *src, u
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// se_aes_cmac() was derived from Atmosphère's se_compute_aes_cmac
|
||||||
|
int se_aes_cmac(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size)
|
||||||
|
{
|
||||||
|
int res = 0;
|
||||||
|
u8 *key = (u8 *)calloc(0x10, 1);
|
||||||
|
u8 *last_block = (u8 *)calloc(0x10, 1);
|
||||||
|
|
||||||
|
// generate derived key
|
||||||
|
if (!se_aes_crypt_block_ecb(ks, 1, key, key))
|
||||||
|
goto out;
|
||||||
|
_gf256_mul_x(key);
|
||||||
|
if (src_size & 0xF)
|
||||||
|
_gf256_mul_x(key);
|
||||||
|
|
||||||
|
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_HASHREG);
|
||||||
|
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(ks) | SE_CRYPTO_INPUT_SEL(INPUT_AHB) |
|
||||||
|
SE_CRYPTO_XOR_POS(XOR_TOP) | SE_CRYPTO_VCTRAM_SEL(VCTRAM_AESOUT) | SE_CRYPTO_HASH(HASH_ENABLE) |
|
||||||
|
SE_CRYPTO_CORE_SEL(CORE_ENCRYPT);
|
||||||
|
se_aes_key_iv_clear(ks);
|
||||||
|
|
||||||
|
u32 num_blocks = (src_size + 0xf) >> 4;
|
||||||
|
if (num_blocks > 1)
|
||||||
|
{
|
||||||
|
SE(SE_BLOCK_COUNT_REG_OFFSET) = num_blocks - 2;
|
||||||
|
if (!_se_execute(OP_START, NULL, 0, src, src_size))
|
||||||
|
goto out;
|
||||||
|
SE(SE_CRYPTO_REG_OFFSET) |= SE_CRYPTO_IV_SEL(IV_UPDATED);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (src_size & 0xf)
|
||||||
|
{
|
||||||
|
memcpy(last_block, src + (src_size & ~0xf), src_size & 0xf);
|
||||||
|
last_block[src_size & 0xf] = 0x80;
|
||||||
|
}
|
||||||
|
else if (src_size >= 0x10)
|
||||||
|
{
|
||||||
|
memcpy(last_block, src + src_size - 0x10, 0x10);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (u32 i = 0; i < 0x10; i++)
|
||||||
|
last_block[i] ^= key[i];
|
||||||
|
|
||||||
|
SE(SE_BLOCK_COUNT_REG_OFFSET) = 0;
|
||||||
|
res = _se_execute(OP_START, NULL, 0, last_block, 0x10);
|
||||||
|
|
||||||
|
u32 *dst32 = (u32 *)dst;
|
||||||
|
for (u32 i = 0; i < (dst_size >> 2); i++)
|
||||||
|
dst32[i] = SE(SE_HASH_RESULT_REG_OFFSET + (i << 2));
|
||||||
|
|
||||||
|
out:;
|
||||||
|
free(key);
|
||||||
|
free(last_block);
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
|
// se_calc_sha256() was derived from Atmosphère's se_calculate_sha256.
|
||||||
int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
||||||
{
|
{
|
||||||
int res;
|
int res;
|
||||||
@@ -319,76 +557,46 @@ int se_calc_sha256(void *dst, const void *src, u32 src_size)
|
|||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int se_gen_prng128(void *dst)
|
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size)
|
||||||
{
|
{
|
||||||
// Setup config for X931 PRNG.
|
int res = 0;
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_MEMORY);
|
u8 *secret = (u8 *)malloc(0x40);
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_HASH(HASH_DISABLE) | SE_CRYPTO_XOR_POS(XOR_BYPASS) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
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);
|
if (key_size > 0x40)
|
||||||
//SE(SE_RNG_SRC_CONFIG_REG_OFFSET) =
|
|
||||||
// SE_RNG_SRC_CONFIG_ENT_SRC(RNG_SRC_RO_ENT_ENABLE) | SE_RNG_SRC_CONFIG_ENT_SRC_LOCK(RNG_SRC_RO_ENT_LOCK_ENABLE);
|
|
||||||
SE(SE_RNG_RESEED_INTERVAL_REG_OFFSET) = 1;
|
|
||||||
|
|
||||||
SE(SE_BLOCK_COUNT_REG_OFFSET) = (16 >> 4) - 1;
|
|
||||||
|
|
||||||
// Trigger the operation.
|
|
||||||
return _se_execute(OP_START, dst, 16, NULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize)
|
|
||||||
{
|
|
||||||
u8 *aligned_buf = (u8 *)ALIGN((u32)buf, 0x40);
|
|
||||||
|
|
||||||
// Set Secure Random Key.
|
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_RNG) | SE_CONFIG_DST(DST_SRK);
|
|
||||||
SE(SE_CRYPTO_REG_OFFSET) = SE_CRYPTO_KEY_INDEX(0) | SE_CRYPTO_CORE_SEL(CORE_ENCRYPT) | SE_CRYPTO_INPUT_SEL(INPUT_RANDOM);
|
|
||||||
SE(SE_RNG_CONFIG_REG_OFFSET) = SE_RNG_CONFIG_SRC(RNG_SRC_ENTROPY) | SE_RNG_CONFIG_MODE(RNG_MODE_FORCE_RESEED);
|
|
||||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
|
||||||
_se_execute(OP_START, NULL, 0, NULL, 0);
|
|
||||||
|
|
||||||
// Save AES keys.
|
|
||||||
SE(SE_CONFIG_REG_OFFSET) = SE_CONFIG_ENC_MODE(MODE_KEY128) | SE_CONFIG_ENC_ALG(ALG_AES_ENC) | SE_CONFIG_DST(DST_MEMORY);
|
|
||||||
|
|
||||||
for (u32 i = 0; i < TEGRA_SE_KEYSLOT_COUNT; i++)
|
|
||||||
{
|
{
|
||||||
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
|
if (!se_calc_sha256(secret, key, key_size))
|
||||||
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_0_3);
|
goto out;
|
||||||
|
memset(secret + 0x20, 0, 0x20);
|
||||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
}
|
||||||
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
|
else
|
||||||
memcpy(keys + i * keysize, aligned_buf, 0x10);
|
{
|
||||||
|
memcpy(secret, key, key_size);
|
||||||
if (keysize > 0x10)
|
memset(secret + key_size, 0, 0x40 - key_size);
|
||||||
{
|
|
||||||
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(AES_KEYTABLE) |
|
|
||||||
(i << SE_KEY_INDEX_SHIFT) | SE_CONTEXT_SAVE_WORD_QUAD(KEYS_4_7);
|
|
||||||
|
|
||||||
SE(SE_CRYPTO_LAST_BLOCK) = 0;
|
|
||||||
_se_execute(OP_CTX_SAVE, aligned_buf, 0x10, NULL, 0);
|
|
||||||
memcpy(keys + i * keysize + 0x10, aligned_buf, 0x10);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Save SRK to PMC secure scratches.
|
u32 *secret32 = (u32 *)secret;
|
||||||
SE(SE_CONTEXT_SAVE_CONFIG_REG_OFFSET) = SE_CONTEXT_SAVE_SRC(SRK);
|
u32 *ipad32 = (u32 *)ipad;
|
||||||
SE(0x80) = 0; // SE_CRYPTO_LAST_BLOCK
|
u32 *opad32 = (u32 *)opad;
|
||||||
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
|
for (u32 i = 0; i < 0x10; i++)
|
||||||
|
{
|
||||||
|
ipad32[i] = secret32[i] ^ 0x36363636;
|
||||||
|
opad32[i] = secret32[i] ^ 0x5C5C5C5C;
|
||||||
|
}
|
||||||
|
|
||||||
// End context save.
|
memcpy(ipad + 0x40, src, src_size);
|
||||||
SE(SE_CONFIG_REG_OFFSET) = 0;
|
if (!se_calc_sha256(dst, ipad, 0x40 + src_size))
|
||||||
_se_execute(OP_CTX_SAVE, NULL, 0, NULL, 0);
|
goto out;
|
||||||
|
memcpy(opad + 0x40, dst, 0x20);
|
||||||
|
if (!se_calc_sha256(dst, opad, 0x60))
|
||||||
|
goto out;
|
||||||
|
|
||||||
// Get SRK.
|
res = 1;
|
||||||
u32 srk[4];
|
|
||||||
srk[0] = PMC(0xC0);
|
|
||||||
srk[1] = PMC(0xC4);
|
|
||||||
srk[2] = PMC(0x224);
|
|
||||||
srk[3] = PMC(0x228);
|
|
||||||
|
|
||||||
// Decrypt context.
|
out:;
|
||||||
se_aes_key_clear(3);
|
free(secret);
|
||||||
se_aes_key_set(3, srk, 0x10);
|
free(ipad);
|
||||||
se_aes_crypt_cbc(3, 0, keys, TEGRA_SE_KEYSLOT_COUNT * keysize, keys, TEGRA_SE_KEYSLOT_COUNT * keysize);
|
free(opad);
|
||||||
se_aes_key_clear(3);
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,15 +20,26 @@
|
|||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
|
|
||||||
void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
void se_rsa_acc_ctrl(u32 rs, u32 flags);
|
||||||
|
void se_rsa_key_set(u32 ks, const void *mod, u32 mod_size, const void *exp, u32 exp_size);
|
||||||
|
void se_rsa_key_clear(u32 ks);
|
||||||
|
int se_rsa_exp_mod(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||||
void se_key_acc_ctrl(u32 ks, u32 flags);
|
void se_key_acc_ctrl(u32 ks, u32 flags);
|
||||||
void se_get_aes_keys(u8 *buf, u8 *keys, u32 keysize);
|
void se_aes_key_set(u32 ks, const void *key, u32 size);
|
||||||
void se_aes_key_set(u32 ks, void *key, u32 size);
|
void se_aes_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);
|
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_unwrap_key(u32 ks_dst, u32 ks_src, const void *input);
|
||||||
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
int se_aes_crypt_ecb(u32 ks, u32 enc, void *dst, u32 dst_size, const void *src, u32 src_size);
|
||||||
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
int se_aes_crypt_block_ecb(u32 ks, u32 enc, void *dst, const void *src);
|
||||||
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
int se_aes_crypt_ctr(u32 ks, void *dst, u32 dst_size, const void *src, u32 src_size, void *ctr);
|
||||||
|
int se_aes_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_calc_sha256(void *dst, const void *src, u32 src_size);
|
||||||
int se_gen_prng128(void *dst);
|
int se_calc_hmac_sha256(void *dst, const void *src, u32 src_size, const void *key, u32 key_size);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -18,6 +18,7 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "../hos/hos.h"
|
||||||
#include "../sec/tsec.h"
|
#include "../sec/tsec.h"
|
||||||
#include "../sec/tsec_t210.h"
|
#include "../sec/tsec_t210.h"
|
||||||
#include "../sec/se_t210.h"
|
#include "../sec/se_t210.h"
|
||||||
@@ -29,7 +30,6 @@
|
|||||||
#include "../mem/heap.h"
|
#include "../mem/heap.h"
|
||||||
#include "../mem/mc.h"
|
#include "../mem/mc.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
#include "../hos/hos.h"
|
|
||||||
|
|
||||||
// #include "../gfx/gfx.h"
|
// #include "../gfx/gfx.h"
|
||||||
|
|
||||||
@@ -81,7 +81,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
|
|
||||||
kfuse_wait_ready();
|
kfuse_wait_ready();
|
||||||
|
|
||||||
// Configure Falcon.
|
//Configure Falcon.
|
||||||
TSEC(TSEC_DMACTL) = 0;
|
TSEC(TSEC_DMACTL) = 0;
|
||||||
TSEC(TSEC_IRQMSET) =
|
TSEC(TSEC_IRQMSET) =
|
||||||
TSEC_IRQMSET_EXT(0xFF) |
|
TSEC_IRQMSET_EXT(0xFF) |
|
||||||
@@ -103,7 +103,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
goto out;
|
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)
|
if (kb == KB_FIRMWARE_VERSION_620)
|
||||||
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
TSEC(TSEC_DMATRFBASE) = (u32)tsec_ctxt->fw >> 8;
|
||||||
else
|
else
|
||||||
@@ -127,7 +127,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
{
|
{
|
||||||
// Init SMMU translation for TSEC.
|
// Init SMMU translation for TSEC.
|
||||||
pdir = smmu_init_for_tsec();
|
pdir = smmu_init_for_tsec();
|
||||||
smmu_init(tsec_ctxt->secmon_base);
|
smmu_init(0x4002B000);
|
||||||
// Enable SMMU
|
// Enable SMMU
|
||||||
if (!smmu_is_used())
|
if (!smmu_is_used())
|
||||||
smmu_enable();
|
smmu_enable();
|
||||||
@@ -170,7 +170,7 @@ int tsec_query(u8 *tsec_keys, u8 kb, tsec_ctxt_t *tsec_ctxt)
|
|||||||
iram = page_alloc(0x30);
|
iram = page_alloc(0x30);
|
||||||
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
memcpy(iram, tsec_ctxt->pkg1, 0x30000);
|
||||||
// PKG1.1 magic offset.
|
// 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);
|
smmu_map(pdir, 0x40010000, (u32)iram, 0x30, _READABLE | _WRITABLE | _NONSECURE);
|
||||||
|
|
||||||
// Exception vectors
|
// 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);
|
smmu_map(pdir, EXCP_VEC_BASE, (u32)evec, 1, _READABLE | _WRITABLE | _NONSECURE);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Execute firmware.
|
//Execute firmware.
|
||||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0x34C2E1DA;
|
||||||
TSEC(TSEC_STATUS) = 0;
|
TSEC(TSEC_STATUS) = 0;
|
||||||
TSEC(TSEC_BOOTKEYVER) = 1; // HOS uses key version 1.
|
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;
|
goto out_free;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fetch result.
|
//Fetch result.
|
||||||
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
HOST1X(HOST1X_CH0_SYNC_SYNCPT_160) = 0;
|
||||||
u32 buf[4];
|
u32 buf[4];
|
||||||
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
buf[0] = SOR1(SOR_NV_PDISP_SOR_DP_HDCP_BKSV_LSB);
|
||||||
@@ -275,7 +275,7 @@ out_free:;
|
|||||||
|
|
||||||
out:;
|
out:;
|
||||||
|
|
||||||
// Disable clocks.
|
//Disable clocks.
|
||||||
clock_disable_kfuse();
|
clock_disable_kfuse();
|
||||||
clock_disable_sor1();
|
clock_disable_sor1();
|
||||||
clock_disable_sor0();
|
clock_disable_sor0();
|
||||||
|
|||||||
@@ -27,8 +27,6 @@ typedef struct _tsec_ctxt_t
|
|||||||
void *fw;
|
void *fw;
|
||||||
u32 size;
|
u32 size;
|
||||||
void *pkg1;
|
void *pkg1;
|
||||||
u32 pkg11_off;
|
|
||||||
u32 secmon_base;
|
|
||||||
} tsec_ctxt_t;
|
} tsec_ctxt_t;
|
||||||
|
|
||||||
typedef struct _tsec_key_data_t
|
typedef struct _tsec_key_data_t
|
||||||
|
|||||||
@@ -26,7 +26,6 @@
|
|||||||
#include "pinmux.h"
|
#include "pinmux.h"
|
||||||
#include "pmc.h"
|
#include "pmc.h"
|
||||||
#include "t210.h"
|
#include "t210.h"
|
||||||
#include "uart.h"
|
|
||||||
#include "../gfx/di.h"
|
#include "../gfx/di.h"
|
||||||
#include "../mem/mc.h"
|
#include "../mem/mc.h"
|
||||||
#include "../mem/minerva.h"
|
#include "../mem/minerva.h"
|
||||||
@@ -102,7 +101,7 @@ void _config_gpios()
|
|||||||
|
|
||||||
pinmux_config_i2c(I2C_1);
|
pinmux_config_i2c(I2C_1);
|
||||||
pinmux_config_i2c(I2C_5);
|
pinmux_config_i2c(I2C_5);
|
||||||
pinmux_config_uart(UART_A);
|
pinmux_config_uart(0);
|
||||||
|
|
||||||
// Configure volume up/down as inputs.
|
// Configure volume up/down as inputs.
|
||||||
gpio_config(GPIO_PORT_X, GPIO_PIN_6, GPIO_MODE_GPIO);
|
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;
|
APB_MISC(APB_MISC_PP_PINMUX_GLOBAL) = 0;
|
||||||
_config_gpios();
|
_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_cl_dvfs();
|
||||||
|
|
||||||
clock_enable_i2c(I2C_1);
|
clock_enable_i2c(I2C_1);
|
||||||
@@ -319,6 +313,7 @@ void config_hw()
|
|||||||
sdram_init();
|
sdram_init();
|
||||||
|
|
||||||
bpmp_mmu_enable();
|
bpmp_mmu_enable();
|
||||||
|
mc_enable_ahb_redirect();
|
||||||
|
|
||||||
// Clear flags from PMC_SCRATCH0
|
// Clear flags from PMC_SCRATCH0
|
||||||
PMC(APBDEV_PMC_SCRATCH0) &= ~PMC_SCRATCH0_MODE_PAYLOAD;
|
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.
|
// 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_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)
|
if (extra_reconfig)
|
||||||
{
|
{
|
||||||
@@ -357,7 +352,7 @@ void reconfig_hw_workaround(bool extra_reconfig, u32 magic)
|
|||||||
if (magic == 0xBAADF00D)
|
if (magic == 0xBAADF00D)
|
||||||
{
|
{
|
||||||
CLOCK(CLK_RST_CONTROLLER_CLK_OUT_ENB_L) |= (1 << 22);
|
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();
|
clock_disable_cl_dvfs();
|
||||||
|
|
||||||
msleep(200);
|
msleep(200);
|
||||||
|
|||||||
@@ -32,6 +32,7 @@ extern sdmmc_storage_t sd_storage;
|
|||||||
extern FATFS sd_fs;
|
extern FATFS sd_fs;
|
||||||
|
|
||||||
extern hekate_config h_cfg;
|
extern hekate_config h_cfg;
|
||||||
|
emummc_cfg_t emu_cfg;
|
||||||
|
|
||||||
extern bool sd_mount();
|
extern bool sd_mount();
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ typedef struct _emummc_cfg_t
|
|||||||
int fs_ver;
|
int fs_ver;
|
||||||
} emummc_cfg_t;
|
} emummc_cfg_t;
|
||||||
|
|
||||||
emummc_cfg_t emu_cfg;
|
extern emummc_cfg_t emu_cfg;
|
||||||
|
|
||||||
bool emummc_load_cfg();
|
bool emummc_load_cfg();
|
||||||
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
int emummc_storage_init_mmc(sdmmc_storage_t *storage, sdmmc_t *sdmmc);
|
||||||
|
|||||||
@@ -25,6 +25,10 @@
|
|||||||
bool sd_mounted = false, sd_inited = false;
|
bool sd_mounted = false, sd_inited = false;
|
||||||
static u32 sd_mode = SD_UHS_SDR82;
|
static u32 sd_mode = SD_UHS_SDR82;
|
||||||
|
|
||||||
|
sdmmc_t sd_sdmmc;
|
||||||
|
sdmmc_storage_t sd_storage;
|
||||||
|
FATFS sd_fs;
|
||||||
|
|
||||||
u32 sd_get_mode()
|
u32 sd_get_mode()
|
||||||
{
|
{
|
||||||
return sd_mode;
|
return sd_mode;
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ enum
|
|||||||
SD_UHS_SDR82 = 3,
|
SD_UHS_SDR82 = 3,
|
||||||
};
|
};
|
||||||
|
|
||||||
sdmmc_t sd_sdmmc;
|
extern sdmmc_t sd_sdmmc;
|
||||||
sdmmc_storage_t sd_storage;
|
extern sdmmc_storage_t sd_storage;
|
||||||
FATFS sd_fs;
|
extern FATFS sd_fs;
|
||||||
|
|
||||||
u32 sd_get_mode();
|
u32 sd_get_mode();
|
||||||
int sd_init_retry(bool power_cycle);
|
int sd_init_retry(bool power_cycle);
|
||||||
|
|||||||
@@ -21,7 +21,7 @@
|
|||||||
#include "../utils/types.h"
|
#include "../utils/types.h"
|
||||||
#include "sdmmc_driver.h"
|
#include "sdmmc_driver.h"
|
||||||
|
|
||||||
u32 sd_power_cycle_time_start;
|
extern u32 sd_power_cycle_time_start;
|
||||||
|
|
||||||
typedef enum _sdmmc_type
|
typedef enum _sdmmc_type
|
||||||
{
|
{
|
||||||
|
|||||||
@@ -29,6 +29,11 @@
|
|||||||
#include "../soc/t210.h"
|
#include "../soc/t210.h"
|
||||||
#include "../utils/util.h"
|
#include "../utils/util.h"
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
|
u32 sd_power_cycle_time_start;
|
||||||
|
|
||||||
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
//#define DPRINTF(...) gfx_printf(__VA_ARGS__)
|
||||||
#define DPRINTF(...)
|
#define DPRINTF(...)
|
||||||
|
|
||||||
@@ -1158,6 +1163,8 @@ int sdmmc_init(sdmmc_t *sdmmc, u32 id, u32 power, u32 bus_width, u32 type, int a
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|
||||||
void sdmmc_end(sdmmc_t *sdmmc)
|
void sdmmc_end(sdmmc_t *sdmmc)
|
||||||
{
|
{
|
||||||
if (!sdmmc->clock_stopped)
|
if (!sdmmc->clock_stopped)
|
||||||
|
|||||||
@@ -21,9 +21,11 @@ enum utils_err_codes_te_call {
|
|||||||
ERR_EMMC_WRITE_FAILED,
|
ERR_EMMC_WRITE_FAILED,
|
||||||
ERR_FILE_TOO_BIG_FOR_DEST,
|
ERR_FILE_TOO_BIG_FOR_DEST,
|
||||||
ERR_SD_EJECTED,
|
ERR_SD_EJECTED,
|
||||||
ERR_PARSE_FAIL,
|
ERR_SCRIPT_LOOKUP_FAIL,
|
||||||
ERR_CANNOT_COPY_FILE_TO_FS_PART,
|
ERR_CANNOT_COPY_FILE_TO_FS_PART,
|
||||||
ERR_NO_DESTINATION
|
ERR_NO_DESTINATION,
|
||||||
|
ERR_INI_PARSE_FAIL,
|
||||||
|
ERR_IN_FUNC
|
||||||
};
|
};
|
||||||
|
|
||||||
extern const char *utils_err_codes_te[];
|
extern const char *utils_err_codes_te[];
|
||||||
@@ -58,8 +60,7 @@ extern menu_entry mainmenu_shutdown[];
|
|||||||
enum mainmenu_tools_return {
|
enum mainmenu_tools_return {
|
||||||
TOOLS_DISPLAY_INFO = 1,
|
TOOLS_DISPLAY_INFO = 1,
|
||||||
TOOLS_DISPLAY_GPIO,
|
TOOLS_DISPLAY_GPIO,
|
||||||
TOOLS_DUMPFIRMWARE,
|
TOOLS_DUMPFIRMWARE
|
||||||
TOOLS_DUMPUSERSAVE
|
|
||||||
};
|
};
|
||||||
|
|
||||||
extern menu_entry mainmenu_tools[];
|
extern menu_entry mainmenu_tools[];
|
||||||
@@ -86,7 +87,8 @@ enum fs_menu_file_return {
|
|||||||
FILE_PAYLOAD,
|
FILE_PAYLOAD,
|
||||||
FILE_SCRIPT,
|
FILE_SCRIPT,
|
||||||
FILE_HEXVIEW,
|
FILE_HEXVIEW,
|
||||||
FILE_DUMPBIS
|
FILE_DUMPBIS,
|
||||||
|
FILE_SIGN
|
||||||
};
|
};
|
||||||
|
|
||||||
extern menu_entry fs_menu_file[];
|
extern menu_entry fs_menu_file[];
|
||||||
@@ -114,3 +116,5 @@ extern gpt_entry_rule gpt_fs_rules[];
|
|||||||
extern menu_entry mmcmenu_start[];
|
extern menu_entry mmcmenu_start[];
|
||||||
|
|
||||||
extern menu_entry mmcmenu_filemenu[];
|
extern menu_entry mmcmenu_filemenu[];
|
||||||
|
|
||||||
|
extern menu_entry fwDump_typeMenu[];
|
||||||
@@ -50,9 +50,11 @@ const char *utils_err_codes_te[] = { // these start at 50
|
|||||||
"EMMC WRITE FAILED",
|
"EMMC WRITE FAILED",
|
||||||
"FILE TOO BIG FOR DEST",
|
"FILE TOO BIG FOR DEST",
|
||||||
"SD EJECTED",
|
"SD EJECTED",
|
||||||
"PARSING FAILED",
|
"FUNC LOOKUP FAIL",
|
||||||
"CANNOT COPY FILE TO FS PART",
|
"CANNOT COPY FILE TO FS PART",
|
||||||
"NO DESTINATION"
|
"NO DESTINATION",
|
||||||
|
"INI PARSE FAIL",
|
||||||
|
"ERR IN FUNC"
|
||||||
};
|
};
|
||||||
/*
|
/*
|
||||||
const char *pkg2names[] = {
|
const char *pkg2names[] = {
|
||||||
|
|||||||
@@ -2,74 +2,74 @@
|
|||||||
#include "types.h"
|
#include "types.h"
|
||||||
|
|
||||||
menu_entry mainmenu_main[] = {
|
menu_entry mainmenu_main[] = {
|
||||||
{"[SD:/] SD CARD", COLOR_GREEN, ISMENU},
|
{"[SD:/] SD CARD", COLOR_GREEN, {ISMENU}},
|
||||||
{"[EMMC:/] EMMC", COLOR_ORANGE, ISMENU},
|
{"[EMMC:/] EMMC", COLOR_ORANGE, {ISMENU}},
|
||||||
{"[EMMC:/] EMUMMC", COLOR_BLUE, ISMENU},
|
{"[EMMC:/] EMUMMC", COLOR_BLUE, {ISMENU}},
|
||||||
{"\nMount/Unmount SD", COLOR_WHITE, ISMENU},
|
{"\nMount/Unmount SD", COLOR_WHITE, {ISMENU}},
|
||||||
{"Tools", COLOR_VIOLET, ISMENU},
|
{"Tools", COLOR_VIOLET, {ISMENU}},
|
||||||
{"SD format", COLOR_VIOLET, ISMENU},
|
{"SD format", COLOR_VIOLET, {ISMENU}},
|
||||||
{"\nCredits", COLOR_WHITE, ISMENU},
|
{"\nCredits", COLOR_WHITE, {ISMENU}},
|
||||||
{"Exit", COLOR_WHITE, ISMENU}
|
{"Exit", COLOR_WHITE, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry mainmenu_shutdown[] = {
|
menu_entry mainmenu_shutdown[] = {
|
||||||
{"Back", COLOR_WHITE, ISMENU},
|
{"Back", COLOR_WHITE, {ISMENU}},
|
||||||
{"\nReboot to RCM", COLOR_VIOLET, ISMENU},
|
{"\nReboot to RCM", COLOR_VIOLET, {ISMENU}},
|
||||||
{"Reboot normally", COLOR_ORANGE, ISMENU},
|
{"Reboot normally", COLOR_ORANGE, {ISMENU}},
|
||||||
{"Power off\n", COLOR_BLUE, ISMENU},
|
{"Power off\n", COLOR_BLUE, {ISMENU}},
|
||||||
{"Reboot to Hekate", COLOR_GREEN, ISMENU},
|
{"Reboot to Hekate", COLOR_GREEN, {ISMENU}},
|
||||||
{"Reboot to Atmosphere", COLOR_GREEN, ISMENU}
|
{"Reboot to Atmosphere", COLOR_GREEN, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry mainmenu_tools[] = {
|
menu_entry mainmenu_tools[] = {
|
||||||
{"Back", COLOR_WHITE, ISMENU},
|
{"Back", COLOR_WHITE, {ISMENU}},
|
||||||
{"\nDisplay Console Info", COLOR_GREEN, ISMENU},
|
{"\nDisplay Console Info", COLOR_GREEN, {ISMENU}},
|
||||||
{"Display GPIO pins", COLOR_VIOLET, ISMENU},
|
{"Display GPIO pins", COLOR_VIOLET, {ISMENU}},
|
||||||
{"Dump Firmware", COLOR_BLUE, ISMENU},
|
{"Dump Firmware", COLOR_BLUE, {ISMENU}}
|
||||||
{"Dump User Saves", COLOR_YELLOW, ISMENU}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry mainmenu_format[] = {
|
menu_entry mainmenu_format[] = {
|
||||||
{"Back\n", COLOR_WHITE, ISMENU},
|
{"Back\n", COLOR_WHITE, {ISMENU}},
|
||||||
{"Format entire SD to FAT32", COLOR_RED, ISMENU},
|
{"Format entire SD to FAT32", COLOR_RED, {ISMENU}},
|
||||||
{"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, ISMENU}
|
{"Format for EmuMMC setup (FAT32/RAW)", COLOR_RED, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry utils_mmcChoice[] = {
|
menu_entry utils_mmcChoice[] = {
|
||||||
{"Back\n", COLOR_WHITE, ISMENU},
|
{"Back\n", COLOR_WHITE, {ISMENU}},
|
||||||
{"SysMMC", COLOR_ORANGE, ISMENU},
|
{"SysMMC", COLOR_ORANGE, {ISMENU}},
|
||||||
{"EmuMMC", COLOR_BLUE, ISMENU}
|
{"EmuMMC", COLOR_BLUE, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry fs_menu_file[] = {
|
menu_entry fs_menu_file[] = {
|
||||||
{NULL, COLOR_GREEN, ISMENU | ISSKIP},
|
{NULL, COLOR_GREEN, {ISMENU | ISSKIP}},
|
||||||
{NULL, COLOR_VIOLET, ISMENU | ISSKIP},
|
{NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
|
||||||
{NULL, COLOR_VIOLET, ISMENU | ISSKIP},
|
{NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
|
||||||
{"\n\n\nBack", COLOR_WHITE, ISMENU},
|
{"\n\n\nBack", COLOR_WHITE, {ISMENU}},
|
||||||
{"\nCopy to clipboard", COLOR_BLUE, ISMENU},
|
{"\nCopy to clipboard", COLOR_BLUE, {ISMENU}},
|
||||||
{"Move to clipboard", COLOR_BLUE, ISMENU},
|
{"Move to clipboard", COLOR_BLUE, {ISMENU}},
|
||||||
{"Rename file", COLOR_BLUE, ISMENU},
|
{"Rename file", COLOR_BLUE, {ISMENU}},
|
||||||
{"\nDelete file\n", COLOR_RED, ISMENU},
|
{"\nDelete file\n", COLOR_RED, {ISMENU}},
|
||||||
{"Launch Payload", COLOR_ORANGE, ISMENU},
|
{"Launch Payload", COLOR_ORANGE, {ISMENU}},
|
||||||
{"Launch Script", COLOR_YELLOW, ISMENU},
|
{"Launch Script", COLOR_YELLOW, {ISMENU}},
|
||||||
{"View Hex", COLOR_GREEN, ISMENU},
|
{"View Hex", COLOR_GREEN, {ISMENU}},
|
||||||
{"\nExtract BIS", COLOR_YELLOW, ISMENU}
|
{"\nExtract BIS", COLOR_YELLOW, {ISMENU}},
|
||||||
|
{"Sign Save", COLOR_ORANGE, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry fs_menu_folder[] = {
|
menu_entry fs_menu_folder[] = {
|
||||||
{NULL, COLOR_VIOLET, ISMENU | ISSKIP},
|
{NULL, COLOR_VIOLET, {ISMENU | ISSKIP}},
|
||||||
{"\nBack", COLOR_WHITE, ISMENU},
|
{"\nBack", COLOR_WHITE, {ISMENU}},
|
||||||
{"Return to main menu\n", COLOR_BLUE, ISMENU},
|
{"Return to main menu\n", COLOR_BLUE, {ISMENU}},
|
||||||
{"Copy to clipboard", COLOR_VIOLET, ISMENU},
|
{"Copy to clipboard", COLOR_VIOLET, {ISMENU}},
|
||||||
{"Delete folder\n", COLOR_RED, ISMENU},
|
{"Delete folder\n", COLOR_RED, {ISMENU}},
|
||||||
{"Rename folder", COLOR_BLUE, ISMENU},
|
{"Rename folder", COLOR_BLUE, {ISMENU}},
|
||||||
{"Create folder", COLOR_BLUE, ISMENU}
|
{"Create folder", COLOR_BLUE, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry fs_menu_startdir[] = {
|
menu_entry fs_menu_startdir[] = {
|
||||||
{"Folder -> previous folder ", COLOR_ORANGE, ISMENU},
|
{"Folder -> previous folder ", COLOR_ORANGE, {ISMENU}},
|
||||||
{"Clipboard -> Current folder", COLOR_ORANGE, ISMENU},
|
{"Clipboard -> Current folder", COLOR_ORANGE, {ISMENU}},
|
||||||
{"Current folder menu ", COLOR_ORANGE, ISMENU}
|
{"Current folder menu ", COLOR_ORANGE, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
gpt_entry_rule gpt_fs_rules[] = {
|
gpt_entry_rule gpt_fs_rules[] = {
|
||||||
@@ -81,15 +81,22 @@ gpt_entry_rule gpt_fs_rules[] = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
menu_entry mmcmenu_start[] = {
|
menu_entry mmcmenu_start[] = {
|
||||||
{"Back", COLOR_ORANGE, ISMENU},
|
{"Back", COLOR_ORANGE, {ISMENU}},
|
||||||
{"Dump File Partitions", COLOR_ORANGE, ISMENU},
|
{"Dump File Partitions", COLOR_ORANGE, {ISMENU}},
|
||||||
{"Clipboard -> Partition\n", COLOR_ORANGE, ISMENU},
|
{"Clipboard -> Partition\n", COLOR_ORANGE, {ISMENU}},
|
||||||
{"BOOT0/1", COLOR_BLUE, isBOOT | ISMENU}
|
{"BOOT0/1", COLOR_BLUE, {ISNULL | ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
menu_entry mmcmenu_filemenu[] = {
|
menu_entry mmcmenu_filemenu[] = {
|
||||||
{"Part:", COLOR_ORANGE, ISSKIP | ISMENU},
|
{"Part:", COLOR_ORANGE, {ISSKIP | ISMENU}},
|
||||||
{NULL, COLOR_VIOLET, ISSKIP | ISMENU},
|
{NULL, COLOR_VIOLET, {ISSKIP | ISMENU}},
|
||||||
{"\nBack", COLOR_WHITE, ISMENU},
|
{"\nBack", COLOR_WHITE, {ISMENU}},
|
||||||
{"Dump to SD", COLOR_YELLOW, ISMENU}
|
{"Dump to SD", COLOR_YELLOW, {ISMENU}}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
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}}
|
||||||
|
};
|
||||||
|
|||||||
@@ -1,18 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../../utils/types.h"
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
#define ISDIR (1 << 0)
|
#define BIT(n) (1U << n)
|
||||||
#define ISARC (1 << 1)
|
|
||||||
|
|
||||||
#define ISHIDE (1 << 8)
|
#define ISDIR BIT(0)
|
||||||
#define ISMENU (1 << 9)
|
#define ISMENU BIT(1)
|
||||||
#define ISSKIP (1 << 10)
|
#define SETSIZE(x) (x << 2)
|
||||||
|
#define ISNULL BIT(4)
|
||||||
#define ISGB (1 << 7)
|
#define ISHIDE BIT(5)
|
||||||
#define ISMB (1 << 6)
|
#define ISSKIP BIT(6)
|
||||||
#define ISKB (1 << 5)
|
|
||||||
#define ISB (1 << 4)
|
|
||||||
#define ISNULL (1 << 3)
|
|
||||||
|
|
||||||
#define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift))
|
#define SETBIT(object, shift, value) ((value) ? (object |= shift) : (object &= ~shift))
|
||||||
|
|
||||||
@@ -27,7 +23,7 @@
|
|||||||
|
|
||||||
#define COPY_MODE_PRINT 0x1
|
#define COPY_MODE_PRINT 0x1
|
||||||
#define COPY_MODE_CANCEL 0x2
|
#define COPY_MODE_CANCEL 0x2
|
||||||
#define BUFSIZE 32768
|
#define BUFSIZE 65536 //32768
|
||||||
|
|
||||||
#define OPERATIONCOPY 0x2
|
#define OPERATIONCOPY 0x2
|
||||||
#define OPERATIONMOVE 0x4
|
#define OPERATIONMOVE 0x4
|
||||||
@@ -43,7 +39,17 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
char *name;
|
char *name;
|
||||||
u32 storage;
|
u32 storage;
|
||||||
u16 property;
|
union {
|
||||||
|
u8 property;
|
||||||
|
struct {
|
||||||
|
u8 isDir:1;
|
||||||
|
u8 isMenu:1;
|
||||||
|
u8 size:2;
|
||||||
|
u8 isNull:1;
|
||||||
|
u8 isHide:1;
|
||||||
|
u8 isSkip:1;
|
||||||
|
};
|
||||||
|
};
|
||||||
} menu_entry;
|
} menu_entry;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|||||||
@@ -217,9 +217,7 @@ int dump_biskeys(){
|
|||||||
|
|
||||||
//sdmmc_storage_set_mmc_partition(&storage, 0);
|
//sdmmc_storage_set_mmc_partition(&storage, 0);
|
||||||
//nx_emmc_gpt_parse(&sys_gpt, &storage);
|
//nx_emmc_gpt_parse(&sys_gpt, &storage);
|
||||||
|
|
||||||
se_aes_key_set(8, bis_key[2] + 0x00, 0x10);
|
|
||||||
se_aes_key_set(9, bis_key[2] + 0x10, 0x10);
|
|
||||||
|
|
||||||
pkg1inf.ver = pkg1_id->kb;
|
pkg1inf.ver = pkg1_id->kb;
|
||||||
strcpy(pkg1inf.id, pkg1_id->id);
|
strcpy(pkg1inf.id, pkg1_id->id);
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
|
|||||||
f_lseek(&fp, 0);
|
f_lseek(&fp, 0);
|
||||||
|
|
||||||
while (totalSectors > 0){
|
while (totalSectors > 0){
|
||||||
num = MIN(totalSectors, 64);
|
num = MIN(totalSectors, 128);
|
||||||
if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){
|
if (!emummc_storage_read(mmcstorage, lba_curr, num, buf)){
|
||||||
gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3);
|
gfx_errDisplay("dump_emmc_part", ERR_EMMC_READ_FAILED, 3);
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -16,35 +16,33 @@
|
|||||||
#include "../../utils/list.h"
|
#include "../../utils/list.h"
|
||||||
#include "../../mem/heap.h"
|
#include "../../mem/heap.h"
|
||||||
#include "emmcmenu.h"
|
#include "emmcmenu.h"
|
||||||
#include "../fs/fsreader.h"
|
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../gfx/menu.h"
|
#include "../gfx/menu.h"
|
||||||
#include "../fs/fsmenu.h"
|
#include "../fs/fsmenu.h"
|
||||||
#include "emmcoperations.h"
|
#include "emmcoperations.h"
|
||||||
#include "../fs/fsutils.h"
|
#include "../fs/fsutils.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
|
||||||
menu_entry *mmcMenuEntries = NULL;
|
menu_entry *mmcMenuEntries = NULL;
|
||||||
extern sdmmc_storage_t storage;
|
extern sdmmc_storage_t storage;
|
||||||
extern emmc_part_t *system_part;
|
extern emmc_part_t *system_part;
|
||||||
extern char *clipboard;
|
extern char *clipboard;
|
||||||
extern u8 clipboardhelper;
|
extern u8 clipboardhelper;
|
||||||
|
extern bool sd_mounted;
|
||||||
|
|
||||||
|
|
||||||
void addEntry(emmc_part_t *part, u8 property, int spot){
|
void addEntry(emmc_part_t *part, u8 property_GPT, int spot){
|
||||||
if (mmcMenuEntries[spot].name != NULL){
|
u32 storage = 0;
|
||||||
free(mmcMenuEntries[spot].name);
|
u8 property = 0;
|
||||||
}
|
|
||||||
|
|
||||||
utils_copystring(part->name, &mmcMenuEntries[spot].name);
|
if (property_GPT & isFS){
|
||||||
|
storage = (u32)(property_GPT & 0x7F);
|
||||||
if (property & isFS){
|
property = ISDIR;
|
||||||
mmcMenuEntries[spot].storage = (u32)(property & 0x7F);
|
|
||||||
mmcMenuEntries[spot].property = ISDIR;
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
u64 size = 0;
|
u64 size = 0;
|
||||||
int sizes = 0;
|
u32 sizes = 0;
|
||||||
mmcMenuEntries[spot].property = 0;
|
|
||||||
size = (u64)(part->lba_end + 1 - part->lba_start);
|
size = (u64)(part->lba_end + 1 - part->lba_start);
|
||||||
size *= (u64)NX_EMMC_BLOCKSIZE;
|
size *= (u64)NX_EMMC_BLOCKSIZE;
|
||||||
|
|
||||||
@@ -54,31 +52,36 @@ void addEntry(emmc_part_t *part, u8 property, int spot){
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (sizes > 3)
|
if (sizes > 3)
|
||||||
sizes = 0;
|
sizes = 3;
|
||||||
|
|
||||||
mmcMenuEntries[spot].property |= (1 << (4 + sizes));
|
property |= SETSIZE(sizes);
|
||||||
mmcMenuEntries[spot].storage = (u32)size;
|
storage = (u32)size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
mu_copySingle(part->name, storage, property, &mmcMenuEntries[spot]);
|
||||||
}
|
}
|
||||||
|
|
||||||
int fillMmcMenu(short mmcType){
|
int fillMmcMenu(short mmcType){
|
||||||
int count = 4, i;
|
int count = 4, i;
|
||||||
|
|
||||||
if (mmcMenuEntries != NULL)
|
if (mmcMenuEntries != NULL)
|
||||||
clearfileobjects(&mmcMenuEntries);
|
mu_clearObjects(&mmcMenuEntries);
|
||||||
|
|
||||||
link_t *gpt = selectGpt(mmcType);
|
link_t *gpt = selectGpt(mmcType);
|
||||||
|
|
||||||
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
|
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link)
|
||||||
count++;
|
count++;
|
||||||
|
|
||||||
createfileobjects(count, &mmcMenuEntries);
|
mu_createObjects(count, &mmcMenuEntries);
|
||||||
|
|
||||||
for (i = 0; i < 4; i++){
|
if (!sd_mounted)
|
||||||
utils_copystring(mmcmenu_start[i].name, &mmcMenuEntries[i].name);
|
sd_mount();
|
||||||
mmcMenuEntries[i].property = mmcmenu_start[i].property;
|
|
||||||
mmcMenuEntries[i].storage = mmcmenu_start[i].storage;
|
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){
|
LIST_FOREACH_ENTRY(emmc_part_t, part, gpt, link){
|
||||||
addEntry(part, checkGptRules(part->name), i++);
|
addEntry(part, checkGptRules(part->name), i++);
|
||||||
@@ -96,13 +99,17 @@ int handleEntries(short mmcType, menu_entry part){
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
if (!mount_mmc(part.name, part.storage))
|
if (!mount_mmc(part.name, part.storage))
|
||||||
fileexplorer("emmc:/", 1);
|
fileexplorer("emmc:/", 1);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
/*
|
||||||
if (mmcmenu_filemenu[1].name != NULL)
|
if (mmcmenu_filemenu[1].name != NULL)
|
||||||
free(mmcmenu_filemenu[1].name);
|
free(mmcmenu_filemenu[1].name);
|
||||||
|
|
||||||
utils_copystring(part.name, &mmcmenu_filemenu[1].name);
|
utils_copystring(part.name, &mmcmenu_filemenu[1].name);
|
||||||
|
*/
|
||||||
|
|
||||||
|
mu_copySingle(part.name, mmcmenu_filemenu[1].storage, mmcmenu_filemenu[1].property, &mmcmenu_filemenu[1]);
|
||||||
|
|
||||||
if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3)
|
if ((menu_make(mmcmenu_filemenu, 4, "-- RAW PARTITION --")) < 3)
|
||||||
return 0;
|
return 0;
|
||||||
@@ -112,7 +119,7 @@ int handleEntries(short mmcType, menu_entry part){
|
|||||||
|
|
||||||
gfx_clearscreen();
|
gfx_clearscreen();
|
||||||
|
|
||||||
if (part.property & isBOOT){
|
if (part.isNull){
|
||||||
res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps");
|
res = emmcDumpBoot("sd:/tegraexplorer/partition_dumps");
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
@@ -146,7 +153,7 @@ int makeMmcMenu(short mmcType){
|
|||||||
f_mkdir("sd:/tegraexplorer/partition_dumps");
|
f_mkdir("sd:/tegraexplorer/partition_dumps");
|
||||||
|
|
||||||
for (int i = 0; i < count; i++){
|
for (int i = 0; i < count; i++){
|
||||||
if (mmcMenuEntries[i].property & ISMENU || mmcMenuEntries[i].property & ISDIR)
|
if (mmcMenuEntries[i].property & (ISMENU | ISDIR))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
//gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name);
|
//gfx_printf("Dumping %s...\n", mmcMenuEntries[i].name);
|
||||||
@@ -159,10 +166,10 @@ int makeMmcMenu(short mmcType){
|
|||||||
case 2:
|
case 2:
|
||||||
if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){
|
if (!(clipboardhelper & ISDIR) && (clipboardhelper & OPERATIONCOPY)){
|
||||||
gfx_clearscreen();
|
gfx_clearscreen();
|
||||||
if (!mmcFlashFile(clipboard, mmcType)){
|
if (!mmcFlashFile(clipboard, mmcType, true)){
|
||||||
gfx_printf("\nDone!");
|
gfx_printf("\nDone!");
|
||||||
hidWait();
|
hidWait();
|
||||||
}
|
}
|
||||||
clipboardhelper = 0;
|
clipboardhelper = 0;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -173,4 +180,4 @@ int makeMmcMenu(short mmcType){
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@
|
|||||||
|
|
||||||
int emmcDumpSpecific(char *part, char *path);
|
int emmcDumpSpecific(char *part, char *path);
|
||||||
int emmcDumpBoot(char *basePath);
|
int emmcDumpBoot(char *basePath);
|
||||||
int mmcFlashFile(char *path, short mmcType);
|
int mmcFlashFile(char *path, short mmcType, bool warnings);
|
||||||
|
|
||||||
int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part);
|
int emmcDumpPart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part);
|
||||||
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part);
|
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part, bool warnings);
|
||||||
@@ -17,7 +17,7 @@
|
|||||||
extern sdmmc_storage_t storage;
|
extern sdmmc_storage_t storage;
|
||||||
extern emmc_part_t *system_part;
|
extern emmc_part_t *system_part;
|
||||||
|
|
||||||
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
|
int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part, bool warnings){
|
||||||
FIL fp;
|
FIL fp;
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
u8 *buf;
|
u8 *buf;
|
||||||
@@ -32,7 +32,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
|
|||||||
|
|
||||||
gfx_printf("Initializing\r");
|
gfx_printf("Initializing\r");
|
||||||
|
|
||||||
buf = calloc(16384, sizeof(u8));
|
buf = calloc(BUFSIZE, sizeof(u8));
|
||||||
|
|
||||||
if (!buf){
|
if (!buf){
|
||||||
gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1);
|
gfx_errDisplay("restore_emmc_part", ERR_MEM_ALLOC_FAILED, 1);
|
||||||
@@ -54,10 +54,10 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
|
|||||||
|
|
||||||
gfx_printf("Flashing %s\n", part->name);
|
gfx_printf("Flashing %s\n", part->name);
|
||||||
|
|
||||||
if (totalSize < totalSizeDest){
|
if (totalSize < totalSizeDest && warnings){
|
||||||
SWAPCOLOR(COLOR_ORANGE);
|
SWAPCOLOR(COLOR_ORANGE);
|
||||||
gfx_printf("File is too small for destination.\nDo you want to flash it anyway?\n\nB to Cancel\n");
|
gfx_printf("File is too small for destination.\nDo you want to flash it anyway?\n\nB to Cancel\n");
|
||||||
u8 btnres = gfx_makewaitmenu(
|
u32 btnres = gfx_makewaitmenu(
|
||||||
"A to Confirm",
|
"A to Confirm",
|
||||||
3
|
3
|
||||||
);
|
);
|
||||||
@@ -78,7 +78,7 @@ int emmcRestorePart(char *path, sdmmc_storage_t *mmcstorage, emmc_part_t *part){
|
|||||||
}
|
}
|
||||||
|
|
||||||
while (totalSectors > 0){
|
while (totalSectors > 0){
|
||||||
num = MIN(totalSectors, 32);
|
num = MIN(totalSectors, 128);
|
||||||
|
|
||||||
if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
|
if ((res = f_read(&fp, buf, num * NX_EMMC_BLOCKSIZE, NULL))){
|
||||||
gfx_errDisplay("restore_emmc_part", res, 5);
|
gfx_errDisplay("restore_emmc_part", res, 5);
|
||||||
@@ -214,13 +214,13 @@ emmc_part_t *mmcFindPart(char *path, short mmcType){
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int mmcFlashFile(char *path, short mmcType){
|
int mmcFlashFile(char *path, short mmcType, bool warnings){
|
||||||
emmc_part_t *part;
|
emmc_part_t *part;
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
part = mmcFindPart(path, mmcType);
|
part = mmcFindPart(path, mmcType);
|
||||||
if (part != NULL){
|
if (part != NULL){
|
||||||
res = emmcRestorePart(path, &storage, part);
|
res = emmcRestorePart(path, &storage, part, warnings);
|
||||||
emummc_storage_set_mmc_partition(&storage, 0);
|
emummc_storage_set_mmc_partition(&storage, 0);
|
||||||
return res;
|
return res;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
#include "../script/parser.h"
|
#include "../script/parser.h"
|
||||||
#include "../emmc/emmcoperations.h"
|
#include "../emmc/emmcoperations.h"
|
||||||
#include "../../hid/hid.h"
|
#include "../../hid/hid.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
#include "savesign.h"
|
||||||
|
|
||||||
extern char *currentpath;
|
extern char *currentpath;
|
||||||
extern char *clipboard;
|
extern char *clipboard;
|
||||||
@@ -120,40 +122,45 @@ void copyfile(const char *src_in, const char *outfolder){
|
|||||||
|
|
||||||
int filemenu(menu_entry file){
|
int filemenu(menu_entry file){
|
||||||
int temp;
|
int temp;
|
||||||
FILINFO attribs;
|
char *tempchar;
|
||||||
|
|
||||||
for (int i = 0; i < 3; i++)
|
/*
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
if (fs_menu_file[i].name != NULL)
|
if (fs_menu_file[i].name != NULL)
|
||||||
free(fs_menu_file[i].name);
|
free(fs_menu_file[i].name);
|
||||||
|
|
||||||
utils_copystring(file.name, &fs_menu_file[0].name);
|
utils_copystring(file.name, &fs_menu_file[0].name);
|
||||||
|
*/
|
||||||
|
mu_copySingle(file.name, fs_menu_file[0].storage, fs_menu_file[0].property, &fs_menu_file[0]);
|
||||||
|
|
||||||
|
|
||||||
|
if (fs_menu_file[1].name != NULL)
|
||||||
|
free(fs_menu_file[1].name);
|
||||||
|
|
||||||
fs_menu_file[1].name = malloc(16);
|
fs_menu_file[1].name = malloc(16);
|
||||||
fs_menu_file[2].name = malloc(16);
|
sprintf(fs_menu_file[1].name, "\nSize: %d %s", file.storage, gfx_file_size_names[file.size]);
|
||||||
|
|
||||||
for (temp = 4; temp < 8; temp++)
|
|
||||||
if ((file.property & (1 << temp)))
|
|
||||||
break;
|
|
||||||
|
|
||||||
|
if ((tempchar = fsutil_formatFileAttribs(fsutil_getnextloc(currentpath, file.name))) == NULL)
|
||||||
sprintf(fs_menu_file[1].name, "\nSize: %d %s", file.storage, gfx_file_size_names[temp - 4]);
|
fs_menu_file[2].isHide = 1;
|
||||||
|
|
||||||
if (f_stat(fsutil_getnextloc(currentpath, file.name), &attribs))
|
|
||||||
SETBIT(fs_menu_file[2].property, ISHIDE, 1);
|
|
||||||
else {
|
else {
|
||||||
SETBIT(fs_menu_file[2].property, ISHIDE, 0);
|
fs_menu_file[2].isHide = 0;
|
||||||
sprintf(fs_menu_file[2].name, "Attribs: %c%c%c%c",
|
mu_copySingle(tempchar, fs_menu_file[2].storage, fs_menu_file[2].property, &fs_menu_file[2]);
|
||||||
(attribs.fattrib & AM_RDO) ? 'R' : '-',
|
|
||||||
(attribs.fattrib & AM_SYS) ? 'S' : '-',
|
|
||||||
(attribs.fattrib & AM_HID) ? 'H' : '-',
|
|
||||||
(attribs.fattrib & AM_ARC) ? 'A' : '-');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fs_menu_file[6].isHide = !hidConnected();
|
||||||
|
fs_menu_file[8].isHide = (!(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL);
|
||||||
|
fs_menu_file[9].isHide = (strstr(file.name, ".te") == NULL);
|
||||||
|
fs_menu_file[11].isHide = (strstr(file.name, ".bis") == NULL);
|
||||||
|
fs_menu_file[12].isHide = (!!strcmp(currentpath, "emmc:/save"));
|
||||||
|
|
||||||
|
/*
|
||||||
SETBIT(fs_menu_file[6].property, ISHIDE, !hidConnected());
|
SETBIT(fs_menu_file[6].property, ISHIDE, !hidConnected());
|
||||||
SETBIT(fs_menu_file[8].property, ISHIDE, !(strstr(file.name, ".bin") != NULL && file.property & ISKB) && strstr(file.name, ".rom") == NULL);
|
SETBIT(fs_menu_file[8].property, ISHIDE, !(strstr(file.name, ".bin") != NULL && file.size == 1) && strstr(file.name, ".rom") == NULL);
|
||||||
SETBIT(fs_menu_file[9].property, ISHIDE, strstr(file.name, ".te") == NULL);
|
SETBIT(fs_menu_file[9].property, ISHIDE, strstr(file.name, ".te") == NULL);
|
||||||
SETBIT(fs_menu_file[11].property, ISHIDE, strstr(file.name, ".bis") == NULL);
|
SETBIT(fs_menu_file[11].property, ISHIDE, strstr(file.name, ".bis") == NULL);
|
||||||
|
*/
|
||||||
|
|
||||||
temp = menu_make(fs_menu_file, 12, "-- File Menu --");
|
temp = menu_make(fs_menu_file, 13, "-- File Menu --");
|
||||||
switch (temp){
|
switch (temp){
|
||||||
case FILE_COPY:
|
case FILE_COPY:
|
||||||
fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY);
|
fsreader_writeclipboard(fsutil_getnextloc(currentpath, file.name), OPERATIONCOPY);
|
||||||
@@ -208,6 +215,17 @@ int filemenu(menu_entry file){
|
|||||||
extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath);
|
extract_bis_file(fsutil_getnextloc(currentpath, file.name), currentpath);
|
||||||
fsreader_readfolder(currentpath);
|
fsreader_readfolder(currentpath);
|
||||||
hidWait();
|
hidWait();
|
||||||
|
break;
|
||||||
|
case FILE_SIGN:
|
||||||
|
if (gfx_defaultWaitMenu("WARNING!\n\nThis should only be used if you know what signing and a save is\nDo not do this if you don't know what this does\n\nRequires you to have a prod.keys located in the switch folder\n", 5)){
|
||||||
|
gfx_clearscreen();
|
||||||
|
gfx_printf("Signing save...\n");
|
||||||
|
if (save_sign("sd:/switch/prod.keys", fsutil_getnextloc(currentpath, file.name))){
|
||||||
|
gfx_printf("Done!\nPress any key to exit");
|
||||||
|
hidWait();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
break;
|
break;
|
||||||
case -1:
|
case -1:
|
||||||
return -1;
|
return -1;
|
||||||
|
|||||||
@@ -11,6 +11,7 @@
|
|||||||
#include "../../utils/sprintf.h"
|
#include "../../utils/sprintf.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../../hid/hid.h"
|
#include "../../hid/hid.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
|
||||||
extern char *currentpath;
|
extern char *currentpath;
|
||||||
extern char *clipboard;
|
extern char *clipboard;
|
||||||
@@ -42,21 +43,23 @@ void copyfolder(char *in, char *out){
|
|||||||
int foldermenu(){
|
int foldermenu(){
|
||||||
int res, hidConn;
|
int res, hidConn;
|
||||||
char *name;
|
char *name;
|
||||||
FILINFO attribs;
|
|
||||||
|
|
||||||
if (fs_menu_folder[0].name != NULL)
|
|
||||||
free(fs_menu_folder[0].name);
|
|
||||||
|
|
||||||
fs_menu_folder[0].name = malloc(16);
|
|
||||||
|
|
||||||
hidConn = hidConnected();
|
hidConn = hidConnected();
|
||||||
|
|
||||||
res = strlen(currentpath);
|
res = strlen(currentpath);
|
||||||
|
|
||||||
|
fs_menu_folder[3].isHide = (*(currentpath + res - 1) == '/');
|
||||||
|
fs_menu_folder[4].isHide = (*(currentpath + res - 1) == '/');
|
||||||
|
fs_menu_folder[5].isHide = (*(currentpath + res - 1) == '/' || !hidConn);
|
||||||
|
fs_menu_folder[6].isHide = !hidConn;
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
SETBIT(fs_menu_folder[3].property, ISHIDE, (*(currentpath + res - 1) == '/'));
|
SETBIT(fs_menu_folder[3].property, ISHIDE, (*(currentpath + res - 1) == '/'));
|
||||||
SETBIT(fs_menu_folder[4].property, ISHIDE, (*(currentpath + res - 1) == '/'));
|
SETBIT(fs_menu_folder[4].property, ISHIDE, (*(currentpath + res - 1) == '/'));
|
||||||
SETBIT(fs_menu_folder[5].property, ISHIDE, (*(currentpath + res - 1) == '/') || !hidConn);
|
SETBIT(fs_menu_folder[5].property, ISHIDE, (*(currentpath + res - 1) == '/') || !hidConn);
|
||||||
SETBIT(fs_menu_folder[6].property, ISHIDE, !hidConn);
|
SETBIT(fs_menu_folder[6].property, ISHIDE, !hidConn);
|
||||||
|
|
||||||
if (f_stat(currentpath, &attribs))
|
if (f_stat(currentpath, &attribs))
|
||||||
SETBIT(fs_menu_folder[0].property, ISHIDE, 1);
|
SETBIT(fs_menu_folder[0].property, ISHIDE, 1);
|
||||||
else {
|
else {
|
||||||
@@ -67,6 +70,17 @@ int foldermenu(){
|
|||||||
(attribs.fattrib & AM_HID) ? 'H' : '-',
|
(attribs.fattrib & AM_HID) ? 'H' : '-',
|
||||||
(attribs.fattrib & AM_ARC) ? 'A' : '-');
|
(attribs.fattrib & AM_ARC) ? 'A' : '-');
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
if ((name = fsutil_formatFileAttribs(currentpath)) == NULL){
|
||||||
|
fs_menu_folder[0].isHide = 1;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
fs_menu_folder[0].isHide = 0;
|
||||||
|
mu_copySingle(name, fs_menu_folder[0].storage, fs_menu_folder[0].property, &fs_menu_folder[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
res = menu_make(fs_menu_folder, 7, currentpath);
|
res = menu_make(fs_menu_folder, 7, currentpath);
|
||||||
|
|
||||||
|
|||||||
@@ -8,15 +8,15 @@
|
|||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../../mem/heap.h"
|
#include "../../mem/heap.h"
|
||||||
#include "../../hid/hid.h"
|
#include "../../hid/hid.h"
|
||||||
|
#include "../../utils/btn.h"
|
||||||
#include "fsutils.h"
|
#include "fsutils.h"
|
||||||
|
|
||||||
int fsact_copy(const char *locin, const char *locout, u8 options){
|
int fsact_copy(const char *locin, const char *locout, u8 options){
|
||||||
FIL in, out;
|
FIL in, out;
|
||||||
FILINFO in_info;
|
FILINFO in_info;
|
||||||
u64 sizeoffile, sizecopied = 0, totalsize;
|
u64 sizeRemaining, toCopy;
|
||||||
UINT temp1, temp2;
|
u8 *buff, toPrint = options & COPY_MODE_PRINT, toCancel = options & COPY_MODE_CANCEL;
|
||||||
u8 *buff;
|
u32 x, y, i = 11;
|
||||||
unsigned int x, y, i = 0;
|
|
||||||
int res;
|
int res;
|
||||||
|
|
||||||
gfx_con_getpos(&x, &y);
|
gfx_con_getpos(&x, &y);
|
||||||
@@ -31,64 +31,73 @@ int fsact_copy(const char *locin, const char *locout, u8 options){
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f_stat(locin, &in_info)){
|
if ((res = f_stat(locin, &in_info))){
|
||||||
gfx_errDisplay("copy", res, 3);
|
gfx_errDisplay("copy", res, 3);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (f_open(&out, locout, FA_CREATE_ALWAYS | FA_WRITE)){
|
if ((res = f_open(&out, locout, FA_CREATE_ALWAYS | FA_WRITE))){
|
||||||
gfx_errDisplay("copy", res, 4);
|
gfx_errDisplay("copy", res, 4);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (toPrint){
|
||||||
|
SWAPCOLOR(COLOR_GREEN);
|
||||||
|
gfx_printf("[ ]");
|
||||||
|
x += 16;
|
||||||
|
gfx_con_setpos(x, y);
|
||||||
|
}
|
||||||
|
|
||||||
buff = malloc (BUFSIZE);
|
buff = malloc (BUFSIZE);
|
||||||
sizeoffile = f_size(&in);
|
sizeRemaining = f_size(&in);
|
||||||
totalsize = sizeoffile;
|
const u64 totalsize = sizeRemaining;
|
||||||
|
|
||||||
while (sizeoffile > 0){
|
while (sizeRemaining > 0){
|
||||||
if ((res = f_read(&in, buff, (sizeoffile > BUFSIZE) ? BUFSIZE : sizeoffile, &temp1))){
|
toCopy = MIN(sizeRemaining, BUFSIZE);
|
||||||
|
|
||||||
|
if ((res = f_read(&in, buff, toCopy, NULL))){
|
||||||
gfx_errDisplay("copy", res, 5);
|
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);
|
gfx_errDisplay("copy", res, 6);
|
||||||
return 1;
|
break;
|
||||||
}
|
|
||||||
|
|
||||||
if (temp1 != temp2){
|
|
||||||
gfx_errDisplay("copy", ERR_DISK_WRITE_FAILED, 7);
|
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
sizeoffile -= temp1;
|
sizeRemaining -= toCopy;
|
||||||
sizecopied += temp1;
|
|
||||||
|
|
||||||
if (options & COPY_MODE_PRINT && 10 > i++){
|
if (toPrint && (i > 16 || !sizeRemaining)){
|
||||||
gfx_printf("%k[%d%%]%k", COLOR_GREEN, ((sizecopied * 100) / totalsize) ,COLOR_WHITE);
|
gfx_printf("%3d%%", (u32)(((totalsize - sizeRemaining) * 100) / totalsize));
|
||||||
gfx_con_setpos(x, y);
|
gfx_con_setpos(x, y);
|
||||||
|
|
||||||
i = 0;
|
|
||||||
|
|
||||||
if (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(&in);
|
||||||
f_close(&out);
|
f_close(&out);
|
||||||
free(buff);
|
free(buff);
|
||||||
|
|
||||||
if ((res = f_chmod(locout, in_info.fattrib, 0x3A))){
|
f_chmod(locout, in_info.fattrib, 0x3A);
|
||||||
gfx_errDisplay("copy", res, 8);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
f_stat(locin, &in_info); //somehow stops fatfs from being weird
|
f_stat(locin, &in_info); //somehow stops fatfs from being weird
|
||||||
return 0;
|
return res;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsact_del_recursive(char *path){
|
int fsact_del_recursive(char *path){
|
||||||
|
|||||||
@@ -13,25 +13,15 @@
|
|||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "fsactions.h"
|
#include "fsactions.h"
|
||||||
|
|
||||||
u32 DecodeInt(u8* data) {
|
|
||||||
u32 out = 0;
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++) {
|
|
||||||
out |= (data[i] << ((3 - i) * 8));
|
|
||||||
}
|
|
||||||
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
void copy_fil_size(FIL* in_src, FIL* out_src, int size_src){
|
void copy_fil_size(FIL* in_src, FIL* out_src, int size_src){
|
||||||
u8* buff;
|
u8* buff;
|
||||||
buff = calloc(16384, sizeof(u8));
|
buff = calloc(BUFSIZE, sizeof(u8));
|
||||||
|
|
||||||
int size = size_src;
|
int size = size_src;
|
||||||
int copysize;
|
int copysize;
|
||||||
|
|
||||||
while (size > 0){
|
while (size > 0){
|
||||||
copysize = MIN(16834, size);
|
copysize = MIN(BUFSIZE, size);
|
||||||
f_read(in_src, buff, copysize, NULL);
|
f_read(in_src, buff, copysize, NULL);
|
||||||
f_write(out_src, buff, copysize, NULL);
|
f_write(out_src, buff, copysize, NULL);
|
||||||
size -= copysize;
|
size -= copysize;
|
||||||
@@ -48,56 +38,50 @@ void gen_part(int size, FIL* in, char *path){
|
|||||||
f_close(&out);
|
f_close(&out);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const char *filenames[] = {
|
||||||
|
"BOOT0.bin",
|
||||||
|
"BOOT1.bin",
|
||||||
|
"BCPKG2-1-Normal-Main",
|
||||||
|
"BCPKG2-3-SafeMode-Main",
|
||||||
|
"BCPKG2-2-Normal-Sub",
|
||||||
|
"BCPKG2-4-SafeMode-Sub"
|
||||||
|
};
|
||||||
|
|
||||||
int extract_bis_file(char *path, char *outfolder){
|
int extract_bis_file(char *path, char *outfolder){
|
||||||
FIL in;
|
FIL in;
|
||||||
int res;
|
int res;
|
||||||
u8 version[0x10];
|
|
||||||
u8 args;
|
|
||||||
u8 temp[0x4];
|
|
||||||
u32 filesizes[4];
|
|
||||||
char *tempPath;
|
char *tempPath;
|
||||||
|
BisFile header;
|
||||||
|
|
||||||
if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){
|
if ((res = f_open(&in, path, FA_READ | FA_OPEN_EXISTING))){
|
||||||
gfx_errDisplay("extract_bis_file", res, 0);
|
gfx_errDisplay("extract_bis_file", res, 0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
f_read(&in, version, 0x10, NULL);
|
f_read(&in, &header, sizeof(BisFile), NULL);
|
||||||
f_read(&in, &args, 1, NULL);
|
|
||||||
|
|
||||||
for (int i = 0; i < 4; i++){
|
|
||||||
f_read(&in, temp, 4, NULL);
|
|
||||||
filesizes[i] = DecodeInt(temp);
|
|
||||||
}
|
|
||||||
|
|
||||||
gfx_printf("Version: %s\n\n", version);
|
|
||||||
|
|
||||||
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){
|
for (int i = 0; i < 4; i++)
|
||||||
utils_copystring(fsutil_getnextloc(outfolder, "BCPKG2-3-SafeMode-Main"), &tempPath);
|
header.sizes[i] = FLIPU32(header.sizes[i]);
|
||||||
gfx_printf("Extracting BCPKG2_3/4\n");
|
|
||||||
|
|
||||||
gen_part(filesizes[3], &in, tempPath);
|
gfx_printf("Version: %s\n\n", header.version);
|
||||||
fsact_copy(tempPath, fsutil_getnextloc(outfolder, "BCPKG2-4-SafeMode-Sub"), COPY_MODE_PRINT);
|
|
||||||
|
// Loop to actually extract stuff
|
||||||
|
for (int i = 0; i < 4; i++){
|
||||||
|
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]));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Loop to copy pkg2_1->2 and pkg2_3->4
|
||||||
|
for (int i = 4; i < 6; i++){
|
||||||
|
if (!(header.args & BIT((9 - i))))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
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;
|
RESETCOLOR;
|
||||||
free(tempPath);
|
free(tempPath);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "../common/common.h"
|
#include "../common/common.h"
|
||||||
#include "../../libs/fatfs/ff.h"
|
#include "../../libs/fatfs/ff.h"
|
||||||
#include "entrymenu.h"
|
#include "entrymenu.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
|
||||||
extern char *currentpath;
|
extern char *currentpath;
|
||||||
extern char *clipboard;
|
extern char *clipboard;
|
||||||
@@ -35,7 +36,7 @@ void fileexplorer(const char *startpath, int type){
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
while (1){
|
while (1){
|
||||||
res = menu_make(fsreader_files, fsutil_getfileobjamount(fsreader_files), currentpath);
|
res = menu_make(fsreader_files, mu_countObjects(fsreader_files, 0, 0), currentpath);
|
||||||
switch (res){
|
switch (res){
|
||||||
case FILEMENU_RETURN:
|
case FILEMENU_RETURN:
|
||||||
if (!strcmp(startpath, currentpath))
|
if (!strcmp(startpath, currentpath))
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
#include "../gfx/gfxutils.h"
|
#include "../gfx/gfxutils.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
#include "../../mem/heap.h"
|
#include "../../mem/heap.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
|
||||||
menu_entry *fsreader_files = NULL;
|
menu_entry *fsreader_files = NULL;
|
||||||
char *currentpath = NULL;
|
char *currentpath = NULL;
|
||||||
@@ -29,59 +30,16 @@ void fsreader_writeclipboard(const char *in, u8 args){
|
|||||||
utils_copystring(in, &clipboard);
|
utils_copystring(in, &clipboard);
|
||||||
}
|
}
|
||||||
|
|
||||||
void clearfileobjects(menu_entry **menu){
|
|
||||||
if ((*menu) != NULL){
|
|
||||||
for (int i = 0; (*menu)[i].name != NULL; i++){
|
|
||||||
free((*menu)[i].name);
|
|
||||||
(*menu)[i].name = NULL;
|
|
||||||
}
|
|
||||||
free((*menu));
|
|
||||||
(*menu) = NULL;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void createfileobjects(int size, menu_entry **menu){
|
|
||||||
(*menu) = calloc (size + 1, sizeof(menu_entry));
|
|
||||||
(*menu)[size].name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addobject(char* name, int spot, u8 attribs){
|
void addobject(char* name, int spot, u8 attribs){
|
||||||
/*
|
u8 property = 0;
|
||||||
u64 size = 0;
|
|
||||||
int sizes = 0;
|
|
||||||
*/
|
|
||||||
fsreader_files[spot].property = 0;
|
|
||||||
|
|
||||||
if (fsreader_files[spot].name != NULL){
|
|
||||||
free(fsreader_files[spot].name);
|
|
||||||
fsreader_files[spot].name = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
utils_copystring(name, &(fsreader_files[spot].name));
|
|
||||||
|
|
||||||
if (attribs & AM_DIR)
|
if (attribs & AM_DIR)
|
||||||
fsreader_files[spot].property |= (ISDIR);
|
property |= ISDIR;
|
||||||
else {
|
else
|
||||||
/*
|
property |= ISNULL;
|
||||||
size = fsutil_getfilesize(fsutil_getnextloc(currentpath, name));
|
|
||||||
|
|
||||||
while (size > 1024){
|
|
||||||
size /= 1024;
|
|
||||||
sizes++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sizes > 3)
|
mu_copySingle(name, 0, property, &fsreader_files[spot]);
|
||||||
sizes = 0;
|
|
||||||
|
|
||||||
fsreader_files[spot].property |= (1 << (4 + sizes));
|
|
||||||
fsreader_files[spot].storage = size;
|
|
||||||
*/
|
|
||||||
fsreader_files[spot].storage = 0;
|
|
||||||
fsreader_files[spot].property = ISNULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (attribs & AM_ARC)
|
|
||||||
fsreader_files[spot].property |= (ISARC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsreader_readfolder(const char *path){
|
int fsreader_readfolder(const char *path){
|
||||||
@@ -89,14 +47,13 @@ int fsreader_readfolder(const char *path){
|
|||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
int folderamount, res;
|
int folderamount, res;
|
||||||
|
|
||||||
clearfileobjects(&fsreader_files);
|
mu_clearObjects(&fsreader_files);
|
||||||
createfileobjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files);
|
mu_createObjects(fsutil_getfolderentryamount(path) + 3, &fsreader_files);
|
||||||
|
|
||||||
for (folderamount = 0; folderamount < 3; folderamount++){
|
|
||||||
utils_copystring(fs_menu_startdir[folderamount].name, &(fsreader_files[folderamount].name));
|
|
||||||
fsreader_files[folderamount].storage = fs_menu_startdir[folderamount].storage;
|
for (folderamount = 0; folderamount < 3; folderamount++)
|
||||||
fsreader_files[folderamount].property = fs_menu_startdir[folderamount].property;
|
mu_copySingle(fs_menu_startdir[folderamount].name, fs_menu_startdir[folderamount].storage, fs_menu_startdir[folderamount].property, &fsreader_files[folderamount]);
|
||||||
}
|
|
||||||
|
|
||||||
if ((res = f_opendir(&dir, path))){
|
if ((res = f_opendir(&dir, path))){
|
||||||
gfx_errDisplay("readfolder", res, 0);
|
gfx_errDisplay("readfolder", res, 0);
|
||||||
|
|||||||
@@ -47,15 +47,6 @@ char *fsutil_getprevloc(char *current){
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int fsutil_getfileobjamount(menu_entry *entries){
|
|
||||||
int amount = 0;
|
|
||||||
|
|
||||||
while (entries[amount].name != NULL)
|
|
||||||
amount++;
|
|
||||||
|
|
||||||
return amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fsutil_checkfile(char* path){
|
bool fsutil_checkfile(char* path){
|
||||||
FRESULT fr;
|
FRESULT fr;
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
@@ -87,4 +78,21 @@ int fsutil_getfolderentryamount(const char *path){
|
|||||||
|
|
||||||
f_closedir(&dir);
|
f_closedir(&dir);
|
||||||
return folderamount;
|
return folderamount;
|
||||||
|
}
|
||||||
|
|
||||||
|
char *fsutil_formatFileAttribs(char *path){
|
||||||
|
FILINFO attribs;
|
||||||
|
char *out;
|
||||||
|
out = malloc(16);
|
||||||
|
|
||||||
|
if (f_stat(path, &attribs))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
sprintf(out, "Attribs: %c%c%c%c",
|
||||||
|
(attribs.fattrib & AM_RDO) ? 'R' : '-',
|
||||||
|
(attribs.fattrib & AM_SYS) ? 'S' : '-',
|
||||||
|
(attribs.fattrib & AM_HID) ? 'H' : '-',
|
||||||
|
(attribs.fattrib & AM_ARC) ? 'A' : '-');
|
||||||
|
|
||||||
|
return out;
|
||||||
}
|
}
|
||||||
@@ -2,10 +2,18 @@
|
|||||||
#include "../common/types.h"
|
#include "../common/types.h"
|
||||||
#include "../../utils/types.h"
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
u8 version[0x10];
|
||||||
|
u8 args;
|
||||||
|
u32 sizes[4];
|
||||||
|
} __attribute__((__packed__)) BisFile;
|
||||||
|
|
||||||
|
#define FLIPU32(in) ((in >> 24) & 0xFF) | ((in >> 8) & 0xFF00) | ((in << 8) & 0xFF0000) | ((in << 24) & 0xFF000000)
|
||||||
|
|
||||||
char *fsutil_getnextloc(const char *current, const char *add);
|
char *fsutil_getnextloc(const char *current, const char *add);
|
||||||
char *fsutil_getprevloc(char *current);
|
char *fsutil_getprevloc(char *current);
|
||||||
int fsutil_getfileobjamount(menu_entry *entries);
|
|
||||||
bool fsutil_checkfile(char* path);
|
bool fsutil_checkfile(char* path);
|
||||||
u64 fsutil_getfilesize(char *path);
|
u64 fsutil_getfilesize(char *path);
|
||||||
int fsutil_getfolderentryamount(const char *path);
|
int fsutil_getfolderentryamount(const char *path);
|
||||||
int extract_bis_file(char *path, char *outfolder);
|
int extract_bis_file(char *path, char *outfolder);
|
||||||
|
char *fsutil_formatFileAttribs(char *path);
|
||||||
62
source/tegraexplorer/fs/keys.c
Normal file
62
source/tegraexplorer/fs/keys.c
Normal 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;
|
||||||
|
}
|
||||||
4
source/tegraexplorer/fs/keys.h
Normal file
4
source/tegraexplorer/fs/keys.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
|
u8 *GetKey(const char *keypath, const char *keyName);
|
||||||
46
source/tegraexplorer/fs/nca.c
Normal file
46
source/tegraexplorer/fs/nca.c
Normal 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;
|
||||||
|
}
|
||||||
4
source/tegraexplorer/fs/nca.h
Normal file
4
source/tegraexplorer/fs/nca.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
int GetNcaType(char *ncaPath);
|
||||||
|
int SetHeaderKey();
|
||||||
77
source/tegraexplorer/fs/savesign.c
Normal file
77
source/tegraexplorer/fs/savesign.c
Normal 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;
|
||||||
|
}
|
||||||
4
source/tegraexplorer/fs/savesign.h
Normal file
4
source/tegraexplorer/fs/savesign.h
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
|
bool save_sign(const char *keypath, const char *savepath);
|
||||||
@@ -23,7 +23,7 @@ void gfx_clearscreen(){
|
|||||||
gfx_boxGrey(0, 703, 1279, 719, 0xFF);
|
gfx_boxGrey(0, 703, 1279, 719, 0xFF);
|
||||||
gfx_boxGrey(0, 0, 1279, 15, 0xFF);
|
gfx_boxGrey(0, 0, 1279, 15, 0xFF);
|
||||||
gfx_con_setpos(0, 0);
|
gfx_con_setpos(0, 0);
|
||||||
gfx_printf("Tegraexplorer v2.0.0 | Battery: %3d%%\n", battery >> 8);
|
gfx_printf("Tegraexplorer v2.0.5 | Battery: %3d%%\n", battery >> 8);
|
||||||
|
|
||||||
RESETCOLOR;
|
RESETCOLOR;
|
||||||
}
|
}
|
||||||
@@ -41,7 +41,7 @@ u32 gfx_message(u32 color, const char* message, ...){
|
|||||||
return hidWait()->buttons;
|
return hidWait()->buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 gfx_errDisplay(char *src_func, int err, int loc){
|
u32 gfx_errDisplay(const char *src_func, int err, int loc){
|
||||||
if (!printerrors)
|
if (!printerrors)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
@@ -52,20 +52,20 @@ u32 gfx_errDisplay(char *src_func, int err, int loc){
|
|||||||
|
|
||||||
if (err < 15)
|
if (err < 15)
|
||||||
gfx_printf("Desc: %s\n", utils_err_codes[err]);
|
gfx_printf("Desc: %s\n", utils_err_codes[err]);
|
||||||
else if (err >= ERR_SAME_LOC && err <= ERR_NO_DESTINATION)
|
else if (err >= ERR_SAME_LOC && err <= ERR_IN_FUNC)
|
||||||
gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]);
|
gfx_printf("Desc: %s\n", utils_err_codes_te[err - 50]);
|
||||||
|
|
||||||
if (loc)
|
if (loc)
|
||||||
gfx_printf("Loc: %d\n", loc);
|
gfx_printf("Loc: %d\n", loc);
|
||||||
|
|
||||||
gfx_printf("\nPress any button to return");
|
gfx_printf("\nPress any button to return\n");
|
||||||
|
|
||||||
RESETCOLOR;
|
RESETCOLOR;
|
||||||
|
|
||||||
return hidWait()->buttons;
|
return hidWait()->buttons;
|
||||||
}
|
}
|
||||||
|
|
||||||
int gfx_makewaitmenu(char *hiddenmessage, int timer){
|
int gfx_makewaitmenu(const char *hiddenmessage, int timer){
|
||||||
u32 start = get_tmr_s();
|
u32 start = get_tmr_s();
|
||||||
Inputs *input = NULL;
|
Inputs *input = NULL;
|
||||||
|
|
||||||
@@ -86,7 +86,7 @@ int gfx_makewaitmenu(char *hiddenmessage, int timer){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_printlength(int size, char *toprint){
|
void gfx_printlength(int size, const char *toprint){
|
||||||
char *temp;
|
char *temp;
|
||||||
temp = (char*) malloc (size + 1);
|
temp = (char*) malloc (size + 1);
|
||||||
|
|
||||||
@@ -102,7 +102,7 @@ void gfx_printlength(int size, char *toprint){
|
|||||||
free(temp);
|
free(temp);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_printandclear(char *in, int length, int endX){
|
void gfx_printandclear(const char *in, int length, int endX){
|
||||||
u32 x, y;
|
u32 x, y;
|
||||||
|
|
||||||
gfx_printlength(length, in);
|
gfx_printlength(length, in);
|
||||||
@@ -126,12 +126,6 @@ void gfx_printandclear(char *in, int length, int endX){
|
|||||||
*/
|
*/
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_printfilesize(int size, char *type){
|
|
||||||
SWAPCOLOR(COLOR_VIOLET);
|
|
||||||
gfx_printf("\a%4d\e%s", size, type);
|
|
||||||
RESETCOLOR;
|
|
||||||
}
|
|
||||||
|
|
||||||
static u32 sideY = 0;
|
static u32 sideY = 0;
|
||||||
void _gfx_sideSetYAuto(){
|
void _gfx_sideSetYAuto(){
|
||||||
u32 getX, getY;
|
u32 getX, getY;
|
||||||
@@ -147,7 +141,7 @@ u32 gfx_sideGetY(){
|
|||||||
return sideY;
|
return sideY;
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_sideprintf(char* message, ...){
|
void gfx_sideprintf(const char* message, ...){
|
||||||
va_list ap;
|
va_list ap;
|
||||||
va_start(ap, message);
|
va_start(ap, message);
|
||||||
|
|
||||||
@@ -158,7 +152,7 @@ void gfx_sideprintf(char* message, ...){
|
|||||||
va_end(ap);
|
va_end(ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
void gfx_sideprintandclear(char* message, int length){
|
void gfx_sideprintandclear(const char* message, int length){
|
||||||
gfx_con_setpos(800, sideY);
|
gfx_con_setpos(800, sideY);
|
||||||
gfx_printandclear(message, length, 1279);
|
gfx_printandclear(message, length, 1279);
|
||||||
gfx_putc('\n');
|
gfx_putc('\n');
|
||||||
@@ -180,7 +174,7 @@ void gfx_drawScrollBar(int minView, int maxView, int count){
|
|||||||
gfx_boxGrey(740, 16 + offsetSize, 755, 16 + barSize + offsetSize, 0x66);
|
gfx_boxGrey(740, 16 + offsetSize, 755, 16 + barSize + offsetSize, 0x66);
|
||||||
}
|
}
|
||||||
|
|
||||||
int gfx_defaultWaitMenu(char *message, int time){
|
int gfx_defaultWaitMenu(const char *message, int time){
|
||||||
gfx_clearscreen();
|
gfx_clearscreen();
|
||||||
SWAPCOLOR(COLOR_ORANGE);
|
SWAPCOLOR(COLOR_ORANGE);
|
||||||
gfx_printf("\n%s\n\nPress B to return\n", message);
|
gfx_printf("\n%s\n\nPress B to return\n", message);
|
||||||
|
|||||||
@@ -4,20 +4,20 @@
|
|||||||
|
|
||||||
#define SWAPCOLOR(color) gfx_printf("%k", color)
|
#define SWAPCOLOR(color) gfx_printf("%k", color)
|
||||||
#define SWAPBGCOLOR(color) gfx_printf("%K", color)
|
#define SWAPBGCOLOR(color) gfx_printf("%K", color)
|
||||||
|
#define SWAPALLCOLOR(fg, bg) gfx_printf("%k%K", fg, bg)
|
||||||
#define RESETCOLOR gfx_printf("%k%K", COLOR_WHITE, COLOR_DEFAULT)
|
#define RESETCOLOR gfx_printf("%k%K", COLOR_WHITE, COLOR_DEFAULT)
|
||||||
|
|
||||||
void gfx_clearscreen();
|
void gfx_clearscreen();
|
||||||
u32 gfx_message(u32 color, const char* message, ...);
|
u32 gfx_message(u32 color, const char* message, ...);
|
||||||
u32 gfx_errDisplay(char *src_func, int err, int loc);
|
u32 gfx_errDisplay(const char *src_func, int err, int loc);
|
||||||
int gfx_makewaitmenu(char *hiddenmessage, int timer);
|
int gfx_makewaitmenu(const char *hiddenmessage, int timer);
|
||||||
void gfx_printlength(int size, char *toprint);
|
void gfx_printlength(int size, const char *toprint);
|
||||||
void gfx_printandclear(char *in, int length, int endX);
|
void gfx_printandclear(const char *in, int length, int endX);
|
||||||
void gfx_printfilesize(int size, char *type);
|
|
||||||
void gfx_sideSetY(u32 setY);
|
void gfx_sideSetY(u32 setY);
|
||||||
u32 gfx_sideGetY();
|
u32 gfx_sideGetY();
|
||||||
void gfx_sideprintf(char* message, ...);
|
void gfx_sideprintf(const char* message, ...);
|
||||||
void gfx_sideprintandclear(char* message, int length);
|
void gfx_sideprintandclear(const char* message, int length);
|
||||||
void gfx_drawScrollBar(int minView, int maxView, int count);
|
void gfx_drawScrollBar(int minView, int maxView, int count);
|
||||||
int gfx_defaultWaitMenu(char *message, int time);
|
int gfx_defaultWaitMenu(const char *message, int time);
|
||||||
|
|
||||||
extern int printerrors;
|
extern int printerrors;
|
||||||
@@ -9,82 +9,63 @@
|
|||||||
#include "../../soc/gpio.h"
|
#include "../../soc/gpio.h"
|
||||||
#include "../../hid/hid.h"
|
#include "../../hid/hid.h"
|
||||||
#include "../fs/fsutils.h"
|
#include "../fs/fsutils.h"
|
||||||
|
#include "../utils/menuUtils.h"
|
||||||
|
|
||||||
extern void sd_unmount();
|
extern void sd_unmount();
|
||||||
extern bool sd_inited;
|
extern bool sd_inited;
|
||||||
|
|
||||||
void _printentry(menu_entry *entry, bool highlighted, bool refresh, char *path){
|
#pragma GCC push_options
|
||||||
u64 size;
|
#pragma GCC optimize ("O2")
|
||||||
u16 sizes = 0;
|
|
||||||
u32 color = (entry->property & ISMENU) ? entry->storage : ((entry->property & ISDIR) ? COLOR_WHITE : COLOR_VIOLET);
|
|
||||||
/*
|
|
||||||
if (entry.property & ISMENU)
|
|
||||||
SWAPCOLOR(entry.storage);
|
|
||||||
else if (entry.property & ISDIR)
|
|
||||||
SWAPCOLOR(COLOR_WHITE);
|
|
||||||
else {
|
|
||||||
SWAPCOLOR(COLOR_VIOLET);
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
if (!(entry->property & ISMENU && entry->property & ISDIR)){
|
void _printentry(menu_entry *entry, bool highlighted, bool refresh, const char *path){
|
||||||
if (entry->property & ISNULL){
|
if (entry->isHide)
|
||||||
size = fsutil_getfilesize(fsutil_getnextloc(path, entry->name));
|
return;
|
||||||
|
|
||||||
while (size > 1024){
|
|
||||||
size /= 1024;
|
|
||||||
sizes++;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sizes > 3)
|
u32 color = (entry->isMenu) ? entry->storage : ((entry->isDir) ? COLOR_WHITE : COLOR_VIOLET);
|
||||||
sizes = 0;
|
|
||||||
|
|
||||||
entry->property |= (1 << (4 + sizes));
|
SWAPALLCOLOR((highlighted) ? COLOR_DEFAULT : color, (highlighted) ? color : COLOR_DEFAULT);
|
||||||
entry->storage = size;
|
|
||||||
SETBIT(entry->property, ISNULL, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
for (sizes = 4; sizes < 8; sizes++)
|
if (!(entry->isMenu))
|
||||||
if ((entry->property & (1 << sizes)))
|
gfx_printf("%c ", (entry->isDir) ? 30 : 31);
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
if (highlighted){
|
|
||||||
SWAPBGCOLOR(COLOR_WHITE);
|
|
||||||
if ((entry.property & ISMENU) ? entry.storage == COLOR_WHITE : entry.property & ISDIR)
|
|
||||||
SWAPCOLOR(COLOR_DEFAULT);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
SWAPBGCOLOR(COLOR_DEFAULT);
|
|
||||||
*/
|
|
||||||
SWAPCOLOR((highlighted) ? COLOR_DEFAULT : color);
|
|
||||||
SWAPBGCOLOR((highlighted) ? color : COLOR_DEFAULT);
|
|
||||||
|
|
||||||
if (!(entry->property & ISMENU))
|
|
||||||
gfx_printf("%c ", (entry->property & ISDIR) ? 30 : 31);
|
|
||||||
|
|
||||||
if (refresh)
|
if (refresh)
|
||||||
gfx_printandclear(entry->name, 37, 720);
|
gfx_printandclear(entry->name, 37, 720);
|
||||||
else
|
else
|
||||||
gfx_printlength(37, entry->name);
|
gfx_printlength(37, entry->name);
|
||||||
|
|
||||||
if (entry->property & ISDIR || entry->property & ISMENU)
|
if (entry->property & (ISMENU | ISDIR))
|
||||||
gfx_printf("\n");
|
gfx_printf("\n");
|
||||||
else {
|
else {
|
||||||
SWAPCOLOR(COLOR_BLUE);
|
if (entry->isNull){
|
||||||
SWAPBGCOLOR(COLOR_DEFAULT);
|
u64 totalSize;
|
||||||
|
u32 sizeType = 0;
|
||||||
|
totalSize = fsutil_getfilesize(fsutil_getnextloc(path, entry->name));
|
||||||
|
|
||||||
|
while (totalSize > 1024){
|
||||||
|
totalSize /= 1024;
|
||||||
|
sizeType++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sizeType > 3)
|
||||||
|
sizeType = 3;
|
||||||
|
|
||||||
|
entry->size = sizeType;
|
||||||
|
entry->storage = totalSize;
|
||||||
|
SETBIT(entry->property, ISNULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SWAPALLCOLOR(COLOR_BLUE, COLOR_DEFAULT);
|
||||||
gfx_printf("\a%4d", entry->storage);
|
gfx_printf("\a%4d", entry->storage);
|
||||||
gfx_con.fntsz = 8;
|
gfx_con.fntsz = 8;
|
||||||
gfx_printf("\n\e%s\n", gfx_file_size_names[sizes - 4]);
|
gfx_printf("\n\e%s\n", gfx_file_size_names[entry->size]);
|
||||||
gfx_con.fntsz = 16;
|
gfx_con.fntsz = 16;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool disableB = false;
|
bool disableB = false;
|
||||||
int menu_make(menu_entry *entries, int amount, char *toptext){
|
int menu_make(menu_entry *entries, int amount, const char *toptext){
|
||||||
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, maxscreen = 39, calculatedamount = 0;
|
int currentpos = 0, offset = 0, delay = 300, minscreen = 0, calculatedamount = 0, cursub = 0, temp;
|
||||||
u32 scrolltimer, timer, sideY;
|
u32 scrolltimer, timer, sideY;
|
||||||
bool refresh = true;
|
bool refresh = true;
|
||||||
Inputs *input = hidRead();
|
Inputs *input = hidRead();
|
||||||
@@ -92,23 +73,9 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
|
|||||||
|
|
||||||
gfx_clearscreen();
|
gfx_clearscreen();
|
||||||
|
|
||||||
for (int i = 0; i < amount; i++)
|
calculatedamount = mu_countObjects(entries, amount, ISMENU);
|
||||||
if (!(entries[i].property & ISMENU))
|
|
||||||
calculatedamount++;
|
|
||||||
|
|
||||||
gfx_con_setpos(0, 16);
|
gfx_con_setpos(0, 16);
|
||||||
/*
|
|
||||||
if (calculatedamount){
|
|
||||||
SWAPCOLOR(COLOR_DEFAULT);
|
|
||||||
SWAPBGCOLOR(COLOR_WHITE);
|
|
||||||
gfx_printf("%3d entries\n", calculatedamount);
|
|
||||||
RESETCOLOR;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
gfx_printf("\n");
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
SWAPCOLOR(COLOR_GREEN);
|
SWAPCOLOR(COLOR_GREEN);
|
||||||
gfx_printlength(42, toptext);
|
gfx_printlength(42, toptext);
|
||||||
@@ -131,80 +98,79 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
|
|||||||
gfx_sideprintf("\n\n\n");
|
gfx_sideprintf("\n\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
gfx_drawScrollBar(minscreen, maxscreen, amount);
|
for (;;){
|
||||||
|
|
||||||
while (!(input->a)){
|
|
||||||
gfx_con_setpos(0, 48);
|
gfx_con_setpos(0, 48);
|
||||||
timer = get_tmr_ms();
|
timer = get_tmr_ms();
|
||||||
|
|
||||||
if (!currentpos){
|
if (!currentpos)
|
||||||
while (currentpos < amount && entries[currentpos].property & (ISSKIP | ISHIDE))
|
cursub = 1;
|
||||||
currentpos++;
|
else if (currentpos == amount - 1)
|
||||||
}
|
cursub = -1;
|
||||||
if (currentpos == amount - 1){
|
else
|
||||||
while (currentpos >= 1 && entries[currentpos].property & (ISSKIP | ISHIDE))
|
cursub = 0;
|
||||||
currentpos--;
|
|
||||||
}
|
while (entries[currentpos].property & (ISSKIP | ISHIDE))
|
||||||
|
currentpos += cursub;
|
||||||
|
|
||||||
|
|
||||||
if (currentpos > maxscreen){
|
if (currentpos > (minscreen + SCREENMAXOFFSET)){
|
||||||
offset += currentpos - maxscreen;
|
offset += currentpos - (minscreen + SCREENMAXOFFSET);
|
||||||
minscreen += currentpos - maxscreen;
|
minscreen += currentpos - (minscreen + SCREENMAXOFFSET);
|
||||||
maxscreen += currentpos - maxscreen;
|
|
||||||
refresh = true;
|
refresh = true;
|
||||||
}
|
}
|
||||||
|
else if (currentpos < minscreen){
|
||||||
if (currentpos < minscreen){
|
|
||||||
offset -= minscreen - currentpos;
|
offset -= minscreen - currentpos;
|
||||||
maxscreen -= minscreen - currentpos;
|
minscreen -= minscreen - currentpos;
|
||||||
minscreen -= minscreen - currentpos;
|
refresh = true;
|
||||||
refresh = true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
if (refresh || currentfolder == NULL || !calculatedamount){
|
if (refresh || currentfolder == NULL || !calculatedamount){
|
||||||
for (int i = 0 + offset; i < amount && i < 40 + offset; i++)
|
for (int i = 0 + offset; i < amount && i < SCREENMAXOFFSET + 1 + offset; i++)
|
||||||
if (!(entries[i].property & ISHIDE))
|
_printentry(&entries[i], (i == currentpos), refresh, toptext);
|
||||||
_printentry(&entries[i], (i == currentpos), refresh, toptext);
|
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if (currentpos - minscreen > 0){
|
temp = (currentpos - minscreen > 0) ? 0 : 16;
|
||||||
gfx_con_setpos(0, 32 + (currentpos - minscreen) * 16);
|
gfx_con_setpos(0, 32 + temp + (currentpos - minscreen) * 16);
|
||||||
|
|
||||||
|
if (!temp)
|
||||||
_printentry(&entries[currentpos - 1], false, false, toptext);
|
_printentry(&entries[currentpos - 1], false, false, toptext);
|
||||||
}
|
|
||||||
else
|
|
||||||
gfx_con_setpos(0, 48 + (currentpos - minscreen) * 16);
|
|
||||||
|
|
||||||
_printentry(&entries[currentpos], true, false, toptext);
|
_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);
|
_printentry(&entries[currentpos + 1], false, false, toptext);
|
||||||
}
|
}
|
||||||
|
|
||||||
RESETCOLOR;
|
RESETCOLOR;
|
||||||
|
|
||||||
|
|
||||||
sideY = gfx_sideGetY();
|
sideY = gfx_sideGetY();
|
||||||
if (!(entries[currentpos].property & ISMENU)){
|
if (!(entries[currentpos].isMenu)){
|
||||||
gfx_sideprintf("Current selection:\n");
|
gfx_sideprintf("Current selection:\n");
|
||||||
SWAPCOLOR(COLOR_YELLOW);
|
SWAPCOLOR(COLOR_YELLOW);
|
||||||
gfx_sideprintandclear(entries[currentpos].name, 28);
|
gfx_sideprintandclear(entries[currentpos].name, 28);
|
||||||
RESETCOLOR;
|
RESETCOLOR;
|
||||||
gfx_sideprintf("Type: %s", (entries[currentpos].property & ISDIR) ? "Dir " : "File");
|
gfx_sideprintf("Type: %s", (entries[currentpos].isDir) ? "Dir " : "File");
|
||||||
gfx_sideSetY(sideY);
|
gfx_sideSetY(sideY);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
gfx_boxGrey(800, sideY, 1279, sideY + 48, 0x1B);
|
gfx_boxGrey(800, sideY, 1279, sideY + 48, 0x1B);
|
||||||
|
|
||||||
gfx_con_setpos(0, 703);
|
gfx_con_setpos(0, 703);
|
||||||
SWAPCOLOR(COLOR_DEFAULT);
|
SWAPALLCOLOR(COLOR_DEFAULT, COLOR_WHITE);
|
||||||
SWAPBGCOLOR(COLOR_WHITE);
|
|
||||||
gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - timer);
|
gfx_printf("Time taken for screen draw: %dms ", get_tmr_ms() - timer);
|
||||||
|
|
||||||
if (refresh)
|
if (refresh)
|
||||||
gfx_drawScrollBar(minscreen, maxscreen, amount);
|
gfx_drawScrollBar(minscreen, minscreen + SCREENMAXOFFSET, amount);
|
||||||
|
|
||||||
|
refresh = false;
|
||||||
|
|
||||||
|
|
||||||
while (hidRead()->buttons & (KEY_B | KEY_A));
|
while (hidRead()->buttons & (KEY_B | KEY_A));
|
||||||
|
|
||||||
input->buttons = 0;
|
scrolltimer = get_tmr_ms();
|
||||||
while (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){
|
while (1){
|
||||||
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){
|
if (sd_inited && !!gpio_read(GPIO_PORT_Z, GPIO_PIN_1)){
|
||||||
gfx_errDisplay("menu", ERR_SD_EJECTED, 0);
|
gfx_errDisplay("menu", ERR_SD_EJECTED, 0);
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
@@ -213,47 +179,58 @@ int menu_make(menu_entry *entries, int amount, char *toptext){
|
|||||||
|
|
||||||
input = hidRead();
|
input = hidRead();
|
||||||
|
|
||||||
if (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)))
|
if (!(input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))){
|
||||||
delay = 300;
|
delay = 300;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
if (delay < 300){
|
if (input->buttons & (KEY_RDOWN | KEY_RUP)){
|
||||||
scrolltimer = get_tmr_ms();
|
delay = 1;
|
||||||
while (input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN)){
|
input->Lup = input->Rup;
|
||||||
if (scrolltimer + delay <= get_tmr_ms())
|
input->Ldown = input->Rdown;
|
||||||
break;
|
|
||||||
|
|
||||||
input = hidRead();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (delay > 46 && input->buttons & (KEY_A | KEY_LDOWN | KEY_LUP | KEY_B | KEY_RUP | KEY_RDOWN))
|
if (delay < 300){
|
||||||
delay -= 45;
|
if (scrolltimer + delay < get_tmr_ms()){
|
||||||
|
break;
|
||||||
if (input->buttons & (KEY_RUP | KEY_RDOWN))
|
}
|
||||||
delay = 1;
|
}
|
||||||
|
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++;
|
|
||||||
}
|
|
||||||
|
|
||||||
else if (input->b && !disableB){
|
if (input->a){
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (input->b && !disableB){
|
||||||
currentpos = 0;
|
currentpos = 0;
|
||||||
break;
|
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();
|
minerva_periodic_training();
|
||||||
//return (mode) ? currentpos : entries[currentpos].property;
|
//return (mode) ? currentpos : entries[currentpos].property;
|
||||||
return currentpos;
|
return currentpos;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
@@ -1,4 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
#include "../common/types.h"
|
#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);
|
||||||
@@ -37,24 +37,12 @@ void MainMenu_SDCard(){
|
|||||||
|
|
||||||
void MainMenu_EMMC(){
|
void MainMenu_EMMC(){
|
||||||
if (gfx_defaultWaitMenu("You're about to enter EMMC\nModifying anything here can result in a BRICK!\n\nPlease only continue if you know what you're doing", 4)){
|
if (gfx_defaultWaitMenu("You're about to enter EMMC\nModifying anything here can result in a BRICK!\n\nPlease only continue if you know what you're doing", 4)){
|
||||||
/*
|
|
||||||
connect_mmc(SYSMMC);
|
|
||||||
|
|
||||||
if (!mount_mmc(emmc_fs_entries[res - 2], res - 1))
|
|
||||||
fileexplorer("emmc:/", 1);
|
|
||||||
*/
|
|
||||||
makeMmcMenu(SYSMMC);
|
makeMmcMenu(SYSMMC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu_EMUMMC(){
|
void MainMenu_EMUMMC(){
|
||||||
/*
|
makeMmcMenu(EMUMMC);
|
||||||
connect_mmc(EMUMMC);
|
|
||||||
|
|
||||||
if (!mount_mmc(emmc_fs_entries[res - 5], res - 4))
|
|
||||||
fileexplorer("emmc:/", 1);
|
|
||||||
*/
|
|
||||||
makeMmcMenu(EMUMMC);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu_MountSD(){
|
void MainMenu_MountSD(){
|
||||||
@@ -62,8 +50,7 @@ void MainMenu_MountSD(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu_Tools(){
|
void MainMenu_Tools(){
|
||||||
//res = makemenu(toolsmenu, 8);
|
res = menu_make(mainmenu_tools, 4, "-- Tools Menu --");
|
||||||
res = menu_make(mainmenu_tools, 5, "-- Tools Menu --");
|
|
||||||
|
|
||||||
switch(res){
|
switch(res){
|
||||||
case TOOLS_DISPLAY_INFO:
|
case TOOLS_DISPLAY_INFO:
|
||||||
@@ -71,21 +58,17 @@ void MainMenu_Tools(){
|
|||||||
break;
|
break;
|
||||||
case TOOLS_DISPLAY_GPIO:
|
case TOOLS_DISPLAY_GPIO:
|
||||||
displaygpio();
|
displaygpio();
|
||||||
//makeMmcMenu(SYSMMC);
|
|
||||||
break;
|
break;
|
||||||
case TOOLS_DUMPFIRMWARE:
|
case TOOLS_DUMPFIRMWARE:
|
||||||
dumpfirmware(SYSMMC);
|
res = menu_make(fwDump_typeMenu, 4, "-- Fw Type --");
|
||||||
break;
|
if (res >= 2)
|
||||||
case TOOLS_DUMPUSERSAVE:
|
dumpfirmware(SYSMMC, (res == 2));
|
||||||
if ((res = utils_mmcMenu()) > 0)
|
|
||||||
dumpusersaves(res);
|
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainMenu_SDFormat(){
|
void MainMenu_SDFormat(){
|
||||||
//res = makemenu(formatmenu, 4);
|
|
||||||
res = menu_make(mainmenu_format, 3, "-- Format Menu --");
|
res = menu_make(mainmenu_format, 3, "-- Format Menu --");
|
||||||
|
|
||||||
if (res > 0){
|
if (res > 0){
|
||||||
@@ -114,7 +97,7 @@ void MainMenu_Exit(){
|
|||||||
}
|
}
|
||||||
|
|
||||||
res = menu_make(mainmenu_shutdown, 6, "-- Shutdown Menu --");
|
res = menu_make(mainmenu_shutdown, 6, "-- Shutdown Menu --");
|
||||||
|
|
||||||
switch(res){
|
switch(res){
|
||||||
case SHUTDOWN_REBOOT_RCM:
|
case SHUTDOWN_REBOOT_RCM:
|
||||||
reboot_rcm();
|
reboot_rcm();
|
||||||
@@ -131,6 +114,7 @@ void MainMenu_Exit(){
|
|||||||
case SHUTDOWN_AMS:
|
case SHUTDOWN_AMS:
|
||||||
launch_payload("/atmosphere/reboot_payload.bin");
|
launch_payload("/atmosphere/reboot_payload.bin");
|
||||||
} //todo declock bpmp
|
} //todo declock bpmp
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func_void_ptr mainmenu_functions[] = {
|
func_void_ptr mainmenu_functions[] = {
|
||||||
@@ -153,27 +137,31 @@ void RunMenuOption(int option){
|
|||||||
void te_main(){
|
void te_main(){
|
||||||
int setter;
|
int setter;
|
||||||
|
|
||||||
|
//gfx_printf("Initing controller\n");
|
||||||
|
hidInit();
|
||||||
|
|
||||||
|
//gfx_printf("Getting biskeys\n");
|
||||||
if (dump_biskeys() == -1){
|
if (dump_biskeys() == -1){
|
||||||
gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0);
|
gfx_errDisplay("dump_biskey", ERR_BISKEY_DUMP_FAILED, 0);
|
||||||
//mainmenu_main[1].property |= ISHIDE;
|
//mainmenu_main[1].property |= ISHIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
//gfx_message(COLOR_ORANGE, "%d %d %d", sd_mount(), sd_mounted, sd_inited);
|
//gfx_printf("Mounting SD\n");
|
||||||
sd_mount();
|
sd_mount();
|
||||||
|
|
||||||
|
//gfx_printf("Loading possible EMU\n");
|
||||||
if (emummc_load_cfg()){
|
if (emummc_load_cfg()){
|
||||||
mainmenu_main[2].property |= ISHIDE;
|
mainmenu_main[2].property |= ISHIDE;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//gfx_printf("Dumping gpt\n");
|
||||||
dumpGpt();
|
dumpGpt();
|
||||||
|
|
||||||
|
//gfx_printf("Disconnecting EMMC\n");
|
||||||
disconnect_mmc();
|
disconnect_mmc();
|
||||||
|
|
||||||
hidInit();
|
//gfx_printf("Entering main menu\n");
|
||||||
|
|
||||||
while (1){
|
while (1){
|
||||||
//fillmainmenu();
|
|
||||||
|
|
||||||
setter = sd_mounted;
|
setter = sd_mounted;
|
||||||
|
|
||||||
if (emu_cfg.enabled){
|
if (emu_cfg.enabled){
|
||||||
|
|||||||
@@ -64,6 +64,9 @@ int parseStringInput(char *in, char **out){
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#pragma GCC push_options
|
||||||
|
#pragma GCC optimize ("Os")
|
||||||
|
|
||||||
u32 currentcolor = COLOR_WHITE;
|
u32 currentcolor = COLOR_WHITE;
|
||||||
int part_printf(){
|
int part_printf(){
|
||||||
SWAPCOLOR(currentcolor);
|
SWAPCOLOR(currentcolor);
|
||||||
@@ -71,14 +74,14 @@ int part_printf(){
|
|||||||
if (argv[i][0] == '@'){
|
if (argv[i][0] == '@'){
|
||||||
int toprintint;
|
int toprintint;
|
||||||
if (parseIntInput(argv[i], &toprintint))
|
if (parseIntInput(argv[i], &toprintint))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
gfx_printf("%d", toprintint);
|
gfx_printf("%d", toprintint);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
char *toprintstring;
|
char *toprintstring;
|
||||||
if (parseStringInput(argv[i], &toprintstring))
|
if (parseStringInput(argv[i], &toprintstring))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
gfx_printf(toprintstring);
|
gfx_printf(toprintstring);
|
||||||
}
|
}
|
||||||
@@ -91,7 +94,7 @@ int part_printf(){
|
|||||||
int part_print_int(){
|
int part_print_int(){
|
||||||
int toprint;
|
int toprint;
|
||||||
if (parseIntInput(argv[0], &toprint))
|
if (parseIntInput(argv[0], &toprint))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
SWAPCOLOR(currentcolor);
|
SWAPCOLOR(currentcolor);
|
||||||
gfx_printf("%s: %d\n", argv[0], toprint);
|
gfx_printf("%s: %d\n", argv[0], toprint);
|
||||||
@@ -104,7 +107,7 @@ int part_Wait(){
|
|||||||
SWAPCOLOR(currentcolor);
|
SWAPCOLOR(currentcolor);
|
||||||
|
|
||||||
if (parseIntInput(argv[0], &arg))
|
if (parseIntInput(argv[0], &arg))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
begintime = get_tmr_s();
|
begintime = get_tmr_s();
|
||||||
|
|
||||||
@@ -119,9 +122,9 @@ int part_Wait(){
|
|||||||
int part_Check(){
|
int part_Check(){
|
||||||
int left, right;
|
int left, right;
|
||||||
if (parseIntInput(argv[0], &left))
|
if (parseIntInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseIntInput(argv[2], &right))
|
if (parseIntInput(argv[2], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (!strcmp(argv[1], "=="))
|
if (!strcmp(argv[1], "=="))
|
||||||
return (left == right);
|
return (left == right);
|
||||||
@@ -136,13 +139,13 @@ int part_Check(){
|
|||||||
else if (!strcmp(argv[1], "<"))
|
else if (!strcmp(argv[1], "<"))
|
||||||
return (left < right);
|
return (left < right);
|
||||||
else
|
else
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int part_if(){
|
int part_if(){
|
||||||
int condition;
|
int condition;
|
||||||
if (parseIntInput(argv[0], &condition))
|
if (parseIntInput(argv[0], &condition))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
getfollowingchar('{');
|
getfollowingchar('{');
|
||||||
|
|
||||||
@@ -164,7 +167,7 @@ int part_if(){
|
|||||||
int part_if_args(){
|
int part_if_args(){
|
||||||
int condition;
|
int condition;
|
||||||
if ((condition = part_Check()) < 0)
|
if ((condition = part_Check()) < 0)
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
getfollowingchar('{');
|
getfollowingchar('{');
|
||||||
|
|
||||||
@@ -177,9 +180,9 @@ int part_if_args(){
|
|||||||
int part_Math(){
|
int part_Math(){
|
||||||
int left, right;
|
int left, right;
|
||||||
if (parseIntInput(argv[0], &left))
|
if (parseIntInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseIntInput(argv[2], &right))
|
if (parseIntInput(argv[2], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
switch (argv[1][0]){
|
switch (argv[1][0]){
|
||||||
case '+':
|
case '+':
|
||||||
@@ -191,7 +194,7 @@ int part_Math(){
|
|||||||
case '/':
|
case '/':
|
||||||
return left / right;
|
return left / right;
|
||||||
}
|
}
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
int part_SetInt(){
|
int part_SetInt(){
|
||||||
@@ -203,9 +206,9 @@ int part_SetInt(){
|
|||||||
int part_SetString(){
|
int part_SetString(){
|
||||||
char *arg0;
|
char *arg0;
|
||||||
if (parseStringInput(argv[0], &arg0))
|
if (parseStringInput(argv[0], &arg0))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (argv[1][0] != '$')
|
if (argv[1][0] != '$')
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
str_str_add(argv[1], arg0);
|
str_str_add(argv[1], arg0);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -215,11 +218,11 @@ int part_SetStringIndex(){
|
|||||||
int index;
|
int index;
|
||||||
char *out;
|
char *out;
|
||||||
if (parseIntInput(argv[0], &index))
|
if (parseIntInput(argv[0], &index))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (argv[1][0] != '$')
|
if (argv[1][0] != '$')
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (str_str_index(index, &out))
|
if (str_str_index(index, &out))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
str_str_add(argv[1], out);
|
str_str_add(argv[1], out);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -228,7 +231,10 @@ int part_SetStringIndex(){
|
|||||||
int part_goto(){
|
int part_goto(){
|
||||||
int target = 0;
|
int target = 0;
|
||||||
if (parseIntInput(argv[0], &target))
|
if (parseIntInput(argv[0], &target))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
|
str_int_add("@RETURN", (int)f_tell(&scriptin));
|
||||||
|
|
||||||
f_lseek(&scriptin, target);
|
f_lseek(&scriptin, target);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -236,14 +242,14 @@ int part_goto(){
|
|||||||
int part_invert(){
|
int part_invert(){
|
||||||
int arg;
|
int arg;
|
||||||
if (parseIntInput(argv[0], &arg))
|
if (parseIntInput(argv[0], &arg))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
return (arg) ? 0 : 1;
|
return (arg) ? 0 : 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int part_fs_exists(){
|
int part_fs_exists(){
|
||||||
char *path;
|
char *path;
|
||||||
if (parseStringInput(argv[0], &path))
|
if (parseStringInput(argv[0], &path))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return fsutil_checkfile(path);
|
return fsutil_checkfile(path);
|
||||||
}
|
}
|
||||||
@@ -257,7 +263,7 @@ int part_ConnectMMC(){
|
|||||||
else if (!strcmp(arg, "EMUMMC"))
|
else if (!strcmp(arg, "EMUMMC"))
|
||||||
connect_mmc(EMUMMC);
|
connect_mmc(EMUMMC);
|
||||||
else
|
else
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -282,6 +288,7 @@ int part_Pause(){
|
|||||||
str_int_add("@BTN_DOWN", input->Ldown);
|
str_int_add("@BTN_DOWN", input->Ldown);
|
||||||
str_int_add("@BTN_LEFT", input->Lleft);
|
str_int_add("@BTN_LEFT", input->Lleft);
|
||||||
str_int_add("@BTN_RIGHT", input->Lright);
|
str_int_add("@BTN_RIGHT", input->Lright);
|
||||||
|
str_int_add("@JOYCONN", hidConnected());
|
||||||
|
|
||||||
return input->buttons;
|
return input->buttons;
|
||||||
}
|
}
|
||||||
@@ -289,11 +296,11 @@ int part_Pause(){
|
|||||||
int part_addstrings(){
|
int part_addstrings(){
|
||||||
char *combined, *left, *middle;
|
char *combined, *left, *middle;
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &middle))
|
if (parseStringInput(argv[1], &middle))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (argv[2][0] != '$')
|
if (argv[2][0] != '$')
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
combined = calloc(strlen(left) + strlen(middle) + 1, sizeof(char));
|
combined = calloc(strlen(left) + strlen(middle) + 1, sizeof(char));
|
||||||
sprintf(combined, "%s%s", left, middle);
|
sprintf(combined, "%s%s", left, middle);
|
||||||
@@ -306,7 +313,7 @@ int part_addstrings(){
|
|||||||
int part_setColor(){
|
int part_setColor(){
|
||||||
char *arg;
|
char *arg;
|
||||||
if (parseStringInput(argv[0], &arg))
|
if (parseStringInput(argv[0], &arg))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (!strcmp(arg, "RED"))
|
if (!strcmp(arg, "RED"))
|
||||||
currentcolor = COLOR_RED;
|
currentcolor = COLOR_RED;
|
||||||
@@ -323,7 +330,7 @@ int part_setColor(){
|
|||||||
else if (!strcmp(arg, "WHITE"))
|
else if (!strcmp(arg, "WHITE"))
|
||||||
currentcolor = COLOR_WHITE;
|
currentcolor = COLOR_WHITE;
|
||||||
else
|
else
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@@ -337,9 +344,9 @@ int part_fs_Move(){
|
|||||||
char *left, *right;
|
char *left, *right;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &right))
|
if (parseStringInput(argv[1], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
res = f_rename(left, right);
|
res = f_rename(left, right);
|
||||||
@@ -353,7 +360,7 @@ int part_fs_Delete(){
|
|||||||
char *arg;
|
char *arg;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &arg))
|
if (parseStringInput(argv[0], &arg))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
res = f_unlink(arg);
|
res = f_unlink(arg);
|
||||||
@@ -367,7 +374,7 @@ int part_fs_DeleteRecursive(){
|
|||||||
char *arg;
|
char *arg;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &arg))
|
if (parseStringInput(argv[0], &arg))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return fsact_del_recursive(arg);
|
return fsact_del_recursive(arg);
|
||||||
}
|
}
|
||||||
@@ -376,9 +383,9 @@ int part_fs_Copy(){
|
|||||||
char *left, *right;
|
char *left, *right;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &right))
|
if (parseStringInput(argv[1], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return fsact_copy(left, right, COPY_MODE_PRINT);
|
return fsact_copy(left, right, COPY_MODE_PRINT);
|
||||||
}
|
}
|
||||||
@@ -387,9 +394,9 @@ int part_fs_CopyRecursive(){
|
|||||||
char *left, *right;
|
char *left, *right;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &right))
|
if (parseStringInput(argv[1], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return fsact_copy_recursive(left, right);
|
return fsact_copy_recursive(left, right);
|
||||||
}
|
}
|
||||||
@@ -398,7 +405,7 @@ int part_fs_MakeDir(){
|
|||||||
char *arg;
|
char *arg;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &arg))
|
if (parseStringInput(argv[0], &arg))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
int res;
|
int res;
|
||||||
res = f_mkdir(arg);
|
res = f_mkdir(arg);
|
||||||
@@ -415,10 +422,10 @@ int part_fs_OpenDir(){
|
|||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &path))
|
if (parseStringInput(argv[0], &path))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (f_opendir(&dir, path))
|
if (f_opendir(&dir, path))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
isdirvalid = true;
|
isdirvalid = true;
|
||||||
str_int_add("@ISDIRVALID", isdirvalid);
|
str_int_add("@ISDIRVALID", isdirvalid);
|
||||||
@@ -437,7 +444,7 @@ int part_fs_CloseDir(){
|
|||||||
|
|
||||||
int part_fs_ReadDir(){
|
int part_fs_ReadDir(){
|
||||||
if (!isdirvalid)
|
if (!isdirvalid)
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (!f_readdir(&dir, &fno) && fno.fname[0]){
|
if (!f_readdir(&dir, &fno) && fno.fname[0]){
|
||||||
str_str_add("$FILENAME", fno.fname);
|
str_str_add("$FILENAME", fno.fname);
|
||||||
@@ -454,16 +461,16 @@ int part_setPrintPos(){
|
|||||||
int left, right;
|
int left, right;
|
||||||
|
|
||||||
if (parseIntInput(argv[0], &left))
|
if (parseIntInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (parseIntInput(argv[1], &right))
|
if (parseIntInput(argv[1], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (left > 78)
|
if (left > 78)
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (right > 42)
|
if (right > 42)
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
gfx_con_setpos(left * 16, right * 16);
|
gfx_con_setpos(left * 16, right * 16);
|
||||||
return 0;
|
return 0;
|
||||||
@@ -473,9 +480,9 @@ int part_stringcompare(){
|
|||||||
char *left, *right;
|
char *left, *right;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &right))
|
if (parseStringInput(argv[1], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return (strcmp(left, right)) ? 0 : 1;
|
return (strcmp(left, right)) ? 0 : 1;
|
||||||
}
|
}
|
||||||
@@ -483,11 +490,11 @@ int part_stringcompare(){
|
|||||||
int part_fs_combinePath(){
|
int part_fs_combinePath(){
|
||||||
char *combined, *left, *middle;
|
char *combined, *left, *middle;
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &middle))
|
if (parseStringInput(argv[1], &middle))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (argv[2][0] != '$')
|
if (argv[2][0] != '$')
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
combined = fsutil_getnextloc(left, middle);
|
combined = fsutil_getnextloc(left, middle);
|
||||||
|
|
||||||
@@ -500,9 +507,9 @@ int part_mmc_dumpPart(){
|
|||||||
char *left, *right;
|
char *left, *right;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &left))
|
if (parseStringInput(argv[0], &left))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &right))
|
if (parseStringInput(argv[1], &right))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (!strcmp(left, "BOOT")){
|
if (!strcmp(left, "BOOT")){
|
||||||
return emmcDumpBoot(right);
|
return emmcDumpBoot(right);
|
||||||
@@ -516,21 +523,21 @@ int part_mmc_restorePart(){
|
|||||||
char *path;
|
char *path;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &path))
|
if (parseStringInput(argv[0], &path))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
if (currentlyMounted < 0)
|
if (currentlyMounted < 0)
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return mmcFlashFile(path, currentlyMounted);
|
return mmcFlashFile(path, currentlyMounted, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
int part_fs_extractBisFile(){
|
int part_fs_extractBisFile(){
|
||||||
char *path, *outfolder;
|
char *path, *outfolder;
|
||||||
|
|
||||||
if (parseStringInput(argv[0], &path))
|
if (parseStringInput(argv[0], &path))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
if (parseStringInput(argv[1], &outfolder))
|
if (parseStringInput(argv[1], &outfolder))
|
||||||
return -1;
|
return INFUNC_FAIL;
|
||||||
|
|
||||||
return extract_bis_file(path, outfolder);
|
return extract_bis_file(path, outfolder);
|
||||||
}
|
}
|
||||||
@@ -544,6 +551,60 @@ int part_getPos(){
|
|||||||
return (int)f_tell(&scriptin);
|
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[] = {
|
str_fnc_struct functions[] = {
|
||||||
{"printf", part_printf, 255},
|
{"printf", part_printf, 255},
|
||||||
{"printInt", part_print_int, 1},
|
{"printInt", part_print_int, 1},
|
||||||
@@ -560,6 +621,9 @@ str_fnc_struct functions[] = {
|
|||||||
{"setColor", part_setColor, 1},
|
{"setColor", part_setColor, 1},
|
||||||
{"combineStrings", part_addstrings, 3},
|
{"combineStrings", part_addstrings, 3},
|
||||||
{"compareStrings", part_stringcompare, 2},
|
{"compareStrings", part_stringcompare, 2},
|
||||||
|
{"subString", part_subString, 4},
|
||||||
|
{"inputString", part_inputString, 3},
|
||||||
|
{"stringLength", part_strLen, 1},
|
||||||
{"invert", part_invert, 1},
|
{"invert", part_invert, 1},
|
||||||
{"fs_exists", part_fs_exists, 1},
|
{"fs_exists", part_fs_exists, 1},
|
||||||
{"fs_move", part_fs_Move, 2},
|
{"fs_move", part_fs_Move, 2},
|
||||||
@@ -584,6 +648,8 @@ str_fnc_struct functions[] = {
|
|||||||
{NULL, NULL, 0}
|
{NULL, NULL, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#pragma GCC pop_options
|
||||||
|
|
||||||
int run_function(char *func_name, int *out){
|
int run_function(char *func_name, int *out){
|
||||||
for (u32 i = 0; functions[i].key != NULL; i++){
|
for (u32 i = 0; functions[i].key != NULL; i++){
|
||||||
if (!strcmp(functions[i].key, func_name)){
|
if (!strcmp(functions[i].key, func_name)){
|
||||||
@@ -591,8 +657,8 @@ int run_function(char *func_name, int *out){
|
|||||||
continue;
|
continue;
|
||||||
|
|
||||||
*out = functions[i].value();
|
*out = functions[i].value();
|
||||||
return (*out < 0) ? -1 : 0;
|
return (*out == INFUNC_FAIL) ? -1 : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return -2;
|
||||||
}
|
}
|
||||||
@@ -16,15 +16,15 @@
|
|||||||
#include "variables.h"
|
#include "variables.h"
|
||||||
#include "../fs/fsreader.h"
|
#include "../fs/fsreader.h"
|
||||||
#include "../utils/utils.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 len = strlen(in);
|
||||||
u32 count = 0;
|
u32 count = 0;
|
||||||
|
|
||||||
for (u32 i = 0; i < len; i++) {
|
for (u32 i = 0; i < len; i++) {
|
||||||
if (in[i] == '"'){
|
if (in[i] == '"'){
|
||||||
i++;
|
while (in[++i] != '"'){
|
||||||
while (in[i] != '"'){
|
|
||||||
i++;
|
|
||||||
if (i >= len)
|
if (i >= len)
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@@ -32,54 +32,55 @@ u32 countchars(char* in, char target) {
|
|||||||
if (in[i] == target)
|
if (in[i] == target)
|
||||||
count++;
|
count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
char **argv = NULL;
|
char **argv = NULL;
|
||||||
u32 argc;
|
u32 argc;
|
||||||
u32 splitargs(char* in) {
|
u32 splitargs(const char* in) {
|
||||||
// arg like '5, "6", @arg7'
|
// 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;
|
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));
|
|
||||||
|
|
||||||
|
argv = calloc(count + 1, sizeof(char*));
|
||||||
for (i = 0; i < len && curcount < count; i++) {
|
|
||||||
if (in[i] == ',') {
|
while (i < len && curcount < count) {
|
||||||
curcount++;
|
if (in[i] == ' ' || in[i] == ','){
|
||||||
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] == '"') {
|
|
||||||
i++;
|
i++;
|
||||||
while (in[i] != '"') {
|
continue;
|
||||||
argv[curcount][current++] = in[i++];
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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;
|
FIL scriptin;
|
||||||
@@ -201,17 +202,6 @@ void mainparser(){
|
|||||||
getnextvalidchar();
|
getnextvalidchar();
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
if (currentchar == '?'){
|
|
||||||
char *jumpname;
|
|
||||||
jumpname = readtilchar(';', ' ');
|
|
||||||
getnextchar();
|
|
||||||
str_jmp_add(jumpname, f_tell(&scriptin));
|
|
||||||
getfollowingchar('\n');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
*/
|
|
||||||
|
|
||||||
functionparser();
|
functionparser();
|
||||||
|
|
||||||
res = run_function(funcbuff, &out);
|
res = run_function(funcbuff, &out);
|
||||||
@@ -219,7 +209,16 @@ void mainparser(){
|
|||||||
printerrors = true;
|
printerrors = true;
|
||||||
//gfx_printf("%s|%s|%d", funcbuff, argv[0], argc);
|
//gfx_printf("%s|%s|%d", funcbuff, argv[0], argc);
|
||||||
//btn_wait();
|
//btn_wait();
|
||||||
gfx_errDisplay("mainparser", ERR_PARSE_FAIL, f_tell(&scriptin));
|
int lineNumber = 1;
|
||||||
|
u64 end = f_tell(&scriptin);
|
||||||
|
f_lseek(&scriptin, 0);
|
||||||
|
|
||||||
|
while (f_tell(&scriptin) < end && !f_eof(&scriptin)){
|
||||||
|
if (getnextchar() == '\n')
|
||||||
|
lineNumber++;
|
||||||
|
}
|
||||||
|
|
||||||
|
gfx_errDisplay((res == -1) ? funcbuff : "run_function", (res == -1) ? ERR_IN_FUNC : ERR_SCRIPT_LOOKUP_FAIL, lineNumber);
|
||||||
forceExit = true;
|
forceExit = true;
|
||||||
//gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]);
|
//gfx_printf("Func: %s\nArg1: %s\n", funcbuff, argv[0]);
|
||||||
}
|
}
|
||||||
@@ -287,6 +286,7 @@ void runScript(char *path){
|
|||||||
//add builtin vars
|
//add builtin vars
|
||||||
str_int_add("@EMUMMC", emu_cfg.enabled);
|
str_int_add("@EMUMMC", emu_cfg.enabled);
|
||||||
str_int_add("@RESULT", 0);
|
str_int_add("@RESULT", 0);
|
||||||
|
str_int_add("@JOYCONN", hidConnected());
|
||||||
str_str_add("$CURRENTPATH", currentpath);
|
str_str_add("$CURRENTPATH", currentpath);
|
||||||
|
|
||||||
//str_int_printall();
|
//str_int_printall();
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#define INFUNC_FAIL (int)0xC0000000
|
||||||
|
|
||||||
void runScript(char *path);
|
void runScript(char *path);
|
||||||
void skipbrackets();
|
void skipbrackets();
|
||||||
void getfollowingchar(char end);
|
void getfollowingchar(char end);
|
||||||
41
source/tegraexplorer/utils/menuUtils.c
Normal file
41
source/tegraexplorer/utils/menuUtils.c
Normal 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;
|
||||||
|
}
|
||||||
8
source/tegraexplorer/utils/menuUtils.h
Normal file
8
source/tegraexplorer/utils/menuUtils.h
Normal 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);
|
||||||
@@ -17,6 +17,7 @@
|
|||||||
#include "../fs/fsutils.h"
|
#include "../fs/fsutils.h"
|
||||||
#include "../../mem/heap.h"
|
#include "../../mem/heap.h"
|
||||||
#include "../utils/utils.h"
|
#include "../utils/utils.h"
|
||||||
|
#include "../fs/nca.h"
|
||||||
|
|
||||||
extern bool sd_mount();
|
extern bool sd_mount();
|
||||||
extern void sd_unmount();
|
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;
|
DIR dir;
|
||||||
FILINFO fno;
|
FILINFO fno;
|
||||||
bool fail = false;
|
bool fail = false;
|
||||||
@@ -107,6 +110,22 @@ int dumpfirmware(int mmc){
|
|||||||
connect_mmc(mmc);
|
connect_mmc(mmc);
|
||||||
mount_mmc("SYSTEM", 2);
|
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("PKG1 version: %d\n", pkg1.ver);
|
||||||
|
|
||||||
gfx_printf("Creating folders...\n");
|
gfx_printf("Creating folders...\n");
|
||||||
@@ -115,7 +134,24 @@ int dumpfirmware(int mmc){
|
|||||||
|
|
||||||
sdbase = calloc(32 + strlen(pkg1.id), sizeof(char));
|
sdbase = calloc(32 + strlen(pkg1.id), sizeof(char));
|
||||||
sprintf(sdbase, "sd:/tegraexplorer/Firmware/%d (%s)", pkg1.ver, pkg1.id);
|
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);
|
f_mkdir(sdbase);
|
||||||
|
|
||||||
if ((ret = f_opendir(&dir, sysbase)))
|
if ((ret = f_opendir(&dir, sysbase)))
|
||||||
@@ -127,16 +163,39 @@ int dumpfirmware(int mmc){
|
|||||||
printerrors = 0;
|
printerrors = 0;
|
||||||
|
|
||||||
while(!f_readdir(&dir, &fno) && fno.fname[0] && !fail){
|
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);
|
utils_copystring(fsutil_getnextloc(sysbase, fno.fname), &syspathtemp);
|
||||||
|
|
||||||
if (fno.fattrib & AM_DIR){
|
if (fno.fattrib & AM_DIR){
|
||||||
utils_copystring(fsutil_getnextloc(syspathtemp, "00"), &syspath);
|
utils_copystring(fsutil_getnextloc(syspathtemp, "00"), &syspath);
|
||||||
free(syspathtemp);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
syspath = syspathtemp;
|
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);
|
ret = fsact_copy(syspath, sdpath, 0);
|
||||||
|
|
||||||
gfx_printf("%d %s\r", ++amount, fno.fname);
|
gfx_printf("%d %s\r", ++amount, fno.fname);
|
||||||
@@ -145,7 +204,9 @@ int dumpfirmware(int mmc){
|
|||||||
fail = true;
|
fail = true;
|
||||||
|
|
||||||
free(sdpath);
|
free(sdpath);
|
||||||
free(syspath);
|
free(syspathtemp);
|
||||||
|
if (syspath != syspathtemp)
|
||||||
|
free(syspath);
|
||||||
}
|
}
|
||||||
|
|
||||||
printerrors = 1;
|
printerrors = 1;
|
||||||
@@ -159,7 +220,7 @@ int dumpfirmware(int mmc){
|
|||||||
|
|
||||||
return fail;
|
return fail;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
void dumpusersaves(int mmc){
|
void dumpusersaves(int mmc){
|
||||||
connect_mmc(mmc);
|
connect_mmc(mmc);
|
||||||
mount_mmc("USER", 2);
|
mount_mmc("USER", 2);
|
||||||
@@ -180,14 +241,15 @@ void dumpusersaves(int mmc){
|
|||||||
gfx_printf("Press any key to continue");
|
gfx_printf("Press any key to continue");
|
||||||
hidWait();
|
hidWait();
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
int format(int mode){
|
int format(int mode){
|
||||||
gfx_clearscreen();
|
gfx_clearscreen();
|
||||||
int res;
|
int res;
|
||||||
bool fatalerror = false;
|
bool fatalerror = false;
|
||||||
DWORD plist[] = {666, 61145088};
|
DWORD plist[] = {666, 61145088, 0, 0};
|
||||||
u32 timer, totalsectors, alignedsectors, extrasectors;
|
u32 timer, totalsectors, alignedsectors, extrasectors;
|
||||||
BYTE work[FF_MAX_SS];
|
u8 *work;
|
||||||
DWORD clustsize = 32768;
|
DWORD clustsize = 32768;
|
||||||
BYTE formatoptions = 0;
|
BYTE formatoptions = 0;
|
||||||
formatoptions |= (FM_FAT32);
|
formatoptions |= (FM_FAT32);
|
||||||
@@ -198,6 +260,15 @@ int format(int mode){
|
|||||||
timer = get_tmr_s();
|
timer = get_tmr_s();
|
||||||
totalsectors = sd_storage.csd.capacity;
|
totalsectors = sd_storage.csd.capacity;
|
||||||
|
|
||||||
|
gfx_printf("Initializing...\n");
|
||||||
|
|
||||||
|
work = calloc(BUFSIZE, sizeof(BYTE));
|
||||||
|
|
||||||
|
if (work == NULL){
|
||||||
|
gfx_errDisplay("format", ERR_MEM_ALLOC_FAILED, 0);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
if (mode == FORMAT_EMUMMC){
|
if (mode == FORMAT_EMUMMC){
|
||||||
if (totalsectors < 83886080){
|
if (totalsectors < 83886080){
|
||||||
gfx_printf("%kYou seem to be running this on a <=32GB SD\nNot enough free space for emummc!", COLOR_RED);
|
gfx_printf("%kYou seem to be running this on a <=32GB SD\nNot enough free space for emummc!", COLOR_RED);
|
||||||
@@ -219,7 +290,7 @@ int format(int mode){
|
|||||||
|
|
||||||
if (!fatalerror){
|
if (!fatalerror){
|
||||||
gfx_printf("\nPartitioning SD...\n");
|
gfx_printf("\nPartitioning SD...\n");
|
||||||
res = f_fdisk(0, plist, &work);
|
res = f_fdisk(0, plist, work);
|
||||||
|
|
||||||
if (res){
|
if (res){
|
||||||
gfx_printf("%kf_fdisk returned %d!\n", COLOR_RED, res);
|
gfx_printf("%kf_fdisk returned %d!\n", COLOR_RED, res);
|
||||||
@@ -231,7 +302,7 @@ int format(int mode){
|
|||||||
|
|
||||||
if (!fatalerror){
|
if (!fatalerror){
|
||||||
gfx_printf("\n\nFormatting Partition1...\n");
|
gfx_printf("\n\nFormatting Partition1...\n");
|
||||||
res = f_mkfs("0:", formatoptions, clustsize, &work, sizeof work);
|
res = f_mkfs("0:", formatoptions, clustsize, work, BUFSIZE * sizeof(BYTE));
|
||||||
|
|
||||||
if (res){
|
if (res){
|
||||||
gfx_printf("%kf_mkfs returned %d!\n", COLOR_RED, res);
|
gfx_printf("%kf_mkfs returned %d!\n", COLOR_RED, res);
|
||||||
@@ -241,6 +312,8 @@ int format(int mode){
|
|||||||
gfx_printf("Smells like a formatted SD\n\n");
|
gfx_printf("Smells like a formatted SD\n\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
free(work);
|
||||||
|
|
||||||
sd_unmount();
|
sd_unmount();
|
||||||
|
|
||||||
if (!fatalerror){
|
if (!fatalerror){
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
#include "../../utils/types.h"
|
||||||
|
|
||||||
void displayinfo();
|
void displayinfo();
|
||||||
void displaygpio();
|
void displaygpio();
|
||||||
int format(int mode);
|
int format(int mode);
|
||||||
int dumpfirmware(int mmc);
|
int dumpfirmware(int mmc, bool daybreak);
|
||||||
void dumpusersaves(int mmc);
|
|
||||||
@@ -192,4 +192,14 @@ char *utils_InputText(char *start, int maxLen){
|
|||||||
}
|
}
|
||||||
|
|
||||||
return buff;
|
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;
|
||||||
}
|
}
|
||||||
@@ -23,4 +23,5 @@ typedef struct _bmp_t
|
|||||||
int utils_mmcMenu();
|
int utils_mmcMenu();
|
||||||
void utils_copystring(const char *in, char **out);
|
void utils_copystring(const char *in, char **out);
|
||||||
char *utils_InputText(char *start, int maxLen);
|
char *utils_InputText(char *start, int maxLen);
|
||||||
void utils_takeScreenshot();
|
void utils_takeScreenshot();
|
||||||
|
char *utils_copyStringSize(const char *in, int size);
|
||||||
Reference in New Issue
Block a user